Browse Source

initial commit

richarddobson 3 years ago
parent
commit
f4e1ed42eb
42 changed files with 39869 additions and 0 deletions
  1. 32 0
      dev/tabedit/CMakeLists.txt
  2. 152 0
      dev/tabedit/columns.c
  3. 3157 0
      dev/tabedit/columns0.c
  4. 1270 0
      dev/tabedit/columns1.c
  5. 251 0
      dev/tabedit/columns2.c
  6. 148 0
      dev/tabedit/columns3.c
  7. 1840 0
      dev/tabedit/columns4.c
  8. 4510 0
      dev/tabedit/columns5.c
  9. 1709 0
      dev/tabedit/columns6.c
  10. 245 0
      dev/tabedit/getcol.c
  11. 359 0
      dev/tabedit/putcol.c
  12. 1742 0
      dev/tabedit/vectors.c
  13. 20 0
      dev/texture/CMakeLists.txt
  14. 891 0
      dev/texture/ap_texture.c
  15. 234 0
      dev/texture/main.c
  16. BIN
      dev/texture/prevsrc/prev-src.zip
  17. 889 0
      dev/texture/prevsrc/prev-src/ap_texture.c
  18. 236 0
      dev/texture/prevsrc/prev-src/main.c
  19. 194 0
      dev/texture/prevsrc/prev-src/texperm.c
  20. 1527 0
      dev/texture/prevsrc/prev-src/texprepro.c
  21. 223 0
      dev/texture/prevsrc/prev-src/texture1.c
  22. 520 0
      dev/texture/prevsrc/prev-src/texture2.c
  23. 2362 0
      dev/texture/prevsrc/prev-src/texture3.c
  24. 1477 0
      dev/texture/prevsrc/prev-src/texture4.c
  25. 623 0
      dev/texture/prevsrc/prev-src/texture5.c
  26. 191 0
      dev/texture/texperm.c
  27. 1661 0
      dev/texture/texprepro.c
  28. 220 0
      dev/texture/texture1.c
  29. 517 0
      dev/texture/texture2.c
  30. 2360 0
      dev/texture/texture3.c
  31. 1474 0
      dev/texture/texture4.c
  32. 627 0
      dev/texture/texture5.c
  33. 891 0
      dev/texture/v8/ap_texture.c
  34. 234 0
      dev/texture/v8/main.c
  35. 191 0
      dev/texture/v8/texperm.c
  36. 1661 0
      dev/texture/v8/texprepro.c
  37. 33 0
      dev/texture/v8/texture.h
  38. 220 0
      dev/texture/v8/texture1.c
  39. 517 0
      dev/texture/v8/texture2.c
  40. 2360 0
      dev/texture/v8/texture3.c
  41. 1474 0
      dev/texture/v8/texture4.c
  42. 627 0
      dev/texture/v8/texture5.c

+ 32 - 0
dev/tabedit/CMakeLists.txt

@@ -0,0 +1,32 @@
+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(columns columns0.c columns1.c columns2.c columns3.c
+                       columns4.c columns5.c columns6.c)
+target_link_libraries(columns cdp2k sfsys ${EXTRA_LIBRARIES})
+my_install(columns)
+
+add_executable(vectors vectors.c)
+target_link_libraries(vectors cdp2k sfsys ${EXTRA_LIBRARIES})
+my_install(vectors)
+
+
+add_executable(getcol getcol.c)
+target_link_libraries(getcol cdp2k sfsys ${EXTRA_LIBRARIES})
+my_install(getcol)
+
+
+add_executable(putcol putcol.c)
+target_link_libraries(putcol cdp2k sfsys ${EXTRA_LIBRARIES})
+my_install(putcol)

+ 152 - 0
dev/tabedit/columns.c

@@ -0,0 +1,152 @@
+/*
+ * 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 <columns.h>
+
+void do_shuffle(int, int);
+
+/**************************** M_REPOS ********************************/
+
+int m_repos(int j)
+{
+	int n, m, k=cnt, OK, is_set = 0;
+	int zib = -ifactor, zab = ifactor;
+	for(n=0;n<k;n++) {
+		OK = 1;
+		if(n>j && !is_set) {
+			zib++;
+			zab++;
+			is_set = 1;
+		}
+		for(m=zib;m<zab;m++) {
+			if(n+m<0)	  continue;
+			if(n+m>=cnt)  break;
+			if(flteq(fmod(number[j],12.0),fmod(number[n+m],12.0))) {
+				OK = 0;
+				break;
+			}
+		}
+		if(OK) {
+		   do_shuffle(n,j);
+		   if(j>n)
+			   return(1);	/* list shuffled forward */
+		   return(0);		/* list not shuffled forward */
+		}
+	}
+	return(-1);
+}	   
+
+/**************************** F_REPOS ********************************/
+
+int f_repos(int j)
+{
+	int n, m, k=cnt-ifactor, OK, is_set = 0;
+	double interval;
+	int zib = -ifactor, zab = ifactor;
+	for(n=0;n<k;n++) {
+		OK = 1;
+		if(n>j && !is_set) {
+			zib++;
+			zab++;
+			is_set = 1;
+		}
+		for(m=zib;m<zab;m++) {
+			if(n+m<0)	  continue;
+			if(n+m>=cnt)  break;
+			interval = log(number[j]/number[n+m])/LOG_2_TO_BASE_E;
+			interval = fmod(fabs(interval),1.0);
+			if(interval<ONEMAX || interval>ONEMIN) {
+				OK = 0;
+				break;
+			}
+		}
+		if(OK) {
+		   do_shuffle(n,j);
+		   if(j>n)
+			   return(1);	/* list shuffled forward */
+		   return(0);		/* list not shuffled forward */
+		}
+	}
+	return(-1);
+}	   
+
+/**************************** DO_SHUFFLE ******************************/
+
+void do_shuffle(int n,int j)
+{
+	int m;
+	double keep = number[j];
+	if(j > n) {
+		for(m=j;m>n;m--)
+		   number[m] = number[m-1];
+	} else {
+		for(m=j;m<n;m++)
+			number[m] = number[m+1];
+	}
+	number[n] = keep;
+}
+
+/************************* CHECK_FOR_CONDITIONAL ************************/
+
+void check_for_conditional(int *argc,char *argv[])
+{
+	int n;
+	char less_than, greater_than;
+	int condit_set = 0;
+
+	if(sloom) {
+		less_than = '@';
+		greater_than = '+';
+	} else {
+		less_than = '{';
+		greater_than = '}';
+	}
+	for(n=1;n<*argc;n++) {
+		if((condit = *argv[n])==less_than || condit==greater_than) {
+			if(condit==less_than)
+				condit = '<';
+			else
+				condit = '>';
+			argv[n]++;
+			if(sscanf(argv[n],"%lf",&thresh)!=1) {
+				sprintf(errstr,"Cannot read conditional value.\n");
+				do_error();
+			}
+			while(n<(*argc)-1) {
+				*(argv+n) = *(argv+n+1);
+				n++;
+			}
+			(*argc)--;
+			condit_set = 1;
+		}
+	}
+	if(!condit_set)
+		condit = 0;
+	if(*argc < 4) {
+		sprintf(errstr,"Too few arguments on commandline.\n");
+		do_error();
+	}
+}

+ 3157 - 0
dev/tabedit/columns0.c

@@ -0,0 +1,3157 @@
+/*
+ * 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
+ *
+ */
+
+
+
+/* Manipulate or Generate columns of numbers */
+
+#include <columns.h>
+#include <srates.h>
+#include <string.h>
+
+#define STACK_WITH_OVERLAP 1111
+
+void	usage(void), logo(void);
+
+static void read_flags(char *,char *);
+static void do_string_params(char *argv[],int pcnt);
+static void read_data(char *startarg,char *endarg,int *ro);
+static void do_help(char *str);
+static int option_takes_NO_data_but_has_extra_params(char *agv);
+static int option_takes_data_and_has_extra_params(char *agv);
+static void check_exceptional_processes(int ro,int argc);
+static void handle_multifile_processes_and_the_output_file(int argc,char flag,int ro,char **argv);
+
+static void cant_read_numeric_value(char flag,int ro);
+static void cant_read_numeric_value_with_flag_only(char flag);
+static void unknown_flag_only(char flag);
+static void unknown_flag(char flag,int ro);
+static void cannot_read_flags(char *flagstr);
+static void flag_takes_no_params(char flag,int ro);
+static void flag_only_takes_no_params(char flag);
+static void unknown_flag_or_bad_param(void);
+static void no_value_with_flag(char flag,int ro);
+static void no_value_with_flag_only(char flag);
+static void no_value_required_with_flag(char flag,int ro);
+static void no_value_required_with_flag_only(char flag);
+static void read_flags_data_error(char *str);
+static void unknown_flag_string(char *flagstr);
+
+static void check_for_columnextract(char *argv1,int *argc,char *argv[]);
+static int valid_call_for_multicol_input(char flag,int ro);
+static int noro(int ro);
+static void output_multicol_data();
+
+int	cnt = 0, firstcnt, arraysize = BIGARRAY, infilecnt, outfilecnt, colcnt, thecol, allcols = 1;
+double 	*number, *permm, *permmm, factor, scatter, *pos, *outcoldata;
+int outcoldatacnt = 0;
+FILE 	**fp;
+char 	temp[20000], flag, *filename, *thisfilename, string[200];
+int	ro = 0, ifactor = 0, len, condit = 0;
+double thresh;
+int *file_cnt; 
+int sloom = 0;
+int sloombatch = 0;
+
+char errstr[400];
+char srcfile[2000],goalfile[2000];
+
+#define TOO_BIG_ARRAY (100000)
+void reorganise_extra_params(char *agv,int argc,char *argv[]);
+const char* cdp_version = "7.1.0";
+
+int main(int argc,char *argv[])
+{
+	int extra_params = 0, k = 0, *perm = (int *)0;
+	char *agv = (char *)0;
+	char *p;
+	goalfile[0] = ENDOFSTR;
+	if(argc==2 && (strcmp(argv[1],"--version") == 0)) {
+		fprintf(stdout,"%s\n",cdp_version);
+		fflush(stdout);
+		return 0;
+	}
+	if(argc < 2)
+		usage();
+	if(!strcmp(argv[1],"#")) {
+		sloom = 1;
+		argv++;
+		argc--;
+	} else if (!strcmp(argv[1],"##")) {
+		p = argv[0];
+		argc--;
+		argv++;
+		argv[0] = p;
+		sloombatch = 1;
+	}
+    initrand48();
+    number = (double *)exmalloc(arraysize * sizeof(double));
+    fp     = (FILE **)exmalloc(2 * sizeof(FILE *));
+    fp[1]  = stderr;
+	if(!sloom && !sloombatch) {
+    	if(argc==2)
+			do_help(argv[1]);
+	}
+    if(argc<3)
+		usage();
+    check_for_columnextract(argv[1],&argc,argv);
+    check_for_conditional(&argc,argv);
+	agv = argv[argc-1];
+	if(!sloom) {
+		if(allcols > 1)
+			read_data("__temp.txt",argv[argc-1],&ro);
+		else
+			read_data(argv[1],argv[argc-1],&ro);
+	    read_flags(agv,argv[2]);
+	} else {
+		if(option_takes_NO_data_but_has_extra_params(agv))
+			extra_params = 1;
+		else {
+			if(allcols > 1)
+				read_data("__temp.txt",argv[argc-1],&ro);
+			else
+				read_data(argv[1],argv[argc-1],&ro);
+		}
+		if(option_takes_data_and_has_extra_params(agv)) {	 
+			extra_params = 1;
+			read_flags(agv,argv[2]);
+		}
+		if(!extra_params)
+		    read_flags(agv,argv[2]);
+	}
+	check_exceptional_processes(ro,argc);
+
+	if(!sloom) {
+	    if(argc>=4)
+			handle_multifile_processes_and_the_output_file(argc,flag,ro,argv);
+	    if((number=(double *)exrealloc((char *)number,(cnt+1)*sizeof(double)))==NULL) {
+			fprintf(stdout, "ERROR: Out of memory\n");
+			fflush(stdout);
+			exit(1);		/* EXTRA ONE IS TEMPORARY FOR QIKSORT INDEXING PROBLEM !! */
+		}
+	} else {
+	    if(argc>=4 && !extra_params)
+			handle_multifile_processes_and_the_output_file(argc,flag,ro,argv);
+		else if(flag =='K' && ro == 'b') {
+			handle_multifile_processes_and_the_output_file(argc,flag,ro,argv);
+		}
+		if(extra_params)
+			reorganise_extra_params(agv,argc,argv);
+		else if((number=(double *)exrealloc((char *)number,(cnt+1)*sizeof(double)))==NULL) {
+			fprintf(stdout, "ERROR: Out of memory\n");
+			fflush(stdout);
+			exit(1);		/* EXTRA ONE IS TEMPORARY FOR QIKSORT INDEXING PROBLEM !! */
+		}
+	}
+    switch(flag) {
+    case('A'): 
+		switch(ro) {
+		case('d'):	accel_durations();			break; /* Ad */
+		case('e'):	abutt();					break; /* Ae */
+		case('s'):	alphabetic_sort();			break; /* As */
+		case('t'):	accel_time_seq();			break; /* At */
+		default:	approx_vals();				break; /* A */
+		}
+		break;
+    case('a'):	
+		switch(ro) {
+		case(0):	add();						break; /* a */
+		case('o'):	ascending_order();			break; /* ao */
+		case('T'):	append_text(0);				break; /* aT */
+		case('X'):	append_text(1);				break; /* aX */
+		}
+		break;
+    case('B'):		plain_bob();				break; /* B */
+    case('b'):
+		switch(ro) {
+		case('b'):	band_cut();									break; /* bb */
+		case('g'):	reduce_to_bound();		print_numbers();	break; /* bg */
+		case('l'):	increase_to_bound();	print_numbers();	break; /* bl */
+		}
+	   	break;
+    case('C'):
+    	switch(ro) {
+		case(ENDOFSTR): concatenate_files(argv[1]);		break; /* C */
+		case('c'):		concatenate_files_cyclically(argv[1]);		break; /* Cc */
+		case('a'): 		cyclic_select('a');				break; /* Ca */
+		case('m'): 		cyclic_select('m');				break; /* Cm */
+		}
+		break;
+    case('c'):
+	    switch(ro) {
+		case(ENDOFSTR):	count_items(argv[1]);			break; /* c  */
+		case('c'): 		columnate();					break; /* cc */
+		case('l'): 		count_items(argv[1]);			break; /* cl */
+		case('s'): 		cosin_spline();					break; /* cs */
+		case('t'): 		cut_table_at_time();			break; /* ct */
+		}
+		break;
+    case('D'):
+		switch(ro) {
+	    case('B'):		db_to_level(0);				break; /* DB */
+	    case('s'):		db_to_level(1);				break; /* Ds */
+		}
+		break;
+    case('d'):
+		switch(ro) {
+		case(ENDOFSTR): divide_list();			break; /* d */
+		case('b'):	level_to_db(0);				break; /* db */
+		case('d'):	duplicate_values_stepped();	break; /* dd */
+		case('g'):	distance_from_grid();		break; /* dg */
+		case('h'):	delay_to_pitch(0);			break; /* dh */
+		case('i'):	delete_small_intervals();	break; /* di */
+		case('l'):	duplicate_list();			break; /* dl */
+		case('L'):	duplicate_list_at_step();	break; /* dL */
+		case('M'):	delay_to_pitch(1);			break; /* dM */
+		case('o'):	duplicate_octaves();		break; /* do */
+		case('O'):	duplicate_octfrq();			break; /* dO */
+		case('v'):	duplicate_values();			break; /* dv */
+		}
+        break;
+    case('E'):	vals_end_to_end_in_2_cols();	break; /* E */
+	case('e'):
+		switch(ro) {
+		case(ENDOFSTR):	eliminate_equivalents();	print_numbers();	break; /* e */
+		case('a'):	env_append(); 					break; /* ea */
+		case('b'):	eliminate_dupltext();			break; /* eb */
+		case('d'):	eliminate_duplicates();			print_numbers();	break; /* ed */
+		case('e'):	eliminate_even_items();			print_numbers();	break; /* ee */
+		case('f'):	expand_table_dur_by_factor();						break; /* ef */
+		case('g'):	eliminate_greater_than();		print_numbers();	break; /* eg */
+		case('i'):	env_superimpos(INVERT,MULT); 	break; /* ei */
+		case('l'):	eliminate_less_than();			print_numbers();	break; /* el */
+		case('L'):	list_warp();					break; /* eL */
+		case('m'):	env_superimpos(0,ENVMAX);		break; /* em */
+		case('Q'):	seqtime_warp();					break; /* eQ */
+		case('s'):	env_superimpos(0,MULT);			break; /* es */
+		case('t'):	expand_table_to_dur();			break; /* et */
+		case('v'):	expand_table_vals_by_factor();	break; /* ev */
+		case('w'):	time_warp();					break; /* ew */
+		case('W'):	brktime_warp();					break; /* eW */
+		case('x'):	extend_table_to_dur();			break; /* ex */
+		case('X'):	brkval_warp();					break; /* eX */
+		case('Y'):	brktime_owarp();				break; /* eY */
+		case('A'):	env_superimpos(0,ADD);			break; /* eA */
+		case('D'):	env_del_inv();					break; /* eD */
+		case('P'):	env_plateau();					break; /* eP */
+		case('S'):	env_superimpos(0,SUBTRACT);		break; /* eS */
+		}
+	   	break;
+    case('F'):	
+		switch(ro) {
+		case(ENDOFSTR): format_vals();			break; /* F */	 /* RWD */
+		case('r'):      column_format_vals();	break; /* Fr */	
+		case('f'):      format_strs();			break; /* Ff */	
+		case('R'):      column_format_strs();	break; /* FR */	
+		}
+		break;
+	case('f'):
+	    switch(ro) {
+	    case('r'):		remove_frq_pitchclass_duplicates();    	break; /* fr */
+	    case('l'):		floor_vals();    						break; /* fl */
+	    case('t'):		pitchtotext(0);    						break; /* ft */
+		}
+		break;
+    case('G'):		group();				break; /* G */
+    case('g'):
+		switch(ro) {
+		case(ENDOFSTR):	greatest();				break; /* g */
+		case('s'):		multiply(1);			break; /* gs */
+		case('a'):		cumuladd();				break; /* ga */
+		}
+		break;
+	case('H'):
+		switch(ro) {
+		case(ENDOFSTR):	generate_harmonics();	break;	/* H */
+		case('g'):		group_harmonics();		break;	/* Hg */
+ 		case('r'):		get_harmonic_roots();	break;  /* Hr */
+		}
+		break;
+    case('h'):
+		switch(ro) {
+		case('d'):		pitch_to_delay(0);		break; /* hd */
+		case('M'):		hz_to_midi();			break; /* hM */
+		}
+		break;
+    case('I'):
+		switch(ro) {
+		case(ENDOFSTR):	print_numbers();			break; /* I */
+		case('r'):		interval_to_ratio(1,0);		break; /* Ir */
+		case('v'):		invert_normd_env();			break; /* Iv */
+		case('V'):		interp_n_vals();			break; /* IV */
+		}
+		break;
+    case('i'):
+		switch(ro) {
+		case(ENDOFSTR):	get_intervals();			break; /* i */
+		case('r'):	repeat_intervals();				break; /* ir */
+		case('='):	make_equal_intevals_btwn_given_vals();	break; /* i= */
+		case('e'):	create_equal_vals();			break; /* ie */
+		case('c'):	create_intervals();				break; /* ic */
+		case('C'):	create_intervals_from_base();	break; /* iC */
+		case('R'):	create_ratios_from_base();		break; /* iR */
+		case('p'):	insert_intermediate_valp();		break; /* ip */
+		case('Q'):	create_equal_steps();			break; /* iQ */
+		case('a'):	change_value_of_intervals();	break; /* ia */
+		case('m'):	change_value_of_intervals();	break; /* im */
+		case('v'):	get_intermediate_values();		break; /* iv */
+		case('V'):	insert_intermediate_values();	break; /* iV */
+		case('M'):	motivically_invert_midi();		break; /* iM */
+		case('h'):	motivically_invert_hz();		break; /* ih */
+		case('l'):										   /* il */
+		case('L'):	interval_limit();				break; /* iL */
+		}
+		break;
+    case('J'): 
+    	switch(ro) {
+		case(0):	join_many_files_as_columns(argv[1],0);	break; /* J */
+		case('j'):	join_many_files_as_columns(argv[1],1);	break; /* Jj */
+		}
+		break;
+    case('j'):
+    	switch(ro) {
+		case(0):	join_files_as_rows();			break; /* j */
+		case('j'):	join_many_files_as_rows();		break; /* jj */
+		}
+		break;
+    case('k'):		
+	    switch(ro) {
+		case('A'):		kill_path();				break;	/* kA */
+		case('B'):		kill_extension();			break;	/* kB */
+		case('C'):		kill_path_and_extension();	break;	/* kC */
+		case('T'):		kill_text(0);				break;	/* kT */
+		case('X'):		kill_text(1);				break;	/* kX */
+		case('Y'):		kill_text(2);				break;	/* kY */
+		}
+		break;
+    case('K'):		
+		switch(ro) {
+		case('a'): ta_reverse_sequence(1);		break;	/* Ka */
+		case('A'): a_reverse_sequence(1);		break;	/* KA */
+		case('b'): abut_sequences(1);			break;	/* Kb */
+		case('c'): compress_sequence(1);		break;	/* Kc */
+		case('E'): p_expandset_sequence(1);		break;	/* KE */
+		case('I'): p_invertset_sequence(1);		break;	/* KI */
+		case('i'): p_invert_sequence(1);		break;	/* Ki */
+		case('l'): loop_sequence(1);			break;	/* Kl */
+		case('m'): uptempo_sequence(1);			break;	/* Km */
+		case('M'): accel_sequence(1);			break;	/* KM */
+		case('P'): p_reverse_sequence(1);		break;	/* KP */
+		case('r'): t_reverse_sequence(1);		break;	/* Kr */
+		case('R'): pa_reverse_sequence(1);		break;	/* KR */
+		case('t'): transpose_sequence(1);		break;	/* Kt */
+		case('T'): tp_reverse_sequence(1);		break;	/* KT */
+		case('Z'): tpa_reverse_sequence(1);		break;	/* KZ */
+		}
+		break;
+    case('L'):		log_equal_divisions();			break; /* L */
+    case('l'):
+	    switch(ro) {
+	    case(ENDOFSTR):	least();					break; /* l */
+		case('i'):		limit_vals();				break;	/* li */
+		case('v'):		limit_table_val_range();	break;	/* lv */
+		}
+		break;
+    case('M'):
+		switch(ro) {
+		case(ENDOFSTR):	find_mean();				break; /* M */
+		case('d'):		pitch_to_delay(1);			break; /* Md */
+		case('h'):		midi_to_hz();				break; /* Mh */
+		case('m'):	major_to_minor();				break; /* Mm */
+		case('r'):	remove_midi_pitchclass_duplicates();	break; /* Mr */
+		case('t'):	pitchtotext(1);					break; /* Mt */
+		}
+    	break;
+    case('m'):		
+		switch(ro) {
+		case(0):	multiply(0);				break; /* m */
+		case('g'):	mark_greater_than();		break; /* mg */
+		case('l'):	mark_less_than();			break; /* ml */
+		case('m'):	mark_multiples();			break; /* mm */
+		case('M'):	minor_to_major();			break; /* mM */
+		case('e'):	mark_event_groups();		break; /* me */
+		case('i'):	min_interval(0);			break; /* mi */
+		case('I'):	min_interval(1);			break; /* mI */
+		}
+		break;
+    case('N'):
+    	switch(ro) {
+		case('r'):	rotate_partition_values_to_files();	break; /* Nr */
+    	default:	partition_values_to_files();		break; /* N */
+		}
+		break;
+    case('n'):
+    	switch(ro) {
+		case('F'):	note_to_midi(2);					break; /* nF */
+		case('M'):	note_to_midi(0);					break; /* nM */
+		case('T'):	note_to_midi(1);					break; /* nT */
+		}
+		break;
+    case('O'):
+		switch(ro) {
+	    case('s'):		multiply(0);				break; /* Os */
+	    case('T'):		interval_to_ratio(0,1);		break; /* OT */
+		}
+		break;
+    case('o'):
+		switch(ro) {
+		case(ENDOFSTR): qiksort(); print_numbers(); break; /* o */
+	 	case('r'):		interval_to_ratio(0,0);		break; /* or */
+		}
+		break;
+    case('p'):
+		switch(ro) {
+		case(ENDOFSTR): product();					break; /* p */
+		case('p'):		tw_psuedopan();				break; /* pp */
+		}
+		break;
+    case('P'):		take_power();			break; /* P */
+    case('Q'):		quadratic_curve_steps();	break; /* Q */
+    case('q'):		
+    	switch(ro) {
+		case(ENDOFSTR): quantise();					break; /* q */
+		case('t'): quantise_time();					break; /* qt */
+		case('v'): quantise_val();					break; /* qv */
+		case('z'): rand_zigs();						break; /* qz */
+		}
+		break;
+    case('R'):
+		switch(ro) {
+		case(ENDOFSTR):	reciprocals(0);				break; /* R */
+		case('o'):	
+		case('x'):	
+			if((perm=(int *)malloc(stringscnt * sizeof(int)))==NULL) {
+				fprintf(stdout, "ERROR: Out of memory\n");
+				fflush(stdout);
+				exit(1);
+			}
+			for(k=0;k<stringscnt;k++)
+				perm[k] = k;
+			if(ro=='o')
+				randomise_order(perm);					   /* Ro */
+			else
+				randomise_Ntimes(perm);				break; /* Rx */
+		case('a'):	add_randval_plus_or_minus();	break; /* Ra */
+		case('A'):	add_randval();					break; /* RA */
+		case('c'):	randchunks();					break; /* Rc */
+		case('e'):	random_elimination();			break; /* Re */
+		case('g'):	random_0s_and_1s();				break; /* Rg */
+		case('G'):	random_0s_and_1s_restrained();	break; /* RG */
+		case('i'):	random_integers();				break; /* Ri */
+		case('I'): random_integers_evenly_spread(); break; /* RI */
+		case('m'):	multiply_by_randval();			break; /* Rm */
+		case('r'):	generate_randomised_vals();		break; /* Rr */
+		case('s'):	random_scatter();				break; /* Rs */
+		case('v'):	generate_random_values();		break; /* Rv */
+		}
+		break;
+    case('r'):
+		switch(ro) {
+		case(ENDOFSTR):	reverse_order_of_brkvals();	break; /* r  */
+		case('a'):	ratios();						break; /* ra */
+		case('I'):	ratio_to_interval(1,0);			break; /* rI */
+		case('o'):	ratio_to_interval(0,0);			break; /* ro */
+		case('r'):	reverse_list();					break; /* rr */
+		case('G'):	random_pairs();					break; /* rG */
+		case('J'):	random_pairs_restrained();		break; /* rJ */
+		case('R'):	rotate_list(0);					break; /* rR */
+		case('X'):	rotate_list(1);					break; /* rX */
+		case('m'):	rotate_motif();					break; /* rm */
+		case('p'):	mean_of_reversed_pairs();		break; /* rp */
+		case('T'):	condit = 0; reciprocals(1);		break; /* rT */
+		case('z'): rand_ints_with_fixed_ends();		break; /* rz */
+		}
+		break;
+    case('S'):
+		switch(ro) {
+		case(ENDOFSTR):	separate_columns_to_files();	break; /* S */
+		case('M'):		splice_pos();					break; /* SM */
+		}
+		break;
+    case('s'):
+		switch(ro) {
+		case(ENDOFSTR):	stack(1);				break; /* s */
+		case('a'):	scale_above();				break; /* sa */
+		case('b'):	scale_below();				break; /* sb */
+		case('c'):	sinjoin('c');				break; /* sc */
+		case('d'):	sum_absolute_differences();	break; /* sd */
+		case('D'):	level_to_db(1);				break; /* sD */
+		case('E'):	convert_to_edits();			break; /* sE */
+		case('f'):	scale_from();				break; /* sf */
+		case('g'):	multiply(0);				break; /* sg */
+		case('k'):	get_one_skip_n();			break; /* sk */
+		case('K'):	get_n_skip_one();			break; /* sK */
+		case('l'):	do_slope();					break; /* sl */
+		case('n'):	sum_nwise();				break; /* sn */
+		case('o'):	sum_minus_overlaps();		break; /* so */
+		case('u'):	substitute();				break; /* su */
+		case('U'):	substitute_all();			break; /* sU */
+		case('O'):	multiply(0);				break; /* sO */
+		case('p'):	spanpair();					break; /* sp */
+		case('s'):	sinusoid();					break; /* ss */
+		case('t'):	samp_to_time();				break; /* st */
+		case('v'):	sinjoin('v');				break; /* sv */
+		case('x'):	sinjoin('x');				break; /* sx */
+		case('A'):	span_all();					break; /* sA */
+		case('F'):	span_fall();				break; /* sF */
+		case('X'):	span_xall();				break; /* sX */
+		case('P'):	span();						break; /* sP */
+		case('R'):	span_rise();				break; /* sR */
+		case('T'):	interval_to_ratio(1,1);		break; /* sT */
+		case('z'):	stack(0);					break; /* sz */
+		}
+		break;
+    case('T'):
+		switch(ro) {
+		case('B'):	time_from_bar_beat_metre_tempo(1);	break; /* TB */
+		case('b'):	time_from_bar_beat_metre_tempo(0);	break; /* Tb */
+		case('c'):	time_from_crotchet_count();			break; /* Tc */
+		case('h'):	temper_hz_data();					break; /* Th */
+		case('l'):	time_from_beat_lengths();			break; /* Tl */
+		case('M'):	temper_midi_data();					break; /* TM */
+		case('O'):	ratio_to_interval(0,1);				break; /* TO */
+		case('p'):	time_from_beat_position(0);			break; /* Tp */
+		case('P'):	time_from_beat_position(1);			break; /* TP */
+		case('r'):	condit = 0; reciprocals(1);			break; /* Tr */
+		case('s'):	ratio_to_interval(1,1);				break; /* Ts */
+		}
+    	break;
+    case('t'):
+		switch(ro) {
+		case(ENDOFSTR):	total();				break; /* t */
+		case('B'):	time_to_crotchets(1);		break; /* tB */
+		case('c'):	thresh_cut();				break; /* tc */
+		case('C'):	time_to_crotchets(0);		break; /* tC */
+		case('d'):	time_density();		    	break; /* td */
+		case('e'):	mean_tempo();		    	break; /* te */
+		case('h'):	text_to_hz();		    	break; /* th */
+		case('M'):	print_numbers();	    	break; /* tM */
+		case('r'):	reverse_time_intervals();	break; /* tr */
+		case('R'):	reverse_time_intervals2();	break; /* tR */
+		case('s'):	time_to_samp();				break; /* ts */
+		}
+	    break;
+	case('v'):	rank_vals();					break;	/* v */
+	case('V'):	rank_frqs();					break;	/* V */
+	case('w'):
+		switch(ro) {
+		case('o'): warped_times(1);				break;	/* wo */
+		case('t'): warped_times(0);				break;	/* wt */
+		}
+		break;
+	case('W'):
+		switch(ro) {
+		case('a'): ta_reverse_sequence(0);		break;	/* Wa */
+		case('A'): a_reverse_sequence(0);		break;	/* WA */
+		case('b'): abut_sequences(0);			break;	/* Wb */
+		case('c'): compress_sequence(0);		break;	/* Wc */
+		case('E'): p_expandset_sequence(0);		break;	/* WE */
+		case('I'): p_invertset_sequence(0);		break;	/* WI */
+		case('i'): p_invert_sequence(0);		break;	/* Wi */
+		case('l'): loop_sequence(0);			break;	/* Wl */
+		case('m'): uptempo_sequence(0);			break;	/* Wm */
+		case('M'): accel_sequence(0);			break;	/* WM */
+		case('P'): p_reverse_sequence(0);		break;	/* WP */
+		case('r'): t_reverse_sequence(0);		break;	/* Wr */
+		case('R'): pa_reverse_sequence(0);		break;	/* WR */
+		case('t'): transpose_sequence(0);		break;	/* Wt */
+		case('T'): tp_reverse_sequence(0);		break;	/* WT */
+		case('Z'): tpa_reverse_sequence(0);		break;	/* WZ */
+		}
+		break;
+	case('y'):
+		switch(ro) {
+		case('a'):	replace_with_rand(0);		break; /* ya */
+		case('A'):	insert_after_val();			break; /* yA */
+		case('b'):	replace_with_rand(-1);		break; /* yb */
+		case('B'):	insert_at_start();			break; /* yB */
+		case('c'):	replace_with_rand(1);		break; /* yc */
+		case('C'):	cyclic_select('s');			break; /* yC */
+		case('d'):	delete_vals();				break; /* yd */
+		case('e'):	replace_equal();			break; /* ye */
+		case('E'):	insert_at_end();			break; /* yE */
+		case('g'):	replace_greater();			break; /* yg */
+		case('i'):	insert_val();				break; /* yi */
+		case('I'):	invert_over_range();		break; /* yI */
+		case('l'):	replace_less();				break; /* yl */
+		case('o'):	insert_in_order();			break; /* yo */
+		case('p'):	invert_around_pivot();		break; /* yp */
+		case('P'):	targeted_pan();				break; /* yP */
+		case('q'):	randquanta_in_gaps();		break; /* yq */
+		case('Q'):	do_squeezed_pan();			break; /* yQ */
+		case('r'):	replace_val();				break; /* yr */
+		case('R'):	randdel_not_adjacent();		break; /* yR */
+		case('s'):	grid(1);					break; /* ys */
+		case('S'):	grid(0);					break; /* yS */
+		case('x'):	targeted_stretch();			break; /* yx */
+		}
+		break;
+	case('Y'):
+		switch(ro) {
+		case('s'):	convert_space_pan_to_tex();	break; /* Ys */
+		case('S'):	convert_space_tex_to_pan();	break; /* YS */
+		}
+		break;
+	case('z'):
+		switch(ro) {
+		case('q'):
+			if(number[2] > 1.0)  {
+				if(number[0] < .001) {
+					fprintf(stdout, "ERROR: Quantisation too small for scatter > 1.0\n");
+					fflush(stdout);
+					exit(1);
+				}
+				k = (int)floor(number[1]/number[0]) + 1;
+				k = (int)ceil(k/(cnt-1));
+				k *= round(number[2]);
+				if(k > TOO_BIG_ARRAY) {
+					fprintf(stdout, "ERROR: Combination of scatter > 1 with small quantisation: requires too much memory\n");
+					fflush(stdout);
+					exit(1);
+				}
+				if((perm=(int *)malloc(k * sizeof(int)))==NULL) {
+					fprintf(stdout, "ERROR: Out of memory\n");
+					fflush(stdout);
+					exit(1);
+				}
+			}
+			quantised_scatter(perm,k);    		break; /* za */
+		case('X'):	alt0101();					break; /* zX */
+		case('Y'):	alt0011();					break; /* zY */
+		case('Z'):	alt01100();					break; /* zZ */
+		case('A'):	alt0r0r();					break; /* zA */
+		case('B'):	altr0r0();					break; /* zB */
+		case('C'):	alt00rr();					break; /* zC */
+		case('D'):	altrr00();					break; /* zD */
+		case('e'):	tw_pseudo_exp();			break; /* ze */
+		case('E'):	alt0rr00r();				break; /* zE */
+		case('F'):	altr00rr0();				break; /* zF */
+		case('G'):	alt00RR();					break; /* zG */
+		case('H'):	altrr00();					break; /* zH */
+		case('I'):	alt0RR00R();				break; /* zI */
+		case('J'):	altR00RR0();				break; /* zJ */
+		}
+		break;
+ 	case('Z'):
+		switch(ro) {
+		case('h'):	just_intonation_Hz();		break; /* Zh */
+		case('M'):	just_intonation_midi();		break; /* ZM */
+		case('H'):	create_just_intonation_Hz();	break; /* ZH */
+		case('m'):	create_just_intonation_midi();	break; /* Zm */
+		case('s'):	random_warp();					break; /* Zs */
+		}
+		break;
+    }
+	if(allcols > 1)
+		output_multicol_data();
+	return 0;
+}
+
+/****************************** USAGE ****************************/
+
+void usage(void)
+{
+	if(!sloom) { 
+	    logo();
+	    fprintf(stderr,
+	    "USAGE: columns infile [outfile] -flag[@] [{threshold|}threshold] [--cCOLCNT]\n\n");
+	    fprintf(stderr,  "     { = less than:     } = greater than      THRESHOLD is numeric value.\n");
+	    fprintf(stderr,  "     threshold can only be used with R,a,m,d,P,c.\n");
+	    fprintf(stderr,  "     and specified operation then applies ONLY to vals > OR < threshold value.\n\n");
+	    fprintf(stderr,  "     If multicolumn data is being processed\n");
+	    fprintf(stderr,  "     COLCNT is the column of the input data to which process is applied.\n");
+	    fprintf(stderr,  "     Not all processes work with multicolumn data.\n");
+	    fprintf(stderr,  "FOR MORE INFORMATION:\n");
+	    fprintf(stderr,  "       columns -f   to see all available flags.\n");
+	    fprintf(stderr,  "       columns -g   for generative operations.\n");
+	    fprintf(stderr,  "       columns -l   for list manipulation and editing.\n");
+	    fprintf(stderr,  "       columns -m   for mathematical operations.\n");
+	    fprintf(stderr,  "       columns -M   for musical operations.\n");
+	    fprintf(stderr,  "       columns -R   for random operations.\n");
+	    fprintf(stderr,  "ALSO\n");
+	    fprintf(stderr,  "columns inoutfile1 infile2 [infile3....] -J      to juxtapose cols in one file\n");
+	    fprintf(stderr,  "columns infile1 outfiles -SX   to separate cols to X distinct files.\n");
+	    fprintf(stderr,  "columns infile1 outfiles -NX   to separate vals to X distinct files, in blocks.\n");
+	    fprintf(stderr,  "columns infile1 outfiles -NrX  to separate vals to X distinct files, in rotation\n");
+	}
+    exit(1);
+}
+
+/********************************** READ_FLAGS *************************/
+
+void read_flags(char *argv,char *argv2)
+{
+	char *p, *q;
+	double qtone = 0.0;
+	int maxpos;
+
+	if(*argv++!='-')
+		cannot_read_flags(argv-1);
+	if(sscanf(argv++,"%c",&flag)!=1)
+		cannot_read_flags(argv-2);
+	if(allcols > 1) {
+		ro = *argv;
+		if(!valid_call_for_multicol_input(flag,ro)) {
+			fprintf(stdout,"ERROR: Operation invalid with multicolumn input.\n");
+			fflush(stdout);
+			exit(1);
+		}
+	}
+	switch(flag) {
+	case('A'):
+		ro = *argv++;
+		switch(ro) {
+			case('b'):		/* Ab */
+			case('e'):		/* Ae */
+			case('s'):		/* As */
+				if(strlen(argv))
+					no_value_required_with_flag(flag,ro);
+				break;
+			case('d'):		/* Ad */
+			case('t'):		/* At */
+				if(sscanf(argv,"%lf",&factor)!=1)
+					cant_read_numeric_value(flag,ro);
+				break;
+			default:
+				if(sscanf(--argv,"%lf",&factor)!=1)  				/* A */
+					unknown_flag(flag,ro);
+
+		}
+		break;
+	case('a'):	 		/* a */
+		ro = *argv++;
+		switch(ro) {
+		case('o'):		/* ao */
+			break;
+		case('T'):		/* aT */
+		case('X'):		/* aX */
+			if(sscanf(argv,"%s",temp)!=1) {
+				fprintf(stdout,"ERROR: Cannot read string text parameter.\n");
+				fflush(stdout);
+				exit(1);
+			}
+			break;
+		default:		/* a */
+			if(sscanf(--argv,"%lf",&factor)!=1) {
+				cant_read_numeric_value_with_flag_only(flag);
+			}
+			ro = 0;
+			ifactor = round(factor);
+			break;
+		}
+		break;
+	case('B'):			/* B */
+		if((cnt & 1))
+			read_flags_data_error("Must have even number of 'bells' for bell-ringing, at present.");
+		if(cnt > 32)
+			read_flags_data_error("Too many bells (max 32, at present).");
+		if(*argv!=ENDOFSTR)
+			flag_only_takes_no_params(flag);
+		break;
+	case('b'):
+		ro = (int)*argv++;
+		switch(ro) {
+			case('b'):		/* bb */
+				break;
+			case('g'):	 	/* bg */
+			case('l'):		/* bl */
+				if(sscanf(argv,"%lf",&factor)!=1)
+					cant_read_numeric_value(flag,ro);
+				break;
+			default:		
+				unknown_flag_string(argv-2);
+		}
+		break;
+	case('C'):   			/* C */
+		ro =*argv++;
+		switch(ro) {
+		case(ENDOFSTR):	case('a'):	case('m'):	case('c'):
+			break;
+		}
+		break;
+	case('c'):
+		ro = *argv++;
+		switch(ro) {
+		case(ENDOFSTR):
+			break;			/* c */
+		case('l'):		 	/* cl */
+		case('c'):			/* cc */
+			if(*argv!=ENDOFSTR)
+				flag_takes_no_params(flag,ro);
+			break;
+		case('s'):			/* cs */
+		case('t'):			/* ct */
+			if(sscanf(argv,"%lf",&factor)!=1)
+				no_value_with_flag(flag,ro);
+			break;
+		default:
+			if(isdigit(ro) || ro=='.' || ro=='-') {
+				--argv;
+				if(sscanf(argv,"%lf",&thresh)!=1)
+					cant_read_numeric_value(flag,ro);
+				else {
+					ro = 0;
+					condit = '>';
+				}
+				break;
+			}
+			unknown_flag(flag,ro);
+		}
+		break;
+	case('D'):
+		ro = (int)*argv++;
+		switch(ro) {
+			case('B'):	/* DB */
+			case('s'):	/* Ds */
+				break;
+			default:
+				unknown_flag(flag,ro);
+		}
+		break;
+	case('d'):
+		ro = (int)*argv++;
+		switch(ro) {
+			case('v'):	 	/* dv */
+			case('l'):	 	/* dl */
+			case('o'):	 	/* do */
+			case('O'):	 	/* dO */
+				if(sscanf(argv,"%d",&ifactor)!=1)
+					cant_read_numeric_value(flag,ro);
+				break;
+			case('i'):	 	/* di */
+				if(sscanf(argv,"%lf",&factor)!=1)
+					cant_read_numeric_value(flag,ro);
+				break;
+			case('b'):	 	/* db */
+			case('d'):	 	/* dd */
+			case('g'):	 	/* dg */
+			case('h'):	 	/* dh */
+			case('L'):	 	/* dL */
+			case('M'):	 	/* dM */
+				break;
+			default:
+				if(isalpha(ro))
+					unknown_flag(flag,ro);
+				else {
+					if(sscanf(argv-1,"%lf",&factor)!=1)
+						cant_read_numeric_value_with_flag_only(flag);
+					ro = ENDOFSTR; 	/* d */
+				}
+				break;
+		}
+		break;
+	case('E'):	 		/* E */
+		if(sscanf(argv,"%lf",&factor)!=1)
+		   factor = 0.0;
+		break;
+	case('e'):
+		ro = (int)*argv;
+		if(ro==ENDOFSTR)
+			no_value_with_flag_only(flag);
+		if(isdigit(ro) || ro=='.' || ro=='-') {
+			if(sscanf(argv,"%lf",&factor)!=1)
+				cant_read_numeric_value_with_flag_only(flag);
+			ro = ENDOFSTR; 	/* e */
+			break;
+		}
+		argv++;
+		switch(ro) {
+			case('e'):	 	/* ee */
+			case('b'):	 	/* eb */
+			case('Q'):		/* eQ */
+			case('L'):	 	/* eL */
+			case('w'):	 	/* ew */
+			case('W'):	 	/* eW */
+			case('X'):	 	/* eX */
+			case('Y'):	 	/* eY */
+				if(*argv!=ENDOFSTR)
+					read_flags_data_error("No parameter required with this option.");
+				break;
+			case('a'):	 	/* ea */
+			case('d'):	 	/* ed */
+			case('g'):	 	/* eg */
+			case('l'): 	 	/* el */
+			case('f'):	 	/* ef */
+			case('t'):	 	/* et */
+			case('x'):	 	/* ex */
+			case('v'):	 	/* ev */
+				if(sscanf(argv,"%lf",&factor)!=1)
+					cant_read_numeric_value(flag,ro);
+				break;
+			case('i'):	 	/* ei */
+			case('m'):	 	/* em */
+			case('s'): 	 	/* es */
+			case('A'): 	 	/* eA */
+			case('S'): 	 	/* eS */
+				if(*argv == ENDOFSTR)
+					factor = 0.0;
+				else {
+					if(sscanf(argv,"%lf",&factor)!=1) {
+						fprintf(stdout,"ERROR: Cannot read numerical value.\n");
+						fflush(stdout);
+						exit(1);
+					}
+					if(factor < 0.0) {
+						fprintf(stdout,"ERROR: Cannot insert at a time before zero.\n");
+						fflush(stdout);
+						exit(1);
+					}
+				}
+				break;
+			case('D'): 	 	/* eD */
+				if(sscanf(argv,"%lf",&factor)!=1) {
+					fprintf(stdout,"ERROR: Cannot read numerical value.\n");
+					fflush(stdout);
+					exit(1);
+				}
+				if(factor < 0.0) {
+					fprintf(stdout,"ERROR: Cannot delay to a time before zero.\n");
+					fflush(stdout);
+					exit(1);
+				}
+				break;
+			case('P'): 	 	/* eP */
+				if(sscanf(argv,"%d",&ifactor)!=1) {
+					fprintf(stdout,"ERROR: Cannot read line number.\n");
+					fflush(stdout);
+					exit(1);
+				}
+				if(ifactor < 1 || ifactor > cnt) {
+					fprintf(stdout,"ERROR: Line %d does not exist.\n",ifactor);
+					fflush(stdout);
+					exit(1);
+				}
+				if(ifactor == 1) {
+					fprintf(stdout,"ERROR: Cannot plateau at line 1 (No change to file).\n");
+					fflush(stdout);
+					exit(1);
+				}
+				break;
+			default:		
+				unknown_flag_string(argv-2);
+		}
+		break;
+/*RWD new Format option */
+	case('F'):
+		ro = (int)*argv;
+		if(ro=='r' || ro == 'f' || ro == 'R')
+			argv++;
+		else
+			ro = ENDOFSTR;
+		if(((int)*argv) == ENDOFSTR)
+			no_value_with_flag_only(flag);
+		if(sscanf(argv,"%d",&ifactor)!=1)
+			cant_read_numeric_value_with_flag_only(flag);
+		if(ifactor <= 0)
+			read_flags_data_error("Value must be > zero.");
+		if(!sloom) {
+			if(ifactor > 8)
+				read_flags_data_error("Maximum of 8 values possible on a line.");
+		}
+		break;
+	case('f'):   
+		ro = *argv++;
+		switch(ro) {
+		case('t'):	 		/* ft */
+			break;
+		case('r'):	 		/* fr */
+			if(sscanf(argv,"%d",&ifactor)!=1)
+				ifactor = 1;
+			break;
+		case('l'):	 		/* fl */
+			if(sscanf(argv,"%lf",&factor)!=1)
+				no_value_with_flag(flag,ro);
+			break;
+		default:
+			unknown_flag(flag,ro);
+		}
+		break;
+	case('G'):				/* G */
+		if(sscanf(argv,"%d",&ifactor)!=1)
+			no_value_with_flag_only(flag);
+		if(ifactor >= stringscnt) {
+			sprintf(errstr,"ERROR: regrouping value (%d) is too big for list of numbers (only %d in list).\n",ifactor,cnt);
+			do_error();
+		}
+		break;
+	case('g'):
+		ro = *argv++;
+		switch(ro) {
+		case(ENDOFSTR):		/* g  */
+		case('a'):			/* ga */
+			break;
+		case('s'):			/* gs */
+			factor = (double)MAXSAMP;
+			break;
+		default:
+			unknown_flag_or_bad_param();
+		}
+		break;
+ 	case('H'):
+		if((ro = (int)*argv++)!='g' && ro !='r') {
+			if(isalpha(ro))
+				unknown_flag(flag,ro);
+			if(sscanf(--argv,"%d",&ifactor)!=1)
+				no_value_with_flag_only(flag);
+			ro = ENDOFSTR;
+		} else {
+			switch(ro) {
+				case('r'):
+					if(sscanf(argv,"%d",&ifactor)!=1)
+						no_value_with_flag(flag,ro);
+					break;
+				case('g'):
+					if(sscanf(argv,"%lf",&factor)!=1)
+						factor = HARMONIC_TUNING_TOLERANCE;
+					break;
+				default:
+					unknown_flag(flag,ro);
+			}
+		}
+		break;
+	case('h'):	 		
+		ro = *argv++;
+		switch(ro) {
+		case('d'):		/* hd */
+		case('M'):		/* hM */
+			break;
+		default:
+			unknown_flag_string(argv-1);
+		}
+		if(*argv!=ENDOFSTR)
+			read_flags_data_error("No parameter required with this flag.");
+		break;
+	case('I'):
+		ro =*argv++;
+		switch(ro) {
+			case(ENDOFSTR):			break;   			/* I */
+			case('r'):				break;   			/* Ir */
+			case('v'):				break;   			/* Iv */
+			case('V'):									/* IV */
+				if(sscanf(argv,"%d",&ifactor)!=1)
+					cant_read_numeric_value(flag,ro);
+				break;   								
+		}
+		break;
+	case('i'):
+		ro = (int)*argv++;
+		switch(ro) {
+			case(ENDOFSTR):		/* i */
+				break;
+			case('M'):		/* iM */
+			case('p'):		/* ip */
+			case('v'):		/* iv */
+			case('V'):		/* iV */
+			case('h'):		/* ih */
+				if(*argv!=ENDOFSTR)
+					no_value_required_with_flag(flag,ro);
+				break;
+			case('='):		/* i= */
+				if(cnt!=2) {
+					if(!sloom)
+						read_flags_data_error("Must have two values in infile with flag i=.");
+					exit(1);
+				}
+				if(flteq(number[0],number[1])) {
+					if(!sloom)
+						read_flags_data_error("Two values in infile must be different.");
+					exit(1);
+				}
+				if(sscanf(argv,"%lf",&factor)!=1)
+					cant_read_numeric_value(flag,ro);
+				if(flteq(factor,0.0))
+					read_flags_data_error("Parameter cannot be zero.");
+				break;
+			case('r'):		/* ir */
+			case('c'):		/* ic */
+				if(sscanf(argv,"%d",&ifactor)!=1)
+					cant_read_numeric_value(flag,ro);
+				if(flag=='c' && cnt!=1)
+					read_flags_data_error("Must have only one value in infile.");
+				break;
+			case('a'):		/* ia */
+			case('m'):		/* im */
+			case('l'):		/* il */
+			case('L'):		/* iL */
+				if(sscanf(argv,"%lf",&factor)!=1)
+					cant_read_numeric_value(flag,ro);
+				break;
+			default:
+				if(isdigit(ro) || ro=='.' || ro=='-')
+					flag_only_takes_no_params(flag);
+				unknown_flag_string(argv-2);
+		}
+		break;
+	case('J'):
+		ro = *argv;
+		if(ro=='j') {							/*Jj */	
+			if(sscanf(++argv,"%d",&ifactor)!=1)
+				no_value_with_flag_only(flag);
+		} else if(*argv!=ENDOFSTR)   			/* J */
+			flag_only_takes_no_params(flag);
+		break;
+	case('j'):
+		ro = *argv;
+		if(ro == 'j')		/* jj */
+			break;
+		else {				/* j */
+			ro = 0;
+			maxpos = (cnt/colcnt) + 1;
+			if(sscanf(argv,"%d",&ifactor)!=1)
+				no_value_with_flag_only(flag);
+		   	else if(ifactor > maxpos) {
+				fprintf(stdout,"ERROR: Insertion point is beyond end of file: reverting to end of file.\n");
+				fflush(stdout);
+				ifactor = maxpos;
+			}
+		}
+		break;
+   case('L'):			/* L */
+		if(cnt!=2)
+			read_flags_data_error("Must have two values in infile.");
+		if(flteq(number[0],number[1]))
+			read_flags_data_error("Two values in infile must be different.");
+		if(number[0]<=0 || number[1]<=0)
+			read_flags_data_error("This option only works on values >0.\n");
+		if(sscanf(argv,"%lf",&factor)!=1)
+			cant_read_numeric_value_with_flag_only(flag);
+		if(flteq(factor,0.0))
+			read_flags_data_error("Parameter cannot be zero.");
+		break;
+	case('l'):
+		ro =*argv++;
+		switch(ro) {
+		case(ENDOFSTR):			break;   			/* l */
+		case('i'):									/* li */
+		case('v'):									/* lv */
+			if(sscanf(argv,"%lf",&factor)!=1)
+				no_value_with_flag(flag,ro);
+			break;
+		default:
+			unknown_flag(flag,ro);
+		}
+		break;
+	case('k'):
+		ro =*argv++;
+		switch(ro) {
+		case('A'):									/* kA */
+		case('B'):									/* kB */
+		case('C'):									/* kC */
+		case('T'):									/* kT */
+		case('X'):									/* kX */
+		case('Y'):									/* kY */
+			break;
+		default:
+			unknown_flag(flag,ro);
+		}
+		break;
+	case('K'):
+		ro =*argv++;
+		switch(ro) {
+		case('c'): case('t'): case('E'): 
+		case('l'): case('b'): case('m'): case('M'):
+			if(sscanf(argv,"%lf",&factor)!=1)
+				read_flags_data_error("Cannot read parameter value.");
+			break;
+		case('I'): case('i'): case('P'): case('A'): case('R'):	case('r'):
+		case('Z'): case('T'): case('a'): 
+			break;
+		default:
+			fprintf(stdout,"ERROR: Unknown option\n");
+			fflush(stdout);
+			exit(1);
+		}
+		break;
+	case('M'):
+		ro = *argv++;
+
+		switch(ro) {
+			case(ENDOFSTR):	/* M  */
+			case('d'):	 	/* Md */
+				break;
+			case('h'):	 	/* Mh */
+				if(*argv!=ENDOFSTR)
+					no_value_required_with_flag(flag,ro);
+				break;
+			case('m'): 	 	/* Mm */
+				if((p=get_pitchclass(argv,&ifactor,0))==(char *)0) {
+					sprintf(errstr,"key not specified, or unknown (%s)\n",argv);
+					do_error();
+				}
+				break;
+			case('t'): 	 	/* Mt */
+				break;
+			case('r'): 	 	/* Mr */
+				if(sscanf(argv,"%d",&ifactor)!=1)
+					ifactor = 1;
+				break;
+			default:
+				if(isdigit(ro) || ro=='.' || ro=='-')
+					no_value_required_with_flag_only(flag);
+				unknown_flag(flag,ro);
+		}
+		break;
+	case('m'):	   
+		ro = *argv++;
+		switch(ro) {
+			case('i'):		/* mi */
+			case('I'):		/* mI */
+				break;
+			case('M'):		/* mM */
+				if((p=get_pitchclass(argv,&ifactor,0))==(char *)0) {
+					sprintf(errstr,"key not specified, or unknown (%s)\n",argv);
+					do_error();
+				}
+				break;
+			case('g'): 		/* mg */
+			case('l'): 		/* ml */
+			case('e'): 		/* me */
+			case('m'): 		/* mm */
+				if(sscanf(argv,"%lf",&factor)!=1) {
+					cant_read_numeric_value(flag,ro);
+				}
+				if(ro == 'm' && flteq(factor,0.0)) {
+					fprintf(stdout,"ERROR: Mutiples of numbers very close to zero cannot be handled.\n");
+					fflush(stdout);
+					exit(1);
+				}	
+				ifactor = round(factor);
+				break;
+			default: 		/* m */
+				if(sscanf(--argv,"%lf",&factor)!=1) {
+					cant_read_numeric_value_with_flag_only(flag);
+				}
+				ro = 0;
+				break;
+		}
+		break;
+	case('N'):	 		/* N */
+		ro = *argv;
+		if(ro == 'r')		/* Nr */
+			argv++;
+		if(*argv==ENDOFSTR) {
+			if(ro=='r')
+				cant_read_numeric_value(flag,ro);
+			else
+				cant_read_numeric_value_with_flag_only(flag);
+		}
+		if(ro!='r' && !isdigit(ro))
+			unknown_flag(flag,ro);
+		if(sscanf(argv,"%d",&outfilecnt)!=1) {
+			if(ro=='r')
+				cant_read_numeric_value(flag,ro);
+			else
+				cant_read_numeric_value_with_flag_only(flag);
+		}
+		if(outfilecnt<2)
+			read_flags_data_error("Number of partitioning sets must be >1.");
+		if(outfilecnt > 99)
+			read_flags_data_error("You can't have more than 99 outfiles (at present).");
+		len = strlen(argv2);
+		filename = (char *)exmalloc(len+1);
+		*filename = ENDOFSTR;
+		strcpy(filename,argv2);
+		len+=2;
+		if(factor>9)
+			len++;
+		thisfilename = (char *)exmalloc(len+1);
+		break;
+	case('n'):	 		/* n */
+		ro = *argv++;
+		switch(ro) {
+		case('F'):		/* nF */
+		case('M'):		/* nM */
+			break;
+		case('T'):		/* nT */
+			switch(*argv++) {
+			case('c'): case('C'): factor = 60.0;	break;
+			case('d'): case('D'): factor = 62.0;	break;
+			case('e'): case('E'): factor = 64.0;	break;
+			case('f'): case('F'): factor = 65.0;	break;
+			case('g'): case('G'): factor = 67.0;	break;
+			case('a'): case('A'): factor = 69.0;	break;
+			case('b'): case('B'): factor = 71.0;	break;
+			default: 
+				fprintf(stdout,"ERROR: Cannot read note parameter.\n");
+				fflush(stdout);
+				exit(1);
+			}
+			switch(*argv) {
+			case('b'): factor -= 1.0; argv++; break;
+			case('#'): factor += 1.0; argv++; break;
+			case(ENDOFSTR): break;
+			}
+			ifactor = 0;
+			switch(*argv) {
+			case(ENDOFSTR):	break;
+			default:
+				qtone = 0.0;
+				q = argv + strlen(argv) - 1;
+				if(*q == '-') {
+					qtone = -.5;
+					*q = ENDOFSTR;
+				} else if(*q == '+') {
+					qtone = .5;
+					*q = ENDOFSTR;
+				}
+				if(sscanf(argv,"%d",&ifactor)!=1) {
+					fprintf(stdout,"ERROR: Invalid octave data in note parameter.\n");
+					fflush(stdout);
+					exit(1);
+				}
+				break;
+			}
+			factor += (double)(12 * ifactor);
+			factor += qtone;
+			break;
+		default:
+			unknown_flag_string(argv-1);
+		}
+		break;		
+	case('O'):		
+		ro = *argv++;
+		switch(ro) {
+		case('s'):		/* Os */
+			factor = 12;
+			break;
+		case('T'):		/* OT */
+			break;
+		default:
+			unknown_flag(flag,ro);
+		}
+		break;
+	case('o'):   			
+		ro = *argv++;
+		switch(ro) {
+		case(ENDOFSTR):		/* o  */
+		case('r'):			/* or */
+			break;
+		default:
+			unknown_flag_or_bad_param();
+		}
+		break;
+	case('p'):   			/* p */
+		ro = *argv++;
+		switch(ro) {
+		case(ENDOFSTR):		/* p  */
+		case('p'):			/* pp */
+			break;
+		default:
+			unknown_flag_string(argv-1);
+		}
+		break;
+	case('P'):	 		/* P */
+	case('q'):	 		/* q */
+		ro = (int)*argv;
+		if(ro==ENDOFSTR)
+			no_value_with_flag_only(flag);
+		if(isdigit(ro) || ro=='.' || ro=='-') {
+			if(sscanf(argv,"%lf",&factor)!=1)
+				cant_read_numeric_value_with_flag_only(flag);
+			ro = ENDOFSTR; 	/* q */
+			break;
+		}
+		switch(ro) {
+		case('t'):
+		case('v'):
+			argv++;
+			if(sscanf(argv,"%lf",&factor)!=1) {
+				cant_read_numeric_value(flag,ro);
+				exit(1);
+			}
+			break;
+		default:
+			unknown_flag_string(argv-1);
+			break;
+		}
+		break;
+	case('Q'):			/* Q */
+		if(cnt!=3)
+			read_flags_data_error("Must have three values in infile.");
+		if(flteq(number[0],number[1]))
+			read_flags_data_error("First two values in infile must be different.");
+		if(number[2]<=0.0)
+			read_flags_data_error("Curvature (third value in infile) must be >0.0.");
+		if(sscanf(argv,"%lf",&factor)!=1)
+			cant_read_numeric_value_with_flag_only(flag);
+		if(flteq(factor,0.0))
+			read_flags_data_error("Parameter cannot be zero.");
+		break;
+	case('R'):
+		ro = (int)*argv++;
+		switch(ro) {
+			case(ENDOFSTR):	/* R */
+				factor = 1.0;
+				break;
+			case('g'):		/* Rg */
+			case('G'):		/* RG */
+				if(*argv!=ENDOFSTR)
+					read_flags_data_error("No parameter required with this option.");
+				break;
+		case('o'):		/* Ro */
+		case('i'):		/* Ri */
+		case('I'):		/* RI */
+		case('r'):		/* Rr */
+			if(*argv!=ENDOFSTR) {
+				fprintf(stdout,"ERROR: No parameter required with this option\n");
+				fflush(stdout);
+				exit(1);
+			}
+			break;
+		case('e'):		/* Re */
+			if(sscanf(argv,"%d",&ifactor)!=1)
+				no_value_with_flag(flag,ro);
+			break;
+		case('a'):		/* Ra */
+		case('A'):		/* RA */
+		case('c'):		/* Rc */
+		case('m'):		/* Rm */
+		case('s'):		/* Rs */
+		case('v'):		/* Rv */
+		case('x'):		/* Rx */
+			if(sscanf(argv,"%lf",&factor)!=1)
+				cant_read_numeric_value(flag,ro);
+			if(ro=='s' && (factor > 1.0 || factor < 0.0))
+				read_flags_data_error("Numerical value out of range [0-1].");
+			else if(ro == 'x') {
+				ifactor = round(factor);
+				if(ifactor < 1)
+					read_flags_data_error("Numerical value out of range [must be >= 1].");
+			}
+			break;
+		default:
+			if(sscanf(argv-1,"%lf",&factor)!=1)
+				unknown_flag_string(argv-2);
+			ro = ENDOFSTR;
+		}
+		break;
+	case('r'):   
+		ro = *argv++;
+		switch(ro) {
+		case(ENDOFSTR):	/* r */
+			break;
+		case('m'):		/* rm */
+			if(sscanf(argv,"%d",&ifactor)!=1)
+				no_value_with_flag(flag,ro);
+			break;
+		case('T'):			/* rT */
+			factor = 1.0;
+			/* fall thro */
+		case('a'):			/* ra */
+		case('G'):			/* rG */
+		case('I'):			/* rI */
+		case('J'):			/* rJ */
+		case('o'):			/* ro */
+		case('p'):			/* rp */
+		case('r'):			/* rr */
+		case('R'):			/* rR */
+		case('X'):			/* rX */
+		case('z'):			/* rz */
+			if(*argv!=ENDOFSTR)
+				no_value_required_with_flag(flag,ro);
+			break;
+		default:
+			unknown_flag(flag,ro);
+		}
+		break;
+	case('S'):	 			/* S */
+		ro = *argv;
+		switch(ro) {
+		case('M'):			/* SM */
+			argv++;		/* NB need to do this here if there are more 'S' flags!! */
+			if(*argv!=ENDOFSTR)
+				no_value_required_with_flag(flag,ro);
+			break;
+		default:
+			if(*argv==ENDOFSTR) {
+				cant_read_numeric_value_with_flag_only(flag);
+				exit(1);
+			}
+			if(sscanf(argv,"%d",&outfilecnt)!=1) {
+				cant_read_numeric_value_with_flag_only(flag);
+				exit(1);
+			}
+			if(outfilecnt<2)
+				read_flags_data_error("Number of partitioning sets must be >1.");
+			if(outfilecnt > 99)
+				read_flags_data_error("You can't have more than 99 outfiles (at present).");
+			len = strlen(argv2);
+			filename = (char *)exmalloc(len+1);
+			*filename = ENDOFSTR;
+			strcpy(filename,argv2);
+			len+=2;
+			if(factor>9)
+				len++;
+			thisfilename = (char *)exmalloc(len+1);
+			ro = ENDOFSTR;
+			break;
+		}
+		break;
+	case('s'):
+		ro = *argv++;
+		switch(ro) {
+		case('R'):		/* sR */
+		case('T'):		/* sT */
+		case('F'):		/* sF */
+		case('X'):		/* sX */
+		case('a'):		/* sa */	
+		case('b'):		/* sb */
+		case('f'):		/* sf */
+			break;
+		case('O'):		/* sO */
+			factor = .083333333333;		/* i.e. 1/12 */
+			break;
+		case('g'):		/* sg */
+			factor = 1.0/MAXSAMP;
+			break;
+		case('d'):		/* sd */
+			if(*argv == ENDOFSTR) {
+				factor = 0.0;
+				break;
+			}
+			/* fall thro */
+						/* sd with param */
+		case('A'):		/* sA */
+			if(sscanf(argv,"%lf",&factor)!=1) 
+				cant_read_numeric_value(flag,ro);
+			break;
+		case('t'):		/* st */
+			if(*argv == ENDOFSTR)
+				no_value_with_flag(flag,ro);
+			else if(sscanf(argv,"%d",&ifactor)!=1)
+				cant_read_numeric_value(flag,ro);
+			else if(BAD_SR(ifactor))
+				read_flags_data_error("Invalid sampling rate.");
+			break;
+		case('P'):		/* sP */
+		case('p'):		/* sp */
+		case('o'):		/* so */
+		case('u'):		/* su */
+		case('k'):		/* sk */
+		case('l'):		/* sl */
+		case('K'):		/* sK */
+		case('n'):		/* sn */
+		case('E'):		/* sE */
+			if(*argv == ENDOFSTR)
+				no_value_with_flag(flag,ro);
+			else if(sscanf(argv,"%lf",&factor)!=1)
+				cant_read_numeric_value(flag,ro);
+			break;
+		case('U'):		/* sn */
+			if(*argv == ENDOFSTR)
+				no_value_with_flag(flag,ro);
+			else if(sscanf(argv,"%s",string)!=1) {
+				fprintf(stdout,"ERROR: Cannot read string text parameter.\n");
+				fflush(stdout);
+				exit(1);
+			}
+			break;
+		case('z'):		/* sz */
+			ifactor = *argv;
+			if(ifactor == ENDOFSTR)
+				factor = 0.0;
+			else {
+				if(sscanf(argv,"%lf",&factor)!=1) {
+					cant_read_numeric_value(flag,ro);
+					exit(1);
+				}
+			}
+			break;
+		case(ENDOFSTR):	 /* s */
+			factor = 0.0;
+			break;
+		default:		 /* s with parameter */
+			if(isdigit(ro) || ro=='.' || ro=='-') {	  
+				argv--;
+				if(sscanf(argv,"%lf",&factor)!=1) {
+					cant_read_numeric_value(flag,ro);
+					exit(1);
+				}
+				ro = ENDOFSTR;
+			} else
+				unknown_flag(flag,ro);
+		}
+		break;
+	case('T'):
+		if((ro = *argv++)==ENDOFSTR)
+			unknown_flag_only(flag);
+		switch(ro) {
+			case('M'): 		/* TM */
+			case('h'): 		/* Th */
+				if(sscanf(argv,"%lf",&factor)!=1)
+					factor = TWELVE;	/* Normal tempering */
+				break;
+			case('c'): 		/* Tc */
+			case('l'): 		/* Tl */
+				if(sscanf(argv,"%lf",&factor)!=1)
+					read_flags_data_error("Cannot read tempo value.");
+				break;
+			case('p'): 		/* Tp */
+			case('P'): 		/* TP */
+				if(sscanf(argv,"%lf",&factor)!=1)
+					read_flags_data_error("Cannot read beat duration.");
+				break;
+			case('r'): 		/* Tr */
+				factor = 1.0;
+				/* fall thro */
+			case('b'):		/* Tb */
+			case('B'): 		/* TB */
+			case('O'): 		/* TO */
+			case('s'): 		/* Ts */
+				break;
+			default:
+				unknown_flag(flag,ro);
+		}
+		break;
+	case('t'):
+		ro = *argv++;
+		switch(ro) {
+		case(ENDOFSTR):		/* t */
+			break;
+		case('s'):			/* ts */
+			if(*argv == ENDOFSTR)
+				no_value_with_flag(flag,ro);
+			else if(sscanf(argv,"%d",&ifactor)!=1) {
+				cant_read_numeric_value(flag,ro);
+			} else if(BAD_SR(ifactor))
+				read_flags_data_error("Invalid sampling rate.");
+			break;
+ 		case('e'):		/* te */
+		case('M'): 		/* tM */
+		case('h'): 		/* th */
+		case('r'): 		/* tr */
+		case('R'): 		/* tR */
+			if(*argv!=ENDOFSTR)
+				no_value_required_with_flag(flag,ro);
+			break;
+		case('d'):
+			if(sscanf(argv,"%d",&ifactor)!=1)
+				read_flags_data_error("Cannot read density value.");
+			break;
+ 		case('B'):			/* tB */
+ 		case('c'):			/* tc */
+ 		case('C'):			/* tC */
+			if(sscanf(argv,"%lf",&factor)!=1)
+				read_flags_data_error("Cannot read parameter value.");
+			break;
+		default:
+			if(isdigit(ro) || ro=='.' || ro=='-')
+				no_value_required_with_flag_only(flag);
+			unknown_flag(flag,ro);
+		}
+		break;
+	case('V'):
+		if(sscanf(argv,"%lf",&factor)!=1)
+			no_value_with_flag_only(flag);
+		break;
+   	case('v'):
+		if(sscanf(argv,"%lf",&factor)!=1)
+			factor = 0.0;
+		break;	
+	case('w'):
+		ro =*argv++;
+		switch(ro) {
+		case('t'): case('o'):
+			break;
+		default:
+			fprintf(stdout,"ERROR: Unknown option\n");
+			fflush(stdout);
+			exit(1);
+		}
+		break;
+	case('W'):
+		ro =*argv++;
+		switch(ro) {
+		case('c'): case('t'): case('E'): 
+		case('l'): case('b'): case('m'): case('M'):
+			if(sscanf(argv,"%lf",&factor)!=1)
+				read_flags_data_error("Cannot read parameter value.");
+			break;
+		case('I'): case('i'): case('P'): case('A'): case('R'):	case('r'):
+		case('Z'): case('T'): case('a'): 
+			break;
+		default:
+			fprintf(stdout,"ERROR: Unknown option\n");
+			fflush(stdout);
+			exit(1);
+		}
+		break;
+	case('y'):
+		ro =*argv++;
+		switch(ro) {
+		case('a'):	case('A'):	case('b'):	case('B'):	case('c'):	case('C'):	
+		case('d'):	case('e'):	case('E'):	case('g'):	case('i'):	case('I'):
+		case('l'):	case('o'):	case('p'):	case('q'):	case('Q'):	case('r'):	case('R'):
+		case('P'):	case('s'):	case('S'):	case('x'):	
+			break;
+		default:
+			fprintf(stdout,"ERROR: Unknown option\n");
+			fflush(stdout);
+			exit(1);
+		}
+		break;
+	case('Y'):
+		ro =*argv++;
+		switch(ro) {
+		case('s'):	case('S'):	
+			break;
+		default:
+			fprintf(stdout,"ERROR: Unknown option\n");
+			fflush(stdout);
+			exit(1);
+		}
+		break;
+	case('z'):
+		ro =*argv++;
+		switch(ro) {
+		case('A'):	case('B'):	case('C'):	case('D'):	case('e'):	case('E'):	case('F'):	case('G'):
+		case('H'):	case('I'):	case('J'):	case('X'):	case('Y'):	case('Z'):	
+		case('q'):
+			break;
+		default:
+			fprintf(stdout,"ERROR: Unknown option\n");
+			fflush(stdout);
+			exit(1);
+		}
+		break;
+	case('Z'):
+		ro =*argv++;
+		switch(ro) {
+		case('h'):	case('M'):	
+			if(sscanf(argv,"%lf",&factor)!=1)
+				read_flags_data_error("Cannot read parameter value.");
+			break;
+		case('s'):	
+			if(sscanf(argv,"%s",string)!=1)
+				read_flags_data_error("Cannot read parameter value.");
+			break;
+		default:
+			fprintf(stdout,"ERROR: Unknown option\n");
+			fflush(stdout);
+			exit(1);
+		}
+		break;
+	default:
+		unknown_flag_string(argv-1);
+	}
+
+	if(condit) {
+		if(!(flag=='s' && (ro=='p' || ro=='P' || ro=='F' || ro=='R' || ro=='u' || ro=='X'))
+		&& !(flag=='W' && (ro=='l' || ro=='M'))
+		&& !(flag=='K' && (ro=='l' || ro=='M'))
+		&& !(flag == 'm' && ro == 'm') && !(flag =='T' && ro == 'P')
+		&& !(flag == 'l' && ro == 'v') 
+		&& !(flag == 'd' && ro == 'L') && !(flag == 'T' && (ro == 'M' || ro == 'h')) 
+		&& !(flag == 'c' && ro == 0)
+		&& (ro!=0 || !(flag=='R'||flag=='a'||flag=='m'||flag=='P'||flag=='c'||flag=='d')))
+			read_flags_data_error("Threshold cannot be used with this option.");
+	}
+}
+
+/***************************** GET_EXTRA_PARAMS *********************************/
+
+void get_extra_params(int no,int argc,char *argv[]) {
+	int n, m;
+	cnt = no;
+	number=(double *)exrealloc((char *)number,(cnt+1)*sizeof(double));
+	for(n=2,m=0;n < argc-1;n++,m++) {
+		if(sscanf(argv[n],"%lf",&number[m])!=1) {
+			fprintf(stdout,"ERROR: Insufficient parameters for this process.\n");
+			fflush(stdout);
+			exit(1);
+		}
+	}			
+}
+
+/***************************** GET_FUNNY_PARAMS *********************************/
+
+void get_funny_params(int no,int argc,char *argv[]) {
+	int n, m;
+	number=(double *)exrealloc((char *)number,(cnt+no)*sizeof(double));
+	for(n=2,m=cnt;n < argc-1;n++,m++) {
+		if(sscanf(argv[n],"%lf",&number[m])!=1) {
+			fprintf(stdout,"ERROR: Insufficient parameters for this process.\n");
+			fflush(stdout);
+			exit(1);
+		}
+	}			
+}
+
+/***************************** REORGANISE_EXTRA_PARAMS *********************************/
+
+void reorganise_extra_params(char *agv,int argc,char *argv[])
+{
+	double range, step, scat, quantisation, dur;
+	int tq, ql;
+
+	agv++;
+	flag = *agv;
+	agv++;
+	ro = *agv;
+	switch(flag) {
+	case('A'):
+		switch(ro) {
+		case('d'):	
+		case('t'):	get_extra_params(3,argc,argv); 
+					factor = number[0];
+					number[0] = number[1];
+					number[1] = number[2];
+					cnt--;
+					if(factor <= 0.0) {
+						fprintf(stdout,"ERROR: Total duration must be greater than zero.\n");
+						fflush(stdout);
+						exit(1);
+					}
+					if((number[0]<=0) || (number[1]<=0)) {
+						fprintf(stdout,"ERROR: Time steps must be greater than zero.\n");
+						fflush(stdout);
+						exit(1);
+					}
+					if(factor < number[0] + number[1]) {
+						fprintf(stdout,"ERROR: Total duration too small to divide thus.\n");
+						fflush(stdout);
+						exit(1);
+					}
+					break;
+		case('T'):	get_extra_params(4,argc,argv); 
+					factor = number[0];
+					number[0] = number[1];
+					number[1] = number[2];
+					number[2] = number[3];
+					cnt--;
+					if((number[0]<=0) || (number[1]<=0)) {
+						fprintf(stdout,"ERROR: Time steps must be greater than zero.\n");
+						fflush(stdout);
+						exit(1);
+					}
+					if(factor <= 0.0) {
+						fprintf(stdout,"ERROR: Total duration must be greater than zero.\n");
+						fflush(stdout);
+						exit(1);
+					}
+					if(factor < number[0] + number[1]) {
+						fprintf(stdout,"ERROR: Total duration too small to divide thus.\n");
+						fflush(stdout);
+						exit(1);
+					}
+					ro = 't';
+					break;
+		default: 
+			fprintf(stdout,"ERROR: Unknown process mode.\n");
+			fflush(stdout);
+			exit(1);
+		}
+		break;
+	case('b'):
+		switch(ro) {
+		case('b'):
+			get_funny_params(2,argc,argv);
+			break;
+		}
+		break;
+	case('C'):
+		switch(ro) {
+		case('a'):	case('m'):
+			get_funny_params(3,argc,argv);
+			break;
+		}
+		break;
+	case('c'):
+		switch(ro) {
+		case('s'):	
+			get_extra_params(4,argc,argv);
+			cnt = round(number[0]);
+			if(cnt < 2) {
+				fprintf(stdout,"ERROR: Number of output values must be more than 1.\n");
+				fflush(stdout);
+				exit(1);
+			}
+			if(number[3] < FLTERR) {
+				fprintf(stdout,"ERROR: skew value must be greater than 0 (1.0 == NO skew).\n");
+				fflush(stdout);
+				exit(1);
+			}
+			break;
+		}
+		break;
+	case('d'):
+		switch(ro) {
+		case('d'):
+		case('L'):
+			get_funny_params(2,argc,argv);
+			break;
+		}
+		break;
+	case('g'):
+		switch(ro) {
+		case('a'):
+			get_funny_params(1,argc,argv);
+			break;
+		}
+		break;
+	case('i'):
+		switch(ro) {
+		case('e'):
+		case('c'):	get_extra_params(2,argc,argv);
+					ifactor = round(number[0]);
+					number[0] = number[1];
+					cnt--;
+					if(ifactor <= 1) {
+						fprintf(stdout,"ERROR: Number of values must be more than 1.\n");
+						fflush(stdout);
+						exit(1);
+					}
+					break;
+		case('R'):	
+		case('Q'):	
+		case('C'):	get_extra_params(3,argc,argv);
+					ifactor = round(number[0]);
+					number[0] = number[1];
+					number[1] = number[2];
+					cnt--;
+					if(ifactor <= 1) {
+						fprintf(stdout,"ERROR: Number of values must be more than 1.\n");
+						fflush(stdout);
+						exit(1);
+					}
+					break;
+		case('='):	get_extra_params(3,argc,argv);
+					factor = number[0];
+					number[0] = number[1];
+					number[1] = number[2];
+					cnt--;
+					range = fabs(number[1] - number[0]);
+					step  = fabs(factor);
+					if(step > range) {
+						fprintf(stdout,"ERROR: Range not large enough to accomodate the steps.\n");
+						fflush(stdout);
+						exit(1);
+					}
+					if(flteq(step,0.0)) {
+						fprintf(stdout,"ERROR: Steps are too small to work with.\n");
+						fflush(stdout);
+						exit(1);
+					}
+					if(range/step >= 10000.0) {
+						fprintf(stdout,"ERROR: More than 10000 steps: can't handle this.\n");
+						fflush(stdout);
+						exit(1);
+					}
+					break;
+		default: 
+			fprintf(stdout,"ERROR: Unknown process mode.\n");
+			fflush(stdout);
+			exit(1);
+		}
+		break;
+	case('L'):
+		if(ro != ENDOFSTR) {
+			fprintf(stdout,"ERROR: Unknown process mode.\n");
+			fflush(stdout);
+			exit(1);
+		}
+		get_extra_params(3,argc,argv);
+		factor = (double)round(number[0]);
+		if(factor <= 0.0) {
+			fprintf(stdout,"ERROR: Number of divisions must be greater than zero.\n");
+			fflush(stdout);
+			exit(1);
+		}
+		number[0] = number[1];
+		number[1] = number[2];
+		if(flteq(number[0],number[1])) {
+			fprintf(stdout,"ERROR: The range to divide up is too small.\n");
+			fflush(stdout);
+			exit(1);
+		}
+		if(number[0] <= 0.0 || number[1] <= 0.0) {
+			fprintf(stdout,"ERROR: The range must be between two positive numbers.\n");
+			fflush(stdout);
+			exit(1);
+		}
+		cnt--;
+		break;
+	case('K'):
+		tq = 2;
+		if(ro == 'b')
+			tq = 3;
+		if(sscanf(argv[tq],"%d",&ifactor)!=1) {
+			fprintf(stdout,"ERROR: Failed to get number of soundfiles in sequence data.\n");
+			fflush(stdout);
+			exit(1);
+		}			
+		break;
+	case('p'):
+		if (ro == 'p') {
+			get_extra_params(7,argc,argv);
+			break;
+		}	
+		break;
+	case('q'):
+		if (ro == 'z') {
+			get_extra_params(4,argc,argv);
+			break;
+		}	
+		break;
+	case('Q'):
+		if(ro != ENDOFSTR) {
+			fprintf(stdout,"ERROR: Unknown process mode.\n");
+			fflush(stdout);
+			exit(1);
+		}
+		get_extra_params(4,argc,argv);
+		factor = (double)round(number[0]);
+		number[0] = number[1];
+		number[1] = number[2];
+		number[2] = number[3];
+		cnt--;
+		if(flteq(number[0],number[1])) {
+			fprintf(stdout,"ERROR: Parameters 2 and 3 must be different.\n");
+			fflush(stdout);
+			exit(1);
+		}
+		if(number[2]<=0.0) {
+			fprintf(stdout,"ERROR: Curvature (4th parameter) must be > 0.0.\n");
+			fflush(stdout);
+			exit(1);
+		}
+		if(factor <= 0.0) {
+			fprintf(stdout,"ERROR: Number of steps cannot be zero\n");
+			fflush(stdout);
+			exit(1);
+		}
+		break;
+	case('R'):
+		switch(ro) {
+		case('g'):	get_extra_params(1,argc,argv);
+					if(round(number[0])<=0) {
+						fprintf(stdout,"ERROR: Number of items to generate must be 1 or more.\n");
+						fflush(stdout);
+						exit(1);
+					}
+					break;
+		case('G'):	get_extra_params(1,argc,argv);
+					if(round(number[0]) <= 0) {
+						fprintf(stdout,"ERROR: Number of items to generate must be 1 or more.\n");
+						fflush(stdout);
+						exit(1);
+					}
+					if(round(number[1]) <= 1) {
+						fprintf(stdout,"ERROR: Number of consecutive repeats must be 2 or more.\n");
+						fflush(stdout);
+						exit(1);
+					}
+					break;
+		case('i'):	get_extra_params(2,argc,argv);
+					if(round(number[0])<=0) {
+						fprintf(stdout,"ERROR: Number of items to generate must be 1 or more.\n");
+						fflush(stdout);
+						exit(1);
+					}
+					if(round(number[1])==1) {
+						fprintf(stdout,"ERROR: All numbers will be the same (1).\n");
+						fflush(stdout);
+						exit(1);
+					}
+					break;
+		case('I'):	get_extra_params(3,argc,argv);
+					if(round(number[0])<=0) {
+						fprintf(stdout,"ERROR: Number of items to generate must be 1 or more.\n");
+						fflush(stdout);
+						exit(1);
+					}
+					if(round(number[1])==1) {
+						fprintf(stdout,"ERROR: All numbers will be the same (1).\n");
+						fflush(stdout);
+						exit(1);
+					}
+					if(round(number[2])<1) {
+						fprintf(stdout,"ERROR: Number of allowable repetitions must be 1 or more.\n");
+						fflush(stdout);
+						exit(1);
+					}
+					break;
+		case('r'):	get_extra_params(3,argc,argv);
+					if(round(number[0])<=0) {
+						fprintf(stdout,"ERROR: TOtal duratihn must be > 0.\n");
+						fflush(stdout);
+						exit(1);
+					}
+					if(round(number[1])<1) {
+						fprintf(stdout,"ERROR: Must be more than one number to generate.\n");
+						fflush(stdout);
+						exit(1);
+					}
+					if(round(number[2])<=0) {
+						fprintf(stdout,"ERROR: Randomisation value must be > 0.\n");
+						fflush(stdout);
+						exit(1);
+					}
+					if(round(number[2])>round(number[1])) {
+						fprintf(stdout,"ERROR: Randomisation Value cannot be greater than number of values to generate.\n");
+						fflush(stdout);
+						exit(1);
+					}
+					break;
+		case('c'):
+		case('v'):	get_extra_params(3,argc,argv); 
+					factor = number[0];
+					number[0] = number[1];
+					number[1] = number[2];
+					cnt--;
+					if(ro == 'v') {
+						if(round(factor) < 1.0) {
+							fprintf(stdout,"ERROR: Number of items to generate must be 1 or more.\n");
+							fflush(stdout);
+							exit(1);
+						}
+					} else {	/* case 'c' */
+						if (number[0] <= 0.0 || number[1] <= 0.0) {
+							fprintf(stdout,"ERROR: Chunk sizes must all be larger than zero.\n");
+							fflush(stdout);
+							exit(1);
+						}
+
+						if (number[1] < number[0]) {
+							number[2] = number[0];
+							number[0] = number[1];
+							number[1] = number[2];
+						}
+						if(factor <= 0.0) {
+							fprintf(stdout,"ERROR: Item to cut must be greater than zero.\n");
+							fflush(stdout);
+							exit(1);
+						}
+						if(factor < number[0]) {
+							fprintf(stdout,"ERROR: Chunk sizes are too large.\n");
+							fflush(stdout);
+							exit(1);
+						}
+						if(factor < number[1]) {
+							number[1] = factor;
+						}
+					}
+					break;
+		default: 
+			fprintf(stdout,"ERROR: Unknown process mode.\n");
+			fflush(stdout);
+			exit(1);
+		}
+		break;
+	case('r'):
+		switch(ro) {
+		case('G'):	get_extra_params(3,argc,argv);
+					if(round(number[0]) <= 0) {
+						fprintf(stdout,"ERROR: Number of items to generate must be 1 or more.\n");
+						fflush(stdout);
+						exit(1);
+					}
+					if((int)round(number[1]) == (int)round(number[2])) {
+						fprintf(stdout,"ERROR: Two numbers to randomise must be different from each other.\n");
+						fflush(stdout);
+						exit(1);
+					}
+					break;
+		case('J'):	get_extra_params(4,argc,argv);
+					if(round(number[0]) <= 0) {
+						fprintf(stdout,"ERROR: Number of items to generate must be 1 or more.\n");
+						fflush(stdout);
+						exit(1);
+					}
+					if((int)round(number[1]) == (int)round(number[2])) {
+						fprintf(stdout,"ERROR: Two numbers to randomise must be different from each other.\n");
+						fflush(stdout);
+						exit(1);
+					}
+					break;
+		case('z'):	get_extra_params(6,argc,argv);
+					if(round(number[0])<3) {
+						fprintf(stdout,"ERROR: Number of items to generate must be 3 or more.\n");
+						fflush(stdout);
+						exit(1);
+					}
+					if(round(number[1]) == round(number[2])) {
+						fprintf(stdout,"ERROR: All 'random' numbers will be the same (%d).\n",(int) round(number[1]));
+						fflush(stdout);
+						exit(1);
+					}
+					if(round(number[5])<1) {
+						fprintf(stdout,"ERROR: Number of allowable repetitions must be 1 or more.\n");
+						fflush(stdout);
+						exit(1);
+					}
+					break;
+		default: 
+			fprintf(stdout,"ERROR: Unknown process mode.\n");
+			fflush(stdout);
+			exit(1);
+		}
+		break;
+
+	case('s'):
+		switch(ro) {
+		case('a'):	case('b'):	case('f'):
+			get_funny_params(2,argc,argv);
+			break;
+		case('s'):
+			get_extra_params(5,argc,argv);
+			if(flteq(number[0],number[1])) {
+				fprintf(stdout,"WARNING: Maximum and minimum vals are equal: no sinusoidal movement.\n");
+				fflush(stdout);
+			}
+			if(number[3] <= 0.0) {
+				fprintf(stdout,"ERROR: No of periods is <= 0. Cannot proceed\n");
+				fflush(stdout);
+				exit(1);
+			}
+			if(number[4] <= 2.0) {
+				fprintf(stdout,"ERROR: No of values per period is <= 2. No sinusoid will be produced\n");
+				fflush(stdout);
+				exit(1);
+			}
+			if (number[3] * number[4] < 1.0) { 
+				fprintf(stdout,"ERROR: No of cycles too short to produce any output with this no. of vals per cycle.\n");
+				fflush(stdout);
+				exit(1);
+			}
+			break;
+		case('c'):	case('v'):	case('x'):
+			get_extra_params(5,argc,argv);
+			if(flteq(number[0],number[1])) {
+				fprintf(stdout,"ERROR: Maximum and minimum vals are equal: no sinusoidal movement.\n");
+				fflush(stdout);
+				exit(1);
+			}
+			if(flteq(number[2],number[3])) {
+				fprintf(stdout,"ERROR: Start and end times equal .. no sinusoidal movement.\n");
+				fflush(stdout);
+				exit(1);
+			}
+			if(number[2] > number[3]) {
+				dur = number[2];
+				number[2] = number[3];
+				number[3] = dur;
+			}
+			if(number[2] < 0.0) {
+				fprintf(stdout,"ERROR: Time value less than zero.\n");
+				fflush(stdout);
+				exit(1);
+			}
+			if (ro == 'c') {
+				if(number[4] <= 3) {
+					fprintf(stdout,"ERROR: No of points < 3. Cannot define sinusoidal motion.\n");
+					fflush(stdout);
+					exit(1);
+				}
+			} else {
+				if(number[4] <= 5) {
+					fprintf(stdout,"ERROR: No of points < 5. Cannot define cosinusoidal motion.\n");
+					fflush(stdout);
+					exit(1);
+				}
+			}
+			break;
+		}
+		break;
+	case('S'):
+		switch(ro) {
+		case('M'):
+			get_funny_params(4,argc,argv);
+			break;
+		}
+		break;
+	case('T'):
+		switch(ro) {
+		case('b'):	
+			do_string_params(argv,2);
+			break;
+		case('B'):	
+			do_string_params(argv,3);
+			break;
+		}
+		break;
+	case('y'):
+		switch(ro) {
+		case('o'):	case('p'):	case('s'):	case('B'):	case('E'):	case('S'):
+			get_funny_params(1,argc,argv);
+			break;
+		case('e'):	case('l'):	case('g'):	case('I'):	case('A'):	case('C'): case('x'):
+			get_funny_params(2,argc,argv);
+			break;
+		case('R'):	case('a'):	case('b'):	case('c'):
+			get_funny_params(3,argc,argv);
+			break;
+		case('q'):	case('Q'):
+			get_funny_params(4,argc,argv);
+			break;
+		case('P'):
+			get_funny_params(5,argc,argv);
+			break;
+		case('i'):	
+			get_funny_params(2,argc,argv);
+			ifactor = (int)round(number[cnt]);
+			factor = number[cnt+1];
+			if(ifactor < 1 || ifactor > cnt+1) {
+				fprintf(stdout,"ERROR: Position must be within or at end of the column (1 to %d).\n",cnt+1);
+				fflush(stdout);
+				exit(1);
+			}
+			break;
+		case('d'):
+			get_funny_params(2,argc,argv);
+			ifactor = (int)round(number[cnt]);
+			factor = round(number[cnt+1]);
+			if((ifactor < 1) || (factor < 1.0)) {
+				fprintf(stdout,"ERROR: Positions must be 1 or greater.\n");
+				fflush(stdout);
+				exit(1);
+			}
+			if((ifactor > cnt) && (factor > (double)cnt)) {
+				fprintf(stdout,"ERROR: Positions must be inside the list you are editing.\n");
+				fflush(stdout);
+				exit(1);
+			}
+			if(((ifactor >= cnt) && (factor <= 1.0)) || ((ifactor == 1) && (factor >= (double)cnt))) {
+				fprintf(stdout,"ERROR: Entire column will be deleted.\n");
+				fflush(stdout);
+				exit(1);
+			}
+			break;
+		case('r'):
+			get_funny_params(2,argc,argv);
+			ifactor = (int)round(number[cnt]);
+			factor = number[cnt+1];
+			if(ifactor < 1 || ifactor > cnt) {
+				fprintf(stdout,"ERROR: Position must be within the column (1 to %d).\n",cnt);
+				fflush(stdout);
+				exit(1);
+			}
+			break;
+		}
+		break;
+	case('z'):
+		switch(ro) {
+		case('X'):	case('Y'):	case('Z'):
+			get_extra_params(3,argc,argv);
+			cnt = round(number[0]);
+			number[0] = number[1];
+			number[1] = number[2];
+			break;
+		case('e'):
+			get_extra_params(5,argc,argv);
+			ifactor = round(number[0]);
+			number[0] = number[1];
+			number[1] = number[2];
+			number[2] = number[3];
+			number[3] = number[4];
+			break;
+		case('A'):	case('B'):	case('C'):	case('D'):	case('E'):
+		case('F'):	case('G'):	case('H'):	case('I'):	case('J'):
+			get_extra_params(4,argc,argv);
+			cnt = round(number[0]);
+			number[0] = number[1];
+			number[1] = number[2];
+			number[2] = number[3];
+			if(cnt <= 0) {
+				fprintf(stdout,"ERROR: Number of steps cannot be less than 1.\n");
+				fflush(stdout);
+				exit(1);
+			}
+			break;
+		case('q'):
+			get_extra_params(4,argc,argv);
+			cnt = round(number[0]);
+			number[0] = number[1];
+			number[1] = number[2];
+			number[2] = number[3];
+			if(cnt<=1) {
+				fprintf(stdout,"ERROR: Can't randomise less than 2 elements.\n");
+				fflush(stdout);
+				exit(1);
+			}
+			quantisation = number[0];
+			dur  		 = number[1]; 	
+			scat 		 = number[2];
+			tq = (int)floor(dur/quantisation) + 1; 			/* total quantised positions */
+			ql = (int)ceil(tq/(cnt-1));				 		/* average number of quanta per placed item */
+			if(ql <= 1) {
+				fprintf(stdout,"ERROR: Quantisation is too coarse to accomodate all these elements.\n");
+				fflush(stdout);
+				exit(1);
+			}
+			if(scat <= 1.0)  {								/* for scatter less than 1 */
+				ql = (int)round(ql * scat);
+				if(ql <= 1) {
+					fprintf(stdout,"ERROR: Scatter is too small to achieve randomisation of position.\n");
+					fflush(stdout);
+					exit(1);
+				}
+			}
+			if((cnt+1 > 4) && (number = (double *)realloc((char *)number,(cnt+1) * sizeof(double)))==NULL) {
+				fprintf(stdout,"ERROR: Out of memory.\n");
+				fflush(stdout);
+				exit(1);
+			}
+			break;
+		}
+		break;
+	case('Z'):
+		switch(ro) {
+		case('H'):	case('m'):
+			get_extra_params(3,argc,argv);
+			break;
+		}
+		break;
+	default:
+		fprintf(stdout,"ERROR: Unknown process mode.\n");
+		fflush(stdout);
+		exit(1);
+	}
+}
+
+/************************* DO_STRING_PARAMS ***************************
+ *
+ * Reads parameters which are strings
+ *
+ * NB stringscnt will then include count of these parameters,
+ * hence count of any strings values read from file gets remembered as 'cnt'.
+ */
+
+void do_string_params(char *argv[],int pcnt)
+{
+	int  strspace, n, k, nn;
+	int space_step = 200, old_stringstoresize, startstringscnt = stringscnt;
+	char temp2[200], *p;
+	int total_space = space_step;
+	cnt = stringscnt;		/* remember count of any existing strings */
+	if(stringstoresize == 0) {
+		if((stringstore = (char *)exmalloc(total_space))==NULL) {
+			sprintf(errstr,"Out of Memory\n");
+			do_error();
+		}
+	}
+	for(n=2,k=0;k<pcnt;k++,n++) {
+		strcpy(temp2,argv[n]);
+		strspace = strlen(temp2)+1;
+		old_stringstoresize = stringstoresize;
+		if((stringstoresize += strspace) >= total_space) {
+			while(stringstoresize  >= total_space)
+				total_space += space_step;
+			if((stringstore = (char *)exrealloc((char *)stringstore,total_space))==NULL) {
+				sprintf(errstr,"Out of Memory\n");
+				do_error();
+			}
+		}
+		strcpy(stringstore + stringstart,temp2);
+		stringstart += strspace;
+		stringscnt++;
+    }
+	if(stringscnt <= cnt) {
+		fprintf(stdout,"ERROR: Invalid or missing data.\n");
+		fflush(stdout);
+		exit(1);
+	}
+	if(strings == 0) {
+		if((strings = (char **)malloc(stringscnt * sizeof(char *)))==NULL) {
+			sprintf(errstr,"Out of Memory\n");
+			do_error();
+		}
+	} else {
+		if((strings = (char **)realloc((char *)strings,stringscnt * sizeof(char *)))==NULL) {
+			sprintf(errstr,"Out of Memory\n");
+			do_error();
+		}
+	}
+	p = stringstore;
+	nn = 0;
+	while(nn < startstringscnt) {
+		while(*p != ENDOFSTR)
+			p++;
+		p++;
+		nn++;
+	}
+	while(nn < stringscnt) {
+		strings[nn] = p;
+		while(*p != ENDOFSTR)
+			p++;
+		p++;
+		nn++;
+	}
+	fclose(fp[0]);
+}
+
+/********************************* READ_DATA *********************************/
+
+void read_data(char *startarg,char *endarg,int *ro)
+{
+									/* READ THE (FIRST) FILE DATA */
+	if(!strncmp(endarg,"-th",3) || !strncmp(endarg,"-tM",3))
+		do_pitchtext_infile(startarg);				/* PITCH-REPRESENTING TEXTS in file */
+	else if(!strncmp(endarg,"-As",3) || !strncmp(endarg,"-dl",3) || !strncmp(endarg,"-rr",3)
+	 || !strncmp(endarg,"-rR",3) || !strncmp(endarg,"-rX",3)
+	 || !strncmp(endarg,"-dv",3) || !strncmp(endarg,"-G",2)	 || !strncmp(endarg,"-sK",3)
+	 || !strncmp(endarg,"-sk",3) || !strncmp(endarg,"-Ro",3) || !strncmp(endarg,"-Ff",3)
+	 || !strncmp(endarg,"-FR",3) || !strncmp(endarg,"-Tb",3) || !strncmp(endarg,"-TB",3)
+	 || !strncmp(endarg,"-nM",3) || !strcmp(endarg,"-kT")	 || !strcmp(endarg,"-kX")
+	 || !strcmp(endarg,"-kA")    || !strcmp(endarg,"-kB")    || !strcmp(endarg,"-kC")
+	 || !strcmp(endarg,"-kY")    || !strncmp(endarg,"-aT",3) || !strncmp(endarg,"-aX",3)
+	 || !strncmp(endarg,"-nT",3) || !strncmp(endarg,"-sU",3) || !strncmp(endarg,"-Rx",3)
+	 || !strncmp(endarg,"-eb",3) || !strncmp(endarg,"-nF",3)) {
+		do_string_infile(startarg);					/* STRINGS in file */
+	} else if(!strncmp(endarg,"-J",2) || !strncmp(endarg,"-j",2) || !strncmp(endarg,"-jj",3) 
+		|| !strncmp(endarg,"-Jj",3) || !strncmp(endarg,"-Wb",3) ) {
+		colcnt = do_stringline_infile(startarg,0);	/* LINES OF STRINGS in file */
+		if(!strncmp(endarg,"-Wb",3) && (colcnt != 3)) {
+			fprintf(stdout,"ERROR: THis process only works with sequence files\n");
+			fflush(stdout);
+			exit(1);
+		}
+		cnt = stringscnt;
+	} else if(!strncmp(endarg,"-DB",3))
+		do_DB_infile(startarg);						/* DB info in file */
+	else if(!strcmp(endarg,"-c"))
+		*ro = ENDOFSTR;								/* COUNT only, option */
+	else if(!strcmp(endarg,"-cl"))
+		*ro = 'l';									/* COUNT lines, option */
+	else
+		do_infile(startarg);						/* read numeric values */
+}
+
+/********************************* DO_HELP *********************************/
+
+void do_help(char *str)
+{
+	if(!strcmp(str,"-f"))    help();
+	if(!strcmp(str,"-m"))    helpm();
+    if(!strcmp(str,"-M"))    helpM();
+    if(!strcmp(str,"-R"))    helpr();
+    if(!strcmp(str,"-l"))    helpl();
+    if(!strcmp(str,"-g"))    helpg();
+}
+
+/********************************* OPTION_TAKES_NO_DATA_BUT_HAS_EXTRA_PARAMS *********************************/
+
+int option_takes_NO_data_but_has_extra_params(char *agv)
+{
+	if(!strcmp(agv,"-Rg") || !strcmp(agv,"-Rv") || !strcmp(agv,"-Rc") || !strcmp(agv,"-Ri") || !strcmp(agv,"-RI")
+	|| !strcmp(agv,"-At") || !strcmp(agv,"-AT") || !strcmp(agv,"-Ad") || !strcmp(agv,"-ic") || !strcmp(agv,"-i=") 
+	|| !strcmp(agv,"-L")  || !strcmp(agv,"-Q")  || !strcmp(agv,"-iC") || !strcmp(agv,"-ie") || !strcmp(agv,"-rz") || !strcmp(agv,"-qz") 
+ 	|| !strcmp(agv,"-Rr") || !strcmp(agv,"-iR") || !strcmp(agv,"-iQ") || !strcmp(agv,"-cs") || !strcmp(agv,"-ss")
+	|| !strcmp(agv,"-sc") || !strcmp(agv,"-sv") || !strcmp(agv,"-sx") || !strncmp(agv,"-Zm",3) || !strncmp(agv,"-ZH",3)
+	|| !strncmp(agv,"-z",2) || !strcmp(agv,"-RG") || !strcmp(agv,"-rG") || !strcmp(agv,"-rJ") || !strcmp(agv,"-pp"))	
+		return 1;			/* all flags starting with 'z', don't read data, but have extra-params */
+	return 0;
+}
+
+/********************************* OPTION_TAKES_DATA_AND_HAS_EXTRA_PARAMS *********************************/
+
+int option_takes_data_and_has_extra_params(char *agv)
+{
+	if(!strncmp(agv,"-y",2) 	/* all flags starting with 'y', read data, and have extra-params */
+	|| !strncmp(agv,"-Tb",3) || !strncmp(agv,"-TB",3) || !strncmp(agv,"-Ca",3) || !strncmp(agv,"-Cm",3)
+	|| !strcmp(agv,"-sa")    || !strcmp(agv,"-sb")	  || !strcmp(agv,"-sf")	   || !strncmp(agv,"-bb",3)
+	|| !strcmp(agv,"-dd")    || !strcmp(agv,"-dL")    || !strcmp(agv,"-SM") || !strcmp(agv,"-ga")
+	|| !strncmp(agv,"-K",2))	/* all flags starting with 'K', read data, and have extra-params */
+		return 1;
+	return 0;
+}
+
+/********************************* CHECK_EXCEPTIONAL_PROCESSES ********************************/
+
+void check_exceptional_processes(int ro,int argc)
+{
+	if(!sloom && !sloombatch) {
+		if(flag=='H' && (ro==ENDOFSTR || ro=='r') && cnt>1) {
+			fprintf(stderr,"Too many values in file for H");
+			if(ro=='r')
+				fprintf(stderr,"r");
+			fprintf(stderr," flag.\n");
+			exit(1);
+		}
+
+		if((flag=='J' || (flag=='C' && (ro == ENDOFSTR || ro == 'c'))) && argc<4) {
+			fprintf(stderr,"Flags J & C need at least 2 input files.\n");
+			exit(1);
+	    }
+	    if(((flag=='S' && ro==ENDOFSTR) || flag=='N') && argc!=4) {
+			fprintf(stderr,"flags S & N or Nr need 1 infilename & 1 generic outfilename.\n");
+			exit(1);
+	    }
+	} else {
+		if(flag=='H' && (ro==ENDOFSTR || ro=='r') && cnt>1) {
+			fprintf(stdout,"ERROR: Too many values in file this option.\n");
+			fflush(stdout);
+			exit(1);
+		}
+	    if((flag=='J' || flag=='j'  
+		|| (flag == 'W' && ro == 'b')
+	    || (flag=='e' && (ro == 's' || ro == 'i' || ro == 'A' || ro == 'S' || ro == 'w' || ro == 'W' || ro == 'L' || ro == 'Q' || ro == 'X' || ro == 'Y'))
+	    || (flag == 'A' && ro == 'e')) && argc<4) {
+			fprintf(stdout,"ERROR: This option needs at least 2 input files.\n");
+			fflush(stdout);
+			exit(1);
+	    }
+	    if(((flag=='S' && ro==ENDOFSTR) || flag=='N') && argc!=4) {
+			fprintf(stdout,"ERROR: These options need 1 infilename & 1 generic outfilename.\n");
+			fflush(stdout);
+			exit(1);
+	    }
+	}
+}
+
+/********************************* HANDLE_MULTIFILE_PROCESSES_AND_THE_OUTPUT_FILE ********************************/
+
+void handle_multifile_processes_and_the_output_file(int argc, char flag,int ro,char **argv)
+{
+	int joico = 0, colcnt2 = 0;
+
+	if(!sloom) {
+		if(flag=='J') {
+			joico = 1;
+		    firstcnt = cnt;
+		    infilecnt = argc-2;		
+	   	    do_other_stringline_infiles(argv,'J');
+		} else if(flag=='C' && (ro == ENDOFSTR || ro == 'c')) {
+			joico = 1;
+		    firstcnt = cnt;
+		    infilecnt = argc-2;		
+			do_other_infiles(argv);
+		} else if(flag =='j') {
+			if(ro == 0) {
+			    infilecnt = 2;	
+				colcnt2 = do_other_stringline_infile(argv[2]);
+				if(colcnt != colcnt2) {
+					fprintf(stdout,"ERROR: Incompatible column counts (%d and %d) in these two files.\n",colcnt,colcnt2);
+					fflush(stdout);
+					exit(1);
+				}
+			} else if(ro =='j') {
+				infilecnt = argc-2;		
+		   	    do_other_stringline_infiles(argv,'j');
+			}
+		} else if(flag =='W' && ro == 'b') {
+			infilecnt = argc-2;		
+	   	    do_other_stringline_infiles(argv,'W');
+		} else if(flag =='K' && ro == 'b') {
+			infilecnt = argc-3;		
+	   	    do_other_infiles(argv);
+		} else {
+		    if(argc>4 && !joico) {
+				fprintf(stdout,"Too many arguments.\n");
+				fflush(stdout);
+				exit(1);
+		    }
+	    	if(flag!='S' && flag!='N') {
+	/*RWD*/		if(!strcmp(argv[2],"con") || !strcmp(argv[2],"CON"))
+		    		fp[1]=stdout;
+				else if(allcols == 1)
+	 	           	do_outfile(argv[2]);
+				else
+					strcpy(goalfile,argv[2]);
+		   	}
+		}
+	} else {
+		if(flag=='A' && ro == 'e') {
+			joico = 1;
+		    infilecnt = argc-2;		
+			if((file_cnt = (int *)malloc(infilecnt * sizeof(int)))==NULL) {
+				fprintf(stdout,"ERROR: Out of memory.\n");
+				fflush(stdout);
+				exit(1);
+			}
+	 		file_cnt[0] = cnt;
+	   	    do_other_infiles(argv);
+		} else if(flag=='J') {
+			joico = 1;
+		    firstcnt = cnt;
+		    infilecnt = argc-2;		
+	   	    do_other_stringline_infiles(argv,'J');
+		} else if(flag=='C' && (ro == ENDOFSTR || ro == 'c')) {
+			joico = 1;
+		    firstcnt = cnt;
+		    infilecnt = argc-2;		
+	   	    do_other_infiles(argv);
+		} else if(flag =='e' 
+			&& (ro == 's' || ro == 'i' || ro == 'a' || ro == 'A' || ro == 'S' || ro == 'w' || ro == 'W' || ro == 'L' || ro == 'Q' 
+			|| ro == 'X' || ro == 'm' || ro =='Y')) {
+		    firstcnt = cnt;
+		    infilecnt = 2;	
+	   	    do_other_infiles(argv);
+		} else if(flag =='w' && (ro == 't' || ro == 'o')) {
+		    firstcnt = cnt;
+		    infilecnt = 2;	
+	   	    do_other_infiles(argv);
+		} else if(flag =='j') {
+			if(ro == 0) {
+			    infilecnt = 2;	
+		   	    colcnt2 = do_other_stringline_infile(argv[2]);
+				if(colcnt != colcnt2) {
+					fprintf(stdout,"ERROR: Incompatible column counts (%d and %d) in these two files.\n",colcnt,colcnt2);
+					fflush(stdout);
+					exit(1);
+				}
+			} else if(ro =='j') {
+			    infilecnt = argc-2;		
+				do_other_stringline_infiles(argv,'j');
+			}
+		} else if(flag =='W' && ro == 'b') {
+			infilecnt = argc-2;		
+	   	    do_other_stringline_infiles(argv,'W');
+		} else if(flag =='K' && ro == 'b') {
+			infilecnt = argc-3;		
+	   	    do_other_infiles(argv);
+		} else if(!joico) {
+		    if(argc>4) {
+				fprintf(stdout,"ERROR: Too many arguments.\n");
+				fflush(stdout);
+				exit(1);
+		    }
+			if(flag!='S' && flag!='N') {
+				if(allcols == 1)
+					do_outfile(argv[2]);
+				else
+					strcpy(goalfile,argv[2]);
+			}
+		}
+	}
+}
+
+/********************************* ERROR_REPORTING ********************************/
+
+
+void cant_read_numeric_value(char flag,int ro) {
+	if(!sloom && !sloombatch)
+		fprintf(stderr,"Cannot read numerical value with flag %c%c\n",flag,ro);
+	else {
+		fprintf(stdout,"ERROR: Cannot read numerical value.\n");
+		fflush(stdout);
+	}
+	exit(1);
+}
+
+void cant_read_numeric_value_with_flag_only(char flag) {
+	if(!sloom && !sloombatch)
+		fprintf(stderr,"Cannot read numerical value with flag %c\n",flag);
+	else {
+		fprintf(stdout,"ERROR: Cannot read numerical value.\n");
+		fflush(stdout);
+	}
+	exit(1);
+}
+
+void unknown_flag_only(char flag)
+{
+	if(!sloom && !sloombatch)
+		fprintf(stderr,"Unknown flag -%c\n",flag);
+	else {
+		fprintf(stdout,"ERROR: Unknown option.\n");
+		fflush(stdout);
+	}
+	exit(1);
+}
+
+void unknown_flag(char flag,int ro)
+{
+	if(!sloom && !sloombatch)
+		fprintf(stderr,"Unknown flag -%c%c\n",flag,ro);
+	else {
+		fprintf(stdout,"ERROR: Unknown option.\n");
+		fflush(stdout);
+	}
+	exit(1);
+}
+
+void cannot_read_flags(char *flagstr)
+{
+	if(!sloom && !sloombatch)
+		fprintf(stderr,"Cannot read flag %s.\n",flagstr);
+	else {
+		fprintf(stdout,"ERROR: Cannot read the option type\n");
+		fflush(stdout);
+	}
+	exit(1);
+}
+
+void flag_takes_no_params(char flag,int ro)
+{
+	if(!sloom && !sloombatch)
+		fprintf(stderr,"flag -%c%c does not take a parameter\n",flag,ro);
+	else {
+		fprintf(stdout,"ERROR: This option does not take a parameter\n");
+		fflush(stdout);
+	}
+	exit(1);
+}
+
+void flag_only_takes_no_params(char flag)
+{
+	if(!sloom && !sloombatch)
+		fprintf(stderr,"flag -%c does not take a parameter\n",flag);
+	else {
+		fprintf(stdout,"ERROR: This option does not take a parameter\n");
+		fflush(stdout);
+	}
+	exit(1);
+}
+
+void unknown_flag_or_bad_param(void)
+{
+	if(!sloom && !sloombatch)
+		fprintf(stderr,"Unknown flag or inappropriate use of parameter.\n");
+	else {
+		fprintf(stdout,"ERROR: Unknown flag or inappropriate use of parameter.\n");
+		fflush(stdout);
+	}
+	exit(1);
+}
+
+void no_value_with_flag(char flag,int ro)
+{
+	if(!sloom && !sloombatch)
+	   	fprintf(stderr,"No value supplied with flag -%c%c\n",flag,ro);
+	else {
+	   	fprintf(stdout,"ERROR: No value supplied with this option\n");
+		fflush(stdout);
+	}
+   	exit(1);
+}
+
+void no_value_with_flag_only(char flag)
+{
+	if(!sloom && !sloombatch)
+	   	fprintf(stderr,"No value supplied with flag -%c\n",flag);
+	else {
+	   	fprintf(stdout,"ERROR: No value supplied with this option\n");
+		fflush(stdout);
+	}
+   	exit(1);
+}
+
+void no_value_required_with_flag(char flag,int ro)
+{
+	if(!sloom && !sloombatch)
+		fprintf(stderr,"No parameter required with flag %c%c.\n",flag,ro);
+	else {
+		fprintf(stdout,"ERROR: No parameter required with this option.\n");
+		fflush(stdout);
+	}
+	exit(1);
+}
+
+void no_value_required_with_flag_only(char flag)
+{
+	if(!sloom && !sloombatch)
+		fprintf(stderr,"No parameter required with flag %c\n",flag);
+	else {
+		fprintf(stdout,"ERROR: No parameter required with this option.\n");
+		fflush(stdout);
+	}
+	exit(1);
+}
+
+void read_flags_data_error(char *str)
+{
+	if(!sloom && !sloombatch)
+		fprintf(stderr,"%s\n",str);
+	else {
+		fprintf(stdout,"ERROR: %s\n",str);
+		fflush(stdout);
+	}
+	exit(1);
+}
+
+void unknown_flag_string(char *flagstr)
+{
+	if(!sloom && !sloombatch)
+		fprintf(stderr,"Unknown flag %s.\n",flagstr);
+	else {
+		fprintf(stdout,"ERROR: Unknown option\n");
+		fflush(stdout);
+	}
+	exit(1);
+}
+
+void do_error(void) {
+	if(!sloom && !sloombatch)
+		fprintf(stderr,"%s\n",errstr);
+	else {
+		fprintf(stdout,"ERROR: %s\n",errstr);
+		fflush(stdout);
+	}
+	exit(1);
+}
+
+void do_valout(double val) {
+	if(!sloom && !sloombatch) {
+		if(allcols > 1)
+			outcoldata[outcoldatacnt++] = val;
+		else
+	        fprintf(fp[1],"%lf\n",val);
+	} else
+		fprintf(stdout,"INFO: %lf\n",val);
+}
+
+void do_valout_as_message(double val) {
+	if(!sloom && !sloombatch)
+        fprintf(fp[1],"%lf\n",val);
+	else
+		fprintf(stdout,"WARNING: %lf\n",val);
+}
+
+void do_valout_flush(double val) {
+	if(!sloom && !sloombatch) {
+		if(allcols > 1)
+			outcoldata[outcoldatacnt++] = val;
+		else
+			fprintf(fp[1],"%lf\n",val);
+	} else {
+		fprintf(stdout,"INFO: %lf\n",val);
+		fflush(stdout);
+	}
+}
+
+void do_stringout(char *str) {
+	if(!sloom && !sloombatch) {
+		if(allcols > 1)
+			outcoldata[outcoldatacnt++] = atof(str);
+		else
+			fprintf(fp[1],"%s\n",str);
+	}
+	else
+		fprintf(stdout,"INFO: %s\n",str);
+}
+
+void do_valpair_out(double val0,double val1) {
+	if(!sloom && !sloombatch)
+		fprintf(fp[1],"%lf  %lf\n",val0,val1);
+	else
+		fprintf(stdout,"INFO: %lf  %lf\n",val0,val1);
+}
+
+/************************* CHECK_FOR_COLUMNEXTRACT ************************/
+
+void check_for_columnextract(char *argv1,int *argc,char *argv[])
+{
+	int this_column, linecnt;
+	double dummy;
+	char temp2[200], *p = argv[*argc-1];
+	if(*p != '-')
+		return;
+	p++;
+	if(*p != '-')
+		return;
+	p++;
+	if(*p != 'c')
+		return;
+	p++;
+	if(sscanf(p,"%d",&thecol)!=1)
+		return;
+	thecol--;
+	strcpy(srcfile,argv1);
+	(*argc)--;
+	if((fp[0] = fopen(argv1,"r"))==NULL) {
+		sprintf(errstr,"Cannot open infile %s\n",argv1);
+		do_error();
+	}
+	if((fp[2] = fopen("__temp.txt","w"))==NULL) {
+		sprintf(errstr,"Cannot open temporary file (__temp.txt) to store extracted column\n");
+		do_error();
+	}
+	this_column = 0;
+	linecnt = 0;
+	while(fgets(temp,200,fp[0])!=NULL) {
+		this_column = 0;
+		p = temp;
+		while(strgetstr(&p,temp2)) {
+			if(this_column == thecol) {
+				if(sscanf(temp2,"%lf",&dummy) != 1) {
+					sprintf(errstr,"Numeric values only for multicolumn data.\n");
+					do_error();
+				}
+		        fprintf(fp[2],"%s\n",temp2);
+			}
+			this_column++;
+		}
+		if(linecnt == 0) {
+			if(this_column <= thecol) {
+				sprintf(errstr,"There is no column %d in the input data.\n",thecol+1);
+				do_error();
+			}
+			allcols = this_column;
+		} else if(allcols != this_column) {
+			sprintf(errstr,"Inconsistent number of columns in data.\n");
+			do_error();
+		}
+		linecnt++;
+	}
+	fclose(fp[0]);
+	fclose(fp[2]);
+	if((outcoldata = (double *)malloc(linecnt * sizeof(double))) == NULL) {
+		sprintf(errstr,"Failed to allocate memory to store column data.\n");
+		do_error();
+	}
+}
+
+/********************************** VALID_CALL_FOR_MULTICOL_INPUT **********************************/
+
+int valid_call_for_multicol_input(char flag,int ro)
+{
+	switch(flag) {
+	case('A'):
+		if(ro == 's')
+			return 1;
+		if(noro(ro))
+			return 1;
+		break;
+	case('D'):
+		if(ro == 'B')
+			return 1;
+		break;
+	case('I'):
+		if(ro == 'r')
+			return 1;
+		break;
+	case('M'):
+		if(ro == 'h')
+			return 1;
+		if(ro == 'm')
+			return 1;
+		if(ro == 't')
+			return 1;
+		break;
+	case('P'):
+		if(noro(ro))
+			return 1;
+		break;
+	case('R'):
+		if(noro(ro))
+			return 1;
+		if(ro == 'A' || ro == 'a' || ro == 'm' || ro == 'o' || ro == 's')
+			return 1;
+		break;
+	case('S'):
+		if(ro == 'L')
+			return 1;
+		break;
+	case('T'):
+		if(ro == 'c' || ro == 'h' || ro == 'M' || ro == 'l')
+			return 1;
+		break;
+	case('a'):
+		if(noro(ro))
+			return 1;
+		break;
+	case('b'):
+		if(ro == 'g' || ro == 'l')
+			return 1;
+		break;
+	case('d'):
+		if(noro(ro))
+			return 1;
+		if(ro == 'b')
+			return 1;
+		break;
+	case('f'):
+		if(ro == 'l')
+			return 1;
+		break;
+	case('h'):
+		if(ro == 'M')
+			return 1;
+		break;
+	case('i'):
+		if(ro == 'L' || ro == 'M' || ro == 'a' || ro == 'h' || ro == 'm' || ro == 'l')
+			return 1;
+		break;
+	case('l'):
+		if(ro == 'i')
+			return 1;
+		break;
+	case('m'):
+		if(noro(ro))
+			return 1;
+		if(ro == 'M' || ro == 'g' || ro == 'l')
+			return 1;
+		break;
+	case('o'):
+	case('q'):
+		if(noro(ro))
+			return 1;
+		break;
+	case('r'):
+		if(ro == 'S' || ro == 'm' || ro == 'r')
+			return 1;
+		break;
+	case('s'):
+		if(ro == 'l' || ro == 't')
+			return 1;
+		break;
+	case('t'):
+		if(ro == 'M' || ro == 'h')
+			return 1;
+		break;
+	}
+	return 0;
+}
+
+int noro(int ro)
+{
+	if(ro == ENDOFSTR || ro == '.' || ro == '-' || isdigit(ro))
+		return 1;
+	return 0;
+}
+
+void output_multicol_data()
+{
+	int xcnt;
+	int this_column;
+	char *p, temp2[200];
+	if(strlen(goalfile) > 0) {
+		if((fp[0] = fopen(srcfile,"r"))==NULL) {
+			sprintf(errstr,"Cannot reopen source file %s\n",srcfile);
+			do_error();
+		}
+		do_outfile(goalfile);
+		xcnt = 0;
+		while(fgets(temp,200,fp[0])!=NULL) {
+			this_column = 0;
+			p = temp;
+			while(strgetstr(&p,temp2)) {
+				if(this_column == thecol)
+					fprintf(fp[1],"%lf",outcoldata[xcnt++]);
+				else
+					fprintf(fp[1],"%s",temp2);
+				fprintf(fp[1],"\t");
+				this_column++;
+			}
+			fprintf(fp[1],"\n");
+		}
+		fclose(fp[0]);
+		fclose(fp[1]);
+	} else {
+		for(xcnt = 0;xcnt < outcoldatacnt;xcnt++)
+			fprintf(stdout,"%lf\n",outcoldata[xcnt]);
+		fflush(stdout);
+	}
+}

+ 1270 - 0
dev/tabedit/columns1.c

@@ -0,0 +1,1270 @@
+/*
+ * 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
+ *
+ */
+
+
+
+/* columns */
+
+#include <columns.h>
+
+#define CALCLIM   		0.001
+#define M 			7
+#define NSTACK 			50
+#define	MIDDLE_C_MIDI_OCTAVE	5
+#define CONVERT_LOG10_TO_LOG2	(double)3.321928
+#define LOW_A   		6.875	   /* Frequency of A below MIDI 0  */
+
+
+
+double 	cntevents(double,double,double);
+int 	samesize(double,double,double,double,double);
+void 	approxtimes(double,double,int);
+void 	getetime(double,double,double,double,int);
+double 	gethibnd(double,double,double,double,double);
+double 	getlobnd(double,double,double,double,double);
+double 	refinesize(double,double,double,double,double,double);
+void	prnt_pitchclass(int,int);
+int		strgetfloat_db(char **,double *);
+static void bublsort(void);
+static void test_warp_data(void);
+
+int		*cntr;
+char 	**strings = 0;
+char	*stringstore;
+int		stringscnt = 0;
+int	stringstoresize = 0, stringstart = 0;
+
+/************************ TIMEVENTS ******************************
+ *
+ * 	Generates event positions from startsize and end size
+ *
+ *	Let start-time be T0 and end time be T1
+ *	Let start size be S0 and end S1
+ *
+ *	number of event is given by :-
+ *
+ *		N = (T1-T0) log S1
+ *		    -------    e__
+ *		    (S1-S0)     S0
+ *
+ *	In general this will be non-integral, and we should
+ *	round N to an integer, and recalculate S1 by successive 
+ *	approximation.
+ *
+ *	Then positions of events are given by
+ *	
+ *	    for X = 0 to N		 (S1-S0)
+ *					  ----- X
+ *	T = (S1T0 - S0T1)   S0(T1 - T0)  (T1-T0)
+ *	 s   -----------  + ----------  e 
+ *	      (S1 - S0)      (S1 - S0)
+ *
+ * 	If difference in eventsizes input to the main program is very small
+ * 	then infinite values result. To avoid this we divert the calculation
+ * 	to another routine (which assumes the input values are equal.
+ * 	The value of CALCLIM  = 0.001. (LArger than usual i.e. 0.05)
+ *
+ *	If size values are so BIG that they exceed segment duration, 
+ *	eventsize becomes segment duration and a Warning is printed.  
+ *(1)	events approx same size.
+ *(2)	events of different sizes, find the number of events which approx
+ *	fit in the duration.
+ *(3)	If there's only one event .. that's it.
+ *(4)	Note the error (difference between approximated whole number of events
+ *	and the actual,non-integer, number of events).
+ *(5)	Calculate acceptable bounds on a new endeventsize, which will give 
+ *	a better fit of the integer number of events within the given duration.
+ *(6)	Find an acceptable final value for endeventsize by successive approx
+ *	NB we don't know whether the function increases as d increases 
+ *	so lobound may be > hibound. However, the maths of the method will 
+ *	still work, just inverting the sense of the search!!
+ *(7)	Calculate the inital times of the events.
+ *
+ * This function returns the number of events within the time-interval,
+ * and returns the times of these events in the array-of-doubles pos.
+ */
+
+int timevents(double intime0,double intime1,double insize0,double insize1)
+{   
+	int    number;
+	double fnum, fnumber, error;
+	double lobound, hibound, duration;
+	if(flteq(insize0,0.0) || flteq(insize1,0.0)) {
+		sprintf(errstr,"Event size of zero encountered.\n");
+		do_error();
+	}
+	duration = (intime1-intime0);
+	if(duration<=0.0)   {
+		sprintf(errstr,"Inconsistent input times (2nd before 1st).\n");
+		do_error();
+	}
+	if(fabs(insize1-insize0)<CALCLIM)			/* 1 */
+		return(number = samesize(intime0,intime1,insize0,insize1,duration));
+	fnum     = cntevents(duration,insize0,insize1);	/* 2 */
+	number   = round(fnum);
+	if(number<=1)					/* 3 */
+		return(1);
+	pos = (double *)exmalloc((number+1) * sizeof(double));
+	fnumber = (double)(number);				/* 4 */
+	error   = fabs(fnum - fnumber);
+	lobound = insize1;					/* 5 */
+	hibound = insize1;
+	if(fnum<fnumber)
+		hibound = gethibnd(fnum,fnumber,insize1,insize0,duration);
+	if(fnum>fnumber)
+		lobound = getlobnd(fnum,fnumber,insize1,insize0,duration);
+	if(error > FLTERR) {				/* 6 */
+		if(lobound < hibound) /* LOBOUND is a HIGH SIZE for a LOW COUNT!! */
+		swap(&hibound,&lobound);
+		insize1 = refinesize(hibound,lobound,fnumber,error,duration,insize0);
+	} else {
+	  	insize1 = (hibound+lobound)/2;
+	}						/* 7 */
+	getetime(intime0,intime1,insize0,insize1,number);
+	pos[number] = intime1;
+	return(number+1);
+}
+
+/*************************** CNTEVENTS *****************************/
+
+double cntevents(double dur,double s0,double s1)
+{   double f1,f2;
+
+	f1  = dur;
+	f2  = s1-s0;
+	f1 /= f2;
+	f2  = s1/s0;
+	f2  = log(f2);
+	f1 *= f2;
+	return(fabs(f1));
+}
+
+/******************************* SAMESIZE *******************************
+ *
+ * get event positions, if eventsize approx same throughout segment.
+ *
+ *(1)	Get average size, find number of events and round to nearest int.
+ *(3)	Recalculate size, and thence event times.
+ */
+
+int samesize
+(double intime0,double intime1,double insize0,double insize1,double duration)
+{
+	int	number;
+	double fnum, size;					/* 1 */
+	size   = (insize0+insize1)/2;
+	fnum   = duration/size;
+	number = round(fnum);
+	size   = duration/(double)(number);
+	pos	= (double *)exmalloc((number+1) * sizeof(double));
+	approxtimes(intime0,size,number);
+	pos[number] = intime1;
+	return(number+1);
+}
+
+/************************ APPROXTIME ***************************
+ *
+ * Calculate time-positions of equally spaced events.
+ */
+
+void approxtimes(double intime0,double size,int number)
+{   int k; 
+	double *q = pos;
+	*q++ = intime0;
+	for(k=1;k<number;k++) {
+		*q = *(q-1) + size;
+		q++;
+	}
+}
+
+/******************************* GETETIME ********************************
+ *
+ * Calculate time-positions of events that vary in size between s0 and s1.
+ */
+
+void getetime(double t0,double t1,double s0,double s1,int number)
+{   int n;
+	double sdiff = s1-s0, tdiff = t1-t0, d1, d2, d3, *q = pos;
+	*q++ = t0;
+	for(n=1;n<number;n++)   {
+		d1	= sdiff/tdiff;
+		d1   *= (double)n;
+		d1    = exp(d1);
+		d2    = s0*tdiff;
+		d2   /= sdiff;
+		d1   *= d2;
+		d2    = s1*t0;
+		d3    = s0*t1;
+		d2   -= d3;
+		d2   /= sdiff;
+		d1   += d2;
+		*q++  = d1;
+	}
+}
+
+/****************************** GETHIBND *****************************
+ *
+ * Find SMALLER VALUE of SIZE, to GIVE a LARGER VALUE of NO-OF-SEGS
+ * which will act as an UPPER BOUND to be used for searching
+ * for an endsize that will give the integer number of events in the duration,
+ *
+ * (0)	Start by REDUCING size, to give BIGGER fnum.
+ *(1)  	If we're going downwards, (try -ve) and we go below zero,restore value
+ * 	and subtract less.
+ *(2)	If the fnums are moving in the opposite direction to what we expect, 
+ *	restore values and increment in the opposite direction,but only half 
+ *	as much!
+ */
+
+double gethibnd(double fnum,double fnumber,double insize1,
+		double insize0,double duration)
+{   double lastfnum, try = -1.0;	/* 0 */
+	double bound = insize1;
+	while(fnum<fnumber)  {
+		lastfnum = fnum;
+		bound += try;
+		while(bound<=0)  {				/* 1 */
+			bound -= try;
+			try /= 2.0;
+			bound += try;
+		}
+		fnum  = cntevents(duration,insize0,bound);
+		if(fnum<lastfnum)  {				/* 2 */
+			fnum=lastfnum;
+			bound -= try;		
+			try	 = -(try/2.0);
+   		}
+	}
+	return(bound);
+}
+
+/****************************** GETLOBND *****************************
+ *
+ *
+ * Find LARGER VALUE of SIZE, to GIVE a SMALLER VALUE of NO-OF-SEGS
+ * which will act as a LOWER BOUND to be used for searching
+ * for an endsize that will give the integer number of events in the duration,
+ *
+ * LOBOUND is a LARGER value of SIZE to give SMALLER value of NUM-OF-SEGS.
+ *
+ * (0)	Start by INCREASING size, to give SMALLER fnum.
+ * (1)	If we're going downwards, (try -ve) and we go below zero, restore 
+ *	propr value of bound, value and subtract less.
+ * (2)	If the fnums are moving in the opposite direction to what we expect, 
+ *	(fnum > lastfnum, while we're trying to DECREASE fnum)
+ *	restore values and increment in the opposite direction,but only half 
+ *	as much!
+ */
+
+double getlobnd(double fnum,double fnumber,double insize1,
+		double insize0,double duration)
+{   double try = 1.0;
+	double lastfnum;
+	double bound = insize1;
+	while(fnum>fnumber)  {
+		lastfnum = fnum;
+		bound += try;
+		while(bound<=0)  {
+			bound -= try;
+			try /= 2;
+			bound += try;
+		}
+		fnum  = cntevents(duration,insize0,bound);
+		if(fnum>lastfnum)  {
+			fnum =lastfnum;
+			bound -= try;		
+			try = -(try/2);
+		}
+	}
+	return(bound);
+}
+
+/***************************** REFINESIZE ******************************
+ *
+ * refine size of final event to reduce error within bounds.
+ */
+
+double refinesize(double hibound,double lobound,double fnumber,
+		  double error,double duration,double insize0)
+{   double size = (hibound+lobound)/2, fnum;
+	while(error>(FLTERR))   {
+		size = (hibound+lobound)/2;
+		fnum  = cntevents(duration,insize0,size);
+		error = fabs(fnumber-fnum);
+		if(error>FLTERR)  {
+			if(fnum<fnumber)
+			lobound = size;
+		else
+			hibound = size;
+		}
+	}
+	return(size);
+}
+
+/**************************STRGETFLOAT **************************
+ * takes a pointer TO A POINTER to a string. If it succeeds in finding 
+ * a float it returns the float value (*val), and it's new position in the
+ * string (*str).
+ */
+
+int  strgetfloat(char **str,double *val)
+{   char *p, *q, *end;
+	double numero;
+	int	point, valid;
+	for(;;) {
+		point = 0;
+		p = *str;
+		while(isspace(*p))
+			p++;
+		q = p;	
+		if(!isdigit(*p) && *p != '.' && *p!='-')
+			return(0);
+		if(*p == '.'|| *p == '-') {
+			if(*p == '-') {
+				p++;
+			} else {
+				point++;
+					p++;
+			}
+		}
+		for(;;) {
+			if(*p == '.') {
+				if(point)
+					return(0);
+				else {
+					point++;
+					p++;
+					continue;
+				}
+			}
+			if(isdigit(*p)) {
+				p++;
+				continue;
+			} else {
+				if(!isspace(*p) && *p!=ENDOFSTR)
+					return(0);
+				else {
+					end = p;
+				    p = q;
+					valid = 0;
+		    		while(p!=end) {
+					   	if(isdigit(*p))
+					  		valid++;
+						p++;
+					}
+					if(valid) {
+			 			if(sscanf(q,"%lf",&numero)!=1)
+							return(0);
+						*val = numero;
+					   *str = end;
+						return(1);
+					}
+					return(0);
+				}
+			}
+ 		}
+	}
+	return(0);				/* NOTREACHED */
+}
+
+/**************************STRGETFLOAT_DB **************************
+ * takes a pointer TO A POINTER to a string. If it succeeds in finding 
+ * a float it returns the float value (*val), and it's new position in the
+ * string (*str).	  IT JUMPS OVER 'db'
+ */
+
+int  strgetfloat_db(char **str,double *val)
+{
+	char *p, *q, *end;
+	double numero;
+	int    point, valid;
+	for(;;) {
+		point = 0;
+		p = *str;
+		while(isspace(*p))
+			p++;
+		q = p;	
+		if(!isdigit(*p) && *p != '.' && *p!='-')
+			return(0);
+		if(*p == '.'|| *p == '-') {
+			if(*p == '-') {
+				p++;
+			} else {
+				point++;
+				p++;
+			}
+		}
+		for(;;) {
+			if(*p == '.') {
+				if(point)
+					return(0);
+				else {
+					point++;
+					p++;
+					continue;
+				}
+			}
+			if(isdigit(*p)) {
+				p++;
+				continue;
+			} else {
+				if(!isspace(*p) && *p!=ENDOFSTR && !(*p=='d' || *p=='D') && !(*(p+1)!='b' || *(p+1)!='B'))
+					return(0);
+				else {
+					end = p;
+					p = q;
+					valid = 0;
+					while(p!=end) {
+						if(isdigit(*p))
+							valid++;
+						p++;
+					}
+					if(*end=='d' || *end=='D')
+						end += 2;
+					if(valid) {
+						if(sscanf(q,"%lf",&numero)!=1)
+							return(0);
+						*val = numero;
+						*str = end;
+						return(1);
+					}
+					return(0);
+				}
+			}
+		}
+	}
+	return(0);	   		 /* NOTREACHED */
+}
+
+/**************************STRGETSTR ***************************/
+
+int  strgetstr(char **str,char *str2)
+{   
+	char *p, *q, c;
+	p = *str;
+	while(isspace(*p))
+		p++;
+	if(*p == ENDOFSTR)
+		return(0);
+	q = p;
+	while(!isspace(*p))
+		p++;
+	c = *p;
+	*p = ENDOFSTR;
+	strcpy(str2,q);
+	*p = c;
+	*str = p;
+	return(1);
+}	
+
+/************************** HZTOMIDI ************************/
+
+double miditohz(double midi)
+{   double frq;
+	frq  = midi;
+	frq += 3.0;
+	frq /= 12.0;
+	frq  = pow((double)2,frq);
+	frq *= LOW_A;
+	return(frq);
+}
+
+/****************************** MIDITOHZ *************************/
+
+double hztomidi(double hz)
+{   double midi;
+	midi  = hz;
+	midi /= LOW_A;
+	midi  = log10(midi) * CONVERT_LOG10_TO_LOG2;
+	midi *= 12.0;
+	midi -= 3.0;
+	return(midi);
+}
+
+/*********************** RNDPERM ************************/
+
+void rndperm(double *z)
+{
+	int n,t;
+	int k = cnt * sizeof(double);
+	permm = (double *)exmalloc(k*2);
+	memset((char *)permm,0,k*2);
+	permmm = permm + cnt;
+	for(n=0;n<cnt;n++) {
+		t = (int)(drand48() * (double)(n+1)); /* TRUNCATE */
+		if(t==n)
+			prefix(z,n);
+		else
+			insert(z,n,t);
+	}
+	memcpy((char *)z,(char *)permmm,k);
+	free(permm);
+}
+
+/*********************** RNDPERM2 ************************
+ *
+ * Does not malloc and free perm internally.
+ */
+
+void rndperm2(double *z)
+{   int n,t;
+	int k = cnt * sizeof(double);
+	memset((char *)permm,0,k*2);
+	permmm = permm + cnt;
+	for(n=0;n<cnt;n++) {
+		t = (int)(drand48() * (double)(n+1)); /* TRUNCATE */
+		if(t==n)
+			prefix(z,n);
+		else
+			insert(z,n,t);
+	}
+	memcpy((char *)z,(char *)permmm,k);
+}
+
+/*********************** MULTRNDPERM ************************
+ *	START
+ *	  orig      orig     orig
+ *	|--------|--------|--------|
+ *	1ST PERM
+ *        perm1     orig     orig
+ *	|--------|--------|--------|
+ *	NEXT PERM
+ *        perm1     perm2    orig
+ *	|--------|--------|--------|
+ *	MEMCPY
+ *     perm1=perm2  orig     orig
+ *	|--------|--------|--------|
+ *	go to NEXT PERM
+ */
+
+void multrndperm(double *blok1)
+{   int n, m;
+	double lastenditem, *blok2, *blok3;
+	int oneblok	= cnt * sizeof(double);
+	int twobloks   = oneblok*2;
+    int threebloks = oneblok*3;
+	blok1 = (double *)exrealloc((char *)blok1,threebloks);
+	blok2 = blok1 + cnt;
+	blok3 = blok2 + cnt;
+    memcpy((char *)blok2,(char *)blok1,oneblok);
+	memcpy((char *)blok3,(char *)blok1,oneblok);
+	permm = (double *)exmalloc(cnt * 2 * sizeof(double));
+	rndperm2(blok1);			/* perm 1st copy */
+	for(n=0;n<cnt;n++)
+		do_valout(blok1[n]);
+	for(m=1;m<ifactor;m++) {	/* now do perms on 2nd copy */
+ 	   lastenditem = *(blok2-1);
+		do {
+ 			rndperm2(blok2);
+		} while(blok2[0]==lastenditem);
+			 /* Avoid element repeat at block boundaries */
+		for(n=0;n<cnt;n++)
+			do_valout(blok2[n]);
+		memcpy((char *)blok1,(char *)blok2,twobloks); 
+			/* Move perm along & restore orig set */
+	}
+ 	fflush(stdout);
+	free(permm);
+}
+
+/************************** INSERT *************************/
+
+void insert(double *z,int m,int t)
+{
+	shuffle(t+1,m);
+	permmm[t+1] = z[m];
+}
+
+/************************** PREFIX ***************************/
+
+void prefix(double *z,int m)
+{   permmm--;
+	permmm[0] = z[m];
+}
+
+/*************************** SHUFFLE ***********************/
+
+void shuffle(int k,int m)
+{
+	int n;
+	double *i;
+	if(k/2 > m) {	/* shuffle up */
+		i = &permmm[m];
+		for(n=m;n>k;n--) {
+			*i = *(i-1);
+			i--;
+		}
+	} else {		/* shuffle down */
+		i = &permmm[0];
+		for(n=0;n<k;n++) {
+			*(i-1) = *i;
+			i++;
+		}
+		permmm--;	/* Move base of perm down by 1 */
+	}
+}
+
+/******************************** EXMALLOC ****************************/
+
+char *exmalloc(int n)
+{
+	char *p;
+	if((p = (char *)malloc(n))==NULL) {
+		sprintf(errstr,"ERROR: Memory allocation failed\n");
+		do_error();
+	}
+	return(p);
+}
+
+/************************ READ_INPUT_FILE ****************************/
+
+void read_input_file(FILE *fpp)
+{   char *p;
+	double *number2;
+	while(fgets(temp,20000,fpp)!=NULL) {
+		p = temp;
+		while(strgetfloat(&p,&number[cnt])) {
+			if(++cnt >= arraysize) {
+				arraysize += BIGARRAY;
+/* NOVEMBER 2001 NEW */
+				number2 = (double *)malloc(arraysize*sizeof(double));
+				memcpy((void *)number2,(void *)number,cnt * sizeof(double));
+				number = number2;
+/* NOVEMBER 2001 OLD			
+				number = (double *)exrealloc((char *)number,arraysize*sizeof(double));
+*/					
+			}
+		}
+	}
+}
+
+/************************* DO_INFILE ***************************/
+
+void do_infile(char *argv)
+{
+	char *p;
+	double *number2;
+	if((fp[0] = fopen(argv,"r"))==NULL) {
+		sprintf(errstr,"Cannot open infile %s\n",argv);
+		do_error();
+	}
+	while(fgets(temp,20000,fp[0])!=NULL) {
+		p = temp;
+		while(strgetfloat(&p,&number[cnt])) {
+			if(++cnt >= arraysize) {
+				arraysize += BIGARRAY;
+/* NOVEMBER 2001 NEW */
+				if((number2=(double *)malloc(arraysize*sizeof(double)))==NULL) {
+					sprintf(errstr,"Out of memory for more numbers at %d numbers\n",cnt);
+					do_error();
+				}
+				memcpy((void *)number2,(void *)number,cnt * sizeof(double));
+				number = number2;
+
+/* NOVEMBER 2001 OLD
+				if((number=(double *)exrealloc((char *)number,arraysize*sizeof(double)))==NULL) {
+					sprintf(errstr,"Out of memory for more numbers at %d numbers\n",cnt);
+					do_error();
+				}
+*/
+			}
+		}
+	}
+	if(cnt <=0) {
+		sprintf(errstr,"Invalid or missing data.\n");
+		do_error();
+	}
+	fclose(fp[0]);
+}
+
+/************************* DO_DB_INFILE ***************************/
+
+void do_DB_infile(char *argv)
+{
+	char *p;
+	if((fp[0] = fopen(argv,"r"))==NULL) {
+		sprintf(errstr,"Cannot open infile %s\n",argv);
+		do_error();
+	}
+	while(fgets(temp,20000,fp[0])!=NULL) {
+		p = temp;
+		while(strgetfloat_db(&p,&number[cnt])) {
+			if(++cnt >= arraysize) {
+				arraysize += BIGARRAY;
+				number=(double *)exrealloc((char *)number,arraysize*sizeof(double));
+			}
+		}
+	}
+	if(cnt <=0) {
+		sprintf(errstr,"Invalid or missing data.\n");
+		do_error();
+	}
+	fclose(fp[0]);
+}
+
+/************************* DO_PITCHTEXT_INFILE ***************************/
+
+void do_pitchtext_infile(char *argv)
+{
+	char *p;
+	char temp2[200];
+	if((fp[0] = fopen(argv,"r"))==NULL) {
+		sprintf(errstr,"Cannot open infile %s\n",argv);
+		do_error();
+	}
+	while(fgets(temp,200,fp[0])!=NULL) {
+		p = temp;
+		while(strgetstr(&p,temp2)) {
+			number[cnt] = texttomidi(temp2);
+			if(++cnt >= arraysize) {
+				arraysize += BIGARRAY;
+				number=(double *)exrealloc((char *)number,arraysize*sizeof(double));
+			}
+		}
+	}
+	if(cnt <=0) {
+		sprintf(errstr,"ERROR: Invalid or missing data.\n");
+		do_error();
+	}
+	fclose(fp[0]);
+}
+
+/************************* DO_OTHER_INFILE **********************/
+
+void do_other_infiles(char *argv[])
+{   
+	int n;
+	if(infilecnt>2)
+		fp = (FILE **)exrealloc((char *)fp,infilecnt*sizeof(FILE *));
+	firstcnt = cnt;
+	for(n=1;n<infilecnt;n++) {
+		if((fp[n] = fopen(argv[n+1],"r"))==NULL) {
+			sprintf(errstr,"\nCannot open file %s to read.\n",argv[n+1]);
+			do_error();
+		}
+		read_input_file(fp[n]);
+		if (flag == 'A' && ro =='e') {
+			file_cnt[n] = cnt - firstcnt;
+			firstcnt = cnt;
+		} else if((flag=='J' || (flag=='C' && ro == 'c')) && cnt != firstcnt * (n+1)) {
+			sprintf(errstr,"Input file %d has wrong number of values to match previous column lengths.\n",n+1);
+			do_error();
+		}
+	}
+	if (flag == 'w' && (ro == 't' || ro == 'o')) {
+		test_warp_data();
+	}
+}
+
+/********************** DO_OUTFILE *****************************/
+
+void do_outfile(char *argv) {
+
+	if((fp[1] = fopen(argv,"w"))==NULL) {
+		sprintf(errstr,"Cannot open file %s to write.\n",argv);
+		do_error();
+		exit(1);
+	}
+}
+
+/**************************** QIKSORT ******************************/
+
+void qiksort(void) {
+	bublsort();
+}
+
+/************************ BELLPERM1 ***************************/
+
+void bellperm1(void)
+{   int n;
+	for(n=0;n<cnt;n+=2)
+		swap(&number[n], &number[n+1]);
+}
+
+/************************** BELLPERM2 ******************************/
+
+void bellperm2(void)
+{   int n;
+	for(n=2;n<cnt;n+=2)
+		swap(&number[n], &number[n-1]);
+}
+
+/************************* BELLPERM3 ******************************/
+
+void bellperm3(void)
+{   int n;
+	for(n=2;n<cnt;n+=2)
+		swap(&number[n], &number[n+1]);
+}
+
+/***************************** SWAP *******************************/
+
+void swap(double *d0,double *d1)
+{
+	double temp = *d0;
+	*d0 = *d1;
+	*d1 = temp;
+}
+
+/**************************** FLTEQ *******************************/
+
+int flteq(double f1,double f2)
+{
+	double upperbnd, lowerbnd;
+	upperbnd = f2 + FLTERR;		
+	lowerbnd = f2 - FLTERR;		
+	if((f1>upperbnd) || (f1<lowerbnd))
+		return(0);
+	return(1);
+}
+
+/***************************** ELIMINATE ********************************/
+
+void eliminate(int m)
+{
+	int n;
+	for(n=m+1;n<cnt;n++)
+		number[n-1] = number[n];
+	cnt--;
+}
+
+/***************************** EXREALLOC *****************************/
+
+char *exrealloc(char *p,int k)
+{
+	char *q;
+	q = exmalloc(k);
+	memcpy(q,p,k);
+	free(p);
+	return(q);
+}
+
+/****************************** TEXTTOMIDI ******************************/
+
+double texttomidi(char *str)
+{   
+	int pitch, octave, octshift = 0;
+	char *p = str;
+	if(!strncmp(str,"B#",2) || !strncmp(str,"b#",2))
+		octshift--;
+	if((str = get_pitchclass(str,&pitch,1))==(char *)0) {
+		sprintf(errstr,"Unknown pitch %s\n",p);
+		do_error();
+	}
+	if(sscanf(str,"%d",&octave)!=1) {
+		sprintf(errstr,"unknown pitch-string %s or no octave value\n",p);
+		do_error();
+	}
+	octave += (MIDDLE_C_MIDI_OCTAVE + octshift);
+	pitch  += (octave * 12);
+	return((double)pitch);
+}
+
+/****************************** GET_PITCHCLASS ******************************/
+
+char *get_pitchclass(char *str,int *pitch,int with_octave)
+{
+	switch(*str++) {
+	case('c'): case('C'): *pitch = 0; break;
+	case('d'): case('D'): *pitch = 2; break;
+	case('e'): case('E'): *pitch = 4; break;
+	case('f'): case('F'): *pitch = 5; break;
+	case('g'): case('G'): *pitch = 7; break;
+	case('a'): case('A'): *pitch = 9; break;
+	case('b'): case('B'): *pitch = 11; break;
+	default: return((char *)0);
+	}
+	switch(*str++) {
+	case('#'): 		(*pitch)++; break;
+	case('b'): 		(*pitch)--; break;
+	default: 		str--; 		break;
+	}
+ 	if(with_octave) {
+		if(*str==ENDOFSTR)
+			return((char *)0);		
+	}
+	return(str);
+}
+
+/******************************** LOGO() **********************************/
+
+void logo(void)
+{   printf("\t    ***************************************************\n");
+	printf("\t    *           COMPOSERS DESKTOP PROJECT             *\n");
+	printf("\t                   %s $Revision: 1.8 $\n",PROG);
+	printf("\t    *    Manipulate or Generate columns of numbers    *\n");
+	printf("\t    *                by TREVOR WISHART                *\n");
+	printf("\t    ***************************************************\n\n");
+}
+
+/****************************** PITCHTOTEXT ******************************/
+
+void pitchtotext(int midi)
+{   int oct, n;
+	int basetone;
+	double diff;
+	for(n=0;n<cnt;n++) {
+		if(midi) {
+			if(number[n] < MIDIMIN || number[n] > MIDIMAX) {
+				fprintf(stdout,"ERROR: MIDI value %d (%lf) is out of range for conversion to pitch.\n", n+1,number[n]);
+				fflush(stdout);
+				exit(1);
+			}
+		} else {
+			if(number[n] < MIDIMINFRQ || number[n] > MIDIMAXFRQ) {
+				fprintf(stdout,"ERROR: frq value %d (%lf) is out of range for conversion to pitch.\n", n+1,number[n]);
+				fflush(stdout);
+				exit(1);
+			}
+		}
+	}
+	for(n=0;n<cnt;n++) {
+		if(!midi)
+			number[n] = hztomidi(number[n]);
+		oct = (int)(number[n]/12.0);	/* TRUNCATE */
+		oct -= 5;
+		basetone = (int)floor(number[n]);
+		diff = number[n] - (double)basetone;
+		if(diff > .5)
+			basetone++;
+		prnt_pitchclass(basetone%12,oct);
+		if(flteq(diff,0.0))
+			strcat(errstr,"\n");
+		else if(flteq(diff,0.5))	/* handle quarter tones */
+			strcat(errstr,"+\n");
+		else if(diff > .5)
+			strcat(errstr,"(--)\n");
+		else
+			strcat(errstr,"(++)\n");
+		fprintf(stdout,"INFO: %s",errstr);
+	}
+	fflush(stdout);
+}
+
+/****************************** PRNT_PITCHCLASS ******************************/
+
+void prnt_pitchclass(int z,int oct)
+{
+   	switch(z) {
+	case(0):	sprintf(errstr,"C%d",oct);	break;
+	case(1):	sprintf(errstr,"C#%d",oct);	break;
+	case(2):	sprintf(errstr,"D%d",oct);	break;
+	case(3):	sprintf(errstr,"Eb%d",oct);	break;
+	case(4):	sprintf(errstr,"E%d",oct);	break;
+	case(5):	sprintf(errstr,"F%d",oct);	break;
+	case(6):	sprintf(errstr,"F#%d",oct);	break;
+	case(7):	sprintf(errstr,"G%d",oct);	break;
+	case(8):	sprintf(errstr,"Ab%d",oct);	break;
+	case(9):	sprintf(errstr,"A%d",oct);	break;
+	case(10):	sprintf(errstr,"Bb%d",oct);	break;
+	case(11):	sprintf(errstr,"B%d",oct);	break;
+	}					  
+}
+
+
+void bublsort(void) {
+	int n, m;
+	double temp;
+	for(n=0;n<cnt-1;n++) {
+		for(m = n; m<cnt; m++) {
+			if(number[m] < number[n]) {
+				temp = number[n];
+				number[n] = number[m];
+				number[m] = temp;
+			}
+		}
+	}
+}
+
+/************************* DO_OTHER_STRINGLINE_INFILE ***************************/
+
+int do_other_stringline_infile(char *argv)
+{
+	int cols;
+/*
+	cnt = stringscnt; DONE PREVIOUSLY
+*/
+	cols = do_stringline_infile(argv,cnt);
+	stringscnt -= cnt;
+	return cols;
+}
+
+/************************* DO_STRINGLINE_INFILE ***************************/
+
+int do_stringline_infile(char *argv,int n)
+{
+	int  strspace, cccnt, ccnt = 0, lcnt = 0;
+
+	int space_step = 200, nn;
+	int old_stringstoresize;
+	char *p, *zong;
+	char temp2[200];
+	int total_space = space_step;
+	if((fp[0] = fopen(argv,"r"))==NULL) {
+		fprintf(stdout,"ERROR: Cannot open infile %s\n",argv);
+		fflush(stdout);
+		exit(1);
+	}
+	if(stringstoresize == 0) {
+		if((stringstore = (char *)exmalloc(total_space))==NULL) {
+			sprintf(errstr,"Out of Memory\n");
+			do_error();
+		}
+	}
+	while(fgets(temp,200,fp[0])!=NULL) {
+		p = temp;
+		cccnt = 0;
+		while(strgetstr(&p,temp2)) {
+			strspace = strlen(temp2)+1;
+			old_stringstoresize = stringstoresize;
+			if((stringstoresize += strspace) >= total_space) {
+				while(stringstoresize  >= total_space)
+					total_space += space_step;
+				if((zong = (char *)malloc(total_space))==NULL) {
+					sprintf(errstr,"Out of Memory\n");
+					do_error();
+				} 
+				memcpy(zong,stringstore,old_stringstoresize);
+				free(stringstore);
+				stringstore = zong;
+			}
+			strcpy(stringstore + stringstart,temp2);
+			stringstart += strspace;
+			stringscnt++;
+			cccnt++;
+		}
+		if(lcnt == 0) {
+			ccnt = cccnt;
+			lcnt++;
+		} else if(ccnt != cccnt) {
+			if(cccnt != 0) {
+				fprintf(stdout,"ERROR: File %s is not a true table file (line %d has %d cols instead of %d).\n",
+				argv,lcnt+1,cccnt,ccnt);
+				fflush(stdout);
+				exit(1);
+			} else {
+				continue;
+			}
+		} else {			
+			lcnt++;
+		}
+	}
+	if(stringscnt <= n) {
+		fprintf(stdout,"ERROR: Invalid or missing data.\n");
+		fflush(stdout);
+		exit(1);
+	}
+	if(strings == 0) {
+		if((strings = (char **)malloc(stringscnt * sizeof(char *)))==NULL) {
+			sprintf(errstr,"Out of Memory\n");
+			do_error();
+		}
+	} else {
+		if((strings = (char **)realloc((char *)strings,stringscnt * sizeof(char *)))==NULL) {
+			sprintf(errstr,"Out of Memory\n");
+			do_error();
+		}
+	}
+	p = stringstore;
+	nn = 0;
+	while(nn < stringscnt) {
+		strings[nn] = p;
+		while(*p != ENDOFSTR)
+			p++;
+		p++;
+		nn++;
+	}
+	fclose(fp[0]);
+	return ccnt;
+}
+
+/************************* DO_OTHER_STRINGLINE_INFILE ***************************/
+
+void do_other_stringline_infiles(char *argv[],char c)
+{
+	int n;
+	int sum, thiscolcnt, last_stringscnt, this_stringscnt, rowcnt=0, thisrowcnt;
+
+	if((cntr = (int *)malloc(infilecnt*sizeof(int)))==NULL) {
+		fprintf(stdout,"ERROR: Out of memory.\n");
+		fflush(stdout);
+		exit(1);
+	}
+	cntr[0] = stringscnt;
+	sum = cntr[0];
+
+	if(c == 'J') {
+		if((rowcnt = stringscnt/colcnt) * colcnt != stringscnt) {
+			fprintf(stdout,
+			"ERROR: Incomplete table 1 : all rows must have same number of columns for this option.\n");
+			fflush(stdout);
+			exit(1);
+		}
+	}
+	for(n=1;n<infilecnt;n++) {
+		last_stringscnt = stringscnt;
+		thiscolcnt = do_stringline_infile(argv[n+1],stringscnt);
+		switch(c) {
+		case('j'):
+			if(thiscolcnt != colcnt) {
+				fprintf(stdout,"ERROR: Count of columns incompatible in the input files.\n");
+				fflush(stdout);
+				exit(1);
+			}
+ 			break;
+		case('W'):
+			if(thiscolcnt != colcnt) {
+				fprintf(stdout,"ERROR: Count of columns incompatible in the input files.\n");
+				fflush(stdout);
+				exit(1);
+			}
+ 			break;
+		case('J'):
+			this_stringscnt = stringscnt - last_stringscnt;
+			if((thisrowcnt = this_stringscnt/thiscolcnt) * thiscolcnt != this_stringscnt) {
+				fprintf(stdout,
+				"ERROR: Table %d incomplete: all rows must have same number of columns for this option.\n",n+1);
+				fflush(stdout);
+				exit(1);
+			}
+			if(thisrowcnt != rowcnt) {
+				fprintf(stdout,"ERROR: File %d does not have same number of rows as 1st file.\n",n+1);
+				fflush(stdout);
+				exit(1);
+			}
+			break;
+		}
+		cntr[n] = stringscnt - sum;
+		sum += cntr[n];
+	}
+	if(c == 'J')
+		colcnt = rowcnt;	/* held temporarily in global */
+}
+
+/************************* DO_STRING_INFILE ***************************/
+
+void do_string_infile(char *argv)
+{
+	int  strspace;
+	int space_step = 200, startstringscnt = stringscnt, n;
+	int old_stringstoresize;
+	char *p;
+	char temp2[200];
+	int total_space = space_step;
+	if((fp[0] = fopen(argv,"r"))==NULL) {
+		sprintf(errstr,"Cannot open infile %s\n",argv);
+		do_error();
+	}
+	if(stringstoresize == 0) {
+		if((stringstore = (char *)malloc(total_space))==NULL) {
+			sprintf(errstr,"Out of Memory\n");
+			do_error();
+		}
+	}
+	while(fgets(temp,200,fp[0])!=NULL) {
+		p = temp;
+		while(strgetstr(&p,temp2)) {
+			strspace = strlen(temp2)+1;
+			old_stringstoresize = stringstoresize;
+			if((stringstoresize += strspace) >= total_space) {
+				while(stringstoresize  >= total_space)
+					total_space += space_step;
+				if((stringstore = (char *)realloc((char *)stringstore,total_space))==NULL) {
+					sprintf(errstr,"Out of Memory\n");
+					do_error();
+				}
+			}
+			strcpy(stringstore + stringstart,temp2);
+			stringstart += strspace;
+			stringscnt++;
+		}
+	}
+	if(stringscnt <=0) {
+		sprintf(errstr,"Invalid or missing data.\n");
+		do_error();
+	}
+	if(strings == 0) {
+		if((strings = (char **)malloc(stringscnt * sizeof(char *)))==NULL) {
+			sprintf(errstr,"Out of Memory\n");
+			do_error();
+		}
+	} else {
+		if((strings = (char **)realloc((char *)strings,stringscnt * sizeof(char *)))==NULL) {
+			sprintf(errstr,"Out of Memory\n");
+			do_error();
+		}
+	}
+	p = stringstore;
+	n = 0;
+	while(n < startstringscnt) {
+		while(*p != ENDOFSTR)
+			p++;
+		p++;
+		n++;
+	}
+	while(n < stringscnt) {
+		strings[n] = p;
+		while(*p != ENDOFSTR)
+			p++;
+		p++;
+		n++;
+	}
+	fclose(fp[0]);
+}
+
+/************************* TEST_WARP_DATA ***************************/
+
+void test_warp_data(void) 
+{
+	int n = 0;
+	if(number[n] < 0) {
+		sprintf(errstr,"Negative time in breakpoint file: Cannot proceed.\n");
+		do_error();
+		exit(1);
+	}
+	if(number[1] < 1.0/1024.0 || number[1] > 1024.0) {
+		sprintf(errstr,"Dubious Timestretch value (%lf) in brkpnt file.\n",number[1]);
+		do_error();
+		exit(1);
+	}
+	for(n = 2; n <firstcnt; n+=2) {
+		if(number[n] <= number[n-2]) {
+			sprintf(errstr,"Times (%lf & %lf) not in increasing order in brkpnt file.\n",number[n-2],number[n]);
+			do_error();
+			exit(1);
+		}
+		if(number[n+1] < 1.0/1024.0 || number[n+1] > 1024.0) {
+			sprintf(errstr,"Dubious Timestretch value (%lf) in brkpnt file.\n",number[n+1]);
+			do_error();
+			exit(1);
+		}
+	}
+	for(n = firstcnt; n <cnt; n++) {
+		if(number[n] < 0.0) {
+			sprintf(errstr,"Negative time (%lf) given in 2nd file: Cannot proceed.\n",number[n]);
+			do_error();
+			exit(1);
+		}
+	}
+}

+ 251 - 0
dev/tabedit/columns2.c

@@ -0,0 +1,251 @@
+/*
+ * 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 <columns.h>
+
+void 	helpm(void),helpM(void),helpg(void),helpr(void),helpl(void),help(void);
+
+/********************************** HELPM **********************************/
+
+void helpm(void)
+{
+fprintf(stderr,
+" ------------------------ MATHEMATICAL OPERATIONS ---------------------------\n"
+"| g     find Greatest                | i    find Intervals (MIDI)            |\n"
+"| l     find Least                   | im@  Multiply Intervals by @          |\n"
+"| t     find Total                   | ia@  Add @ to Intervals               |\n"
+"| p     find Product                 | ra   RAtios btwn succesive values     |\n"
+"| M     find Mean                    | iv   generate Intermediate Values     |\n"
+"| R[@]  find Reciprocals (1/N) (<|>) | iL@  Limit Intervals to < max @       |\n"
+"|       with @, find @/N             | il@  Limit Intervals to > min @       |\n"
+"| a@    Add @                  (<|>) |                                       |\n"
+"| m@    Multiply by @          (<|>) | Ra@  Add Random value between +-@     |\n"
+"| d@    Divide by @            (<|>) | RA@  Add Random value between 0 & @   |\n"
+"| P@    +ve values to Power @  (<|>) | Rm@  Multiply by Randval between 0-@  |\n"
+"|                                    | Rs@  Random Scatter[@=0-1] ascending  |\n"
+"|(<|>) means these can apply to vals |      vals over intervals between vals |\n"
+"|  < or > threshold on command-line. |                                       |\n"
+"|                                    | s[@] Stack values from 0 (overlap @)  |\n"
+"| A@  Approximate to multiplies of @ | sl@  Change Slope by factor @         |\n"
+"| fl@ ensure all vals >= floor-val @ | sd[@] Sum abs Differences (zigzag)    |\n"
+"| li@ ensure all vals <= limit-val @ |       (@=overlap e.g.splicelen)       |\n"
+"|                                    | so@   Sum, minus Overlaps             |\n"
+"| THRESHOLD VALUE IS INDICATED BY an |       @=overlap (e.g.splicelen)       |\n"
+"| extra parameter on command line..  | sn@   Sum N-wise. N = @               |\n"
+"|  e.g. {3 means <3 ;  }7 means >7   |                                       |\n"
+" -------------------- FOR FURTHER HELP TRY -l -M -g -R ----------------------\n");
+exit(1);
+}
+
+/************************************ HELPL ***********************************/
+
+void helpl(void)
+{
+fprintf(stderr,
+" ------------------------ LIST REORDER OR EDIT --------------------------\n"
+"| c     Count vals (<||>threshold) | e@   Eliminate value @ (+-error)    |\n"
+"| mg@   Mark values > @            | eg@  Eliminate vals Greater than @  |\n"
+"| ml@   Mark values < @            | el@  Eliminate vals Less than @     |\n"
+"| cl    Count lines                | ed@  Eliminate Duplicates           |\n"
+"| o     Order list                 |      within range @                 |\n"
+"| rr    Reverse list               | ee   Eliminate Even items           |\n"
+"| Ro[@] Randomise Order (X@)       | Re@  Eliminate @ items at Random    |\n"
+"| dl@   Duplicate List @ times     | bg@  Vals > @ reduced to Bound @    |\n"
+"| dv@   Duplicate each Val @ times | bl@  Vals < @ raised to Bound @     |\n"
+"|                                  | N@   partitioN to @ files,in blocks |\n"
+"| sk@   get 1 value & SKip @       | Nr@  partitioN to @ fils,in rotation|\n"
+"| sK@   get @ values, SKip 1       | C    Concatenate files              |\n"
+"| cc    columnate                  |                                     |\n");
+fprintf(stderr,
+"| As    Alphabetic Sort            | S@   Separate @ columns to @ files  |\n"
+"| F@    Format vals in @ cols      | J    Join as columns in 1 file      |\n"
+"| s[@]  Stack values from 0        | I    Interleave: columns->list      |\n"
+"|       (overlap @)                | E[@] vals End to End in 2 columns   |\n"
+"| Mr[@] Avoid midi-pitch-class     |      (@ = column2 overshoot of      |\n"
+"|       repetition (within @ notes)|      next value in column 1)        |\n"
+"| fr[@] Avoid  frq-pitch-class     | v[@] rank by VOTE: ie. by no. of    |\n"
+"|       repetition (within @ notes)|      times each number(+-@) occurs  |\n"
+"| ir@   Repeat Intervals @ times   | V@   rank frqs by VOTE              |\n"
+"|       starting from last entry   |      @ = semitone range for equalfrq|\n"
+"| F@    format in @ columns        | G@   reGROUP: take every @th item   |\n"
+"|                                  |      from 0, then ditto from 1 etc. |\n"
+"| THRESHOLD IS EXTRA PARAM ON CMDLINE... E.G. {3 MEANS <3 ;  }7 MEANS >7 |\n"
+" ------------------ FOR FURTHER HELP TRY -m -M -g -R --------------------\n");
+exit(1);
+}
+
+/*********************************** HELPM ***********************************/
+
+void helpM(void)
+{
+fprintf(stderr,
+" ----------------------------  MUSICAL OPERATIONS ----------------------------\n"
+"| Mh    MIDI to Hz                    | sd[@] Sum abs Differences (zigzag)    |\n"
+"| Mt    MIDI to Text                  |       (@=overlap e.g. splicelen)      |\n"
+"| hM    hz to MIDI                    | sl@   Change slope by factor @        |\n"
+"| tM    Text to MIDI                  | so@   Sum, minus Overlaps: @=overlap  |\n"
+"| th    Text to Hz                    |       (e.g.splicelen)                 |\n"
+"|                                     | Mm@   Major->Minor,(MIDI) @ = key     |\n"
+"| q@    Quantise over @               | mM@   Minor->Major,(MIDI) @ = key     |\n"
+"| i     get Intervals (e.g. MIDI)     | TM[@] Temper MIDI data. (With @, to a |\n"
+"| Ir    Interval(semitones)-> frqratio|       @-note equal-tempered scale     |\n"
+"| ra    RAtios between succesive vals |       based on concert-C)             |\n"
+"| iM    motivically-Invert MIDI       | Th[@] Temper Hz data. (With @, to a   |\n"
+"| ih    motivically-Invert Hz         |       @-note equal-tempered scale     |\n"
+"| rm@   motivically-ROtate by @       |       based on concert-C)             |\n");
+fprintf(stderr,
+"| B     plain Bob : 8 bells           | do@   Duplicate vals at @ Octaves     |\n"    
+"| At@   Accel Time-seq from event-    |       (MIDI)                          |\n"
+"|       -separation val1 in file      | dO@   Duplicate vals at @ Octaves     |\n"
+"|       to val2 in file, total dur @  |       (FREQUENCIES)                   |\n"
+"|       (optional: starttime val3)    | Mr[@] Avoid midi-pitchclass repeats   |\n"
+"| Tc@   times from crotchet count     |       (within @ notes)                |\n"
+"|       in file, and tempo @          | fr[@] Avoid frq-pitchclass repeats    |\n"
+"| Tl@   Times from crotchet lengths   |       (within @ notes)                |\n"
+"| H@    Generate @ Harmonics          | V@    rank frqs by VOTE               |\n"
+"| Hr@   Generate @ Subharmonics       |       (no. of occcurences)            |\n"
+"| Hg[@] Group frqs as Harmonics:      |       @ = semitone range within which |\n"
+"|       @=tuning tolerance (semitones)|       frqs judged to be equivalent    |\n"
+"|       (default .01)                 | td@   Take set of snd-durations and   |\n"    
+"| Ad@   Accel Durations from val1 to  |       produce list of start-times, to |\n"    
+"|       val2 in file, with total dur @|       give density of @ snds always.  |\n"    
+"| DB    convert dB levels to gain vals| st@   sample to time (@ = srate)      |\n"    
+"| db    convert gain levels to dB     |                                       |\n"    
+" -------------------- FOR FURTHER HELP TRY -m -l -g -R ----------------------\n");
+exit(1);
+}
+
+/**************************************** HELPG *****************************/
+
+void helpg(void)
+{
+fprintf(stderr,"%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
+" -------------------------- GENERATIVE OPERATIONS --------------------------\n",
+"| Rg    Generate Random 0s & 1s      |                                      |\n",
+"|       (number of items, in infile) | ic@   Create @ Intervals, size of    |\n",
+"| Rv@   generate @ Random Values     |       (1) value in file              |\n",
+"|       (maxmin values in infile)    | i=@   Equal Intervals of @ between   |\n",
+"| Rc@   Chop @ to Randomsize chunks  |       2 values in file               |\n",
+"|       (maxmin chunklens in infile) | D@    @ equal Divisions between      |\n",
+"|                                    |       2 values in file               |\n",
+"| iv    gen Intermediate Values      | L@    @ Log-equal divisions between  |\n",
+"|                                    |       2 +ve values in file           |\n",
+"| dv@   Duplicate each Val @ times   | Q@    @ Quadratic-curve steps btwn   |\n",
+"| dl@   Duplicate List @ times       |       2 vals in file, where val3 is  |\n",
+"| ir@   Repeat Intervals @ times,    |       curvature(>0): <1 down: >1 up  |\n",
+"|       starting from last entry     |                                      |\n",
+"|                                    |                                      |\n",
+"| At@   Accel Time-seq from event-   | B     plain Bob : 8 bells            |\n",
+"|       -separation val1 in file, to |                                      |\n",
+"|       val2 in file, total dur @    |                                      |\n",
+"|       (optional: starttime val3)   |                                      |\n",
+"|                                    |                                      |\n",
+"| Ad@   Accel Durations from val1 to |                                      |\n",
+"|       val2 in file, in total dur @ |                                      |\n",
+" ------------------- FOR FURTHER HELP TRY -m -M -l -R ---------------------\n");
+exit(1);
+}
+
+/********************************** HELPR ***********************************/
+
+void helpr(void)
+{
+fprintf(stderr,"%s%s%s%s%s%s%s%s%s%s%s%s",
+" ---------------------------- RANDOM OPERATIONS ---------------------------\n",
+"|                                     |                                    |\n",
+"| Ro[@] Randomise Order               | Rc@   Chop @ to Randchunks         |\n",
+"|       (& again, @ times)            |       (maxmin chunklens in infile) |\n",
+"|                                     | Rg    Generate random 0s & 1s      |\n",
+"| Ra@   Add Randval between +-@       |       (number of items, in infile) |\n",
+"| RA@   Add Randval between 0 & @     | Rv@   Gen @ random Values          |\n",
+"| Rm@   Multiply by Randval btwn 0-@  |       (maxmin vals in infile)      |\n",
+"| Rs@   Scatter[@=0-1] ascending vals |                                    |\n",
+"|       over intervals between vals   | Re@   Eliminate @ items at Random  |\n",
+"|                                     |                                    |\n",
+" -------------------- FOR FURTHER HELP TRY -m -M -l -g --------------------\n");
+exit(1);
+}
+
+/******************************* HELP *******************************/
+
+void help(void)
+{
+fprintf(stderr,
+"a@ .... Add @                          l ..... find LEAST\n"
+"A@ .... Approx to multiples of @       li@ ....LIMIT values to <=@\n"
+"At@ ... ACCELERATING TIME-seq          M ..... find MEAN\n"
+"Ad@ ... ACCELERATING DURATIONS         m@ .... MULTIPLY by @\n"
+"As .... ALPHABETIC SORT                mg@ ... MARK values > @\n"
+"B ..... plain BOB (bell-ringing)       Mr[@].. MIDI-pitchclass-REPETS avoided.\n"
+"bg@ ... Vals >@ reduced to BOUND @     Mh .... MIDI to HZ\n"
+"bl@ ... Vals <@ increased to BOUND @   ml@ ... MARK values < @\n"
+"C ..... CONCATENATE                    Mm@ ... MAJOR->MINOR (MIDI) in key @\n"
+"c ..... COUNT vals    cc...COLUMNATE   Mt .... MIDI to TEXT\n"
+"cl .... COUNT LINES                    mM@ ... MINOR->MAJOR (MIDI) in key @\n"
+"D@ .... @ equal DIVISIONS btwn 2 vals  N@ .... partitioN -> @ files, in blocks\n"
+"DB .... DB values to gain vals         Nr@ ....partN-> @ files, in rotation\n"
+"d@ .... DIVIDE  by @                   o ..... ORDER list\n"
+"db .... gain vals to DB values         P@ .... +ve vals raised to POWER\n"
+"dl@ ... DUPLICATE LIST @ times         p ..... find PRODUCT\n"
+"do@ ... DUPL LIST at @ OCTAVES (MIDI)  Q@ ..@ QUADRATIC-curve steps btwn vals.\n"
+"dO@ ... DUPL LIST at @ OCTAVES (FRQS)  q@ .... QUANTISE over @\n"
+"dv@ ... DUPLICATE each VALUE @ times   R[@]... find RECIPROCALS\n"
+"E[@] .. vals END to END in 2 cols      RA@ ... RANDVAL ADDED\n"
+"e@ .... ELIMINATE value                Ra@ ... RANDVAL +- ADDED\n"
+"ed@ ... ELIMINATE DUPLICATES           ra .... RATIOS betwn vals\n"
+"ee .... ELIMINATE EVEN items           Rc@ ... cut @ into RANDOM CHUNKS\n"
+"eg@ ... ELIMINATE vals > @             Re@ ... RANDOMLY ELIMINATE items\n"
+"el@ ... ELIMINATE vals < @             Rg  ... RANDOM GEN of 0s & 1s\n"
+"fr[@].. FRQ pitchclass REPETS avoided  Rm@ ... MULTIPLY by RAND\n"
+"F@ .... FORMAT in @ columns            rm@ ... motivic-ROTATE\n"
+"fl@ ... FLOOR vals to >=@              Ro[@].. RANDOMISE ORDER\n"
+"g ..... find GREATEST                  rr..... REVERSE list\n"
+"G@ .... GROUP @th items, cyclically    Rs@ ... RANDOM SCATTER vals\n");
+fprintf(stderr,
+"hM .... HZ to MIDI                     Rv@ ... generate RAND VALS\n"
+"H@ .... Generate HARMONICS             S@ .....SEPARATE cols->files\n"
+"Hr@ ... Gen HARMONIC ROOTS (subharms)  s[@] .. STACK vals from 0\n"
+"Hg[@].. GROUP freqs as HARMONICS.      sd[@]...SUM abs DIFFERENCES\n"
+"I ..... INTERLEAVE                     sK@ ... get @ vals,SKIP 1\n"
+"Ir .... INTERVAL(semitones)->frqRATIO  sk@ ... get 1 val, SKIP @\n"
+"i ..... get INTERVALS                  sl@ ... change slope by factor @\n"
+"i=@ ... create EQUAL INTVLS of @       sn@ ... SUM N-WISE. N = @\n"
+"ia@ ... ADD @ to INTERVALS             so@ ... SUM,minus OVERLAPS\n"
+"ic@ ... CREATE @ INTERVALS             st@ ... SAMPLE-CNT to TIME\n"
+"ih .... motiv-INVERT HZ                t ..... find TOTAL\n"
+"iL@ ....LIMIT INTERVALS to < max @     Tc@ ... TEMPO with beatCOUNT ->time\n"
+"il@ ....LIMIT INTERVALS to > min @     td@ ... Time density in @ layers.\n"
+"iM .... motiv-INVERT:MIDI              Th[@].. TEMPER HZ data\n"
+"im@ ... INTERVALS, MULTIPLIED          th .... TEXT to HZ\n"
+"ir@ ... INTERVS, REPEATED              Tl@ ... TEMPO & beatLENGTHS ->time\n"
+"iv .... INTERMEDIATE VALS              TM[@].. TEMPER MIDI data\n"
+"J ..... JOIN as columns                tM .... TEXT to MIDI\n"
+"L@ .... LOG-equal divisions            v[@] .. rank by VOTE(no of times occurs)\n"
+"                                       V@ ..rank frqs by VOTE(@-semitone steps)\n");
+exit(1);
+}
+																	  
+

+ 148 - 0
dev/tabedit/columns3.c

@@ -0,0 +1,148 @@
+/*
+ * 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 <columns.h>
+
+void do_shuffle(int, int);
+
+/**************************** M_REPOS ********************************/
+
+int m_repos(int j)
+{
+	int n, m, k=cnt, OK, is_set = 0;
+	int zib = -ifactor, zab = ifactor;
+	for(n=0;n<k;n++) {
+		OK = 1;
+		if(n>j && !is_set) {
+			zib++;
+			zab++;
+			is_set = 1;
+		}
+		for(m=zib;m<zab;m++) {
+			if(n+m<0)	  continue;
+			if(n+m>=cnt)  break;
+			if(flteq(fmod(number[j],12.0),fmod(number[n+m],12.0))) {
+				OK = 0;
+				break;
+			}
+		}
+		if(OK) {
+		   do_shuffle(n,j);
+		   if(j>n)
+			   return(1);	/* list shuffled forward */
+		   return(0);		/* list not shuffled forward */
+		}
+	}
+	return(-1);
+}	   
+
+/**************************** F_REPOS ********************************/
+
+int f_repos(int j)
+{
+	int n, m, k=cnt-ifactor, OK, is_set = 0;
+	double interval;
+	int zib = -ifactor, zab = ifactor;
+	for(n=0;n<k;n++) {
+		OK = 1;
+		if(n>j && !is_set) {
+			zib++;
+			zab++;
+			is_set = 1;
+		}
+		for(m=zib;m<zab;m++) {
+			if(n+m<0)	  continue;
+			if(n+m>=cnt)  break;
+			interval = log(number[j]/number[n+m])/LOG_2_TO_BASE_E;
+			interval = fmod(fabs(interval),1.0);
+			if(interval<ONEMAX || interval>ONEMIN) {
+				OK = 0;
+				break;
+			}
+		}
+		if(OK) {
+		   do_shuffle(n,j);
+		   if(j>n)
+			   return(1);	/* list shuffled forward */
+		   return(0);		/* list not shuffled forward */
+		}
+	}
+	return(-1);
+}	   
+
+/**************************** DO_SHUFFLE ******************************/
+
+void do_shuffle(int n,int j)
+{
+	int m;
+	double keep = number[j];
+	if(j > n) {
+		for(m=j;m>n;m--)
+		   number[m] = number[m-1];
+	} else {
+		for(m=j;m<n;m++)
+			number[m] = number[m+1];
+	}
+	number[n] = keep;
+}
+
+/************************* CHECK_FOR_CONDITIONAL ************************/
+
+void check_for_conditional(int *argc,char *argv[])
+{
+	int n;
+	char less_than, greater_than;
+	int condit_set = 0;
+
+	if(sloom) {
+		less_than = '@';
+		greater_than = '+';
+	} else {
+		less_than = '{';
+		greater_than = '}';
+	}
+	for(n=1;n<*argc;n++) {
+		if((condit = *argv[n])==less_than || condit==greater_than) {
+			if(condit==less_than)
+				condit = '<';
+			else
+				condit = '>';
+			argv[n]++;
+			if(sscanf(argv[n],"%lf",&thresh)!=1) {
+				sprintf(errstr,"Cannot read conditional value.\n");
+				do_error();
+			}
+			while(n<(*argc)-1) {
+				*(argv+n) = *(argv+n+1);
+				n++;
+			}
+			(*argc)--;
+			condit_set = 1;
+		}
+	}
+	if(!condit_set)
+		condit = 0;
+}

+ 1840 - 0
dev/tabedit/columns4.c

@@ -0,0 +1,1840 @@
+/*
+ * 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 <columns.h>
+
+void sort_numbers(int *);
+
+/***************************** PRINT_NUMBERS() ************************/
+
+void print_numbers(void)
+{
+	int n;
+	for(n=0;n<cnt;n++)
+		do_valout_flush(number[n]);
+}
+
+/********************** REMOVE_FRQ_PITCHCLASS_DUPLICATES ******************/
+
+void remove_frq_pitchclass_duplicates(void)
+{
+	int n, m, k, z, failed = 0, move;
+	double interval;
+	k = cnt-ifactor;
+	z = 1;
+	for(n=0;n<k;n++) {
+		for(m=1;m<=ifactor;m++) {
+			if(n+m >= cnt)
+				break;
+			interval = log(number[n]/number[n+m])/LOG_2_TO_BASE_E;
+			interval = fmod(fabs(interval),1.0);
+			if(interval<ONEMAX || interval>ONEMIN) {
+				if((move = f_repos(n+m))<0) {
+					failed++;
+				} else {
+					n += move;	/* list shuffled forward, or not */
+					m--;		/* m+1th item now at m */
+				}
+			}
+		}
+	}
+	if(failed)
+		fprintf(stdout,"WARNING: %d Items failed to be separated.\n",failed);
+	print_numbers();
+}
+
+
+/***************************** COUNT_ITEMS ****************************/
+
+void count_items(char *filename)
+{
+	char *p;
+ 	char temp[10000];
+	cnt = 0;
+	if((fp[0] = fopen(filename,"r"))==NULL) {
+		fprintf(stdout,"ERROR: Cannot open infile %s\n",filename);
+		fflush(stdout);
+		exit(1);
+	}
+	while(fgets(temp,200,fp[0])!=NULL) {
+		p = temp;
+		if(ro=='l') {
+			cnt++;
+		} else {
+ 		   while(strgetfloat(&p,&factor)) {
+				switch(condit) {
+				case(0):   cnt++;   break;
+				case('>'): if(factor>thresh) cnt++; break;
+				case('<'): if(factor<thresh) cnt++; break;
+ 				}
+			}
+		}
+	}
+	fclose(fp[0]);
+	sprintf(errstr,"%d items",cnt);
+	if(condit) {
+		sprintf(temp," %c %lf",condit,thresh);
+		strcat(errstr,temp);
+	}
+	strcat(errstr,"\n");
+	if(!sloom && !sloombatch)
+		fprintf(stdout,"%s\n",errstr);
+	else
+		fprintf(stdout,"WARNING: %s\n",errstr);
+	fflush(stdout);
+}
+
+/**************************** ACCEL_TIME_SEQ ******************/
+
+void accel_time_seq(void)
+{
+	int n; 
+	double q;
+	if(cnt<2 || cnt>3) {
+		fprintf(stdout,"ERROR: Input file must have either 2 or 3 vals.\n");
+		fflush(stdout);
+		exit(1);
+	}
+	if(cnt==3)	q = number[2];			/* q = starttime */
+	else		q = 0.0;
+	cnt = timevents(0.0,factor,number[0],number[1]);
+	for(n=0;n<cnt;n++)
+		do_valout(pos[n] + q);
+	fflush(stdout);
+}
+
+/**************************** ACCEL_DURATIONS *****************************/
+
+void accel_durations(void)
+{
+	int n;
+	if(cnt!=2) {
+		fprintf(stdout,"ERROR: Input file must have 2 vals.\n");
+		fflush(stdout);
+		exit(1);
+	}
+	cnt = timevents(0.0,factor,number[0],number[1]);
+	do_valout(number[0]);
+	for(n=1;n<cnt;n++)
+		do_valout(pos[n]-pos[n-1]);
+	fflush(stdout);
+}
+
+
+/************************ SEPARATE_COLUMNS_TO_FILES *********************/
+
+void separate_columns_to_files(void)
+{
+	int n, m, k;
+	if((firstcnt = cnt/outfilecnt)*outfilecnt!=cnt) {
+		fprintf(stdout,
+		"ERROR: Number of vals in input file does not divide exactly %d outfiles\n",outfilecnt);
+		fflush(stdout);
+		exit(1);
+	}
+	for(n=0;n<outfilecnt;n++) {
+		sprintf(temp,"%d",n);
+		strcpy(thisfilename,filename);
+		strcat(thisfilename,"_");
+		strcat(thisfilename,temp);
+		strcat(thisfilename,".txt");
+		if(!sloom) {
+			if((fp[1] = fopen(thisfilename,"w"))==NULL) {
+				fprintf(stdout,"ERROR: Cannot open file %s to write.\n",thisfilename);
+				fflush(stdout);
+				exit(1);
+			} else {
+				fprintf(stdout,"Writing to file %s\n",thisfilename);
+	 		}
+		}
+		k = n;
+		for(m=0;m<firstcnt;m++) {
+			do_valout(number[k]);
+			k += outfilecnt;
+		}
+		if(!sloom)
+			fclose(fp[1]);
+	}
+	fflush(stdout);
+}
+
+
+/************************* PARTITION_VALUES_TO_FILES ********************/
+
+void partition_values_to_files(void)
+{
+	int n,m,k;
+	firstcnt   = cnt/outfilecnt;
+	if(firstcnt * outfilecnt!= cnt)
+		firstcnt++;
+	k = 0;
+	for(n=0;n<outfilecnt;n++) {
+		sprintf(temp,"%d",n);
+		strcpy(thisfilename,filename);
+		strcat(thisfilename,".");
+		strcat(thisfilename,temp);
+		if(!sloom) {
+			if((fp[1] = fopen(thisfilename,"w"))==NULL) {
+				fprintf(stdout,"ERROR: Cannot open file %s to write.\n",thisfilename);
+				fflush(stdout);
+				exit(1);
+			} else {
+				fprintf(stdout,"Writing to file %s\n",thisfilename);
+			}
+		}
+		if(n==outfilecnt-1)
+		firstcnt = cnt - k;
+		for(m=0;m<firstcnt;m++,k++)
+			do_valout(number[k]);
+		fflush(stdout);
+		if(!sloom)
+			fclose(fp[1]);
+	}
+}
+
+/***************** ROTATE_PARTITION_VALUES_TO_FILES ********************/
+
+void rotate_partition_values_to_files(void)
+{	
+	int n,m,k;
+	firstcnt   = cnt/outfilecnt;
+	if(firstcnt * outfilecnt!= cnt)
+		firstcnt++;
+	k = 0;
+	for(n=0;n<outfilecnt;n++) {
+		sprintf(temp,"%d",n);
+		strcpy(thisfilename,filename);
+		strcat(thisfilename,".");
+		strcat(thisfilename,temp);
+		if(!sloom) {
+			if((fp[1] = fopen(thisfilename,"w"))==NULL) {
+				fprintf(stdout,"ERROR: Cannot open file %s to write.\n",thisfilename);
+				fflush(stdout);
+				exit(1);
+			} else {
+				fprintf(stdout,"Writing to file %s\n",thisfilename);
+			}
+		}
+		if(n==outfilecnt-1)
+			firstcnt = cnt - k;
+		for(m=n;m<cnt;m+=outfilecnt)
+			do_valout(number[m]);
+		fflush(stdout);
+		if(!sloom)		
+			fclose(fp[1]);
+	}
+}
+
+/************************* JOIN_FILES_AS_COLUMNS ************************/
+
+void join_files_as_columns(char *filename)
+{
+	int n, m;
+	char temp[64];
+	if(!sloom) {
+		if((fp[0] = fopen(filename,"w"))==NULL) {
+			fprintf(stdout,"Cannot reopen infile1 to write data.\n");
+			fflush(stdout);
+			exit(1);
+		}
+	}
+	errstr[0] = ENDOFSTR;
+	for(n=0;n<firstcnt;n++) {
+		for(m=0;m<infilecnt-1;m++) {
+	 		sprintf(temp,"%.5lf ",number[n + (firstcnt * m)]);
+			strcat(errstr,temp);
+		}
+   		sprintf(temp,"%.5lf ",number[n + (firstcnt * m)]);
+		strcat(errstr,temp);
+		if(!sloom)
+			fprintf(fp[0],"%s\n",errstr);
+		else
+			fprintf(stdout,"INFO: %s\n",errstr);
+		errstr[0] = ENDOFSTR;
+	}
+	fflush(stdout);
+}
+
+/************************* JOIN_FILES_AS_ROWS ************************/
+
+void join_files_as_rows(void)
+{
+	int n, m, locnt = cnt/colcnt, totcnt = (cnt + stringscnt)/colcnt;
+	char temp[64];
+	errstr[0] = ENDOFSTR;
+	for(n=0;n<ifactor;n++) {
+		sprintf(errstr,"INFO: ");
+		for(m = 0; m < colcnt-1; m++) {
+	   		sprintf(temp,"%s ",strings[(n * colcnt) + m]);
+			strcat(errstr,temp);
+		}
+   		sprintf(temp,"%s",strings[(n * colcnt) + m]);
+		strcat(errstr,temp);
+		fprintf(stdout,"%s\n",errstr);
+	}
+	for(n=locnt;n<totcnt;n++) {
+		sprintf(errstr,"INFO: ");
+		for(m = 0; m < colcnt-1; m++) {
+	   		sprintf(temp,"%s ",strings[(n * colcnt) + m]);
+			strcat(errstr,temp);
+		}
+   		sprintf(temp,"%s",strings[(n * colcnt) + m]);
+		strcat(errstr,temp);
+		fprintf(stdout,"%s\n",errstr);
+	}
+
+	for(n=ifactor;n<locnt;n++) {
+		sprintf(errstr,"INFO: ");
+		for(m = 0; m < colcnt-1; m++) {
+	   		sprintf(temp,"%s ",strings[(n * colcnt) + m]);
+			strcat(errstr,temp);
+		}
+   		sprintf(temp,"%s",strings[(n * colcnt) + m]);
+		strcat(errstr,temp);
+		fprintf(stdout,"%s\n",errstr);
+	}
+	fflush(stdout);
+}
+
+/************************* JOIN_MANY_FILES_AS_ROWS ************************/
+
+void join_many_files_as_rows(void)
+{
+	int i, n, m, rowcnt, bas;
+	char temp[200];
+
+	bas = 0;
+	for(i = 0;i < infilecnt; i++) {			/* for each file */
+		rowcnt = cntr[i]/colcnt;			/*	Number of rows in file */
+		for(n=0;n<rowcnt;n++) {				/*	for each row in file */
+			sprintf(errstr,"INFO: ");
+			for(m=0;m<colcnt;m++) {			/* foreach column in row */
+				sprintf(temp,"%s ",strings[bas + (n * colcnt) + m]);
+				strcat(errstr,temp);
+			}
+			fprintf(stdout,"%s\n",errstr);
+		}
+		bas += cntr[i];						/* set bas to start of next file's numbers */
+	}
+	fflush(stdout);
+}
+
+/************************* JOIN_MANY_FILES_AS_COLUMNS ************************/
+
+
+void join_many_files_as_columns(char *filename,int insert)
+{
+	int i, n, m, rowcnt, bas;
+	char temp[200], *p;
+
+	if(!sloom) {
+		if((fp[0] = fopen(filename,"w"))==NULL) {
+			fprintf(stdout,"Cannot reopen infile1 to write data.\n");
+			fflush(stdout);
+			exit(1);
+		}
+	}
+
+	rowcnt = colcnt; 	/* i.e. 'colcnt' has been used to store count-of-rows, not of columns, in this case */	
+
+	if(insert) {
+		if(ifactor > cntr[0]/rowcnt) {
+			fprintf(stdout,"ERROR: Only %d columns in the first file. Can't do insert after column %d\n",cntr[0]/colcnt,ifactor);
+			fflush(stdout);
+			exit(1);
+		}
+		for(n=0;n<rowcnt;n++) {					/*	for each row in files */
+			p = errstr;
+			if(sloom)
+				sprintf(errstr,"INFO: ");
+			else
+				sprintf(errstr,"");
+
+			colcnt = cntr[0]/rowcnt;		/*	Number of columns in file */
+			for(m=0;m<ifactor;m++) {			/* foreach column in row */
+				sprintf(temp,"%s ",strings[(n * colcnt) + m]);
+				strcat(errstr,temp);
+			}
+			colcnt = cntr[1]/rowcnt;		/*	Number of columns in file1 */
+			for(m=0;m<colcnt;m++) {			/* foreach column in row */
+				sprintf(temp,"%s ",strings[cntr[0] + (n * colcnt) + m]);
+				strcat(errstr,temp);
+			}
+			colcnt = cntr[0]/rowcnt;		/*	Number of columns in file */
+
+			for(m=ifactor;m<colcnt;m++) {			/* foreach column in row */
+				sprintf(temp,"%s ",strings[(n * colcnt) + m]);
+				strcat(errstr,temp);
+			}
+
+			fprintf(stdout,"%s\n",p);
+			if(!sloom)
+				fprintf(fp[0],"%s\n",p);
+		}
+	} else {
+		for(n=0;n<rowcnt;n++) {					/*	for each row in files */
+			bas = 0;
+			p = errstr;
+			if(sloom)
+				sprintf(errstr,"INFO: ");
+			else
+				sprintf(errstr,"");
+			for(i = 0;i < infilecnt; i++) {		/* for each file */
+				colcnt = cntr[i]/rowcnt;		/*	Number of columns in file */
+				for(m=0;m<colcnt;m++) {			/* foreach column in row */
+					sprintf(temp,"%s ",strings[bas + (n * colcnt) + m]);
+					strcat(errstr,temp);
+				}
+				bas += cntr[i];					/* set bas to start of next file's numbers */
+			}
+			fprintf(stdout,"%s\n",p);
+			if(!sloom)
+				fprintf(fp[0],"%s\n",p);
+		}
+	}
+	fflush(stdout);
+}
+
+/************************ CONCATENATE_FILES ****************************/
+
+void concatenate_files(char *filename)
+{
+	int n;
+	if(!sloom) {
+		if((fp[0] = fopen(filename,"w"))==NULL) {
+			fprintf(stdout,"Cannot reopen infile1 to write data.\n");
+			fflush(stdout);
+			exit(1);
+		}
+	}
+	for(n=0;n<cnt;n++) {
+		if(!sloom)
+			fprintf(fp[0],"%lf\n",number[n]);
+		else
+			fprintf(stdout,"INFO: %lf\n",number[n]);
+	}
+	fflush(stdout);
+} 
+
+/************************ CONCATENATE_FILES_CYCLICALLY ****************************/
+
+void concatenate_files_cyclically(char *filename)
+{
+	int n, m;
+	if(!sloom) {
+		if((fp[0] = fopen(filename,"w"))==NULL) {
+			fprintf(stdout,"Cannot reopen infile1 to write data.\n");
+			fflush(stdout);
+			exit(1);
+		}
+	}
+	for(n=0;n<firstcnt;n++) {
+		for(m=n;m<cnt;m+=firstcnt) {
+			if(!sloom)
+				fprintf(fp[0],"%lf\n",number[m]);
+			else
+				fprintf(stdout,"INFO: %lf\n",number[m]);
+		}
+	}
+	fflush(stdout);
+} 
+
+/*********************** VALS_END_TO_END_IN_2_COLS *******************/
+
+void vals_end_to_end_in_2_cols(void)
+{
+	int n;
+	for(n=1;n<cnt;n++) {
+		if(n==cnt-1)
+		factor = 0.0;
+		if(!sloom && !sloombatch)
+			fprintf(fp[1],"%lf   %lf\n",number[n-1],number[n] + factor);
+		else
+			fprintf(stdout,"INFO: %lf   %lf\n",number[n-1],number[n] + factor);
+	}
+	fflush(stdout);
+}
+
+/****************************** QUANTISE ****************************/
+
+void quantise(void)
+{
+	int n;
+	for(n=0;n<cnt;n++) {
+		if(number[n]>0.0)
+			ifactor = round(number[n]/factor);
+		else
+/* IS TRUNCATION OK */
+	 	   ifactor = (int)((number[n]/factor) - 0.5 + VERY_TINY); /* TRUNCATION */
+		number[n] = (double)ifactor * factor;
+		if(!sloom && !sloombatch)		
+			fprintf(fp[1],"%lf\n",number[n]);
+		else
+			fprintf(stdout,"INFO: %lf\n",number[n]);
+	}
+	fflush(stdout);
+}
+
+/************************* ELIMINATE_EQUIVALENTS **********************/
+
+void eliminate_equivalents(void)
+{
+	int n;
+	for(n=0;n<cnt;n++) {
+		if(flteq(number[n],factor)) {
+			eliminate(n);
+			n--;
+		}
+	}
+}
+
+/************************** ELIMINATE_EVEN_ITEMS *********************/
+
+void eliminate_even_items(void)
+{
+	int n,m;
+	if(cnt==2) {
+		cnt--;
+		return;
+	}
+	for(n=2,m=1;n<cnt;n+=2,m++)
+		number[m] = number[n];
+	cnt = m;
+}
+
+/************************** ELIMINATE_GREATER_THAN ********************/
+
+void eliminate_greater_than(void)
+{
+	int n;
+	for(n=0;n<cnt;n++) {
+		if(number[n] > factor) {
+			eliminate(n);
+			n--;
+		}
+	}
+}
+
+/************************** ELIMINATE_LESS_THAN ***********************/
+
+void eliminate_less_than(void)
+{
+	int n;
+	for(n=0;n<cnt;n++) {
+		if(number[n] < factor) {
+			eliminate(n);
+			n--;
+		}
+	}
+}
+
+/*************************** ELIMINATE_DUPLICATES *************************/
+
+void eliminate_duplicates(void)
+{
+	int m,n;
+	for(n=0;n<cnt-1;n++) {
+		for(m=n+1;m<cnt;m++) {
+			if(number[m] >= (number[n] - factor) && number[m] <= (number[n] + factor)) {
+				eliminate(m);
+				m--;
+			}
+		}
+	}
+}
+
+/**************************** REDUCE_TO_BOUND ***************************/
+
+void reduce_to_bound(void)
+{
+	int n;
+	for(n=0;n<cnt;n++) {
+		if(number[n] > factor)
+			number[n] = factor;
+	}
+}
+
+/************************* INCREASE_TO_BOUND *******************************/
+
+void increase_to_bound(void)
+{
+	int n;
+	for(n=0;n<cnt;n++) {
+		if(number[n] < factor)
+			number[n] = factor;
+	}
+}
+
+/***************************** GREATEST *******************************/
+
+void greatest(void)
+{
+	int n;
+	factor = number[0];
+	for(n=1;n<cnt;n++) {
+		if(number[n] > factor)
+			factor = number[n];
+	}
+	if(!sloom && !sloombatch)		
+		fprintf(fp[1],"%lf\n",factor);
+	else
+		fprintf(stdout,"ERROR: %lf\n",factor);
+	fflush(stdout);
+}
+
+/****************************** LEAST *****************************/
+
+void least(void)
+{
+	int n;
+	factor = number[0];
+	for(n=1;n<cnt;n++) {
+		if(number[n] < factor)
+		factor = number[n];
+	}
+	if(!sloom && !sloombatch)
+		fprintf(fp[1],"%lf\n",factor);
+	else
+		fprintf(stdout,"WARNING: %lf\n",factor);
+	fflush(stdout);
+}
+
+/***************************** MULTIPLY ************************/
+
+void multiply(int rounded)
+{
+	int n;
+	for(n=0;n<cnt;n++) {
+		switch(condit) {
+		case(0):
+			number[n] *= factor;
+			break;
+		case('>'):
+			if(number[n]>thresh)
+				number[n] *= factor;
+			break;
+		case('<'):
+			if(number[n]<thresh)
+				number[n] *= factor;
+			break;
+		}
+		if(rounded)
+			number[n] = (double)round(number[n]);
+		if(!sloom && !sloombatch)
+			fprintf(fp[1],"%lf\n",number[n]);
+		else
+			fprintf(stdout,"INFO: %lf\n",number[n]);
+	}
+	fflush(stdout);
+}
+
+/**************************** MARK_GREATER_THAN ************************/
+
+void mark_greater_than(void)
+{
+	int n;
+	for(n=0;n<cnt;n++) {
+		if(number[n] > factor) {
+			if(!sloom && !sloombatch)
+				fprintf(fp[1],"*%lf\n",number[n]);
+			else
+				fprintf(stdout,"INFO: *%lf\n",number[n]);
+		} else {
+			if(!sloom && !sloombatch)
+				fprintf(fp[1],"%lf\n",number[n]);
+			else
+				fprintf(stdout,"INFO: %lf\n",number[n]);
+		}
+	}
+	fflush(stdout);
+}
+
+/**************************** MARK_LESS_THAN ************************/
+
+void mark_less_than(void)
+{
+	int n;
+	for(n=0;n<cnt;n++) {
+		if(number[n] < factor) {
+			if(!sloom && !sloombatch)
+				fprintf(fp[1],"*%lf\n",number[n]);
+			else
+				fprintf(stdout,"INFO: *%lf\n",number[n]);
+		} else {
+			if(!sloom && !sloombatch)
+				fprintf(fp[1],"%lf\n",number[n]);
+			else
+				fprintf(stdout,"INFO: %lf\n",number[n]);
+		}
+	}
+	fflush(stdout);
+}
+
+/**************************** MARK_MULTIPLES ************************/
+
+void mark_multiples(void)
+{
+	int n;
+	int k;
+	double z;
+	if(!condit)
+		thresh = 0.0;
+	if(thresh < 0.0)
+		thresh = -thresh;
+	for(n=0;n<cnt;n++) {
+		k = (int)round(number[n]/factor);
+		z = (double)k * factor;
+		if((z <= (number[n] + thresh)) && (z >= (number[n] - thresh)))
+			fprintf(stdout,"INFO: *%lf\n",number[n]);
+		else
+			fprintf(stdout,"INFO: %lf\n",number[n]);
+	}
+	fflush(stdout);
+}
+
+/****************************** MINOR_TO_MAJOR **************************/
+
+void minor_to_major(void)
+{
+	int n;
+	int m3 = (3 + ifactor)%12;	/* MIDI location of minor 3rd */
+	int m6 = (8 + ifactor)%12;	/* MIDI location of minor 6th */
+	int m7 = (10 + ifactor)%12;   /* MIDI location of minor 7th */
+	for(n=0;n<cnt;n++) {
+		factor = fmod(number[n],TWELVE);
+		if(flteq(factor,(double)m3)
+		|| flteq(factor,(double)m6)
+		|| flteq(factor,(double)m7))
+			number[n] += 1.0;
+		do_valout(number[n]);
+	}
+	fflush(stdout);
+}
+
+/****************************** ADD ******************************/
+
+void add(void)
+{
+	int n;
+	for(n=0;n<cnt;n++) {
+		switch(condit) {
+		case(0):
+			number[n] += factor;
+			break;
+		case('>'):
+			if(number[n]>thresh)
+			   	number[n] += factor;
+			break;
+		case('<'):
+			if(number[n]<thresh)
+			   	number[n] += factor;
+			break;
+		}
+		do_valout(number[n]);
+	}
+	fflush(stdout);
+}
+
+/**************************** TAKE_POWER *************************/
+
+void take_power(void)
+{
+	int n, is_neg;
+	for(n=0;n<cnt;n++) {
+		is_neg = 0;
+		switch(condit) {
+		case(0):
+			if(fabs(number[n]) < FLTERR)
+				number[n] = 0;
+			else {
+				if (number[n] < 0) {
+					is_neg = 1;
+					number[n] = -number[n];
+				}
+		 	   	number[n] = pow(number[n],factor);
+			}
+			break;
+		case('>'):
+			if(number[n]>thresh) {
+				if(fabs(number[n]) < FLTERR)
+					number[n] = 0;
+				else {
+					if (number[n] < 0) {
+						is_neg = 1;
+						number[n] = -number[n];
+					}
+					number[n] = pow(number[n],factor);
+				}
+			}
+			break;
+		case('<'):
+			if(number[n]<thresh) {
+				if(fabs(number[n]) < FLTERR)
+					number[n] = 0;
+				else {
+					if (number[n] < 0) {
+						is_neg = 1;
+						number[n] = -number[n];
+					}
+					number[n] = pow(number[n],factor);
+				}
+			}
+			break;
+		}
+		if(is_neg)
+			number[n] = -number[n];
+		do_valout(number[n]);
+	}
+	fflush(stdout);
+}
+
+/*********************** TEMPER_MIDI_DATA *********************/
+
+void temper_midi_data(void)
+{
+	int n, octaves;
+	double step, q, offset = 0.0, maxm, thisval, outval=0.0, diff, thisdiff;
+	if(condit) {
+		offset = thresh - floor(thresh);
+		if(offset > 0.5)
+			offset = 1.0 - offset;
+	}
+	if(flteq(factor,TWELVE) && offset == 0.0) {
+		for(n=0;n<cnt;n++) {
+			ifactor = round(number[n]);
+			number[n] = ifactor;
+			do_valout(number[n]);
+		}
+	} else {
+		if(offset == 0.0) {
+			step = TWELVE/factor;		
+			for(n=0;n<cnt;n++) {
+				q = fmod(number[n],TWELVE);	/* which semitone in 8va */
+				q /= step;			/* which newtempered step */
+				ifactor = round(q);		/* round */
+				q = ifactor * step;		/* which semitone is this */
+				octaves = (int)(number[n]/12.0);   /* TRUNCATE */	/* which octave */
+				number[n] = (octaves * TWELVE) + q;
+				do_valout(number[n]);
+			}
+		} else {
+			step = TWELVE/factor;
+			maxm = -1.0;
+			for(n=0;n<cnt;n++) {
+				if(number[n] > maxm)
+					maxm = number[n];
+			}
+			for(n=0;n<cnt;n++) {
+				thisval = offset;
+				diff = HUGE;
+				while(thisval <= maxm) {
+					thisdiff = fabs(number[n] - thisval);
+					if(thisdiff < diff) {
+						diff = thisdiff;
+						outval = thisval;
+					}
+					thisval += step;
+				}
+				do_valout(outval);
+			}
+		}
+	}
+	fflush(stdout);
+}
+
+/*************************** TEMPER_HZ_DATA ******************************/
+
+void temper_hz_data(void)
+{
+	int n, octaves;
+	double q, this_reffrq, minf = HUGE, reffrq;
+	if(condit) {
+		reffrq = thresh;
+		for(n=0;n<cnt;n++) {
+			if(number[n] < minf)
+				minf = number[n];
+		}
+		while(reffrq > minf)
+			reffrq /= 2.0;
+	} else
+		reffrq = C_HZ;
+	for(n=0;n<cnt;n++) {		   /* factor is tempering number */
+		if(number[n] < 0.0) {
+			do_valout(number[n]);	/* Retain any (subzero) flags that arrive */
+			continue;
+		}
+		q		= number[n]/reffrq;		 /* frq ratio withref frq */
+		octaves  = (int)floor(log(q)/LOG_2_TO_BASE_E); /* Number of 8vas (trunc) */
+		this_reffrq   = reffrq*pow(2.0,(double)octaves); /* C blw actualpch */
+		ifactor  = round(factor*((log(number[n])-log(this_reffrq))/LOG_2_TO_BASE_E));
+	  		  				 /* No. tempered steps, rounded */
+		number[n]= this_reffrq * pow(2.0,(double)ifactor/factor);
+		do_valout(number[n]);
+	}
+	fflush(stdout);
+}
+
+/*************************** JUST_INTONATION_HZ ******************************/
+
+void just_intonation_Hz(void)
+{
+	double *refset, reffrq, minf, maxf, minratio, oct, refval, outval = 0.0, q;
+	int n, m;
+	refset = (double *)exmalloc(12 * sizeof(double));
+	minf  = number[0];
+	maxf  = number[0];
+	for(n=1;n<cnt;n++) {
+		minf = min(minf,number[n]);
+		maxf = max(maxf,number[n]);
+	}
+	reffrq = factor;
+	while(reffrq > minf)
+		reffrq /= 2.0;
+	refset[0] =  reffrq;
+	refset[1] =  reffrq * 135.0 / 128.0;
+	refset[2] =  reffrq *   9.0 / 8.0;
+	refset[3] =  reffrq *   6.0 / 5.0;
+	refset[4] =  reffrq *   5.0 / 4.0;
+	refset[5] =  reffrq *   4.0 / 3.0;
+	refset[6] =  reffrq *  45.0 / 32.0;
+	refset[7] =  reffrq *   3.0 / 2.0;
+	refset[8] =  reffrq *   5.0 / 3.0;
+	refset[9] =  reffrq *  27.0 / 16.0;
+	refset[10] = reffrq *   9.0 / 5.0;
+	refset[11] = reffrq *  15.0 / 8.0;
+	for(n=0;n<cnt;n++) {
+		minratio = HUGE;
+		oct = 1.0;
+		while(refset[0] * oct < maxf * 2.0) {
+			for(m = 0; m < 12; m ++) {
+				refval = refset[m] * oct;
+				q = number[n]/refval;
+				if(q < 1.0)
+					q = 1.0/q;
+				if(q < minratio) {
+					minratio = q;
+					outval = refval;
+				}
+			}
+			oct *= 2.0;
+		}
+		do_valout(outval);
+	}
+}
+
+/*************************** CREATE_JUST_INTONATION_HZ ******************************/
+
+void create_just_intonation_Hz(void)
+{
+	double *refset, reffrq, minf, maxf, oct, outval;
+	int m, OK;
+	refset = (double *)exmalloc(12 * sizeof(double));
+	minf  = number[0];
+	maxf  = number[0];
+	minf = min(number[1],number[2]);
+	maxf = max(number[1],number[2]);
+	reffrq = number[0];
+	while(reffrq > minf)
+		reffrq /= 2.0;
+	refset[0] =  reffrq;
+	refset[1] =  reffrq * 135.0 / 128.0;
+	refset[2] =  reffrq *   9.0 / 8.0;
+	refset[3] =  reffrq *   6.0 / 5.0;
+	refset[4] =  reffrq *   5.0 / 4.0;
+	refset[5] =  reffrq *   4.0 / 3.0;
+	refset[6] =  reffrq *  45.0 / 32.0;
+	refset[7] =  reffrq *   3.0 / 2.0;
+	refset[8] =  reffrq *   5.0 / 3.0;
+	refset[9] =  reffrq *  27.0 / 16.0;
+	refset[10] = reffrq *   9.0 / 5.0;
+	refset[11] = reffrq *  15.0 / 8.0;
+	OK = 1;
+	oct = 1.0;
+	while(OK) {
+		for(m = 0; m < 12; m ++) {
+			outval = refset[m] * oct;
+			if(outval >= minf) {
+				if(outval <= maxf) 
+					do_valout(outval);
+				else
+					OK = 0;
+			}
+		}
+		if(!OK)
+			break;
+		oct *= 2.0;
+	}
+}
+
+/*************************** CREATE_JUST_INTONATION_MIDI ******************************/
+
+void create_just_intonation_midi(void)
+{
+	double *refset, refmidi, reffrq, minf, maxf, oct, outval;
+	int m, OK;
+	refset = (double *)exmalloc(12 * sizeof(double));
+	minf  = number[0];
+	maxf  = number[0];
+	minf = min(number[1],number[2]);
+	maxf = max(number[1],number[2]);
+	refmidi = number[0];
+	reffrq = miditohz(refmidi);
+	while(refmidi > minf) {
+		refmidi -= 12.0;
+		reffrq /= 2.0;
+	}
+	refset[0] =  refmidi;
+	refset[1] =  hztomidi(reffrq * 135.0 / 128.0);
+	refset[2] =  hztomidi(reffrq *   9.0 / 8.0);
+	refset[3] =  hztomidi(reffrq *   6.0 / 5.0);
+	refset[4] =  hztomidi(reffrq *   5.0 / 4.0);
+	refset[5] =  hztomidi(reffrq *   4.0 / 3.0);
+	refset[6] =  hztomidi(reffrq *  45.0 / 32.0);
+	refset[7] =  hztomidi(reffrq *   3.0 / 2.0);
+	refset[8] =  hztomidi(reffrq *   5.0 / 3.0);
+	refset[9] =  hztomidi(reffrq *  27.0 / 16.0);
+	refset[10] = hztomidi(reffrq *   9.0 / 5.0);
+	refset[11] = hztomidi(reffrq *  15.0 / 8.0);
+	OK = 1;
+	oct = 0.0;
+	while(OK) {
+		for(m = 0; m < 12; m ++) {
+			outval = refset[m] + oct;
+			if(outval >= minf) {
+				if(outval <= maxf) 
+					do_valout(outval);
+				else
+					OK = 0;
+			}
+		}
+		if(!OK)
+			break;
+		oct += 12.0;
+	}
+}
+
+/*************************** just_intonation_midi ******************************/
+
+void just_intonation_midi(void)
+{
+	double *refset, refmidi, reffrq, minmidi, maxmidi, minstep, oct, refval, outval = 0.0, q;
+	int n, m;
+	refset = (double *)exmalloc(12 * sizeof(double));
+	minmidi  = number[0];
+	maxmidi  = number[0];
+	for(n=1;n<cnt;n++) {
+		minmidi = min(minmidi,number[n]);
+		maxmidi = max(maxmidi,number[n]);
+	}
+	refmidi = factor;
+	while(refmidi > minmidi)
+		refmidi -= 12.0;
+	reffrq = miditohz(refmidi);
+	refset[0] =  refmidi;
+	refset[1] =  hztomidi(reffrq * 135.0 / 128.0);
+	refset[2] =  hztomidi(reffrq *   9.0 / 8.0);
+	refset[3] =  hztomidi(reffrq *   6.0 / 5.0);
+	refset[4] =  hztomidi(reffrq *   5.0 / 4.0);
+	refset[5] =  hztomidi(reffrq *   4.0 / 3.0);
+	refset[6] =  hztomidi(reffrq *  45.0 / 32.0);
+	refset[7] =  hztomidi(reffrq *   3.0 / 2.0);
+	refset[8] =  hztomidi(reffrq *   5.0 / 3.0);
+	refset[9] =  hztomidi(reffrq *  27.0 / 16.0);
+	refset[10] = hztomidi(reffrq *   9.0 / 5.0);
+	refset[11] = hztomidi(reffrq *  15.0 / 8.0);
+	for(n=0;n<cnt;n++) {
+		minstep = HUGE;
+		oct = 0.0;
+		while(refset[0] + oct < maxmidi + 12.0) {
+			for(m = 0; m < 12; m ++) {
+				refval = refset[m] + oct;
+				q = fabs(number[n] - refval);
+				if(q < minstep) {
+					minstep = q;
+					outval = refval;
+				}
+			}
+			oct += 12.0;
+		}
+		do_valout(outval);
+	}
+}
+
+/************************* TIME_FROM_CROTCHET_COUNT *********************/
+
+void time_from_crotchet_count(void)
+{
+	int n;
+	factor = 60.0/factor; /* factor becomes duration of crotchet */
+	for(n=0;n<cnt;n++)
+		do_valout(number[n]*factor);
+	fflush(stdout);
+}
+
+/********************* TIME_FROM_BEAT_LENGTHS ***********************/
+
+void time_from_beat_lengths(void)
+{
+	int n;
+	double sum;
+	factor = 60.0/factor; /* factor becomes duration of crotchet */
+	sum = 0.0;
+	for(n=0;n<cnt;n++) {
+		do_valout(sum);
+		sum += number[n] * factor;		
+	}
+	fflush(stdout);
+}
+
+/****************************** TOTAL ******************************/
+
+void total(void)
+{   
+	int n;
+	double sum = 0.0;
+	for(n=0;n<cnt;n++)
+		sum += number[n];
+	do_valout_as_message(sum);
+	fflush(stdout);
+}
+
+/***************************** TEXT_TO_HZ **************************/
+
+void text_to_hz(void)
+{
+	int n;
+	for(n=0;n<cnt;n++)
+		do_valout(miditohz(number[n]));
+	fflush(stdout);
+}
+
+/***************************** GENERATE_HARMONICS **************************/
+
+void generate_harmonics(void)
+{
+	int n;
+	for(n=1;n<=ifactor;n++)
+		do_valout(number[n] * (double)n);
+	fflush(stdout);
+}
+
+/***************************** GROUP_HARMONICS **************************/
+
+#define SEMIT_UP	(1.05946309436)	
+#define LOG2(x)		(log(x)/log(2))
+
+void group_harmonics(void)
+{
+	int n, m, got_it, samecnt;
+	int j, hno, bigg, smal, k;
+	double thisintv, thisnum;
+	double **hgrp, semit_up, semit_dn;
+	int	   *hgrpcnt;
+	if(factor<0.0)
+		factor = -factor;
+	semit_up = pow(SEMIT_UP,factor);
+	semit_dn = 1.0/semit_up;
+
+  	for(n=0;n<cnt-1;n++) {	   /* eliminate zeros */
+		if(number[n]<=0.0) {
+			fprintf(stdout,"ERROR: zero or subzero frquency in list: cannot proceed.\n");
+			fflush(stdout);
+			exit(1);
+		}
+	}
+  	for(n=1;n<cnt;n++) {	   /* Sort list into ascending order */
+		thisnum  = number[n];
+		m = n-1;
+		while(m >= 0 && number[m] > thisnum) {
+			number[m+1]  = number[m];
+			m--;
+		}
+		number[m+1]  = thisnum;
+	}
+ 	for(n=0;n<cnt-1;n++) {	   /* Eliminate duplicate frequencies */
+		for(m=n+1;m<cnt;m++) {
+			if(flteq(number[n],number[m])) {
+				for(j=m+1;j<cnt;j++)
+					number[j-1] = number[j];
+				cnt--;
+				m--;
+			}
+		}
+	}
+	hgrp	= (double **)exmalloc(cnt * sizeof(double *));
+	hgrpcnt = (int *)exmalloc(cnt * sizeof(int));
+	for(n=0;n<cnt;n++) {	 	/* For all remaining numbers */
+		hgrp[n]  = (double *)exmalloc(sizeof(double));
+		hgrp[n][0] = number[n];			/* Establish space to store, and to count, harmonic group */
+		hgrpcnt[n] = 1;
+		for(m=n+1;m<cnt;m++) {   			/* Take each higher frq in list */
+   			got_it = 0;
+			thisintv = number[m]/number[n];
+			hno	  = round(thisintv);
+			thisintv = number[n]/(number[m]/(double)hno);
+			if(thisintv < semit_up && thisintv > semit_dn) {
+				hgrpcnt[n]++;
+				hgrp[n] = (double *)exrealloc((char *)hgrp[n],hgrpcnt[n] * sizeof(double));
+				hgrp[n][hgrpcnt[n]-1] = number[m];
+			}
+		}
+	}
+
+	for(n=0;n<cnt-1;n++) {
+  		for(m=n+1;m<cnt;m++) {
+			samecnt = 0;
+			if(hgrpcnt[n] >= hgrpcnt[m]) {
+				bigg = n;
+				smal = m;
+			} else {
+				bigg = m;
+				smal = n;
+			}
+			for(k=0;k<hgrpcnt[smal];k++) {
+				j = 0;
+				for(;;) {
+					if(hgrp[smal][k] == hgrp[bigg][j]) {
+						samecnt++;
+						break;
+					} else {
+						if(++j >=hgrpcnt[bigg])
+							break;
+					}
+				}
+			}
+			if(samecnt==hgrpcnt[smal]) {
+				if(bigg==n) {
+					free(hgrp[m]);
+					for(j = m+1;j<cnt;j++) {
+						hgrp[j-1]	= hgrp[j];
+						hgrpcnt[j-1] = hgrpcnt[j];
+					}
+					cnt--;
+					m--;
+				} else {
+					free(hgrp[n]);
+					for(j = n+1;j<cnt;j++) {
+						hgrp[j-1]	= hgrp[j];
+						hgrpcnt[j-1] = hgrpcnt[j];
+					}
+					cnt--;
+					n--;
+					break;
+				}
+			}
+		}
+	}
+	for(n=0;n<cnt;n++) {
+		for(m=0;m<hgrpcnt[n];m++)
+			do_valout(hgrp[n][m]);
+		if(!sloom && !sloombatch)
+			fprintf(fp[1],"\n");
+		else
+			fprintf(stdout,"INFO: \n");
+		free(hgrp[n]);
+	}
+	fflush(stdout);
+	free(hgrp);
+	free(hgrpcnt);
+}
+
+
+/***************************** GET_HARMONIC_ROOTS **************************/
+
+void get_harmonic_roots(void)
+{
+	int n;
+	for(n=1;n<=ifactor;n++)
+		do_valout(number[n]/(double)n);
+	fflush(stdout);
+}
+
+ /************************* RANK_VALS *****************************/
+
+ void rank_vals(void)
+ {
+ 	int m, n;
+	double hibnd, lobnd;
+ 	int *poll = (int *)exmalloc(cnt * sizeof(int));
+	for(n=0;n<cnt;n++)
+		poll[n] = 1;
+	for(n=0;n<cnt-1;n++) {
+		if(poll[n] > 0) {
+			hibnd = number[n] + factor;
+			lobnd = number[n] - factor;
+			for(m=n+1;m<cnt;m++) {
+				if(poll[m] > 0) {
+					if(number[m] <= hibnd && number[m] >= lobnd) {
+						poll[n]++;
+						poll[m] = -1;
+					}
+				}
+			}
+		}
+	}
+	for(n=0;n<cnt;n++) {
+		if(poll[n]<=0) {
+			for(m=n;m<cnt-1;m++) {
+				number[m] = number[m+1];
+				poll[m]   = poll[m+1];
+			}
+			n--;
+			cnt--;
+		}
+	}
+	sort_numbers(poll);
+	for(n=0;n<cnt;n++)
+		do_valout(number[n]);
+ 	fflush(stdout);
+ }
+
+ /************************* RANK_FRQS *****************************/
+
+ #define TWELFTH_ROOT_OF_2 (1.059463094)
+
+ void rank_frqs(void)
+ {
+ 	int m, n;
+	double hibnd, lobnd, one_over_factor;
+ 	int *poll = (int *)exmalloc(cnt * sizeof(int));
+	for(n=0;n<cnt;n++)
+		poll[n] = 1;
+	factor = pow(TWELFTH_ROOT_OF_2,factor);
+	one_over_factor = 1.0/factor;
+	for(n=0;n<cnt-1;n++) {
+		if(poll[n] > 0) {
+			hibnd = number[n] * factor;
+			lobnd = number[n] * one_over_factor;
+			for(m=n+1;m<cnt;m++) {
+				if(poll[m] > 0) {
+					if(number[m] <= hibnd && number[m] >= lobnd) {
+						poll[n]++;
+						poll[m] = -1;
+					}
+				}
+			}
+		}
+	}
+	for(n=0;n<cnt;n++) {
+		if(poll[n]<=0) {
+			for(m=n;m<cnt-1;m++) {
+				number[m] = number[m+1];
+				poll[m]   = poll[m+1];
+			}
+			n--;
+			cnt--;
+		}
+	}
+	sort_numbers(poll);
+
+	for(n=0;n<cnt;n++)
+		do_valout(number[n]);
+	fflush(stdout);
+}
+
+/************************* SORT_NUMBERS *****************************/
+
+void sort_numbers(int *poll)
+{
+	int n, m, thispoll;
+	double thisnum;
+	for(n=1;n<cnt;n++) {
+		thispoll = poll[n];
+		thisnum  = number[n];
+		m = n-1;
+		while(m >= 0 && poll[m] < thispoll) {
+			number[m+1]  = number[m];
+			poll[m+1]	= poll[m];
+			m--;
+		}
+		number[m+1]  = thisnum;
+		poll[m+1]	= thispoll;
+	}
+}
+
+
+/*********************** APPROX_VALS ********************/
+
+void approx_vals(void)
+{
+	int z;
+	int n;
+	for(n=0;n<cnt;n++) {
+		z = round(number[n]/factor);
+		number[n] = (double)z * factor;
+		do_valout(number[n]);
+	}
+	fflush(stdout);
+}
+
+/*********************** FLOOR_VALS ********************/
+
+void floor_vals(void)
+{
+	int n;
+	for(n=0;n<cnt;n++) {
+		if(number[n]<factor)
+			number[n] = factor;
+		do_valout(number[n]);
+	}
+	fflush(stdout);
+}
+
+/*********************** LIMIT_VALS ********************/
+
+void limit_vals(void)
+{
+	int n;
+	for(n=0;n<cnt;n++) {
+		if(number[n]>factor)
+			number[n] = factor;
+		do_valout(number[n]);
+	}
+	fflush(stdout);
+}
+
+/****************************** NOTE_TO_MIDI ******************************/
+
+void note_to_midi(int is_transpos)
+{
+	int n, oct, midi;
+	char *p, *q;
+	double qtone = 0.0, midiflt;
+	for(n=0;n< stringscnt;n++) {
+		p = strings[n];	
+		switch(*p) {
+		case('c'):	case('C'):	midi = 0;	break;
+		case('d'):	case('D'):	midi = 2;	break;
+		case('e'):	case('E'):	midi = 4;	break;
+		case('f'):	case('F'):	midi = 5;	break;
+		case('g'):	case('G'):	midi = 7;	break;
+		case('a'):	case('A'):	midi = 9;	break;
+		case('b'):	case('B'):  midi = 11;	break;
+		default:
+			fprintf(stdout,"ERROR: Unknown pitch value '%c' at note %d\n",*p,n+1);
+			fflush(stdout);
+			exit(1);
+		}
+		p++;
+		switch(*p) {
+		case('#'): midi = (midi+1)%12;	p++;	break;
+		case('b'): midi = (midi-1)%12;	p++;	break;
+		}
+		q = p + strlen(p) - 1;
+		qtone = 0.0;
+		if(*q == '-') {
+			qtone = -.5;
+			*q = ENDOFSTR;
+		} else if(*q == '+') {
+			qtone = .5;
+			*q = ENDOFSTR;
+		}		
+		if(sscanf(p,"%d",&oct)!=1) {
+			fprintf(stdout,"ERROR: No octave value given at note %d\n",n+1);
+			fflush(stdout);
+			exit(1);
+		}
+		if(oct > 5 || oct < -5) {
+			fprintf(stdout,"ERROR: octave value out of range (-5 to +5) at note %d\n",n+1);
+			fflush(stdout);
+			exit(1);
+		}
+		oct += 5;
+		midi += (oct * 12);
+		midiflt = (double)midi + qtone;
+		if(is_transpos == 1)
+			midiflt -= factor;
+		else if(is_transpos == 2) /* to frq */
+			midiflt = miditohz(midiflt);
+		fprintf(stdout,"INFO: %lf\n",midiflt);			
+	}
+	fflush(stdout);
+}
+
+/****************************** APPEND_TEXT ******************************/
+
+void append_text(int after)
+{
+	int n, k = strlen(temp);
+	char temp2[64], *p;
+	if(after) {
+		for(n=0;n<stringscnt;n++) {
+			sprintf(temp2,"%s",strings[n]);
+			p = temp2 + strlen(temp2);
+			sprintf(p,"%s",temp);
+			fprintf(stdout,"INFO: %s\n",temp2);			
+		}
+	} else {
+		sprintf(temp2,"%s",temp);
+		p = temp2 + k;
+		for(n=0;n<stringscnt;n++) {
+			sprintf(p,"%s",strings[n]);
+			fprintf(stdout,"INFO: %s\n",temp2);			
+		}
+	}
+
+	fflush(stdout);
+}
+
+/****************************** KILL_TEXT ******************************/
+
+void kill_text(int where)
+{
+	int n;
+	char *p;
+	switch(where) {
+	case(0):	/* Before */
+		for(n=0;n<stringscnt;n++) {
+			p = strings[n];
+			p += strlen(strings[n]);
+			p--;
+			while(isdigit(*p) || (*p == '.') || (*p == '-')) {
+				p--;
+				if(p < strings[n])
+					break;
+			}
+			p++;
+			if(p == strings[n] + strlen(strings[n])) {
+				fprintf(stdout,"ERROR: Cannot find numeric ending of value.\n");
+				fflush(stdout);
+				exit(1);
+			}
+			fprintf(stdout,"INFO: %s\n",p);			
+		}				
+		break;
+	case(1):	/* After */
+		for(n=0;n<stringscnt;n++) {
+			p = strings[n];
+			p += strlen(strings[n]);
+			p--;
+			while(!isdigit(*p)) {
+				p--;
+				if(p < strings[n]) {
+					fprintf(stdout,"ERROR: Cannot find numeric part of value.\n");
+					fflush(stdout);
+					exit(1);
+				}
+			}
+			if(*(p+1) =='.')
+				p++;
+			p++;
+			*p = ENDOFSTR;
+			fprintf(stdout,"INFO: %s\n",strings[n]);			
+		}				
+		break;
+	case(2):	/* Before & After */
+		for(n=0;n<stringscnt;n++) {
+			p = strings[n];
+			p += strlen(strings[n]);
+			p--;
+			while(!isdigit(*p)) {
+				p--;
+				if(p < strings[n]) {
+					fprintf(stdout,"ERROR: Cannot find numeric part of value.\n");
+					fflush(stdout);
+					exit(1);
+				}
+			}
+			if(*(p+1) =='.')
+				p++;
+			p++;
+			*p = ENDOFSTR;
+			p--;
+			while(isdigit(*p) || (*p == '.') || (*p == '-')) {
+				p--;
+				if(p < strings[n])
+					break;
+			}
+			p++;
+			fprintf(stdout,"INFO: %s\n",p);			
+		}				
+		break;
+	}
+	fflush(stdout);
+}
+
+/****************************** TARGETED_STRETCH ******************************/
+
+void targeted_stretch(void)
+{
+	int n;
+	double time_shoulder = number[cnt];
+	double stretch = number[cnt+1], lastime;
+	if(time_shoulder < 0.0) {
+		fprintf(stdout,"ERROR: timestep (%lf) cannot be less than zero.\n",time_shoulder);
+		fflush(stdout);
+		exit(1);
+	}
+	if(number[0] < 0.0) {
+		fprintf(stdout,"ERROR: First time value less than zero encountered.\n");
+		fflush(stdout);
+		exit(1);
+	} else if(number[0] <= time_shoulder) {
+		fprintf(stdout,"ERROR: First time is too close to zero\n");
+		fflush(stdout);
+		exit(1);
+	}
+	lastime = number[0];
+	for(n = 1; n < cnt; n++) {
+		if(ODD(n)) {
+			if(number[n] <= lastime) {
+				fprintf(stdout,"ERROR: Times out of sequence (between %lf and %lf).\n",number[n],lastime);
+				fflush(stdout);
+				exit(1);
+			}
+		} else {
+			if(number[n] <= lastime + (2 * time_shoulder)) {
+				fprintf(stdout,"ERROR: Too small time step encountered (between %lf and %lf).\n",number[n],lastime);
+				fflush(stdout);
+				exit(1);
+			}
+		}
+		lastime = number[n];
+	}
+
+	if(flteq(number[n],0.0)) {
+		fprintf(stdout,"INFO: 0.0  %lf\n",stretch);
+	} else {
+		fprintf(stdout,"INFO: 0.0  1.0\n");
+		fprintf(stdout,"INFO: %lf  1.0\n",number[0] - time_shoulder);
+		fprintf(stdout,"INFO: %lf  %lf\n",number[0],stretch);
+	}
+	for(n = 1; n < cnt; n++) {
+		if(ODD(n)) {	/* already stretched */
+			fprintf(stdout,"INFO: %lf  %lf\n",number[n],stretch);
+			fprintf(stdout,"INFO: %lf  1.0\n",number[n] + time_shoulder);
+		} else {		/* not stretched at the moment */
+			fprintf(stdout,"INFO: %lf  1.0\n",number[n] - time_shoulder);
+			fprintf(stdout,"INFO: %lf  %lf\n",number[n],stretch);
+		}
+	}
+	lastime = max(100.0,2.0 * number[cnt-1]);
+	if(ODD(cnt))
+		fprintf(stdout,"INFO: %lf  %lf\n",lastime,stretch);
+	else
+		fprintf(stdout,"INFO: %lf  1.0\n",lastime);
+	fflush(stdout);
+}
+
+/****************************** TARGETED_PAN ******************************/
+
+void targeted_pan(void)
+{
+	int n;
+	double time_shoulder = number[cnt];
+	double panedj        = number[cnt+1];
+	double start_panpos  = number[cnt+2];
+	double end_panpos    = number[cnt+3];
+	double end_pantime   = number[cnt+4];
+	double lastime;
+	double pan_subedj = panedj * (7.5/9.0);
+
+	if(time_shoulder < 0.0) {
+		fprintf(stdout,"ERROR: half lingertime (%lf) cannot be less than zero.\n",time_shoulder);
+		fflush(stdout);
+		exit(1);
+	}
+	if(number[0] < 0.0) {
+		fprintf(stdout,"ERROR: First time value less than zero encountered.\n");
+		fflush(stdout);
+		exit(1);
+	} else if(number[0] <= time_shoulder) {
+		fprintf(stdout,"ERROR: First time is too close to zero\n");
+		fflush(stdout);
+		exit(1);
+	}
+	lastime = number[0];
+	for(n = 1; n < cnt; n++) {
+		if(number[n] <= lastime + (2 * time_shoulder)) {
+			fprintf(stdout,"ERROR: Too small time step encountered (between %lf and %lf).\n",number[n],lastime);
+			fflush(stdout);
+			exit(1);
+		}
+	}
+	if(end_pantime - time_shoulder <= number[cnt-1]) {
+		fprintf(stdout,"ERROR: Too small time step encountered before end pantime (%lf to %lf).\n",number[cnt -1],end_pantime);
+		fflush(stdout);
+		exit(1);
+	}
+	if(flteq(number[0],0.0))
+		fprintf(stdout,"INFO: 0.0  %lf\n",panedj);
+	else {
+		fprintf(stdout,"INFO: 0.0  %lf\n",start_panpos);
+		fprintf(stdout,"INFO: %lf  %lf\n",number[0] - time_shoulder,pan_subedj);
+		fprintf(stdout,"INFO: %lf  %lf\n",number[0],panedj);
+		fprintf(stdout,"INFO: %lf  %lf\n",number[0] + time_shoulder,pan_subedj);
+	}
+	panedj = -panedj;
+	pan_subedj = -pan_subedj;
+	for(n = 1; n < cnt; n++) {
+		fprintf(stdout,"INFO: %lf  %lf\n",number[n] - time_shoulder,pan_subedj);
+		fprintf(stdout,"INFO: %lf  %lf\n",number[n],panedj);
+		fprintf(stdout,"INFO: %lf  %lf\n",number[n] + time_shoulder,pan_subedj);
+		lastime = number[n];
+		panedj = -panedj;
+		pan_subedj = -pan_subedj;
+	}
+	fprintf(stdout,"INFO: %lf  %lf\n",end_pantime,end_panpos);
+	fflush(stdout);
+}
+
+/******************************** DO_SQUEEZED_PAN ****************************/
+
+void do_squeezed_pan(void) {
+	int n, neg = 1;
+	double time_shoulder = number[cnt];
+	double start_panpos  = number[cnt+1];
+	double end_panpos    = number[cnt+2];
+	double end_pantime   = number[cnt+3];
+	double lastime;
+	double pan_subedj;
+
+	if(time_shoulder < 0.0) {
+		fprintf(stdout,"ERROR: half lingertime (%lf) cannot be less than zero.\n",time_shoulder);
+		fflush(stdout);
+		exit(1);
+	}
+	if(number[0] < 0.0) {
+		fprintf(stdout,"ERROR: First time value less than zero encountered.\n");
+		fflush(stdout);
+		exit(1);
+	} else if(number[0] <= time_shoulder) {
+		fprintf(stdout,"ERROR: First time (%lf) is too close to zero for half-lingertime %lf\n",number[0],time_shoulder);
+		fflush(stdout);
+		exit(1);
+	}
+	lastime = number[0];
+	for(n = 2; n < cnt; n+=2) {
+		if(number[n] <= lastime + (2 * time_shoulder)) {
+			fprintf(stdout,"ERROR: Too small time step encountered (between %lf and %lf).\n",number[n],lastime);
+			fflush(stdout);
+			exit(1);
+		}
+	}
+	if(end_pantime - time_shoulder <= number[cnt-2]){
+		fprintf(stdout,"ERROR: Too small time step encountered before end pantime (%lf to %lf).\n",number[cnt-2],end_pantime);
+		fflush(stdout);
+		exit(1);
+	}
+	if(flteq(number[0],0.0))
+		fprintf(stdout,"INFO: 0.0  %lf\n",number[1]);
+	else {
+		pan_subedj = number[1] * (7.5/9.0); 
+		fprintf(stdout,"INFO: 0.0  %lf\n",start_panpos);
+		fprintf(stdout,"INFO: %lf  %lf\n",number[0] - time_shoulder,pan_subedj);
+		fprintf(stdout,"INFO: %lf  %lf\n",number[0],number[1]);
+		fprintf(stdout,"INFO: %lf  %lf\n",number[0] + time_shoulder,pan_subedj);
+	}
+	if(number[1] > 0.0)
+		neg = -1;
+	for(n = 2; n < cnt; n+=2) {
+		number[n+1] *= neg;
+		pan_subedj = number[n+1] * (7.5/9.0); 
+		fprintf(stdout,"INFO: %lf  %lf\n",number[n] - time_shoulder,pan_subedj);
+		fprintf(stdout,"INFO: %lf  %lf\n",number[n],number[n+1]);
+		fprintf(stdout,"INFO: %lf  %lf\n",number[n] + time_shoulder,pan_subedj);
+		neg = -neg;
+	}
+	fprintf(stdout,"INFO: %lf  %lf\n",end_pantime,end_panpos);
+	fflush(stdout);
+}	
+
+/****************************** KILL_PATH ******************************/
+
+void kill_path(void)
+{
+	int n;
+	char *p;
+	for(n=0;n<stringscnt;n++) {
+		p = strings[n];
+		p += strlen(strings[n]);
+		p--;
+		while((*p != '\\') && (*p != '/')) {
+			p--;
+			if(p < strings[n])
+				break;
+		}
+		p++;
+		fprintf(stdout,"INFO: %s\n",p);			
+	}				
+	fflush(stdout);
+}
+
+/****************************** KILL_EXTENSION ******************************/
+
+void kill_extension(void)
+{
+	int n;
+	char *p;
+	for(n=0;n<stringscnt;n++) {
+		p = strings[n];
+		p += strlen(strings[n]);
+		p--;
+		while(*p != '.') {
+			p--;
+			if(p < strings[n]) {
+				p++;
+				break;
+			}
+		}
+		if(p >strings[n])
+			*p = ENDOFSTR;
+		fprintf(stdout,"INFO: %s\n",strings[n]);			
+	}				
+	fflush(stdout);
+}
+
+/****************************** KILL_PATH ******************************/
+
+void kill_path_and_extension(void)
+{
+	int n, gotext;
+	char *p;
+	for(n=0;n<stringscnt;n++) {
+		p = strings[n];
+		p += strlen(strings[n]);
+		p--;
+		gotext = 0;
+		while(p >= strings[n]) {
+			if(!gotext && (*p == '.')) {
+				*p = ENDOFSTR;
+				gotext = 1;
+			}
+			if(*p == '\\' || *p == '/') {
+				p++;
+				break;
+			}
+			p--;
+		}
+		if(strlen(p) <=0) {
+			sprintf(errstr,"Invalid filename (%s) encountered: cannot complete this process\n",strings[n]);
+			do_error();
+		}
+		fprintf(stdout,"INFO: %s\n",p);			
+	}				
+	fflush(stdout);
+}
+

+ 4510 - 0
dev/tabedit/columns5.c

@@ -0,0 +1,4510 @@
+/*
+ * 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 <columns.h>
+#include <cdplib.h>
+
+#define MIN_TEMPO (.01666667)		/* 1 beat per hour ! */
+#define MAX_TEMPO (60000)			/* 1 beat per millisecond ! */
+
+int alphabetical_order(char *,char *);
+double leveltodb(double,int);
+double dbtolevel(double);
+void hinsert(int m,int t,int *perm,int permlen);
+void ascending_sort_cells(int *perm,int ccnt);
+void hshuflup(int k,int *perm,int permlen);
+void hprefix(int m,int *perm,int permlen);
+void randperm(int *perm, int permlen);
+static void invertenv(double piv);
+static void docross
+		(double lastnval,double lastmval,double thisnval, double thismval,double time,int *j,double *out,int typ);
+static void hhinsert(int m,int t,int setlen,int *perm);
+static void hhprefix(int m,int setlen,int *perm);
+static void hhshuflup(int k,int setlen,int *perm);
+static void do_repet_restricted_perm(int *arr, int *perm, int arrsiz, int allowed, int endval);
+static void get_metre(char [],int *barlen,int *beatsize);
+static double get_tempo(char *str);
+static double get_beat(int n,int barlen);
+static void get_offset(char *str,double *offset);
+static double randoffset(double scatter);
+static double readbrk(float *warpvals,double time,int wcnt);
+
+/***************************** PRODUCT ***************************/
+
+void product(void)
+{
+	int n;
+	double sum = number[0];
+	for(n=1;n<cnt;n++)
+	sum *= number[n];
+	do_valout_as_message(sum);
+	fflush(stdout);
+}
+
+/*************************** HZ_TO_MIDI ************************/
+
+void hz_to_midi(void)
+{
+	int n;
+	for(n=0;n<cnt;n++) {
+		number[n] = hztomidi(number[n]);
+		do_valout(number[n]);
+	}
+	fflush(stdout);
+}
+
+/******************************** FIND_MEAN *************************/
+
+void find_mean(void)
+{
+	double sum = 0.0;
+	int n;
+	for(n=0;n<cnt;n++)
+		sum += number[n];
+	sum /= (double)cnt;
+	do_valout_as_message(sum);
+	fflush(stdout);
+}
+
+/******************************** MIDI_TO_HZ **************************/
+
+void midi_to_hz(void)
+{
+	int n;
+	for(n=0;n<cnt;n++) {
+		number[n] = miditohz(number[n]);
+		do_valout(number[n]);
+	}
+	fflush(stdout);
+}
+
+/*************************** MAJOR_TO_MINOR *************************/
+
+void major_to_minor(void)
+{
+	int n;
+	int m3 = (4 + ifactor)%12;	/* MIDI location of major 3rd */
+	int m6 = (9 + ifactor)%12;	/* MIDI location of major 6th */
+	for(n=0;n<cnt;n++) {
+		factor = fmod(number[n],TWELVE);
+		if(flteq(factor,(double)m3) || flteq(factor,(double)m6))
+			number[n] -= 1.0;
+		do_valout(number[n]);
+	}
+	fflush(stdout);
+}
+
+/****************** REMOVE_MIDI_PITCHCLASS_DUPLICATES *******************/
+
+void remove_midi_pitchclass_duplicates(void)
+{
+	int n, m, move;
+	int k = cnt-ifactor;
+	int failed = 0;
+	for(n=0;n<k;n++) {
+		for(m=1;m<=ifactor;m++) {
+			if(n+m >= cnt)
+				break;
+			if(flteq(fmod(number[n],12.0),fmod(number[n+m],12.0))) {
+				if((move = m_repos(n+m))<0) {
+					failed++;
+				} else {
+					n += move;	/* list shufld forwd, or not */
+					m--;		/* m+1th item now at m */
+				}
+			}
+		}
+	}
+	if(failed)
+		fprintf(stdout,"WARNING: %d items failed to be separated.\n",failed);
+	for(n=0;n<cnt;n++)
+		do_valout(number[n]);
+	fflush(stdout);
+}
+
+/************************** REVERSE_LIST *************************/
+
+void reverse_list(void)
+{
+	int n;
+	for(n=stringscnt-1;n>=0;n--)
+		do_stringout(strings[n]);
+	fflush(stdout);
+}
+
+/************************* ROTATE_MOTIF *************************/
+
+void rotate_motif(void)
+{
+	int n;
+	for(n=cnt-ifactor;n<cnt;n++)
+		do_valout(number[n]);
+	for(n=0;n<cnt-ifactor;n++)
+		do_valout(number[n]);
+	fflush(stdout);
+}
+
+/************************** RATIOS ****************************/
+
+void ratios(void)
+{
+	int n;
+	for(n=1;n<cnt;n++) {
+		if(flteq(number[n-1],0.0))
+			do_stringout("INF\n");
+		else
+			do_valout(number[n]/number[n-1]);
+	}
+	fflush(stdout);
+}
+
+/******************************** RECIPROCALS ***********************/
+
+void reciprocals(int positive_vals_only)
+{
+	int n;
+	if(positive_vals_only) {
+		for(n=0;n<cnt;n++) {
+			if(number[n] < FLTERR) {
+				fprintf(stdout,"ERROR: Invalid value %d (%lf) for this process\n",n+1,number[n]);
+				fflush(stdout);
+				exit(1);
+			}
+		}
+	}
+	for(n=0;n<cnt;n++) {
+		switch(condit) {
+		case(0):
+			if(flteq(number[n],0.0)) {
+				if(!sloom && !sloombatch)
+					fprintf(fp[1],"INFINITE\n");
+				else if(sloombatch) {
+					fprintf(stdout,"INFINITE\n");
+					fflush(stdout);
+				} else {
+					fprintf(stdout,"ERROR: Division by zero encountered (item %d) : Impossible\n",n+1);
+					fflush(stdout);
+					exit(1);
+				}
+			} else
+				do_valout(factor/number[n]);
+			break;
+		case('>'):
+			if(number[n]>thresh) {
+				if(flteq(number[n],0.0)) {
+					if(!sloom && !sloombatch)
+						fprintf(fp[1],"INFINITE\n");
+					else if(sloombatch) {
+						fprintf(stdout,"INFINITE\n");
+						fflush(stdout);
+					} else {
+						fprintf(stdout,"ERROR: Division by zero encountered (item %d) : Impossible\n",n+1);
+						fflush(stdout);
+						exit(1);
+					}
+				} else
+					do_valout(factor/number[n]);
+			} else
+				do_valout(number[n]);
+			break;
+		case('<'):
+			if(number[n]<thresh) {
+				if(flteq(number[n],0.0)) {
+					if(!sloom && !sloombatch)
+						fprintf(fp[1],"INFINITE\n");
+					else if(sloombatch) {
+						fprintf(stdout,"INFINITE\n");
+						fflush(stdout);
+					} else {
+						fprintf(stdout,"ERROR: Division by zero encountered (item %d) : Impossible\n",n+1);
+						fflush(stdout);
+						exit(1);
+					}
+				} else
+					do_valout(factor/number[n]);
+			} else
+				do_valout(number[n]);
+			break;
+		}
+	}
+	fflush(stdout);
+}
+
+/****************************** RANDOMISE_ORDER *********************/
+
+void randomise_order(int *perm)
+{
+	int n;
+	randperm(perm,stringscnt);
+	for(n=0;n<stringscnt;n++)
+		do_stringout(strings[perm[n]]);
+	fflush(stdout);
+}
+
+/****************************** RANDOMISE_ORDER *********************/
+
+void randomise_Ntimes(int *perm)
+{
+	int n = 0, m, lastperm;
+	for(m = 0;m< ifactor;m++) {
+		if(n == 0)
+			randperm(perm,stringscnt);
+		else {
+			lastperm = perm[stringscnt - 1];
+			randperm(perm,stringscnt);
+			while(perm[0] == lastperm)
+				randperm(perm,stringscnt);
+		}
+		for(n=0;n<stringscnt;n++)
+			do_stringout(strings[perm[n]]);
+	}
+	fflush(stdout);
+}
+
+/************************** ADD_RANDVAL_PLUS_OR_MINUS ********************/
+
+void add_randval_plus_or_minus(void)
+{
+	int n;
+	for(n=0;n<cnt;n++) {
+		number[n] += ((drand48() * 2.0) - 1.0) * factor;
+		do_valout(number[n]);
+	}
+	fflush(stdout);
+}
+
+/****************************** ADD_RANDVAL ***************************/
+
+void add_randval(void)
+{
+	int n;
+	for(n=0;n<cnt;n++) {
+ 		number[n] += drand48() * factor;
+		do_valout(number[n]);
+	}
+	fflush(stdout);
+}
+
+/************************ MULTIPLY_BY_RANDVAL ************************/
+
+void multiply_by_randval(void)
+{
+	int n;
+	for(n=0;n<cnt;n++) {
+		number[n] *= drand48() * factor;
+		do_valout(number[n]);
+	}
+	fflush(stdout);
+}
+
+/***************************** RANDCHUNKS ************************/
+
+void randchunks(void)
+{
+	double sum = 0.0;
+	double randrange = fabs(number[1] - number[0]);
+	double minn = min(number[1],number[0]);
+	while(sum<factor) {
+		do_valout(sum);
+		sum += (drand48() * randrange) + minn;
+	}
+	fflush(stdout);
+}
+
+/************************** GENERATE_RANDOM_VALUES ***********************/
+
+void generate_random_values(void)
+{
+	double randrange = number[1] - number[0];
+	int n;
+	for(n=0;n<factor;n++)
+		do_valout((drand48() * randrange) + number[0]);
+	fflush(stdout);
+}
+
+/****************************** RANDOM_0S_AND_1S ********************/
+
+void random_0s_and_1s(void)
+{
+	int n;
+	double sum;
+	int totcnt = (int)round(number[0]);
+	for(n=0;n<totcnt;n++) {
+		sum = drand48() * 2.0;
+  		if(sum>=1.0)
+			do_stringout("1\n");
+		else
+			do_stringout("0\n");
+	}
+	fflush(stdout);
+}
+
+/****************************** RANDOM_PAIRS ********************/
+
+void random_pairs(void)
+{
+	int n;
+	double sum;
+	int totcnt = (int)round(number[2]);
+	char tempa[200];
+	char tempb[200];
+	sprintf(tempa,"%d",(int)round(number[0]));
+	sprintf(tempb,"%d",(int)round(number[1]));
+	for(n=0;n<totcnt;n++) {
+		sum = drand48() * 2.0;
+  		if(sum>=1.0)
+			do_stringout(tempb);
+		else
+			do_stringout(tempa);
+	}
+	fflush(stdout);
+}
+
+/****************************** RANDOM_0S_AND_1S_RESTRAINED ********************/
+
+void random_0s_and_1s_restrained(void)
+{
+	int n, cnt0 = 0, cnt1 = 0;
+	double sum;
+	int totcnt = (int)round(number[0]);
+	int limit  = (int)round(number[1]);
+	for(n=0;n<totcnt;n++) {
+		sum = drand48() * 2.0;
+		if(sum>=1.0) {
+			cnt1++;
+			if(cnt1 <= limit) {
+				do_stringout("1\n");
+				cnt0 = 0;
+			} else {
+				do_stringout("0\n");
+				cnt1 = 0;
+				cnt0 = 1;
+			}
+		} else {
+			cnt0++;
+			if(cnt0 <= limit) {
+				do_stringout("0\n");
+				cnt1 = 0;
+			} else {
+				do_stringout("1\n");
+				cnt0 = 0;
+				cnt1 = 1;
+			}
+		}
+	}
+	fflush(stdout);
+}
+
+/****************************** RANDOM_PAIRS_RESTRAINED ********************/
+
+void random_pairs_restrained(void)
+{
+	int n, cnt0 = 0, cnt1 = 0;
+	double sum;
+	int totcnt = (int)round(number[2]);
+	int limit  = (int)round(number[3]);
+	char tempa[200];
+	char tempb[200];
+	sprintf(tempa,"%d",(int)round(number[0]));
+	sprintf(tempb,"%d",(int)round(number[1]));
+	for(n=0;n<totcnt;n++) {
+		sum = drand48() * 2.0;
+		if(sum>=1.0) {
+			cnt1++;
+			if(cnt1 <= limit) {
+				do_stringout(tempb);
+				cnt0 = 0;
+			} else {
+				do_stringout(tempa);
+				cnt1 = 0;
+				cnt0 = 1;
+			}
+		} else {
+			cnt0++;
+			if(cnt0 <= limit) {
+				do_stringout(tempa);
+				cnt1 = 0;
+			} else {
+				do_stringout(tempb);
+				cnt0 = 0;
+				cnt1 = 1;
+			}
+		}
+	}
+	fflush(stdout);
+}
+
+/****************************** RANDOM_SCATTER **********************/
+
+void random_scatter(void)
+{
+	int n;
+	double scatter; 
+	double *diffs = (double *)exmalloc((cnt-1)*sizeof(double));
+	for(n=0;n<cnt-1;n++) {
+	 	diffs[n] = number[n+1] - number[n];
+		diffs[n] /= 2.0;
+	}
+	for(n=1;n<cnt-1;n++) {
+		scatter = ((drand48() * 2.0) - 1.0) * factor;
+		if(scatter > 0.0)
+			number[n] += diffs[n] * scatter;
+		else
+			number[n] += diffs[n-1] * scatter;
+	}
+	print_numbers();
+}
+
+/************************** RANDOM_ELIMINATION ***********************/
+
+void random_elimination(void)
+{
+	int n, m;
+	for(n=0;n<ifactor;n++) {
+		m = (int)(drand48() * cnt);	/* TRUNCATE */
+		eliminate(m);
+	}
+	print_numbers();
+}
+
+/*************************** EQUAL_DIVISIONS ************************/
+
+void equal_divisions(void)
+{
+	double interval = (number[1] - number[0])/factor;
+	double sum = number[0];
+	if(interval > 0.0) {
+		while(sum<=number[1]) {
+			do_valout(sum);
+			 sum += interval;
+		}
+	} else {
+		while(sum>=number[1]) {
+			do_valout(sum);
+			sum += interval;
+		}
+	}
+	fflush(stdout);
+}
+
+/************************* LOG_EQUAL_DIVISIONS ***********************/
+
+void log_equal_divisions(void)
+{
+	double sum		  = log(number[0]);
+	double top	  = log(number[1]);
+	double interval = (top - sum)/factor;
+	if(sum < top) {
+		while(sum <= top - FLTERR) {
+			do_valout(exp(sum));
+			sum += interval;
+		}
+ 		
+	} else {
+		while(sum >= top + FLTERR) {
+			do_valout(exp(sum));
+			sum += interval;
+		}
+	}
+	do_valout(number[1]);
+	fflush(stdout);
+}
+
+/****************************** QUADRATIC_CURVE_STEPS ******************/
+
+void quadratic_curve_steps(void)
+{
+	double sum, diff = number[1] - number[0];
+	double step = fabs(1.0/(factor - 1.0));
+	double thisstep = 0.0;
+	int cnt = 0, ifactor = round(factor);
+	if(diff>0.0)
+		number[2] = 1.0/number[2];
+	for(;;) {
+		sum = pow(thisstep,number[2]);
+		sum = (sum * diff) + number[0];
+		do_valout(sum);
+		if(++cnt >= ifactor)
+			break;
+		thisstep += step;
+	}
+	fflush(stdout);
+}
+
+/*************************** PLAIN_BOB ***************************/
+
+void plain_bob(void)
+{
+	int n, m, k;
+	for(n=0;n<cnt;n++) 
+		do_valout(number[n]);
+	for(m=0;m<cnt-1;m++) {
+		for(k=0;k<cnt-1;k++) {
+			bellperm1();
+			for(n=0;n<cnt;n++)
+				do_valout(number[n]);
+			bellperm2();
+			for(n=0;n<cnt;n++)
+				do_valout(number[n]);
+		}
+		bellperm1();
+		for(n=0;n<cnt;n++)
+			do_valout(number[n]);
+		bellperm3();
+		for(n=0;n<cnt;n++)
+			do_valout(number[n]);
+	}	
+	fflush(stdout);
+}
+
+/*********************** REPEAT_INTERVALS *************************/
+
+void repeat_intervals(void)
+{
+	int n, m;
+	double z, k;
+	for(n=0;n<cnt-1;n++)
+		do_valout(number[n]);
+	z = k = number[n] - number[0];
+	for(m=1;m<=ifactor;m++) {
+		for(n=0;n<cnt-1;n++)	/*TW Feb 2005*/
+			do_valout(number[n] + z);
+		z += k;
+	}
+	fflush(stdout);
+}
+
+/************** MAKE_EQUAL_INTEVALS_BTWN_GIVEN_VALS ************/
+
+void make_equal_intevals_btwn_given_vals(void)
+{
+	double top = number[1];
+	double sum = number[0];
+
+	if(factor > 0.0) {
+		if(number[0] > number[1]) {
+			top = number[0];
+			sum = number[1];
+		}
+	} else {
+			if(number[0] < number[1]) {
+			top = number[0];
+			sum = number[1];
+		}
+	}
+	if(top >= sum ) {
+		while(sum<=top) {
+			do_valout(sum);
+			sum += factor;
+		}
+	} else {
+		while(sum>=top) {
+			do_valout(sum);
+			sum += factor;
+		}
+	}
+	fflush(stdout);
+}
+
+/********************** CREATE_INTERVALS ***********************/
+
+void create_intervals(void)
+{
+	int n;
+	for(n=0;n<ifactor;n++) {
+		do_valout(number[0] * n);
+	}
+	fflush(stdout);
+}
+
+/********************** CREATE_INTERVALS_FROM_BASE ***********************/
+
+void create_intervals_from_base(void)
+{
+	int n;
+	double sum = number[1];
+	for(n=0;n<ifactor;n++) {
+		do_valout(sum);
+		sum += number[0];
+	}
+	fflush(stdout);
+}
+
+/********************** CREATE_RATIOS_FROM_BASE ***********************/
+
+void create_ratios_from_base(void)
+{
+	int n;
+	double sum = number[1];
+	for(n=0;n<ifactor;n++) {
+		do_valout(sum);
+		if(sum > HUGE/2.0 || sum < -HUGE/2.0) {
+			sprintf(errstr,"Calculation overflows.\n");
+			do_error();
+		}
+		sum *= number[0];
+	}
+	fflush(stdout);
+}
+
+/********************** CREATE_EQUAL_STEPS ***********************/
+
+void create_equal_steps(void)
+{
+	int n;
+	double sum = number[0];
+	double step = (number[1] - number[0])/((double)ifactor - 1.0);
+	for(n=0;n<ifactor;n++) {
+		do_valout(sum);
+		sum += step;
+	}
+	fflush(stdout);
+}
+
+/********************** CREATE_EQUAL_VALS ***********************/
+
+void create_equal_vals(void)
+{
+	int n;
+	for(n=0;n<ifactor;n++) {
+		do_valout(number[0]);
+	}
+	fflush(stdout);
+}
+
+/************************ CHANGE_VALUE_OF_INTERVALS ********************/
+
+void change_value_of_intervals(void)
+{
+	double interval, sum = number[0];
+	int n;
+	for(n=1;n<cnt;n++) {
+		do_valout(sum);
+		switch(ro) {
+			case('a'): interval=(number[n]-number[n-1])+factor; break;
+			case('m'): interval=(number[n]-number[n-1])*factor; break;
+			default:
+				fprintf(stdout,"ERROR: Unkonwn case in change_value_of_intervals()\n");
+				fflush(stdout);
+				exit(1);
+				break;
+		}
+		sum += interval;
+	}
+	do_valout(sum);
+	fflush(stdout);
+}
+
+/******************** MOTIVICALLY_INVERT_MIDI **********************/
+
+void motivically_invert_midi(void)
+{
+	double factor = 2.0 * number[0];
+	int n;
+	for(n=1;n<cnt;n++)
+		number[n] = factor - number[n];
+	print_numbers();
+}
+
+/********************** MOTIVICALLY_INVERT_HZ **********************/
+
+void motivically_invert_hz(void)
+{
+	double factor;
+	int n;
+	if(flteq((factor = number[0] * number[0]),0.0)) {
+		sprintf(errstr,"First frq is zero : can't proceed.\n");
+		do_error();
+	}
+	for(n=1;n<cnt;n++)
+		number[n] = factor/number[n];
+	print_numbers();
+}
+
+/******************** GET_INTERMEDIATE_VALUES ************************/
+
+void get_intermediate_values(void)
+{
+	int n;
+	double d;
+	for(n=1;n<cnt;n++) {
+		d = (number[n] + number[n-1])/2.0;
+		do_valout(d);
+	}
+	fflush(stdout);
+}
+
+/******************** INSERT_INTERMEDIATE_VALUES ************************/
+
+void insert_intermediate_values(void)
+{
+	int n;
+	double d;
+	fprintf(stdout,"INFO: %lf\n",number[0]);
+	for(n=1;n<cnt;n++) {
+		d = (number[n] + number[n-1])/2.0;
+		fprintf(stdout,"INFO: %lf\n",d);
+		fprintf(stdout,"INFO: %lf\n",number[n]);
+	}
+	fflush(stdout);
+}
+
+/******************** INSERT_INTERMEDIATE_VALP ************************/
+
+void insert_intermediate_valp(void)
+{
+	int n;
+	double d;
+	for(n=1;n<cnt;n+=2) {
+		fprintf(stdout,"INFO: %lf\n",number[n-1]);
+		d = (number[n] + number[n-1])/2.0;
+		fprintf(stdout,"INFO: %lf\n",d);
+		fprintf(stdout,"INFO: %lf\n",number[n]);
+	}
+	fflush(stdout);
+}
+
+/************************** GET_INTERVALS ***********************/
+
+void get_intervals(void)
+{
+	int n;
+	for(n=1;n<cnt;n++)
+		do_valout(number[n]-number[n-1]);
+	fflush(stdout);
+}
+
+/************************ GET_ONE_SKIP_N ************************/
+
+void get_one_skip_n(void)
+{
+	int n = 0;
+	ifactor = round(factor);
+ 	if(ifactor < 1) {
+		sprintf(errstr,"Invalid parameter (%d)\n",ifactor);
+		do_error();
+	}
+	while(n<stringscnt) {
+		do_stringout(strings[n++]);
+		n += ifactor;
+	}
+	fflush(stdout);
+}
+
+/************************ GET_N_SKIP_ONE *************************/
+
+void get_n_skip_one(void)
+{
+	int m, n = 0;	
+	int k, ifactor = round(factor);
+
+	if(ifactor < 1) {
+		sprintf(errstr,"Invalid parameter (%d)\n",ifactor);
+		do_error();
+	}
+	while(n<stringscnt) {
+		if((k = n + ifactor) >= stringscnt) {
+			for(m=n;m<stringscnt;m++)
+				do_stringout(strings[m]);
+			break;
+		}
+		for(m=n;m<k;m++)
+			do_stringout(strings[m]);
+		n+= ifactor+1;
+	}
+	fflush(stdout);
+}
+
+/************************* SUM_NWISE **************************/
+
+void sum_nwise(void)
+{
+	int n, m;
+	ifactor = round(factor);
+/* RWD */
+	if(ifactor > cnt) {
+		sprintf(errstr,"group size (N) too large for infile\n");
+		do_error();
+	}
+	for(n=0;n<=cnt-ifactor;n++) {	/*RWD: test was just < */
+		for(m=1;m<ifactor;m++)
+			number[n] += number[n+m];
+		do_valout(number[n]);
+	}
+	fflush(stdout);
+}
+
+/************************* SUM_MINUS_OVERLAPS *********************/
+
+void sum_minus_overlaps(void)
+{
+	int n;
+	double sum = 0.0;
+	for(n=0;n<cnt;n++)
+		sum += number[n];
+	sum -= (double)(cnt-1) * factor;
+	do_valout_as_message(sum);
+	fflush(stdout);
+}
+
+/******************** SUM_ABSOLUTE_DIFFERENCES ********************/
+
+void sum_absolute_differences(void)
+{
+	int n;
+	double sum = 0.0;
+	for(n=1;n<cnt;n++)
+		sum += fabs(number[n] - number[n-1]);
+	sum -= (double)(cnt-1) * factor;
+	do_valout_as_message(sum);
+	fflush(stdout);
+}
+
+/**************************** STACK ***************************/
+
+void stack(int with_last)
+{
+	int n;
+		double sum = 0.0;
+	for(n=0;n<cnt;n++) {
+		do_valout(sum);
+		sum += number[n] - factor;
+	}
+	if(with_last) {
+		sum += factor;
+		do_valout(sum);
+	}
+	fflush(stdout);
+}
+
+/*********************** DUPLICATE_VALUES **************************/
+
+void duplicate_values(void)
+{
+	int n, m;
+	for(n=0;n<stringscnt;n++) {
+		for(m=0;m<ifactor;m++)
+			do_stringout(strings[n]);
+	}
+	fflush(stdout);
+}
+
+/*********************** DUPLICATE_VALUES_STEPPED **************************/
+
+void duplicate_values_stepped(void)
+{
+	int n, m;
+	double step = number[cnt+1];
+	double offset = 0.0;
+	ifactor = round(number[cnt]);
+	for(m=0;m<ifactor;m++) {
+		for(n=0;n<cnt;n++)
+			fprintf(stdout,"INFO: %lf\n",number[n] + offset);
+		offset += step;
+	}
+	fflush(stdout);
+}
+/**************************** DUPLICATE_LIST **********************/
+
+void duplicate_list(void)
+{
+	int n, m;
+	for(m=0;m<ifactor;m++) {
+		for(n=0;n<stringscnt;n++)
+			do_stringout(strings[n]);
+	}
+	fflush(stdout);
+}
+
+/****************************** FORMAT_VALS ****************************/
+
+void format_vals(void)
+{ /*RWD new Format option : recast by TW */
+	int n, m, OK = 1;
+	double d = (double)cnt/(double)ifactor;
+	int rowcnt = cnt/ifactor;
+	char temp[64];
+
+	errstr[0] = ENDOFSTR;
+	if(d > (double)rowcnt)
+		rowcnt++;
+	if((rowcnt > 82) && sloom) {
+		sprintf(errstr,"Too many (%d) rows to handle",rowcnt);
+		do_error();
+	}
+	for(n=0;n<cnt;n+=rowcnt) {
+		for(m=0;m<rowcnt;m++) {
+			if(!sloom && !sloombatch) {
+				if(n!=0 && m==0)
+					fprintf(fp[1],"\n");
+				if(n+m < cnt)
+					fprintf(fp[1],"%.5lf ",number[n+m]);
+				else
+					OK = 0;
+			} else {
+				if(n!=0 && m==0) {
+					fprintf(stdout,"INFO: %s\n",errstr);
+					errstr[0] = ENDOFSTR;
+				}
+				if(n+m < cnt) {
+					sprintf(temp,"%.5lf ",number[n+m]);
+					strcat(errstr,temp);
+				} else
+					OK = 0;
+			}
+		}
+		if(!OK)
+			break;
+	}
+	if(!sloom && !sloombatch)
+		fprintf(fp[1],"\n");
+	else
+		fprintf(stdout,"INFO: %s\n",errstr);
+	fflush(stdout);
+}
+
+
+/****************************** COLUMN_FORMAT_VALS ****************************/
+
+void column_format_vals(void)
+{	int n, m;
+
+	double d = (double)cnt/(double)ifactor;
+	int rowcnt = cnt/ifactor;
+	char temp[64];
+	errstr[0] = ENDOFSTR;
+	if(d > (double)rowcnt)
+		rowcnt++;
+	for(n=0;n<rowcnt;n++) {
+		for(m=n;m<cnt;m+=rowcnt) {
+			if(!sloom && !sloombatch)
+				fprintf(fp[1],"%.5lf ",number[m]);
+			else {
+				sprintf(temp,"%.5lf ",number[m]);
+				strcat(errstr,temp);
+			}
+		}
+		if(!sloom && !sloombatch)
+			fprintf(fp[1],"\n");
+		else {
+			fprintf(stdout,"INFO: %s\n",errstr);
+			errstr[0] = ENDOFSTR;
+		}
+	}
+	fflush(stdout);
+}
+
+
+/************************ INTERVAL_LIMIT() ********************/
+
+void interval_limit(void)
+{
+	double interval, sum = number[0];
+	int n;
+	do_valout(sum);
+	for(n=1;n<cnt;n++) {
+		interval=number[n]-number[n-1];
+		switch(ro) {
+		case('l'): interval = max(interval,factor);	break;
+		case('L'): interval = min(interval,factor);	break;
+		}
+		sum += interval;
+		do_valout(sum);
+	}
+	fflush(stdout);	
+}
+
+/********************************** TIME_DENSITY ******************************/
+
+void time_density(void)
+{
+	int n, m = 0, k, ended = 0;
+	double min_endtime, *endtime = (double *)exmalloc(ifactor * sizeof(double));
+	for(n=0;n<ifactor;n++)
+		endtime[n] = 0.0;
+	min_endtime = 0.0;
+	for(;;) {
+		for(n=0;n<ifactor;n++) {
+			if(flteq(endtime[n],min_endtime)) {
+				do_valout(endtime[n]);
+				endtime[n] += number[m];
+				if(++m >= cnt) {
+					ended = 1;
+					break;
+				}
+				min_endtime = endtime[n];
+				for(k=0;k<ifactor;k++) {
+					if(endtime[k] < min_endtime)
+						min_endtime = endtime[k];
+				}
+			}
+		}
+		if(ended)
+			break;
+	}
+	fflush(stdout);
+}
+
+/********************************** DIVIDE_LIST ******************************/
+
+void divide_list(void)
+{
+	int n;
+	for(n=0;n<cnt;n++) {
+		switch(condit) {
+		case(0):
+			number[n] /= factor;
+			break;
+		case('>'):
+			if(number[n]>thresh)
+				number[n] /= factor;
+			break;
+		case('<'):
+			if(number[n]<thresh)
+				number[n] /= factor;
+			break;
+		}
+		do_valout(number[n]);
+	}
+	fflush(stdout);
+}
+
+/********************************** GROUP ******************************/
+
+void group(void)
+{
+	int n, m = 0;
+	while(m < ifactor) {
+		for(n=m;n<stringscnt;n+=ifactor) {
+			do_stringout(strings[n]);
+		}
+		if(!sloom && !sloombatch)
+			fprintf(fp[1],"\n");
+		m++;
+	}
+	fflush(stdout);
+}
+
+/********************************** DUPLICATE_OCTAVES ******************************/
+
+void duplicate_octaves(void)
+{
+	int n, m;
+	double d;
+	for(n=0;n<cnt;n++)
+		do_valout(number[n]);
+	for(m=1;m<=ifactor;m++) {
+		d = 12.0 * m;
+		for(n=0;n<cnt;n++)
+			do_valout(number[n] + d);
+	}
+	fflush(stdout);
+}
+
+/********************************** DUPLICATE_OCTFRQ ******************************/
+
+void duplicate_octfrq(void)
+{
+	int n, m;
+	double d;
+	for(n=0;n<cnt;n++)
+		do_valout(number[n]);
+	for(m=1;m<=ifactor;m++) {
+		d = pow(2.0,(double)m);
+		for(n=0;n<cnt;n++)
+			do_valout(number[n] * d);
+	}
+	fflush(stdout);
+}
+
+/********************************** INTERVAL_TO_RATIO ******************************/
+
+void interval_to_ratio(int semitones,int tstretch) 
+{
+	int n;
+	double bum = 0.0;
+	for(n=0;n<cnt;n++) {
+		if(semitones) {
+			bum = number[n];
+			number[n] /= 12.0;
+		}
+	 	if(fabs(number[n]) > MAXOCTTRANS) {
+			if(!semitones)
+				bum = number[n];
+			sprintf(errstr,"Item %d (%lf) is too large or small to convert.\n",n+1,bum);
+			do_error();
+		}
+	}
+	for(n=0;n<cnt;n++) {
+		number[n] = pow(2.0,number[n]);
+		if(tstretch)
+			number[n] = 1.0/number[n];
+		do_valout(number[n]);
+	}
+	fflush(stdout);
+}
+
+/********************************** RATIO_TO_INTERVAL ******************************/
+
+void ratio_to_interval(int semitones,int tstretch) 
+{
+	int n;
+	for(n=0;n<cnt;n++) {
+		if(number[n] < FLTERR) {
+			fprintf(stdout,"ERROR: ratio %d (%lf) is too small or an impossible (negative) value.\n",n+1,number[n]);
+			fflush(stdout);
+			exit(1);
+		}
+		if(tstretch)
+			number[n] = 1.0/number[n];
+	}
+	for(n=0;n<cnt;n++) {
+		number[n] = log(number[n]) * ONE_OVER_LN2;
+		if(semitones)
+			number[n] *= 12.0;
+		fprintf(stdout,"INFO: %lf\n",number[n]);
+	}
+	fflush(stdout);
+}
+
+/********************************** DO_SLOPE ******************************/
+
+void do_slope(void) 
+{
+	int n;
+	double ddiff;
+	do_valout(number[0]);
+	for(n=1;n<cnt;n++) {
+		ddiff = number[n] - number[0];
+		ddiff *= factor;
+		number[n] = number[0] + ddiff;
+		do_valout(number[n]);
+	}
+	fflush(stdout);
+}
+
+
+/********************************** ALPHABETIC_SORT ******************************/
+
+void alphabetic_sort(void)
+{
+	int n,m;
+	char tempp[200],*p;
+	for(n=1;n<stringscnt;n++)  {
+		p =  strings[n];
+		strcpy(tempp,strings[n]);
+		m = n-1;
+		while(m >= 0 && alphabetical_order(tempp,strings[m])) {
+			strings[m+1] = strings[m];
+			m--; 
+		}
+		strings[m+1] = p;
+	}
+	for(n=0;n<stringscnt;n++)
+		do_stringout(strings[n]);	 
+	fflush(stdout);
+}
+
+/******************************* ALPHABETICAL_ORDER **************************/
+
+#define UPPERCASE(x)  ((x) >= 'A' && (x) < 'Z')
+
+
+int alphabetical_order(char *str1,char *str2)
+{
+	char p, q;
+	int n,m;
+	int j = strlen(str1);
+	int k = strlen(str2);
+	m = min(j,k);
+	for(n=0;n<m;n++) {
+		p = str1[n];
+		q = str2[n];
+		if(UPPERCASE(p))	  p += 32;
+		if(UPPERCASE(q))	  q += 32;
+		if(p > q)  	return(0);
+		if(p < q)  	return(1);
+	}
+	if(k<j)
+		return(0);
+	return(1);
+}
+
+/********************************** LEVEL_TO_DB ******************************/
+
+void level_to_db(int sampleval) 
+{
+	int n;	
+	for(n=0;n<cnt;n++) {
+		if(sampleval)
+			number[n] /= (double)MAXSAMP;
+		number[n] = leveltodb(number[n],n);
+		sprintf(errstr,"%lfdB\n",number[n]);
+		do_stringout(errstr);
+	}
+	fflush(stdout);
+}
+
+/********************************** DB_TO_LEVEL ******************************/
+
+void db_to_level(int sampleval) 
+{
+	int n;
+	for(n=0;n<cnt;n++) {
+		number[n] = dbtolevel(number[n]);
+		if(sampleval)
+			number[n] *= (double)MAXSAMP;
+		do_valout(number[n]);
+	}
+	fflush(stdout);
+}
+
+/******************************** LEVELTODB ***********************/
+
+double leveltodb(double val,int n)
+{
+	
+	if(val <= 0.0) {
+		sprintf(errstr,"Gain value %d <= 0.0: Cannot proceed\n",n+1);
+		do_error();
+	}
+	val = log10(val);
+	val *= 20.0;
+	return(val);
+}	
+	
+/******************************** DBTOLEVEL ***********************/
+
+double dbtolevel(double val)
+{
+	int isneg = 0;
+	if(flteq(val,0.0))
+		return(1.0);
+	if(val < 0.0) {
+		val = -val;
+		isneg = 1;
+	}
+	val /= 20.0;
+	val = pow(10.0,val);
+	if(isneg)
+		val = 1.0/val;
+	return(val);
+}	
+
+/******************************** COLUMNATE ***********************/
+
+void columnate(void)
+{
+	int n;
+	for(n=0;n<cnt;n++)
+		do_valout(number[n]);
+	fflush(stdout);
+}
+
+/******************************** SAMP_TO_TIME ***********************/
+
+void samp_to_time(void)
+{
+	int n;
+	double inv_sr = 1.0/(double)ifactor;
+	for(n=0;n<cnt;n++)
+		do_valout(number[n] * inv_sr);
+	fflush(stdout);
+}
+
+/******************************** TIME_TO_SAMP ***********************/
+
+void time_to_samp(void)
+{
+	int n;
+	for(n=0;n<cnt;n++) {
+		do_valout(number[n] * (double)ifactor);
+	}
+	fflush(stdout);
+}
+
+/******************************** DELETE_SMALL_INTERVALS ***********************/
+
+void delete_small_intervals(void)
+{
+	int n, m;
+	int start = 1, end = 1, shrink;
+	double diff;
+	for(n=1;n<cnt;n++) {
+		if((diff = number[n] - number[n-1]) < 0) {
+			fprintf(stdout,"WARNING: Numbers must be in ascending order for this option.\n");
+			fflush(stdout);
+			exit(1);
+		}
+		if(diff <= factor)
+			end++;
+		else {
+			if((shrink = (end - start))) {
+				for(m = n-1;m < cnt; m++)
+					number[m-shrink] = number[m];
+				end = start;
+				cnt -= shrink;
+				n -= shrink;
+			}
+			start++;
+			end++;
+		}
+	}
+	for(n=0;n<cnt;n++)
+		do_valout(number[n]);
+	fflush(stdout);
+}
+
+/******************************** MARK_EVENT_GROUPS ***********************/
+
+void mark_event_groups(void)
+{
+	int n, m;
+	int start = 1, end = 1, shrink;
+	int orig_cnt = cnt;
+	double diff;
+	for(n=1;n<cnt;n++) {
+		if((diff = number[n] - number[n-1]) < 0) {
+			fprintf(stdout,"WARNING: Numbers must be in ascending order for this option.\n");
+			fflush(stdout);
+			exit(1);
+		}
+		if(diff <= factor) {
+			end++;
+		} else {
+			shrink = end - start;
+			switch(shrink) {
+			case(1):		  	/* 2 in group, preserve */
+				start++;
+				break;
+			case(0):			/* 1 isolated point, duplicate */
+				cnt++;
+				if(cnt > orig_cnt) {
+					if((number = (double *)realloc((char *)number,cnt * sizeof(double)))==NULL) {
+						fprintf(stdout,"WARNING: Out of memory for storing numbers.\n");
+						fflush(stdout);
+						exit(1);
+					}
+					orig_cnt = cnt;
+				}
+				for(m = cnt-1; m >= n; m--)
+					number[m] = number[m-1];
+				n++;
+				start++;
+				end++;
+				break;
+			default:			/* >2 in group, bracket */
+				shrink--;
+				for(m = n-1;m < cnt; m++)
+					number[m-shrink] = number[m];
+				end = start;
+				cnt -= shrink;
+				n -= shrink;
+				break;
+			}
+			start++;
+			end++;
+		}
+	}
+	shrink = end - start;
+	switch(shrink) {
+	case(0):
+		cnt++;
+		if(cnt > orig_cnt) {
+			if((number = (double *)realloc((char *)number,cnt * sizeof(double)))==NULL) {
+				fprintf(stdout,"WARNING: Out of memory for storing numbers.\n");
+				fflush(stdout);
+				exit(1);
+			}
+		}
+		for(m = cnt-1; m >= n; m--)
+			number[m] = number[m-1];
+		break;
+	case(1):
+		break;
+	default: 
+		shrink--;
+		for(m = n-1;m < cnt; m++)
+			number[m-shrink] = number[m];
+		cnt -= shrink;
+		break;
+	}
+	for(n=0;n<cnt;n++)
+		do_valout(number[n]);
+	fflush(stdout);
+}
+
+/******************************** SPANPAIR ***********************
+ *
+ * span pairs of values.
+ */
+
+void spanpair(void)
+{
+	int n, m, is_even = 1;
+	int cnt2 = cnt * 2;
+	if(cnt & 1) {
+		fprintf(stdout,"WARNING: This process only works on an even number of values.\n");
+		fflush(stdout);
+		exit(1);
+	}
+	if((number = (double *)realloc((char *)number,cnt2 * sizeof(double)))==NULL) {
+		fprintf(stdout,"WARNING: Out of memory for storing numbers.\n");
+		fflush(stdout);
+		exit(1);
+	}
+	m = cnt2-1; 
+	for(n=cnt-1;n>=0;n--) {
+		if(number[n] < 0.0) {
+			fprintf(stdout,"WARNING: No negative numbers allowed in this option.\n");
+			fflush(stdout);
+			exit(1);
+		}
+		if(is_even) {
+			number[m--] = number[n] + factor + thresh;
+			number[m--] = number[n] + factor;
+		} else {
+			number[m--] = number[n];
+			number[m--] = max(number[n] - thresh, 0.0);
+		}
+		is_even = !is_even;
+	}
+	for(n=0;n<cnt2;n++)
+		do_valout(number[n]);
+	fflush(stdout);
+}
+
+/******************************** SPAN ***********************
+ *
+ * span single values with a pair.
+ */
+
+void span(void)
+{
+	int n, m;
+	int cnt2 = cnt * 4;
+	if((number = (double *)realloc((char *)number,cnt2 * sizeof(double)))==NULL) {
+		fprintf(stdout,"WARNING: Out of memory for storing numbers.\n");
+		fflush(stdout);
+		exit(1);
+	}
+	m = cnt2-1; 
+	for(n=cnt-1;n>=0;n--) {
+		if(number[n] < 0.0) {
+			fprintf(stdout,"WARNING: No negative numbers allowed in this option.\n");
+			fflush(stdout);
+			exit(1);
+		}
+		number[m--] = number[n] + factor + thresh;
+		number[m--] = number[n] + factor;
+		number[m--] = number[n];
+		number[m--] = max(number[n] - thresh, 0.0);
+	}
+	for(n=0;n<cnt2;n++)
+		do_valout(number[n]);
+	fflush(stdout);
+}
+
+/******************************** SPAN_XALL ***********************
+ *
+ * span single values.
+ */
+
+void span_xall(void)
+{
+	int n, m;
+	int cnt2 = cnt * 3;
+	if((number = (double *)realloc((char *)number,cnt2 * sizeof(double)))==NULL) {
+		fprintf(stdout,"WARNING: Out of memory for storing numbers.\n");
+		fflush(stdout);
+		exit(1);
+	}
+	m = cnt2-1; 
+	for(n=cnt-1;n>=0;n--) {
+		if(number[n] < 0.0) {
+			fprintf(stdout,"WARNING: No negative numbers allowed in this option.\n");
+			fflush(stdout);
+			exit(1);
+		}
+		number[m--] = number[n] + thresh;
+		number[m--] = number[n];
+		number[m--] = max(number[n] - thresh, 0.0);
+	}
+	for(n=0;n<cnt2;n++)
+		do_valout(number[n]);
+	fflush(stdout);
+}
+
+/******************************** ALTERNATION PATTERNS ***********************/
+
+void alt0101(void) {
+	int n;
+	for(n=0;n<cnt;n++)
+		fprintf(stdout,"INFO: %lf\n",number[n & 1]);
+	fflush(stdout);
+}
+		
+void alt0011(void) {
+	int n;
+	for(n=0;n<cnt;n++)
+		fprintf(stdout,"INFO: %lf\n",number[n & 2]);
+	fflush(stdout);
+}
+
+void alt01100(void) {
+	int n;
+	fprintf(stdout,"INFO: %lf\n",number[0]);
+	cnt--;
+	for(n=0;n<cnt;n++)
+		fprintf(stdout,"INFO: %lf\n",number[!(n & 2)]);
+	fflush(stdout);
+}
+
+void alt0r0r(void) {
+	int n;
+	double rrange = number[2] - number[1];
+	for(n=0;n<cnt;n++) {
+		if(n & 1) {
+			fprintf(stdout,"INFO: %lf\n",(drand48() * rrange) + number[1]);
+		} else {
+			fprintf(stdout,"INFO: %lf\n",number[0]);
+		}
+	}
+	fflush(stdout);
+}
+
+void altr0r0(void) {
+	int n;
+	double rrange = number[2] - number[1];
+	for(n=0;n<cnt;n++) {
+		if(n & 1) {
+			fprintf(stdout,"INFO: %lf\n",number[0]);
+		} else {
+			fprintf(stdout,"INFO: %lf\n",(drand48() * rrange) + number[1]);
+		}
+	}
+	fflush(stdout);
+}
+
+void altrr00(void) {
+	int n;
+	double rrange = number[2] - number[1];
+	for(n=0;n<cnt;n++) {
+		if(n & 2) {
+			fprintf(stdout,"INFO: %lf\n",number[0]);
+		} else {
+			fprintf(stdout,"INFO: %lf\n",(drand48() * rrange) + number[1]);
+		}
+	}
+	fflush(stdout);
+}
+
+void alt00rr(void) {
+	int n;
+	double rrange = number[2] - number[1];
+	for(n=0;n<cnt;n++) {
+		if(n & 2) {
+			fprintf(stdout,"INFO: %lf\n",(drand48() * rrange) + number[1]);
+		} else {
+			fprintf(stdout,"INFO: %lf\n",number[0]);
+		}
+	}
+	fflush(stdout);
+}
+
+void alt0rr00r(void) {
+	int n;
+	double rrange = number[2] - number[1];
+	fprintf(stdout,"INFO: %lf\n",number[0]);
+	cnt--;
+	for(n=0;n<cnt;n++) {
+		if(n & 2) {
+			fprintf(stdout,"INFO: %lf\n",number[0]);
+		} else {
+			fprintf(stdout,"INFO: %lf\n",(drand48() * rrange) + number[1]);
+		}
+	}
+	fflush(stdout);
+}
+
+void altr00rr0(void) {
+	int n;
+	double rrange = number[2] - number[1];
+	fprintf(stdout,"INFO: %lf\n",(drand48() * rrange) + number[1]);
+	cnt--;
+	for(n=0;n<cnt;n++) {
+		if(n & 2) {
+			fprintf(stdout,"INFO: %lf\n",(drand48() * rrange) + number[1]);
+		} else {
+			fprintf(stdout,"INFO: %lf\n",number[0]);
+		}
+	}
+	fflush(stdout);
+}
+
+void altRR00(void) {
+	int n;
+	double k = 0.0;
+	double rrange = number[2] - number[1];
+	for(n=0;n<cnt;n++) {
+		if(n & 2) {
+			fprintf(stdout,"INFO: %lf\n",number[0]);
+		} else {
+			if (!(n & 1)) {
+				k = (drand48() * rrange) + number[1];
+			}
+			fprintf(stdout,"INFO: %lf\n",k);
+		}
+	}
+	fflush(stdout);
+}
+
+void alt00RR(void) {
+	int n;
+	double k = 0.0;
+	double rrange = number[2] - number[1];
+	for(n=0;n<cnt;n++) {
+		if(n & 2) {
+			if (!(n & 1)) {
+				k = (drand48() * rrange) + number[1];
+			}
+			fprintf(stdout,"INFO: %lf\n",k);
+		} else {
+			fprintf(stdout,"INFO: %lf\n",number[0]);
+		}
+	}
+	fflush(stdout);
+}
+
+void alt0RR00R(void) {
+	int n;
+	double k = 0.0;
+	double rrange = number[2] - number[1];
+	fprintf(stdout,"INFO: %lf\n",number[0]);
+	cnt--;
+	for(n=0;n<cnt;n++) {
+		if(n & 2) {
+			fprintf(stdout,"INFO: %lf\n",number[0]);
+		} else {
+			if (!(n & 1)) {
+				k = (drand48() * rrange) + number[1];
+			}
+			fprintf(stdout,"INFO: %lf\n",k);
+		}
+	}
+	fflush(stdout);
+}
+
+void altR00RR0(void) {
+	int n;
+	double k = 0.0;
+	double rrange = number[2] - number[1];
+	fprintf(stdout,"INFO: %lf\n",(drand48() * rrange) + number[1]);
+	cnt--;
+	for(n=0;n<cnt;n++) {
+		if(n & 2) {
+			if (!(n & 1)) {
+				k = (drand48() * rrange) + number[1];
+			}
+			fprintf(stdout,"INFO: %lf\n",k);
+		} else {
+			fprintf(stdout,"INFO: %lf\n",number[0]);
+		}
+	}
+	fflush(stdout);
+}
+
+/******************************** CHECK FOR ASCENDING_ORDER ***********************/
+
+void ascending_order(void) {
+	int n, OK = 1;
+	for(n=1;n<cnt;n++) {
+		if(number[n] <= number[n-1]) {
+			OK = 0;
+			break;
+		}
+	}
+	if(!sloom && !sloombatch) {
+		if(OK)
+			fprintf(stdout, "sequence is in ascending order.");
+		else
+			fprintf(stdout, "sequence is NOT in ascending order at item %d (%lf)",n+1,number[n]);
+	} else {
+		if(OK)
+			fprintf(stdout, "WARNING: sequence is in ascending order.");
+		else
+			fprintf(stdout, "WARNING: sequence is NOT in ascending order at item %d (%lf)",n+1,number[n]);
+	}
+	fflush(stdout);
+}
+
+/******************************** EDIT INDIVIDUAL VALUES ***********************/
+
+void delete_vals(void) {
+	int n, m, k = (int)factor;
+	if(k < ifactor) {
+		n = ifactor;
+		ifactor = k;
+		k = n;
+	}
+	k = min(k,cnt);
+	if(k < cnt) {
+		for(n=ifactor-1,m=k;m<cnt;m++,n++)
+			number[n] = number[m];
+		cnt -= (k - ifactor + 1);
+	} else {
+		cnt = ifactor-1;
+	}
+	for(n=0;n<cnt;n++)
+		fprintf(stdout,"INFO: %lf\n",number[n]);
+	fflush(stdout);
+}
+
+void replace_val(void) {
+	int n;
+	number[ifactor-1] = factor;
+	for(n=0;n<cnt;n++)
+		fprintf(stdout,"INFO: %lf\n",number[n]);
+	fflush(stdout);
+}
+
+void insert_val(void) {			/* NB we have already malloced the extra space required */
+	int n;
+	ifactor--;
+	if(ifactor < cnt) {
+		for(n = cnt;n >= ifactor; n--)
+			number[n] = number[n-1];
+	}
+	number[ifactor] = factor;
+	cnt++;
+	for(n=0;n<cnt;n++)
+		fprintf(stdout,"INFO: %lf\n",number[n]);
+	fflush(stdout);
+}
+
+/*************************** QUANTISED_SCATTER *******************************
+ *
+ *	number[0] = quantisation;
+ *	number[1] = duration;
+ *	number[2] = scatter;
+ */
+
+void quantised_scatter(int *perm,int permlen)
+{
+	int n, m, here, k, q_per_step, q_scat, q_hscat, total_q, iscat;
+	double quantisation = number[0], dur = number[1], scat = number[2];
+	total_q = (int)floor(dur/quantisation) + 1;
+	q_per_step = (int)ceil(total_q/(cnt-1));
+	n = 0;
+	number[n++] = 0.0;
+	if(scat <= 1.0)  {
+		q_scat = (int)round(q_per_step * scat);
+		q_hscat = q_scat/2;
+		here = q_per_step;
+		while(n < cnt) {
+			k = (int)floor(drand48() * (double)q_scat) - q_hscat;
+			number[n++] = here + k;
+			here += q_per_step;
+		}
+	} else {
+		iscat = round(scat);
+		q_per_step *= iscat;
+		here = 0;
+		while(n < cnt) {
+			randperm(perm,permlen);				/* permute the next group of quantisation cells */
+			ascending_sort_cells(perm,iscat);	/* sort the first 'iscat' into ascending order */
+
+			for(m=0;m<iscat;m++)
+				perm[m]++;						/*	change range to range 1 to N, rather than 0 to N-1 */
+			for(m=0;m<iscat;m++) {				/* position items above base-cellcnt */
+				number[n] = here + perm[m];
+				if(++n >= cnt)
+					break;	
+			}
+			here += q_per_step;
+		}
+		free(perm);
+	}
+	for(n=0;n<cnt;n++)
+		number[n] *= quantisation;
+	print_numbers();
+}
+
+/*************************** RANDPERM *******************************
+ *
+ * Produce a random permutation of k integers.
+ */
+
+void randperm(int *perm,int permlen)
+{
+	int n, t;
+	for(n=0;n<permlen;n++) {
+		t = (int)floor(drand48() * (n+1));
+		if(t==n) {
+			hprefix(n,perm,permlen);
+		} else {
+			hinsert(n,t,perm,permlen);
+		}
+	}
+}
+
+void hinsert(int m,int t,int *perm,int permlen)
+{
+	hshuflup(t+1,perm,permlen);
+	perm[t+1] = m;
+}
+
+void hprefix(int m,int *perm,int permlen)
+{
+	hshuflup(0,perm,permlen);
+	perm[0] = m;
+}
+
+void hshuflup(int k,int *perm,int permlen)
+{
+	int n, *i;
+	int z = permlen - 1;
+	i = perm+z;
+	for(n = z;n > k;n--) {
+		*i = *(i-1);
+		i--;
+	}
+}
+
+void ascending_sort_cells(int *perm,int ccnt)
+{
+	int n, m, sct;
+	for(n=0;n<(ccnt-1);n++) {
+		for(m=n+1;m<ccnt;m++) {
+			if(*(perm+m) < *(perm+n)) {
+				sct 	  = *(perm+m);
+				*(perm+m) = *(perm+n);
+				*(perm+n) = sct;
+			}
+		}
+	}
+}
+
+/************* REPLACING VALUES EQUAL TO > OR < A GIVEN VAL ****************/
+
+void replace_equal(void) {
+	int n;
+	double maxe = number[cnt] + FLTERR;
+	double mine = number[cnt] - FLTERR;
+	double replace = number[cnt+1];
+	for(n=0;n<cnt;n++) {
+		if((number[n] < maxe) && (number[n] > mine))
+			number[n] = replace;
+		fprintf(stdout,"INFO: %lf\n",number[n]);
+	}
+	fflush(stdout);
+}
+		
+void replace_less(void) {
+	int n;
+	double mine = number[cnt];
+	double replace = number[cnt+1];
+	for(n=0;n<cnt;n++) {
+		if(number[n] < mine)
+			number[n] = replace;
+		fprintf(stdout,"INFO: %lf\n",number[n]);
+	}
+	fflush(stdout);
+}
+		
+void replace_greater(void) {
+	int n;
+	double maxe = number[cnt];
+	double replace = number[cnt+1];
+	for(n=0;n<cnt;n++) {
+		if(number[n] > maxe)
+			number[n] = replace;
+		fprintf(stdout,"INFO: %lf\n",number[n]);
+	}
+	fflush(stdout);
+}
+
+/*************************** GAPPED QUANTISED GRIDS *************************/
+
+void grid(int is_outside)
+{
+	int n, k, tot;
+	double quant = number[cnt], sum, dogrid = 0;
+	if(quant <= .001) {
+		fprintf(stdout,"ERROR: Quantisation step too small.\n");
+		fflush(stdout);
+		return;
+	} else if((tot = (int)ceil(number[cnt-1]/quant)) > 10000) {
+		fprintf(stdout,"ERROR: Quantisation too small, relative to total duration.\n");
+		fflush(stdout);
+		return;
+	} else if(tot < 2) {
+		fprintf(stdout,"ERROR: Quantisation too large, relative to total duration.\n");
+		fflush(stdout);
+		return;
+	}
+	if((permm = (double *)malloc(tot * sizeof(double))) == NULL) {
+		fprintf(stdout,"ERROR: Out of memory.\n");
+		fflush(stdout);
+		return;
+	}
+	if(is_outside)
+		dogrid = 1;	
+	n = 0;
+	k = 0;
+	sum = 0.0;
+	while(n < cnt) {
+		if(dogrid) {
+			while(sum < number[n]) {
+				permm[k++] = sum;
+				sum += quant;
+			}
+		} else {		
+			while(sum < number[n])
+				sum += quant;
+		}
+		dogrid = !dogrid;
+		n++;
+	}
+ 	for(n=0;n<k;n++)
+		fprintf(stdout,"INFO: %lf\n",permm[n]);
+	fflush(stdout);
+}
+
+/****** DELETE N VALS AT RANDOM : NOT MORE THAN M ADJACENT VALS DELETED : NOT MORE THAN K ADJACENT VALS UNDELETED ******/
+
+void randdel_not_adjacent(void)
+{
+	int adj, gap, sum, i, j, k, n, z;
+	int delitems, keptitems, keepset_cnt, delset_cnt;
+	int *vacuum, *box, *boxcnt, *box_assocd_with_cntr_no, *cntr_assocd_with_box_no;
+	int remainder, unfilled_boxes, inverted = 0;
+	delitems = round(number[cnt]);	/* number of items to delete */
+	adj	= round(number[cnt+1]);		/* max no of adjacent items to delete */
+	gap	= round(number[cnt+2]);		/* max no of adjacent non-deleted items */
+
+	if(delitems >= cnt) {
+		fprintf(stdout,"ERROR: This will delete the whole column.");
+		fflush(stdout);
+		return;
+	}
+	if(delitems < 1) {
+		fprintf(stdout,"ERROR: Must delete 1 or more items.");
+		fflush(stdout);
+		return;
+	}
+
+
+	if(delitems > cnt/2) {
+		/* Invert the algorithm */
+		inverted = 1;
+		keptitems = delitems;
+		delitems = cnt - keptitems;
+		k = adj;
+		adj = gap;
+		gap = k;
+	} else {
+		keptitems = cnt - delitems;
+	}	
+	if((vacuum = (int *)malloc(delitems * sizeof(int)))==NULL) {
+		fprintf(stdout,"ERROR: Out of memory.\n");
+		fflush(stdout);
+		return;
+	}
+	delset_cnt = 0;
+	sum = 0;
+	while(sum < delitems-1) {				/* generating deletable groups of random sizes */
+		k = (int)floor(drand48()*adj) + 1;	/* within range set by 'adj' */
+		if((sum+k) > delitems-1)			/* once enough items deleted, break */			
+			break;
+		else {
+			vacuum[delset_cnt++] = k;		/* otherwise store the size of deletable group */
+			sum += k;
+		}
+	}
+	if(sum < delitems)						/* fix the size of final deletable group, to make deleted total correct */
+		vacuum[delset_cnt++] = delitems - sum;
+
+	if((vacuum = (int *)realloc((char *)vacuum,delset_cnt * sizeof(int)))==NULL) {
+		fprintf(stdout,"ERROR: Memory reallocation error.\n");
+		fflush(stdout);
+		return;
+	}
+
+	if(delset_cnt > keptitems) {			/* must be as many kept items as deleted groups, to separate those groups */
+		fprintf(stdout,"ERROR: Not enough undeleted items remaining to complete the task.\n");
+		fflush(stdout);
+		return;
+	} else if(delset_cnt == keptitems) { 	/* exactly as many keptitems as deleted groups, they must alternate */
+		j = 0;
+		n = 0;
+		i = (int)floor(drand48() * 2.0);	/* select at random whether to start with deletes or not */
+		if(inverted) {
+			if(i) {								/* and either ... */
+				while(j < delset_cnt) {
+					for(k=0;k<vacuum[j];k++) {	/* print x items */
+						fprintf(stdout,"INFO: %lf\n",number[n]);
+						if(++n > cnt) {
+							fprintf(stdout,"ERROR: Program anomaly in counting data. 6\n");
+							break;
+						}
+					}							/* then skip 1 */
+					if(++n > cnt) {
+						fprintf(stdout,"ERROR: Program anomaly in counting data. 7\n");
+						break;
+					}
+					j++;
+				}
+				fflush(stdout);			
+				return;
+			} else {							/* or .... */
+				while(j < delset_cnt) {			/* skip 1 */
+					if(++n > cnt) {
+						fprintf(stdout,"ERROR: Program anomaly in counting data. 8\n");
+						break;
+					}
+					for(k=0;k<vacuum[j];k++) {	/* then print x items */
+						fprintf(stdout,"INFO: %lf\n",number[n]);	
+						if(++n > cnt) {
+							fprintf(stdout,"ERROR: Program anomaly in counting data. 9\n");
+							break;
+						}
+					}
+					j++;
+				}
+				fflush(stdout);
+				return;
+			}
+		} else {
+			if(i) {								/* and either ... */
+				while(j < delset_cnt) {
+					for(k=0;k<vacuum[j];k++) {	/* skip x items */
+						if(++n > cnt) {
+							fprintf(stdout,"ERROR: Program anomaly in counting data. 10\n");
+							break;
+						}
+					}							/* then print 1 */
+					fprintf(stdout,"INFO: %lf\n",number[n]);
+					if(++n > cnt) {
+						fprintf(stdout,"ERROR: Program anomaly in counting data. 11\n");
+						break;
+					}
+					j++;
+				}
+				fflush(stdout);			
+				return;
+			} else {							/* or .... */
+				while(j < delset_cnt) {			/* print 1 */
+					fprintf(stdout,"INFO: %lf\n",number[n]);	
+					if(++n > cnt) {
+						fprintf(stdout,"ERROR: Program anomaly in counting data. 12\n");
+						break;
+					}
+					for(k=0;k<vacuum[j];k++) {	/* then skip x items */
+						if(++n > cnt) {
+							fprintf(stdout,"ERROR: Program anomaly in counting data. 13\n");
+							break;
+						}
+					}
+					j++;
+				}
+				fflush(stdout);
+				return;
+			}
+		}
+	}
+	keepset_cnt = delset_cnt+1;				/* otherwise, let there be 1 more sets of kept items then of deleted items */
+											/* This is an aesthetic, choice.. there could be an equal number */
+	if(( k = (int)ceil((double)keptitems/(double)keepset_cnt)) > gap) {
+		gap = k + 1;						/* if min-size of largest kept group is > gap, can't use gap value */
+		fprintf(stdout,"ERROR: Intergap distance incompatible with other demands. Adjusting to %d.\n",gap);
+		fflush(stdout);
+	}		
+	if(((box	 = (int *)malloc(keepset_cnt * sizeof(int)))==NULL)
+	|| ((boxcnt	 = (int *)malloc(keepset_cnt * sizeof(int)))==NULL)
+	|| ((box_assocd_with_cntr_no = (int *)malloc(keepset_cnt * sizeof(int)))==NULL)
+	|| ((cntr_assocd_with_box_no = (int *)malloc(keepset_cnt * sizeof(int)))==NULL)) {
+		fprintf(stdout,"ERROR: Out of memory.\n");
+		fflush(stdout);
+		return;
+	}											
+	for(n=0;n<keepset_cnt;n++) {					/* regard each set of kept items as a box */
+		box_assocd_with_cntr_no[n] = n;				/* link each ball-counter to each box */
+		cntr_assocd_with_box_no[n] = n;				/* link each box to each ball-counter */
+			box[n] = 1;								/* Put 1 ball in each box: every kept set must have at least 1 item */
+		boxcnt[n] = 0;								/* preset the boxcnts to zero */
+	}
+	if((remainder = keptitems - keepset_cnt) > 0) {	/* if any leftover balls */
+		unfilled_boxes = keepset_cnt;				/* set number of unfilled boxes */
+		for(n=0;n<remainder;n++) {					/* for all remaining balls */
+			z = (int)floor(drand48() * unfilled_boxes);		
+			box[z]++;								/* distribute each ball to a random box */
+
+			if(box[z] >= gap) {									/* if the box getting the ball is now full */
+				boxcnt[cntr_assocd_with_box_no[z]] = box[z];	/* store the count of balls in the box */
+				unfilled_boxes--;								/* reduce number of boxes to put random balls into */
+				while(z < unfilled_boxes) {					
+					box[z] = box[z+1];					/* eliminate full box, by shuffling boxes above downwards */
+					k = cntr_assocd_with_box_no[z+1];	/* get the boxcnter associated with the next box */
+					box_assocd_with_cntr_no[k]--;		/* force it to point to next lower box (as boxes have moved down 1) */
+					j = box_assocd_with_cntr_no[k];		/* get the box it now points to */
+					cntr_assocd_with_box_no[j] = k;		/* get that to point back to the box counter */ 			
+					z++;
+				}
+			}
+		}
+	}
+	for(n=0;n<keepset_cnt;n++) {						/* save counts of balls in remaining boxes */
+		if(boxcnt[n] <= 0)
+			boxcnt[n] = box[box_assocd_with_cntr_no[n]];
+	}	
+	j = 0;
+	n = 0;
+	if(inverted) {
+		while(j < delset_cnt) {
+			for(k=0;k<boxcnt[j];k++) {						/* skip x items */
+				if(++n > cnt) {
+					fprintf(stdout,"ERROR: Program anomaly in counting data 4.\n");
+					return;
+				}
+			}
+			for(k=0;k<vacuum[j];k++) {						/* print y items */
+				fprintf(stdout,"INFO: %lf\n",number[n]);
+				if(++n > cnt) {
+					fprintf(stdout,"ERROR: Program anomaly in counting data 5.\n");
+					return;
+				}
+			}	   /* Note, all inverted patterns start and end with OFF events - an aesthetic decision */
+			j++;
+		}
+	} else {
+		while(j < delset_cnt) {
+			for(k=0;k<boxcnt[j];k++) {				   		/* print x items */
+				fprintf(stdout,"INFO: %lf\n",number[n]);
+				if(++n > cnt) {
+					fprintf(stdout,"ERROR: Program anomaly in counting data 1.\n");
+					return;
+				}
+			}
+			for(k=0;k<vacuum[j];k++) {						/* skip y items */
+				if(++n > cnt) {
+					fprintf(stdout,"ERROR: Program anomaly in counting data 2.\n");
+					return;
+				}
+			}
+			j++;
+		}
+		for(k=0;k<boxcnt[j];k++) {				   			/* print last x items */
+			fprintf(stdout,"INFO: %lf\n",number[n]);
+			if(++n > cnt) {
+				fprintf(stdout,"ERROR: Program anomaly in counting data 3.\n");
+				break;										
+			}			/* Note, all patterns start and end with ON events - an aesthetic decision */
+		}	 		
+	}
+	fflush(stdout);					
+}
+
+/****************************** REPLACE_WITH_RAND ******************************/
+
+void replace_with_rand(int type) {
+
+	int n;
+	double lim = number[cnt], randlo = number[cnt+1], randhi = number[cnt+2];
+	double k, randrang, limhi, limlo;
+
+	if(randhi < randlo) {
+		k 	   = randhi;
+		randhi = randlo;
+		randlo = k;
+	}
+	randrang = randhi - randlo;
+	switch(type) {
+	case(0):			/* equal */
+		limhi = lim + FLTERR;
+		limlo = lim - FLTERR;
+		for(n=0;n<cnt;n++) {
+			if((number[n] < limhi) && (number[n] > limlo))
+				number[n] = (drand48() * randrang) + randlo;
+			fprintf(stdout,"INFO: %lf\n",number[n]);
+		}
+		break;
+	case(-1):			/* less */
+		for(n=0;n<cnt;n++) {
+			if(number[n] < lim)
+				number[n] = (drand48() * randrang) + randlo;
+			fprintf(stdout,"INFO: %lf\n",number[n]);
+		}
+		break;
+	case(1):			/* greater */
+		for(n=0;n<cnt;n++) {
+			if(number[n] > lim)
+				number[n] = (drand48() * randrang) + randlo;
+			fprintf(stdout,"INFO: %lf\n",number[n]);
+		}
+		break;
+	}
+	fflush(stdout);
+}
+
+/****************************** RANDQUANTA_IN_GAPS ******************************/
+
+void randquanta_in_gaps(void)
+{
+	int totcnt = round(number[cnt]);			  						/* number of vals to make */
+	double q = number[cnt+1];											/* quantisation of grid */
+	int mincnt = round(number[cnt+2]), maxcnt = round(number[cnt+3]);	/* min & max no of events in each time-interval */
+	int k,j,n,m, posibmax = 0, maxqpnts = 0, tot_boxes,minpos,maxpos,remainder,unfilled_boxes;
+	int boxpos, orig_boxpos;
+	int *perm,*box,*boxcnt,*qpnts,*box_assocd_with_cntr_no,*cntr_assocd_with_box_no;
+	double mintim,maxtim;
+	double *qbas;
+		
+	if(maxcnt < mincnt) {	/* orient cnt-range */
+		n = maxcnt;
+		maxcnt = mincnt;
+		mincnt = n;
+	}
+	if(mincnt < 1) {
+		fprintf(stdout,"ERROR: Invalid count of number of items (%d)\n",mincnt);
+		fflush(stdout);
+		exit(1);
+	}
+	if(cnt & 1)				/* Force even number of pairs */
+		cnt--;
+
+	if((tot_boxes = cnt/2) < 1) {
+		fprintf(stdout,"Too few value pairs in input column.\n");
+		fflush(stdout);
+		exit(1);
+	}
+	if(totcnt < tot_boxes * mincnt) {
+		fprintf(stdout,"Insufficient items to distribute amongst the %d pairs.\n",tot_boxes);
+		fflush(stdout);
+		exit(1);
+	}
+	if(((box 	= (int *)malloc(tot_boxes * sizeof(int)))==NULL) 		/* 'boxes' store random placed 'balls' */
+	|| ((boxcnt	= (int *)malloc(tot_boxes * sizeof(int)))==NULL) 		/* counts of balls in 'boxes' */
+	|| ((qpnts 	= (int *)malloc(tot_boxes * sizeof(int)))==NULL)		/* no. of q-points in each time-interval */
+																		/* = maximum number of balls for each box */
+	|| ((qbas 	= (double *)malloc(tot_boxes * sizeof(double)))==NULL)	/* first q-point time in each time-interval */
+	|| ((box_assocd_with_cntr_no = (int *)malloc(tot_boxes * sizeof(int)))==NULL)
+	|| ((cntr_assocd_with_box_no = (int *)malloc(tot_boxes * sizeof(int)))==NULL)) {
+		fprintf(stdout,"Out of memory.\n");								/* because boxes are 'deleted' & shuffled down */
+		fflush(stdout);
+		exit(1);
+	}
+	for(n=0, m =0; n < cnt; n += 2,m++) {
+		mintim = number[n];
+		maxtim = number[n+1];
+
+		minpos = (int)floor(mintim/q);
+		if(((double)minpos * q) < mintim)
+			minpos++;
+		maxpos = (int)floor(maxtim/q);
+
+		qpnts[m] = maxpos - minpos + 1;
+		if(qpnts[m] < mincnt) {
+			fprintf(stdout,"ERROR: timegap between %lf and %lf will not take  %d items\n",number[n],number[n+1],mincnt);
+			fflush(stdout);
+			exit(1);
+		}
+		if(m == 0)	maxqpnts = qpnts[0];
+		else		maxqpnts = max(maxqpnts,qpnts[m]);
+	
+		qbas[m]  = minpos * q;
+		posibmax += min(qpnts[m],maxcnt);
+	}
+	if(posibmax < totcnt) {
+		fprintf(stdout, "ERROR: total count of items exceeds available spaces.\n");
+		fflush(stdout);
+		exit(1);
+	}
+
+	if((perm = (int *)malloc(maxqpnts * sizeof(int)))==NULL) {
+		fprintf(stdout,"Out of memory.\n");
+		fflush(stdout);
+		exit(1);
+	}
+	remainder = totcnt;
+				
+	/* DISTRIBUTE THE REMAINING ITEMS AT RANDOM (with constraints) BETWEEN THE boxcnt BOXES */
+
+	for(n=0;n<tot_boxes;n++) {							/* regard each set of kept items as a box */
+		box_assocd_with_cntr_no[n] = n;					/* link each ball-counter to each box */
+		cntr_assocd_with_box_no[n] = n;					/* link each box to each ball-counter */
+		box[n] = mincnt;								/* Put min no of balls in each box */
+		remainder -= mincnt;
+		boxcnt[n] = 0;									/* preset the boxcnts to zero */
+	}
+	if(remainder > 0) {									/* if any leftover balls */
+
+							/* ELIMINATE ANY BOXES WHICH ARE ALREADY FULL */
+		unfilled_boxes = tot_boxes;						/* set number of unfilled boxes as total no of boxes */
+		boxpos = 0;
+		for(n=0,m=0;n<tot_boxes;n++) {   				/* for all boxes */
+			if(box[boxpos] >= qpnts[n]) {				/* if the box is already full */
+				boxcnt[n] = box[boxpos];				/* store the count of balls that are in the box */
+				unfilled_boxes--;						/* reduce number of boxes to put random balls into */
+				orig_boxpos = boxpos;					/* save the position of the full-box which is being eliminated */
+				while(boxpos < unfilled_boxes) {				
+					box[boxpos] = box[boxpos+1];		/* eliminate full box, by shuffling boxes above downwards */
+					k = cntr_assocd_with_box_no[boxpos+1];	/* get the boxcnter associated with the next box */
+					box_assocd_with_cntr_no[k]--;		/* force it to point to next lower box (as boxes have moved down 1) */
+					j = box_assocd_with_cntr_no[k];		/* get the box it now points to */
+					cntr_assocd_with_box_no[j] = k;		/* get that to point back to the box counter */ 			
+					boxpos++;
+				}
+				boxpos = orig_boxpos;					/* reset box position to where it was: now points to new box */
+			} else { 									
+				boxpos++;								/* if box getting ball is NOT full, go on to next box */
+			}
+		}
+									/* DISTRIBUTE REMAINING BALLS */
+		for(n=0;n<remainder;n++) {   					/* for all remaining balls */
+			boxpos = (int)floor(drand48() * unfilled_boxes);		
+			box[boxpos]++;								/* distribute each ball to a random box */
+			k = cntr_assocd_with_box_no[boxpos];
+			if(box[boxpos] >= qpnts[k]) {				/* if the box getting the ball is now full */
+				boxcnt[k] = box[boxpos];				/* store the count of balls that are in the box */
+				unfilled_boxes--;						/* reduce number of boxes to put random balls into */
+				while(boxpos < unfilled_boxes) {					
+					box[boxpos] = box[boxpos+1];		/* eliminate full box, by shuffling boxes above downwards */
+					k = cntr_assocd_with_box_no[boxpos+1];	/* get the boxcnter associated with the next box */
+					box_assocd_with_cntr_no[k]--;		/* force it to point to next lower box (as boxes have moved down 1) */
+					j = box_assocd_with_cntr_no[k];		/* get the box it now points to */
+					cntr_assocd_with_box_no[j] = k;		/* get that to point back to the box counter */ 			
+					boxpos++;
+				}
+			}
+		}
+	}
+	for(n=0;n<tot_boxes;n++) {							/* save counts of balls in remaining boxes */
+		if(boxcnt[n] <= 0)
+			boxcnt[n] = box[box_assocd_with_cntr_no[n]];
+	}	
+	/* DISTRIBUTE THE VALS AT RANDOM WITHIN THE BOXES */
+
+	for(n=0;n<tot_boxes;n++) {
+		randperm(perm,qpnts[n]);						/* permute the current group of quantisation cells */
+		ascending_sort_cells(perm,boxcnt[n]);			/* sort the first 'boxcnt' of the perm, into ascending order */
+
+		for(m=0;m<boxcnt[n];m++)						/* for each random value, multiply it by quantisation val */
+			fprintf(stdout,"INFO: %lf\n",qbas[n] + (perm[m] * q));
+	}													/* & add to to 1st quantised position in current time-interval */
+	fflush(stdout);
+}
+
+/****************************** INVERT_NORMD_ENV ******************************/
+
+void invert_normd_env(void)
+{	
+	invertenv(1.0);
+}
+
+/****************************** INVERT_AROUND_PIVOT ******************************/
+
+void invert_around_pivot(void)
+{	
+	invertenv(number[cnt] * 2.0);
+}
+
+/****************************** INVERT_OVER_RANGE ******************************/
+
+void invert_over_range(void)
+{	
+	invertenv(number[cnt] + number[cnt+1]);
+}
+
+/****************************** ENV_SUPERIMPOS ******************************/
+
+void env_superimpos(int inverse,int typ)	/* PRODUCT SHOULD INVOLVE LOGS !! */
+{
+	double *out, *no1, *no2, tdiff, tratio, vdiff, vhere;
+	int n, m, j, cnt2, skipped;
+	double thisnval, thismval, lastnval, lastmval, time = 0.0, lastval = 0.0;
+
+	if((out = (double *)malloc((cnt * 2) * sizeof(double)))==NULL) {
+		fprintf(stdout,"ERROR: Out of memory.\n");
+		fflush(stdout);
+		exit(1);
+	}
+	if(factor != 0.0) {		  			/* if inserted after time zero, move it to start time */
+		for(n=firstcnt;n<cnt;n+=2)
+			number[n] += factor;
+	}
+	if(inverse) {					/* If working with inverse of env, invert it */
+		for(n=firstcnt+1;n<cnt;n+=2)
+			number[n] = 1.0 - number[n];
+	}
+	if(number[firstcnt] < number[0]) {
+		no1  = &(number[firstcnt]);	/* If inserted env starts BEFORE orig env, 'invert' process */
+		no2  = number;
+		cnt  = cnt - firstcnt;			/* establish independent counters for each infile */
+		cnt2 = firstcnt;
+	} else {
+		no1  = number;
+		no2  = &(number[firstcnt]);
+		cnt2 = cnt - firstcnt;			/* establish independent counters for each infile */
+		cnt  = firstcnt;
+	}
+	n = 0;
+	m = 0;
+	j = 0;
+	thisnval = 0.0;
+	thismval = 0.0;
+	while(no1[n] < no2[0]) {
+		out[j++] = no1[n++];
+		thisnval = no1[n];
+		thismval = no2[1];
+		switch(typ) {
+		case(MULT):		out[j++] = no1[n++] * no2[1];	break;
+		case(ADD):		out[j++] = no1[n++] + no2[1];	break;
+		case(SUBTRACT):	out[j++] = no1[n++] - no2[1];	break;
+		case(ENVMAX):	
+			out[j++] = max(no1[n],no2[1]); 
+			n++;
+			break;
+		}
+		if(n >= cnt)
+			break;
+	}
+	while(n < cnt) {				
+		if(no1[n] == no2[m]) {		/* brkpnts coincide */
+			out[j++] = no1[n++];
+			m++;					/* new brkpnt val is product of origs */
+			lastnval = thisnval;
+			lastmval = thismval;
+			thisnval = no1[n];
+			thismval = no2[m];
+			switch(typ) {
+			case(MULT):		out[j++] = no1[n++] * no2[m++];	break;
+			case(ADD):		out[j++] = no1[n++] + no2[m++];	break;
+			case(SUBTRACT):	out[j++] = no1[n++] - no2[m++];	break;
+			case(ENVMAX):	
+				out[j++] = max(no1[n],no2[m]);
+				n++;
+				m++;
+				break;
+			}
+			if(m >= cnt2)			/* If at end of inserted env, break from loop */
+				break;
+		} else if(no1[n] > no2[m]) { 	/* inserted brkpnt falls before next orig-brkpnt */
+			while(no1[n] > no2[m]) {
+				time = no2[m];		/* take time from inserted brkpnt */
+				tdiff = no1[n] - no1[n-2];
+				tratio = (no2[m++] - no1[n-2])/tdiff;
+				n++;
+				vdiff = no1[n] - no1[n-2];
+				vhere = (vdiff * tratio) + no1[n-2];	/* value of orig brkpnt, at this time */
+				lastnval = thisnval;
+				lastmval = thismval;
+				thisnval = vhere;
+				thismval = no2[m];
+				docross(lastnval,lastmval,thisnval,thismval,time,&j,out,typ);
+				out[j++] = time;	
+				switch(typ) {
+				case(MULT):		out[j++] = vhere * no2[m++];	break;
+				case(ADD):		out[j++] = vhere + no2[m++];	break;
+				case(SUBTRACT):	out[j++] = vhere - no2[m++];	break;
+				case(ENVMAX):	
+					out[j++] = max(vhere,no2[m]);	
+					m++;
+					break;
+				}
+				n--;				/* remain at same point in orig-brkfile */
+				if(m >= cnt2)
+					break;			/* If at end of inserted env, break from loop */
+			}
+		} else {					/* orig-brkpnt falls before next inserted brkpnt */
+			while(no2[m] > no1[n]) {
+				time = no1[n];		/* take time from orig brkpnt */
+				tdiff = no2[m] - no2[m-2];
+				tratio = (no1[n++] - no2[m-2])/tdiff;
+				m++;
+				vdiff = no2[m] - no2[m-2];
+				vhere = (vdiff * tratio) + no2[m-2];	/* value of inserted brkpnt, at this time */
+				lastnval = thisnval;
+				lastmval = thismval;
+				thismval = vhere;
+				thisnval = no1[n];
+				docross(lastnval,lastmval,thisnval,thismval,time,&j,out,typ);
+				out[j++] = time;	
+				switch(typ) {
+				case(MULT):		out[j++] = vhere * no1[n++];	break;
+				case(ADD):		out[j++] = vhere + no1[n++];	break;
+				case(SUBTRACT):	out[j++] = vhere - no1[n++];	break;
+				case(ENVMAX):	
+					out[j++] = max(vhere,no1[n]);	
+					n++;
+					break;
+				}
+				m--;				/* remain at same point in inserted-brkfile */
+				if(n >= cnt) {		/* if it at end of orig file */
+					while(m < cnt2) {	  /* calc remaining inserted file points */
+						out[j++] = no2[m++];
+						switch(typ) {
+						case(MULT):		out[j++] = no2[m++] * no1[cnt-1];	break;
+						case(ADD):		out[j++] = no2[m++] + no1[cnt-1];	break;
+						case(SUBTRACT):	out[j++] = no2[m++] - no1[cnt-1];	break;
+						case(ENVMAX):	
+							out[j++] = max(no2[m],no1[cnt-1]);
+							m++;
+							break;
+						}
+					}
+					break;			/* and break from loop */
+				}
+			}
+		}
+		if(m >= cnt2)
+			break;					/* If at end of inserted env, break from outer loop */
+	}
+			/* on leaving loop either m > cnt2 or n > cnt */
+
+	while (n < cnt) {				/* if orig brkfile extends beyond inserted file */
+		out[j++] = no1[n++];		/* calculate remaining points */
+		switch(typ) {
+		case(MULT):		out[j++] = no1[n++] * no2[cnt2 - 1];	break;
+		case(ADD):		out[j++] = no1[n++] + no2[cnt2 - 1];	break;
+		case(SUBTRACT):	out[j++] = no1[n++] - no2[cnt2 - 1];	break;
+		case(ENVMAX):	
+			out[j++] = max(no1[n],no2[cnt2 - 1]);	
+			n++;
+			break;
+		}
+	}
+	while (m < cnt2) {				/* if inserted brkfile extends beyond orig file */
+		out[j++] = no2[m++];		/* calculate remaining points */
+		switch(typ) {
+		case(MULT):		out[j++] = no2[m++] * no1[cnt - 1];	break;
+		case(ADD):		out[j++] = no2[m++] + no1[cnt - 1];	break;
+		case(SUBTRACT):	out[j++] = no2[m++] - no1[cnt - 1];	break;
+		case(ENVMAX):	
+			out[j++] = max(no2[m],no1[cnt - 1]);	
+			m++;
+			break;
+		}
+	}
+	fprintf(stdout,"INFO: %lf  %lf\n",out[0],out[1]);
+	skipped = 0;
+	for(n=2;n<j-2;n += 2) {
+		if(!flteq(out[n-1],out[n+1])) {		/* elementary datareduce */
+			if(skipped)
+				fprintf(stdout,"INFO: %lf  %lf\n",time,lastval);
+			fprintf(stdout,"INFO: %lf  %lf\n",out[n],out[n+1]);
+			skipped = 0;
+		} else {
+			skipped = 1;
+			time 	= out[n];
+			lastval = out[n+1];
+		}
+	}
+	fprintf(stdout,"INFO: %lf  %lf\n",out[n],out[n+1]);
+	fflush(stdout);
+}
+
+/****************************** DOCROSS ******************************/
+
+void docross(double lastnval,double lastmval,double thisnval, double thismval,double time,int *j,double *out,int typ)
+{
+	int prehi = 0, posthi = 0;
+	double lasttime, timediff, timecross, valcross, gradn, gradm;
+	if(lastnval > lastmval)
+		prehi = 1;
+	else if(lastnval < lastmval)
+		prehi = -1;
+	if(thisnval > thismval)
+			posthi = 1;
+	else if(thisnval < thismval)
+		posthi = -1;
+	if(prehi && posthi && (prehi != posthi)) {	/* curves intersect */
+		lasttime = out[*(j)-2];
+		timediff = time - lasttime;
+		if(flteq(timediff,0.0)) {
+			fprintf(stdout,"ERROR: Came across time step too small to calculate.\n");
+			fflush(stdout);
+			exit(1);
+		}
+		gradn = (thisnval - lastnval)/timediff;
+		gradm = (thismval - lastmval)/timediff;
+		if(flteq(gradn,gradm)) {
+			fprintf(stdout,"ERROR: possible error in curve crossing algorithm.\n");
+			fflush(stdout);
+			exit(1);
+		}
+		timecross = (lastmval - lastnval)/(gradn - gradm);
+		valcross = (gradn * timecross) + lastnval;
+		out[(*j)++] = timecross + lasttime;
+		switch(typ) {
+		case(MULT):		out[(*j)++] = (valcross * valcross);	break;
+		case(ADD):		out[(*j)++] = (valcross + valcross);	break;
+		case(SUBTRACT):	out[(*j)++] = 0.0;						break;
+		case(ENVMAX):	out[(*j)++] = valcross;					break;
+		}
+	}
+}
+
+/****************************** ENV_DEL_INV ******************************/
+
+void env_del_inv(void)
+{
+	int n, m;
+	cnt += 2;
+	if((number = (double *)realloc((char *)number,cnt * sizeof(double)))==NULL) {
+		fprintf(stdout,"ERROR: Out of memory.\n");
+		fflush(stdout);
+		exit(1);
+	}
+	m = cnt - 1;
+	n = cnt - 3;
+	while(n > 0) {
+		number[m--] = 1.0 - number[n--];		/* inverse */
+		number[m--]	= number[n--] + factor; 	/* delay */
+	}
+	number[1] = number[3];						/* extend initial val.. */
+	number[0] = 0.0; 							/* ...back to zero time */
+	for(n=0;n<cnt;n+=2)
+		fprintf(stdout,"INFO: %lf  %lf\n",number[n],number[n+1]);
+	fflush(stdout);
+}
+
+/****************************** ENV_DEL_INV ******************************/
+
+void env_plateau(void)
+{
+	double plateau;
+	int n;
+	n = ifactor;
+	n--; 					/* get true line number */
+	n *= 2;					/* get brkpnt pair */
+	n++;					/* get val in brkpnt pair */
+	plateau = number[n];	/* get plateau val */
+	n -= 2;
+	number[n] = plateau;	/* put plateau val in previous val*/
+	n--;					
+	number[n] = 0.0;		/* set time here to zero */
+	while(n < cnt) {
+		fprintf(stdout,"INFO: %lf  %lf\n",number[n],number[n+1]);
+		n += 2;
+	}
+	fflush(stdout);
+}
+
+/****************************** TIME_FROM_BEAT_POSITION ******************************/
+
+void time_from_beat_position(int has_offset)
+{
+	int n;
+	double k;
+	if(factor <= FLTERR) {
+		fprintf(stdout,"ERROR: Beat duration is less than or equal to zero.\n");
+		fflush(stdout);
+		exit(1);
+	}
+	if(has_offset && !condit) {
+		fprintf(stdout,"ERROR: No time offset given.\n");
+		fflush(stdout);
+		exit(1);
+	}
+	for(n=0;n< cnt;n++) {
+		if((k = number[n] - 1.0) < 0.0) {
+			fprintf(stdout,"ERROR: Position of beat %d is less than 1. Impossible.\n",n+1);
+			fflush(stdout);
+			exit(1);
+		}
+		number[n] = k * factor;
+		if(has_offset)
+			number[n] += thresh;
+	}
+	for(n=0;n< cnt;n++)
+		fprintf(stdout,"INFO: %lf\n",number[n]);
+	fflush(stdout);
+}
+
+/****************************** INSERT_AFTER_VAL ******************************/
+
+void insert_after_val(void)
+{
+	int n, m, has_started = 0;
+	for(n=0;n<cnt;n++) {
+		if (!has_started) {
+			if(number[n] == number[cnt]) {
+				for(m=0;m <= n; m++)
+					fprintf(stdout,"INFO: %lf\n",number[m]);
+				fprintf(stdout,"INFO: %lf\n",number[cnt+1]);
+				has_started = 1;
+			}
+		} else {
+			fprintf(stdout,"INFO: %lf\n",number[n]);
+		}
+	}
+	if(!has_started) {
+		fprintf(stdout,"ERROR: Value %lf not found in the table.\n",number[cnt]);
+		fflush(stdout);
+		exit(1);
+	}
+	fflush(stdout);
+}
+
+/****************************** MIN_INTERVAL ******************************/
+
+void min_interval(int ismax) {
+	int n, pos;
+	double min_int, max_int, this_int;
+	if(cnt < 2) {
+		fprintf(stdout,"ERROR: Too few values to run this process.\n");
+		fflush(stdout);
+		exit(1);
+	}
+	pos = 1;
+	if (ismax) {
+		max_int = number[1] - number[0];
+		for(n=2;n<cnt;n++) {
+			if((this_int = number[n] - number[n-1]) > max_int) {
+				max_int = this_int;
+				pos = n;
+			}
+		}
+		fprintf(stdout,"WARNING: Maximum interval is %lf between entries %d and %d.\n",max_int,pos,pos+1);
+		fflush(stdout);
+	} else {
+		min_int = number[1] - number[0];
+		for(n=2;n<cnt;n++) {
+			if((this_int = number[n] - number[n-1]) < min_int) {
+				min_int = this_int;
+				pos = n;
+			}
+		}
+		fprintf(stdout,"WARNING: Minimum interval is %lf between entries %d and %d.\n",min_int,pos,pos+1);
+		fflush(stdout);
+	}
+}
+
+/****************************** INSERT_IN_ORDER ******************************/
+
+void insert_in_order(void) {
+	int n, pos = -1;
+	for(n=0;n<cnt-1;n++) {
+		if(number[n+1] <= number[n]) {
+			fprintf(stdout,"ERROR: column not in ascending order.\n");
+			fflush(stdout);
+			exit(1);
+		}
+		if ((pos < 0) && (number[cnt] <= number[n])) {	/* position not found & new number goes here */
+			pos = n;
+		}
+	}
+	if ((pos < 0) && (number[cnt] <= number[n])) {	/* position not found & new number goes here */
+		pos = n;
+	}
+	if(pos < 0) 			/* new number larger than all in column, goes at end */
+		pos = cnt;			
+	if(pos > 0) {			/* if new number not at start of column */
+		for(n=0;n<pos;n++)
+			fprintf(stdout,"INFO: %lf\n",number[n]);
+	}					   	/* insert new number */
+	fprintf(stdout,"INFO: %lf\n",number[cnt]);
+	if(pos < cnt) {			/* if new mumber not at end of column */
+		for(n=pos;n<cnt;n++)
+			fprintf(stdout,"INFO: %lf\n",number[n]);
+	}
+	fflush(stdout);
+}
+
+/****************************** INSERT_AT_START ******************************/
+
+void insert_at_start(void) {
+	int n;
+	fprintf(stdout,"INFO: %lf\n",number[cnt]);
+	for(n=0;n<cnt;n++)
+		fprintf(stdout,"INFO: %lf\n",number[n]);
+	fflush(stdout);
+}
+
+/****************************** INSERT_AT_END ******************************/
+
+void insert_at_end(void) {
+	int n;
+	for(n=0;n<=cnt;n++)
+		fprintf(stdout,"INFO: %lf\n",number[n]);
+	fflush(stdout);
+}
+
+/****************************** FORMAT_STRS ****************************/
+
+void format_strs(void)
+{
+	int n, m, OK = 1;
+	double d = (double)stringscnt/(double)ifactor;
+	int rowcnt = stringscnt/ifactor;
+	char temp[64];
+	errstr[0] = ENDOFSTR;
+	if(d > (double)rowcnt)
+		rowcnt++;
+	for(n=0;n<stringscnt;n+=rowcnt) {
+		for(m=0;m<rowcnt;m++) {
+			if(n!=0 && m==0) {
+				fprintf(stdout,"INFO: %s\n",errstr);
+				errstr[0] = ENDOFSTR;
+			}
+			if(n+m < stringscnt) {
+				sprintf(temp,"%s ",strings[n+m]);
+				strcat(errstr,temp);
+			} else
+				OK = 0;
+		}
+		if(!OK)
+			break;
+	}
+	fprintf(stdout,"INFO: %s\n",errstr);
+	fflush(stdout);
+}
+
+
+/****************************** COLUMN_FORMAT_STRS ****************************/
+
+void column_format_strs(void)
+{	int n, m;
+
+	double d = (double)stringscnt/(double)ifactor;
+	int rowcnt = stringscnt/ifactor;
+	char temp[64];
+	errstr[0] = ENDOFSTR;
+	if(d > (double)rowcnt)
+		rowcnt++;
+	for(n=0;n<rowcnt;n++) {
+		for(m=n;m<stringscnt;m+=rowcnt) {
+			sprintf(temp,"%s ",strings[m]);
+			strcat(errstr,temp);
+		}
+		fprintf(stdout,"INFO: %s\n",errstr);
+		errstr[0] = ENDOFSTR;
+	}
+	fflush(stdout);
+}
+
+/****************************** RANDOM_INTEGERS ****************************/
+
+void random_integers(void)
+{
+	int n, i, j = round(number[1]);
+	int range = abs(j - 1) + 1;
+	int rangbot = (int)min(j,1);
+	ifactor = round(number[0]);
+
+	for(n=0;n<ifactor;n++) {
+		i = (int)floor(drand48() * range) + rangbot;
+		fprintf(stdout,"INFO: %d\n",i);
+	}
+	fflush(stdout);
+}
+
+/****************************** RANDOM_INTEGERS_EVENLY_SPREAD ****************************/
+
+void random_integers_evenly_spread(void)
+{
+	int z, n, m, i, k, j, repets;
+	int range, rangbot, arrsiz, endcnt, endval, allowed, checkpart;
+	int *arr, *arr2, *perm;
+
+	repets = round(number[2]);
+	j = round(number[1]);
+	range = abs(j - 1) + 1;
+	rangbot = (int)min(j,1);
+	arrsiz = range * repets;
+	ifactor = round(number[0]);
+
+	if((arr = (int *)malloc(arrsiz * sizeof(int)))==NULL) {
+		fprintf(stdout,"ERROR: Out of memory.\n");
+		fflush(stdout);
+		exit(1);
+	}
+	if((perm = (int *)malloc(arrsiz * sizeof(int)))==NULL) {
+		fprintf(stdout,"ERROR: Out of memory.\n");
+		fflush(stdout);
+		exit(1);
+	}
+	if((arr2 = (int *)malloc(repets * sizeof(int)))==NULL) {
+		fprintf(stdout,"ERROR: Out of memory.\n");
+		fflush(stdout);
+		exit(1);
+	}
+	n = 0;
+	for(j=0;j<repets;j++) {					/* fill array with REPET copies of values */
+		z = rangbot;
+		for(i=0;i<range;i++)
+			arr[n++] = z++;
+	}
+	endcnt = 0;							  	/* number of items repeated at end of previous perm */
+	endval = 1;								/* value (possibly repeated) at end of previous perm */
+	allowed = -1;							/* number of permissible repetitions of this val at start of NEW perm */
+	checkpart = arrsiz - repets;			/* items at end of array to test for repetitions */
+	n = 0;
+	while(n < ifactor) {
+		do_repet_restricted_perm(arr,perm,arrsiz,allowed,endval);
+		j = 0;
+		for(m = 0;m <arrsiz;m++,n++) {
+			if(n >= ifactor)
+				break;
+			k = arr[perm[m]];
+			fprintf(stdout,"INFO: %d\n",k);
+			if(m >= checkpart)				/* save last checkable stretch of perm */
+				arr2[j++] = k;
+		}
+		fflush(stdout);
+		if(n >= ifactor)
+			break;
+		j--;
+		endval = arr2[j--];					/* note the val at end of perm */
+		endcnt = 1;							/* and count it */
+		for(k = j; k>= 0; k--) {			
+			if(arr2[k] == endval)			/* check adjacent vals, for repetition of value: count */
+				endcnt++;
+			else							/* if no more repetitions, finish counting */
+				break;
+		}
+		allowed = repets - endcnt;			/* get number of permissible repets at start of next perm */
+	}
+}
+
+/****************************** DO_REPET_RESTRICTED_PERM ****************************/
+
+void do_repet_restricted_perm(int *arr, int *perm, int arrsiz, int allowed, int endval)
+{
+	int n, t;
+	int checklen = allowed + 1;
+	int done = 0;
+	while(!done) {
+		for(n=0;n<arrsiz;n++) {
+			t = (int)(drand48() * (double)(n+1)); /* TRUNCATE */
+			if(t==n)
+				hhprefix(n,arrsiz,perm);
+			else
+				hhinsert(n,t,arrsiz,perm);
+		}
+		if(checklen <= 0)
+			break;
+		for(n=0;n<checklen;n++) {
+			if(arr[perm[n]] == endval) {	/* if this is val (repeated) at end of last perm */
+				if(allowed == 0) 			/* if repetition not allowed, force a new perm val */
+					break;
+				else						/* else, repetitions still allowed */
+					allowed--;				/* decrement number of permissible further repets */ 
+			} else {						
+				done = 1;					/* if this is not val at end of last perm */
+				break;						/* perm is OK */
+			}			
+		}
+	}
+}
+
+/***************************** HHINSERT **********************************
+ *
+ * Insert the value m AFTER the T-th element in perm[].
+ */
+
+void hhinsert(int m,int t,int setlen,int *perm)
+{
+	hhshuflup(t+1,setlen,perm);
+	perm[t+1] = m;
+}
+
+/***************************** HHPREFIX ************************************
+ *
+ * Insert the value m at start of the permutation perm[].
+ */
+
+void hhprefix(int m,int setlen,int *perm)
+{			  
+	hhshuflup(0,setlen,perm);
+	perm[0] = m;
+}
+
+/****************************** HHSHUFLUP ***********************************
+ *
+ * move set members in perm[] upwards, starting from element k.
+ */
+
+void hhshuflup(int k,int setlen,int *perm)
+{
+	int n, *i;
+	int z = setlen - 1;
+	i = (perm+z);
+	for(n = z;n > k;n--) {
+		*i = *(i-1);
+		i--;
+	}
+}
+
+/****************************** TIME_FROM_BAR_BEAT_METRE_TEMPO ***********************************/
+
+void time_from_bar_beat_metre_tempo(int has_offset)
+{
+	int barlen, beatsize, n;
+	double tempo,beat,beatdur,time, offset = 0.0;
+
+	if((tempo = get_tempo(strings[cnt+1])) <= 0.0)
+		exit(1);
+	if(has_offset)
+		get_offset(strings[cnt+2],&offset);
+	get_metre(strings[cnt],&barlen,&beatsize);
+	beatdur = (60.0/(double)tempo) * (4.0/(double)beatsize);
+	for(n=0;n<cnt;n++) {
+		beat = get_beat(n,barlen);
+		time = beat * beatdur;
+		time += offset;
+		fprintf(stdout,"INFO: %lf\n",time);
+	}
+	fflush(stdout);
+}
+
+/****************************** GET_METRE ***********************************/
+
+void get_metre(char str[],int *barlen,int *beatsize)
+{
+	int pointcnt = 0, isvalid = 0, mask;
+	char *q, *start, *p = str;
+	start = p;
+	q = start;
+	p += strlen(p);
+	/* strip trailing zeros */
+	if(p == start) {
+		fprintf(stdout, "ERROR: Invalid metre value. (No data).\n");
+		fflush(stdout);
+		exit(1);
+	}
+	p--;
+	while(*p == '0') {
+		*p = ENDOFSTR;		
+		if(p == start)
+			break;
+		p--;
+	}
+	p = start;
+	while(*p != ENDOFSTR) {
+		if(*p == '.') {
+			pointcnt++;
+			q = p;
+		} else if (!isdigit(*p)) {
+			fprintf(stdout, "ERROR: Invalid metre value. non_digit = '%c' in numerator.\n",*p);
+			fflush(stdout);
+			exit(1);
+		}
+		p++;
+	}
+	if(q == start) {
+		fprintf(stdout, "ERROR: Invalid metre value. No numerator.\n");
+		fflush(stdout);
+		exit(1);
+	}
+	if (pointcnt!=1) {
+		if(pointcnt > 1)
+			fprintf(stdout, "ERROR: Invalid metre value. %d decimal points : must be one only.\n",pointcnt);
+		else
+			fprintf(stdout, "ERROR: Invalid metre value. No decimal point\n");
+		fflush(stdout);
+		exit(1);
+	}
+	*q = ENDOFSTR;
+	if(sscanf(start,"%d",barlen)<1) {							/* SAFETY (redundant) */
+		fprintf(stdout, "ERROR: Invalid metre value. Cannot read barlength.\n");
+		fflush(stdout);
+		exit(1);
+	}
+	p = q+1;
+	if(*p==ENDOFSTR) {
+		fprintf(stdout, "ERROR: Invalid metre value. (No denominator).\n");
+		fflush(stdout);
+		exit(1);
+	}
+	start = p;
+	if(*p == '0') {
+		fprintf(stdout, "ERROR: Invalid metre value. (leading zeros in denominator).\n");		/* leading zero(s) */
+		fflush(stdout);
+		exit(1);
+	}
+	while(*p != ENDOFSTR) {
+		if(!isdigit(*p)) {									 	/* non-numeric characters */
+			fprintf(stdout, "ERROR: Invalid metre value. (non-digit character '%c' in denominator )\n",*p);
+			fflush(stdout);
+			exit(1);
+		}
+		p++;
+	}
+	if(sscanf(start,"%d",beatsize)<1) {							/* SAFETY (redundant) */
+		fprintf(stdout, "ERROR: Invalid metre value. Failed to read beatsize from %s\n",start);
+		fflush(stdout);
+		exit(1);
+	}
+	mask = 1;
+	while(mask < 512) {		/* Powers of 2 only !! Need special dispensation for Ferneyhovian metres like 4:10 */
+		if((*beatsize) == mask) {
+			isvalid = 1;
+			break;
+		}
+		mask <<= 1;
+	}	
+	if(!isvalid) {
+		fprintf(stdout, "ERROR: Invalid metre value. beatsize (%d) is invalid in standard usage\n",*beatsize);
+		fflush(stdout);
+		exit(1);
+	}
+}
+
+/****************************** GET_BEAT ***********************************/
+
+double get_beat(int n,int barlen)
+{
+	int pointcnt = 0;
+	char *q = NULL, *p, *start;
+	int bar;
+	double beat;
+	if(strlen(strings[n]) == 0) {
+		fprintf(stdout, "ERROR: Invalid bar:beat value at item %d. (No value found)\n",n+1);
+		fflush(stdout);
+		exit(1);
+	}
+	p = strings[n];
+		/* must have COLON */
+	while(*p != ENDOFSTR) {
+		if(*p == ':') {
+			pointcnt++;
+			q = p;
+		} else if (!isdigit(*p) && (*p != '.')) {
+			pointcnt = -1;
+			break;
+		}
+		p++;
+	}
+	if(pointcnt != 1) {
+		switch(pointcnt) {
+		case(-1):
+			fprintf(stdout, "ERROR: Invalid character (%c) in bar:beat value '%s' in item %d\n",*p,strings[n],n+1);
+			break;
+		case(0):
+			fprintf(stdout, "ERROR: Invalid bar:beat value '%s' at item %d. (No colon found)\n",strings[n],n+1);
+			break;
+		default:
+			fprintf(stdout, "ERROR: Invalid bar:beat value '%s' at item %d : %d colons found (should be only 1)\n",
+			strings[n],n+1,pointcnt);
+			break;
+		}
+		fflush(stdout);
+		exit(1);
+	}
+	*q = ENDOFSTR;
+	if(sscanf(strings[n],"%d",&bar)<1) {	/* SAFETY (redundant) */
+		fprintf(stdout, "ERROR: Invalid bar:beat value at item %d. Failed to read bar count.\n",n+1);
+		fflush(stdout);
+		exit(1);
+	}
+	if(bar < 1) {
+		fprintf(stdout, "ERROR: Invalid bar:beat value at item %d. Bar count less than 1.\n",n+1);
+		fflush(stdout);
+		exit(1);
+	}
+	bar--;
+	start = q+1;
+	if(*start==ENDOFSTR) {
+		fprintf(stdout, "ERROR: Invalid bar:beat value at item %d. No beatcount.\n",n+1);
+		fflush(stdout);
+		exit(1);
+	}
+	if(sscanf(start,"%lf",&beat)<1) {												/* SAFETY (redundant) */
+		fprintf(stdout, "ERROR: Invalid bar:beat value at item %d. Failed to read beatcount.\n",n+1);
+		fflush(stdout);
+		exit(1);
+	}
+	if(beat < 1.0) {
+		fprintf(stdout, "ERROR: Invalid bar:beat value at item %d. Beat count less than 1.\n",n+1);
+		fflush(stdout);
+		exit(1);
+	} else if(beat >= (double)(barlen + 1)) {
+		fprintf(stdout, "ERROR: Invalid bar:beat value at item %d. Beat count beyond bar end.\n",n+1);
+		fflush(stdout);
+		exit(1);
+	} 
+	beat -= 1.0;
+	beat += (bar * (double)barlen);
+	return beat;
+}
+
+/****************************** SCALE_FROM ***********************************/
+
+void scale_from(void) {
+
+	double interval, pivot = number[cnt];
+	double scaler = number[cnt+1];
+	int n;
+	for(n = 0;n<cnt;n++) {
+		interval = number[n] - pivot;
+		interval *= scaler;
+		fprintf(stdout,"INFO: %lf\n",pivot + interval);
+	}
+	fflush(stdout);
+}
+
+/****************************** SCALE_ABOVE ***********************************/
+
+void scale_above(void) {
+
+	double interval, pivot = number[cnt];
+	double scaler = number[cnt+1];
+	int n;
+	for(n = 0;n<cnt;n++) {
+		interval = number[n] - pivot;
+		if(interval > 0.0) {
+			interval *= scaler;
+			fprintf(stdout,"INFO: %lf\n",pivot + interval);
+		} else
+			fprintf(stdout,"INFO: %lf\n",number[n]);
+	}			
+	fflush(stdout);
+}
+
+/****************************** SCALE_BELOW ***********************************/
+
+void scale_below(void) {
+
+	double interval, pivot = number[cnt];
+	double scaler = number[cnt+1];
+	int n;
+	for(n = 0;n<cnt;n++) {
+		interval = number[n] - pivot;
+		if(interval < 0.0) {
+			interval *= scaler;
+			fprintf(stdout,"INFO: %lf\n",pivot + interval);
+		} else
+			fprintf(stdout,"INFO: %lf\n",number[n]);
+	}			
+	fflush(stdout);
+}
+
+/************************** SPAN_RISE ********************************/
+
+void span_rise(void) {
+
+	int n;
+
+	if(number[0] < 0.0) {
+		fprintf(stdout,"ERROR: This option only works with ascending values greater than or equal to zero.\n");
+		fflush(stdout);
+		exit(1);
+	}
+	for(n = 1;n<cnt;n++) {
+		if(number[n] - number[n-1] <= thresh)  {
+			fprintf(stdout,"ERROR: No space for span between number %d (%lf) and number %d (%lf)\n",
+			n,number[n-1],n+1,number[n]);
+			fflush(stdout);
+			exit(1);
+		}
+	}
+	if(number[0] < thresh) {
+		fprintf(stdout,"WARNING: First value too close to zero: NO span inserted.\n");
+		fflush(stdout);
+	} else {
+		fprintf(stdout,"INFO: %lf\n",number[0] - thresh);
+	}
+	fprintf(stdout,"INFO: %lf\n",number[0]);
+
+	for(n = 1;n<cnt;n++) {
+		fprintf(stdout,"INFO: %lf\n",number[n] - thresh);
+		fprintf(stdout,"INFO: %lf\n",number[n]);
+	}
+	fflush(stdout);
+}
+
+/************************** SPAN_FALL ********************************/
+
+void span_fall(void) {
+
+	int n;
+
+	if(number[0] < 0.0) {
+		fprintf(stdout,"ERROR: This option only works with ascending values greater than or equal to zero.\n");
+		fflush(stdout);
+		exit(1);
+	}
+	for(n = 1;n<cnt;n++) {
+		if(number[n] - number[n-1] <= thresh)  {
+			fprintf(stdout,"ERROR: No space for span between number %d (%lf) and number %d (%lf)\n",
+			n,number[n-1],n+1,number[n]);
+			fflush(stdout);
+			exit(1);
+		}
+	}
+	for(n = 0;n<cnt;n++) {
+		fprintf(stdout,"INFO: %lf\n",number[n]);
+		fprintf(stdout,"INFO: %lf\n",number[n] + thresh);
+	}
+	fflush(stdout);
+}
+
+/************************** CYCLIC_SELECT ********************************/
+
+void cyclic_select(char c) {
+
+	int n, m, start, step, k = (int)c, startpos = 0, steppos=0;
+	double item = 0.0;
+	
+	switch(k) {
+	case('s'):
+		steppos  = cnt;
+		startpos = cnt+1;
+		break;
+	case('a'):
+	case('m'):
+		steppos  = cnt+1;
+		startpos = cnt+2;
+		break;
+	}
+	if((start = (int)round(number[startpos])) > cnt) {
+		fprintf(stdout,"ERROR: There are no numbers at or beyond position %d\n",start);
+		fflush(stdout);
+		exit(1);
+	} else if(start < 1) {
+		fprintf(stdout,"ERROR: There are no numbers at or before position %d\n",start);
+		fflush(stdout);
+		exit(1);
+	}
+	start--;
+	if(abs(step = (int)round(number[steppos])) < 1) {
+		fprintf(stdout,"ERROR: Step between values cannot be zero.\n");
+		fflush(stdout);
+		exit(1);
+	}
+	if(c != 's') {
+		if(step < 0) {
+			fprintf(stdout,"ERROR: Step between values cannot be negative.\n");
+			fflush(stdout);
+			exit(1);
+		}
+		item = number[cnt];
+	}
+	switch(k) {
+	case('s'):
+		if(step > 0) {
+			for(n = start;n<cnt;n+=step)
+				fprintf(stdout,"INFO: %lf\n",number[n]);
+		} else {
+			for(n = start;n>=0;n+=step)
+				fprintf(stdout,"INFO: %lf\n",number[n]);
+		}
+		break;
+	case('a'):
+	case('m'):
+		n = 0;
+		while(n < start)
+			fprintf(stdout,"INFO: %lf\n",number[n++]);
+		for(m = 0;n<cnt;m++,n++) {
+			m %= step;
+			if(m == 0) {
+				switch(k) {
+				case('a'):	fprintf(stdout,"INFO: %lf\n",number[n] + item); break;
+				case('m'):	fprintf(stdout,"INFO: %lf\n",number[n] * item); break;
+				}
+			} else {
+				fprintf(stdout,"INFO: %lf\n",number[n]);
+			}
+		}
+		break;
+	}
+	fflush(stdout);
+}
+
+/************************** SPAN_ALL ********************************/
+
+void span_all(void) {
+
+	int n, zero_exists = 0, top_exists = 0;
+
+	if(number[0] < 0.0) {
+		fprintf(stdout,"ERROR: Numbers begin before zero.\n");
+		fflush(stdout);
+		exit(1);
+	}
+	if(number[cnt-1] > factor) {
+		fprintf(stdout,"ERROR: Numbers already run beyond %lf\n",factor);
+		fflush(stdout);
+		exit(1);
+	}
+	if(number[0] <= 0.0)
+		zero_exists = 1;
+	if(number[cnt-1] >= factor)
+		top_exists = 1;
+	if(zero_exists) {
+		if(top_exists) {
+			fprintf(stdout,"ERROR: Numbers already begin at zero and end at %lf\n",factor);
+			fflush(stdout);
+			exit(1);
+		} else {
+			fprintf(stdout,"WARNING: Numbers already start at zero\n");
+			fflush(stdout);
+		}
+	}
+	if(top_exists) {
+		fprintf(stdout,"WARNING: Numbers already end at %lf\n",factor);
+		fflush(stdout);
+	}
+	if(!zero_exists)
+		fprintf(stdout,"INFO: %lf\n",0.0);
+	for(n=0;n<cnt;n++)
+		fprintf(stdout,"INFO: %lf\n",number[n]);
+	if(!top_exists)
+		fprintf(stdout,"INFO: %lf\n",factor);
+	fflush(stdout);
+}
+
+/************************** GET_TEMPO ********************************/
+
+double get_tempo(char *str)
+{
+	char *p = str;
+	double tempo;
+	int pointcnt = 0;
+	while(*p != ENDOFSTR) {
+		if(*p == '.') {
+			pointcnt++;
+		} else if(!isdigit(*p)) {
+			pointcnt = -1;
+			break;
+		}
+		p++;
+	}
+	if(pointcnt < 0 || pointcnt > 1) {
+		fprintf(stdout, "ERROR: Invalid tempo value.\n");
+		fflush(stdout);
+		return(-1.0);
+	}
+	if(sscanf(str,"%lf",&tempo)!=1) {
+		fprintf(stdout, "ERROR: Invalid tempo value.\n");
+		fflush(stdout);
+		return(-1.0);
+	}
+	if(tempo <= 0.0) {
+		fprintf(stdout, "ERROR: Zero or negative tempo: impossible.\n");
+		fflush(stdout);
+		return(-1.0);
+	} else if(tempo > MAX_TEMPO) {
+		fprintf(stdout, "ERROR: Invalid tempo value. Beats shorter than 1 millisecond (!!).\n");
+		fflush(stdout);
+		return(-1.0);
+	} else if(tempo < MIN_TEMPO) {
+		fprintf(stdout, "ERROR: Invalid tempo value. Beats longer than 1 hour (!!).\n");
+		fflush(stdout);
+		return(-1.0);
+	}
+	return tempo;
+}
+
+/************************** GENERATE_RANDOMISED_VALS ********************************/
+
+void generate_randomised_vals(void)
+{
+	double scatter = number[2], span = number[0], sum = 0.0, mean, range, *temp = NULL, d;
+	int cnt = (int)round(number[1]), n, m, j, subcnt;
+	int bigscat = 0;
+	if(scatter > 1.0)
+		bigscat = (int)round(scatter);
+	if(bigscat) {
+		if((temp = (double *)malloc(bigscat * sizeof(double)))==NULL) {
+			fprintf(stdout,"Out of memory.\n");
+			fflush(stdout);
+			exit(1);
+		}
+	}
+	if((number = (double *)realloc((char *)number,(cnt+1) * sizeof(double)))==NULL) {
+		fprintf(stdout,"Out of memory.\n");
+		fflush(stdout);
+		exit(1);
+	}
+	mean = span/(double)cnt;
+	number[0] = 0.0;
+	number[cnt] = span;
+
+	if(bigscat) {
+		for(n=1;n < cnt;n+= bigscat) {
+			if((subcnt = n + bigscat) > cnt)			/* find position of last number in this pass */
+				subcnt = cnt;	  						/* set end position of pass */
+			subcnt--;									/* allow for item already written at 1 */
+			if((subcnt %= bigscat) == 0)				/* set size of pass */
+				subcnt = bigscat;
+			range = mean * subcnt;						/* set range of pass */
+			for(m = 0; m < subcnt; m++)
+				temp[m] = sum + (drand48() * range);	/* generate values within this range */
+			for(m=0;m < subcnt - 1; m++) {				
+				for(j=1;j < subcnt; j++) {
+					if(temp[m] > temp[j]) {				/* sort */
+						d = temp[j];
+						temp[j] = temp[m];
+						temp[m] = d;
+					}
+				}
+			}
+			for(m=0;m<subcnt;m++)						/* concatenate to list of numbers */
+				number[n+m] = temp[m];
+			sum += range;								/* step over range */
+		}
+	} else {
+		for(n=1;n < cnt;n++) {
+			sum += mean;
+			number[n] = sum + (mean * randoffset(scatter));
+		}
+	}
+	for(n=0;n<=cnt;n++)
+		fprintf(stdout,"INFO: %lf\n",number[n]);
+	fflush(stdout);
+}
+
+/************************** RAND_OFFSET ********************************
+ *
+ * rand number in maximal range -half to +half
+ */
+
+double randoffset(double scatter)
+{
+	return (((drand48() * 2.0) - 1.0) * 0.5) * scatter;
+}
+
+/************************** GET_OFFSET ********************************/
+
+void get_offset(char *str,double *offset)
+{
+	if(sscanf(str,"%lf",offset)!=1) {
+		fprintf(stdout,"Cannot read time offset.\n");
+		fflush(stdout);
+		exit(1);
+	}
+}
+
+/************************** PITCH_TO_DELAY ********************************/
+
+void pitch_to_delay(int midi)
+{
+	int n;
+	for(n = 0;n < cnt; n++) {
+		if(midi) {
+			if(number[n] < MIDIMIN || number[n] > MIDIMAX) {
+				fprintf(stdout,"MIDI value %d (%lf) is out of range.\n", n+1,number[n]);
+				fflush(stdout);
+				exit(1);
+			}
+			number[n] = miditohz(number[n]);
+		} else if(number[n] < FLTERR || number[n] > 24000.0) {
+			fprintf(stdout,"Frequency value %d (%lf) is out or range.\n",n+1,number[n]);
+			fflush(stdout);
+			exit(1);
+		}
+		number[n] = 1000.0/number[n];
+	}
+	for(n=0;n<cnt;n++)
+		fprintf(stdout,"INFO: %lf\n",number[n]);
+	fflush(stdout);
+}
+
+/************************** DELAY_TO_PITCH ********************************/
+
+void delay_to_pitch(int midi)
+{
+	int n;
+	for(n = 0;n < cnt; n++) {
+		number[n] /= 1000; 
+		if(number[n] < FLTERR) {
+			fprintf(stdout,"Delay value %d (%lf) is out or range for conversion to pitch value.\n",n+1,number[n]);
+			fflush(stdout);
+			exit(1);
+		}
+		number[n] = 1.0/number[n];
+		if(midi) {
+			if(number[n] < MIDIMINFRQ || number[n] > MIDIMAXFRQ) {
+				fprintf(stdout,"delay value %d (%lf) is out of range for conversion to MIDI.\n", n+1,number[n]);
+				fflush(stdout);
+				exit(1);
+			}
+			number[n] = hztomidi(number[n]);
+		} else if(number[n] < FLTERR || number[n] > 24000) {
+			fprintf(stdout,"Delay value %d (%lf) is out or range for conversion to frq.\n",n+1,number[n]);
+			fflush(stdout);
+			exit(1);
+		}
+	}
+	for(n=0;n<cnt;n++)
+		fprintf(stdout,"INFO: %lf\n",number[n]);
+	fflush(stdout);
+}
+
+
+/* NEW FUNCS HANDLING BRKTABLES DIRECTLY ***** JUNE 2000 ***/
+
+
+/****************************** REVERSE_TIME_INTERVALS ******************************/
+
+void reverse_time_intervals(void)
+{
+	int n, m;
+	double k = number[0];
+	fprintf(stdout,"INFO: %lf  %lf\n",k,number[1]);
+	for(n=3,m = cnt-2;n<cnt;m-=2,n+=2) {
+		k += (number[m] - number[m-2]);
+		fprintf(stdout,"INFO: %lf  %lf\n",k,number[n]);
+	}
+	fflush(stdout);
+}
+
+/****************************** REVERSE_ORDER_OF_BRKVALS ******************************/
+
+void reverse_order_of_brkvals(void)
+{
+	int n, m;
+	for(n=0,m = cnt-1;n<cnt;m-=2,n+=2)
+		fprintf(stdout,"INFO: %lf  %lf\n",number[n],number[m]);
+	fflush(stdout);
+}
+
+/****************************** INVERTENV ******************************/
+
+void invertenv(double piv)
+{	
+	int n;
+	for(n=1;n<cnt;n+=2)
+		fprintf(stdout,"INFO: %lf  %lf\n",number[n-1],piv - number[n]);
+	fflush(stdout);
+}
+
+/******************************** THRESH_CUT ****************************/
+
+void thresh_cut(void)
+{
+	int n,m, k = 0;
+	double ratio, *time;
+	int isgreater = 0;
+	if((cnt <= 0) || ((time = (double *)malloc(cnt * sizeof(double)))==NULL)) {
+		fprintf(stdout,"ERROR: Insufficient memory.\n");
+		return;
+	}
+	if(number[1] > factor)
+		isgreater = 1;
+	for(m=2,n=3;n<cnt;n+=2,m+=2) {
+		switch(isgreater) {
+		case(0):			
+			if(number[n] > factor) {
+				ratio = (factor - number[n-2])/(number[n] - number[n-2]);
+				time[k++] = ((number[m] - number[m-2]) * ratio) + number[m-2];
+				isgreater = 1;
+			}
+			break;
+		case(1):			
+			if(number[n] <= factor) {
+				ratio = (factor - number[n-2])/(number[n] - number[n-2]);
+				time[k++] = ((number[m] - number[m-2]) * ratio) + number[m-2];
+				isgreater = 0;
+			}
+			break;
+		}
+	}
+	if(k == 0) {
+		fprintf(stdout,"ERROR: The values do not cross the threshold.\n");
+		free(time);
+		return;
+	}
+	for(n=0;n<k;n++)
+		do_valout(time[n]);
+	free(time);
+}
+
+/******************************** BAND_CUT ****************************/
+
+void band_cut(void)
+{
+	int n,m, k = 0;
+	double ratio, *time, z, hibnd, lobnd;
+	int bandpos;
+	if((cnt <= 0) || ((time = (double *)malloc(cnt * sizeof(double)))==NULL)) {
+		fprintf(stdout,"ERROR: Insufficient memory.\n");
+		return;
+	}
+	lobnd = number[cnt];
+	hibnd = number[cnt+1];
+
+	if(lobnd > hibnd) {
+		z = lobnd;
+		lobnd = hibnd;
+		hibnd = z;
+	}
+	if(number[1] >= lobnd && number[1] <= hibnd)
+		bandpos = 0;
+	else if(number[1] < lobnd)
+		bandpos = -1;
+	else
+		bandpos = 1;
+	for(m=2,n=3;n<cnt;n+=2,m+=2) {
+		switch(bandpos) {
+		case(0):			
+			if(number[n] < lobnd) {		   /* crosses out downwards */
+				ratio = (lobnd - number[n-2])/(number[n] - number[n-2]);
+				time[k++] = ((number[m] - number[m-2]) * ratio) + number[m-2];
+				bandpos = -1;				   
+			} else if(number[n] > hibnd) {	   /* crosses out upwards */
+				ratio = (hibnd - number[n-2])/(number[n] - number[n-2]);
+				time[k++] = ((number[m] - number[m-2]) * ratio) + number[m-2];
+				bandpos = 1;
+			}
+			break;
+		case(1):			
+			if(number[n] <= hibnd) {	   		/* crosses in from above */
+				ratio = (hibnd - number[n-2])/(number[n] - number[n-2]);
+				time[k++] = ((number[m] - number[m-2]) * ratio) + number[m-2];
+				bandpos = 0;
+			}
+			if(number[n] < lobnd) {			/* then possibly out below */
+				ratio = (lobnd - number[n-2])/(number[n] - number[n-2]);
+				time[k++] = ((number[m] - number[m-2]) * ratio) + number[m-2];
+				bandpos = -1;
+			}
+			break;
+		case(-1):			
+			if(number[n] >= lobnd) {		   /* crosses in from below */
+				ratio = (lobnd - number[n-2])/(number[n] - number[n-2]);
+				time[k++] = ((number[m] - number[m-2]) * ratio) + number[m-2];
+				bandpos = 0;
+			}
+			if(number[n] > hibnd) {			/* then possibly out above */
+				ratio = (hibnd - number[n-2])/(number[n] - number[n-2]);
+				time[k++] = ((number[m] - number[m-2]) * ratio) + number[m-2];
+				bandpos = 1;
+			}
+			break;
+		}
+	}
+	if(k == 0) {
+		fprintf(stdout,"ERROR: The values in the 2nd column do not cross into or out of the specified band.\n");
+		free(time);
+		return;
+	}
+	for(n=0;n<k;n++)
+		do_valout(time[n]);
+	fflush(stdout);
+	free(time);
+}
+
+
+
+/****************************** ENV_APPEND ******************************/
+
+void env_append(void)
+{
+	int n, dojoin = 0;
+	double first_endtime;
+
+	first_endtime = number[firstcnt-2];
+	if (factor < first_endtime) { 
+		fprintf(stdout,"ERROR: Second envelope starts before first one ends.\n");
+		fflush(stdout);
+		exit(1);
+	} else if(flteq(factor,first_endtime)) {
+		if(!flteq(number[firstcnt-1],number[firstcnt+1])) {
+			fprintf(stdout,"ERROR: Abutting envelopes are not at same level (%lf and %lf).\n",number[firstcnt-1],number[firstcnt+1]);
+			fflush(stdout);
+			exit(1);
+		}
+		dojoin = 1;
+	}
+	for(n = firstcnt; n < cnt; n+=2) {
+		number[n] += factor;
+	}
+	if(dojoin) {
+		for(n=0;n<firstcnt;n+=2)
+			do_valpair_out(number[n],number[n+1]);
+		for(n=firstcnt+2;n<cnt;n+=2)
+			do_valpair_out(number[n],number[n+1]);
+	} else {
+		for(n=0;n<cnt;n+=2)
+			do_valpair_out(number[n],number[n+1]);
+	}
+	fflush(stdout);
+}
+
+/****************************** ABUTT ******************************/
+
+void abutt(void)
+{
+	int n,m = 0, i;
+	double displace;
+	int indx = 0;
+	for(i=0;i<infilecnt-1;i++) { 			/* check abutting values match */
+		indx += file_cnt[i];
+		if(!flteq(number[indx-1],number[indx+1])) {
+			fprintf(stdout,"ERROR: Abutting values between files %d and %d do not match\n",i+1,i+2);
+			fflush(stdout);
+			exit(1);
+		}
+	}
+	for(n=0;n < file_cnt[0]; n+=2) { 		/* print all of file 1 */
+		fprintf(stdout, "INFO: %lf  %lf\n",number[m],number[m+1]);
+		m += 2;
+	}
+	displace = number[m-2];		 			/* displace by last time in 1st file */
+	for(i = 1; i <infilecnt; i++) {			/* for all other files */
+		m += 2;								/* skip first (abutting) value */
+		for(n=2;n < file_cnt[i]; n+=2) { 	/* for all other values in file - displace time values */
+			fprintf(stdout, "INFO: %lf  %lf\n",number[m] + displace,number[m+1]);
+			m += 2;
+		}
+		displace += number[m-2];			/* increase displacement by last time in this file */
+	}
+	fflush(stdout);
+}
+
+/****************************** QUANTISE_TIME ******************************/
+
+void quantise_time(void)
+{
+	int n;
+	for(n=0;n<cnt;n+=2)
+		fprintf(stdout,"INFO: %lf  %lf\n",round(number[n]/factor) * factor,number[n+1]);
+	fflush(stdout);
+}
+
+/****************************** QUANTISE_VAL ******************************/
+
+void quantise_val(void)
+{
+	int n;
+	for(n=0;n<cnt;n+=2)
+		fprintf(stdout,"INFO: %lf  %lf\n",number[n],round(number[n+1]/factor) * factor);
+	fflush(stdout);
+}
+
+/****************************** EXPAND_TABLE_DUR_BY_FACTOR ******************************/
+
+void expand_table_dur_by_factor(void)
+{
+	int n;
+	for(n=0;n<cnt;n+=2)
+		fprintf(stdout,"INFO: %lf  %lf\n",number[n] * factor,number[n+1]);
+	fflush(stdout);
+}
+
+/****************************** EXPAND_TABLE_VALS_BY_FACTOR ******************************/
+
+void expand_table_vals_by_factor(void)
+{
+	int n;
+	for(n=0;n<cnt;n+=2)
+		fprintf(stdout,"INFO: %lf  %lf\n",number[n],number[n+1] * factor);
+	fflush(stdout);
+}
+
+/****************************** EXPAND_TABLE_TO_DUR ******************************/
+
+void expand_table_to_dur(void)
+{
+	int n;
+	double ratio;
+
+	if(number[cnt-2] <= 0.0) {
+		fprintf(stdout,"ERROR: Final time in table is zero: cannot proceed.\n");
+		return;
+	}
+	ratio = factor/number[cnt-2];
+
+	for(n=0;n<cnt;n+=2)
+		fprintf(stdout,"INFO: %lf  %lf\n",number[n] * ratio,number[n+1]);
+	fflush(stdout);
+}
+
+/****************************** CUT_TABLE_AT_TIME ******************************/
+
+void cut_table_at_time(void)
+{
+	int n;
+	double timediff,valdiff,timeratio,outval;
+
+	for(n=0;n<cnt;n+=2) {
+		if(flteq(number[n],factor)) {
+			fprintf(stdout,"INFO: %lf  %lf\n",number[n],number[n+1]);
+			break;
+		} else if(number[n] < factor) {
+			fprintf(stdout,"INFO: %lf  %lf\n",number[n],number[n+1]);
+		} else if(n==0) {
+			fprintf(stdout,"WARNING: No values occur before the cut-off time\n");
+			break;
+		} else {
+			timediff  = number[n] - number[n-2];
+			valdiff   = number[n+1] - number[n-1];
+			timeratio = (factor - number[n-2])/timediff;
+			valdiff  *= timeratio;
+			outval	= number[n-1] + valdiff;
+			fprintf(stdout,"INFO: %lf  %lf\n",factor,outval);
+			break;
+		}
+	}
+	fflush(stdout);
+}
+
+/****************************** EXTEND_TABLE_TO_DUR ******************************/
+
+void extend_table_to_dur(void)
+{
+	int n;
+ 	for(n=0;n<cnt;n+=2)
+		fprintf(stdout,"INFO: %lf  %lf\n",number[n],number[n+1]);
+	fprintf(stdout,"INFO: %lf  %lf\n",factor,number[n-1]);
+	fflush(stdout);
+}
+
+/****************************** LIMIT_TABLE_VAL_RANGE ******************************/
+
+void limit_table_val_range(void)
+{
+	int n;
+ 	if(condit) {
+		for(n=1;n<cnt;n+=2) {
+			number[n] = max((number[n] = min(factor,number[n])),thresh);
+			fprintf(stdout,"INFO: %lf  %lf\n",number[n-1],number[n]);
+		}
+	} else {
+		for(n=1;n<cnt;n+=2) {
+			number[n] = min(factor,number[n]);
+			fprintf(stdout,"INFO: %lf  %lf\n",number[n-1],number[n]);
+		}
+	}
+	fflush(stdout);
+}
+
+/****************************** SUBSTITUTE ******************************/
+
+void substitute(void)
+{
+	int n;
+ 	for(n=0;n<cnt;n++) {
+		if(flteq(number[n],thresh))
+			number[n] = factor;
+		fprintf(stdout,"INFO: %lf\n",number[n]);
+	}
+	fflush(stdout);
+}
+
+/****************************** SUBSTITUTE_ALL ******************************/
+
+void substitute_all(void)
+{
+	int n;
+ 	for(n=0;n<stringscnt;n++)
+		fprintf(stdout,"INFO: %s\n",string);
+	fflush(stdout);
+}
+
+/****************************** SUBSTITUTE ******************************/
+
+void mean_of_reversed_pairs(void)
+{
+	int n;
+	double z1;
+ 	for(n=1;n<cnt;n++) {
+		if(number[n]<number[n-1]) {
+			z1 = (number[n] + number[n-1])/2.0;
+			number[n-1]	= z1 - FLTERR;
+			if((n-2 > 0) && number[n-2] >= number[n-1]) {
+				fprintf(stdout,"WARNING: numbers %d (%lf) and %d (%lf) failed to be separated.\n",
+				n,number[n-1],n+1,number[n]);
+				fflush(stdout);
+				return;
+			}
+			number[n]   = z1 + FLTERR;
+			if((n+1 < cnt) && number[n+1] <= number[n]) {
+				fprintf(stdout,"WARNING: numbers %d (%lf) and %d (%lf) failed to be separated.\n",
+				n+1,number[n],n+2,number[n+1]);
+				fflush(stdout);
+				return;
+			}
+		}
+	}
+ 	for(n=0;n<cnt;n++)
+		fprintf(stdout,"INFO: %lf\n",number[n]);
+	fflush(stdout);
+}
+
+/****************************** CONVERT_SPACE_TEX_TO_PAN ******************************/
+
+void convert_space_tex_to_pan(void)
+{
+	int n;
+	for(n=1;n<cnt;n+=2) {
+		number[n] *=2.0;
+		number[n] -=1.0;
+	}
+ 	for(n=0;n<cnt;n+=2)
+		fprintf(stdout,"INFO: %lf  %lf\n",number[n],number[n+1]);
+	fflush(stdout);
+}
+
+/****************************** CONVERT_SPACE_PAN_TO_TEX ******************************/
+
+void convert_space_pan_to_tex(void)
+{
+	int n;
+	for(n=1;n<cnt;n+=2) {
+		number[n] *=0.5;
+		number[n] +=0.5;
+	}
+ 	for(n=0;n<cnt;n+=2)
+		fprintf(stdout,"INFO: %lf  %lf\n",number[n],number[n+1]);
+	fflush(stdout);
+}
+
+/****************************** CONVERT_TO_EDITS ******************************/
+
+void convert_to_edits(void)
+{
+	int n;
+	double start, end;
+	for(n=0;n<cnt-1;n++) {
+		start = max(0.0,number[n] - factor);
+		end = max(0.0,number[n+1] + factor);
+		fprintf(stdout,"INFO: %lf  %lf\n",start,end);
+	}
+	fflush(stdout);
+}
+
+/****************************** COSIN_SPLINE ******************************/
+
+void cosin_spline(void)
+{
+	int n, cnt_less_one;
+	double val, valchange, skew, startval ,endval;
+	skew = number[3];
+	startval = number[1];
+	endval   = number[2];
+	valchange = endval - startval;
+	cnt_less_one = cnt - 1;
+	if(flteq(skew,1.0)) {
+		for(n=0;n<cnt;n++) {
+			val  = ((double)n/(double)cnt_less_one) * PI;
+			val  = cos(val);
+			val += 1.0;
+			val /= 2.0;
+			val  = 1.0 - val;
+			val  = max(0.0,val);
+			val  = min(val,1.0);
+			val *= valchange;
+			val += startval;
+			fprintf(stdout,"INFO: %lf\n",val);
+		}
+	} else {
+		for(n=0;n<cnt;n++) {
+			val  = ((double)n/(double)cnt_less_one);	/* val in 0 -1 range */
+			val  = pow(val,skew);						/* val skewed, still in 0-1 range */
+			val  = val * PI;							/* (skewed) val in range 0 to PI */
+			val  = cos(val);							/* cosin val running from 1 to -1 */
+			val += 1.0;									/* cosin val running from 2 to 0  */	
+			val /= 2.0;									/* cosin val running from 1 to 0  */	
+			val  = 1.0 - val;							/* cosin val running from 0 to 1  */	
+			val  = max(0.0,val);						/* ensure 0-1 range not exceeeded */
+			val  = min(val,1.0);						
+			val *= valchange;							/* apply cosin shape to val change */
+			val += startval;							/* add cosin change to initial val */
+			fprintf(stdout,"INFO: %lf\n",val);
+		}
+	}
+	fflush(stdout);
+}
+
+/****************************** DISTANCE_FROM_GRID ******************************/
+
+void distance_from_grid()
+{
+	int n, m, besterror;
+	double *diff = (double *)exmalloc((cnt-1)*sizeof(double));
+	double *error = (double *)exmalloc(21 * sizeof(double));
+	double maxdiff = 0.0, mindiff = 0.0, lastmindiff, diffrange, diffstep, thisdiff, thisgrid, minerror;
+	double lowlimit = FLTERR/10000;
+
+	for(n=0;n<cnt-1;n++) {
+		diff[n] = number[n+1] - number[n];
+
+/*
+		if(diff[n]  <= 0.0) {
+			fprintf(stdout, "ERROR: Process only works with increasing sequences of numbers.\n");
+			fflush(stdout);
+			exit(1);
+		}
+*/
+		if(n==0) {
+			mindiff = diff[0];
+			maxdiff = diff[0];
+		} else {
+			mindiff = min(diff[n],mindiff);
+			maxdiff = max(diff[n],maxdiff);
+		}
+	}
+
+	lastmindiff = mindiff;
+	while((diffrange = maxdiff - mindiff) > lowlimit * 20.0) {
+		diffstep = diffrange/20.0;
+		thisdiff = mindiff;
+		for(m=0;m<=20;m++) {
+			error[m] = 0;
+			thisgrid = number[0];
+			for(n=1;n<cnt;n++) {
+				thisgrid += thisdiff;
+				error[m] += fabs(number[n] - thisgrid);
+			}
+			thisdiff += diffstep;
+		}
+		minerror = error[0];
+		besterror = 0;
+		for(m=1;m<=20;m++) {
+			if(minerror > error[m]) {
+				minerror = error[m];
+				besterror = m;
+			}
+		}
+		mindiff = mindiff + (besterror * diffstep);
+		lastmindiff = mindiff;
+		maxdiff = mindiff + diffstep;
+		mindiff -= diffstep;
+	}
+	thisgrid = number[0];
+	for(n=0;n<cnt;n++) {
+		thisdiff = number[n] - thisgrid;
+		if(thisdiff < 0.0 && thisdiff > -FLTERR)
+			thisdiff = 0.0;
+		fprintf(stdout,"INFO: %lf\n",thisdiff);
+		thisgrid += lastmindiff;
+	}
+	fflush(stdout);
+}
+
+/****************************** SINUSOID ******************************/
+
+void sinusoid(void) {
+	double maxval  = number[0], minval  = number[1];
+	double range   = maxval - minval;
+	double phase   = (fmod(number[2],360.0)/360.0) * TWOPI;
+	double periods = number[3];
+	double valdens = number[4];
+	int n, valcnt = (int)floor((periods * valdens) + 1.0);
+	double val, phasestep = TWOPI/valdens;
+
+	for(n = 0; n < valcnt; n++) {
+		val = (sin(phase) + 1.0)/2.0;
+		val *= range;
+		val += minval;
+		fprintf(stdout,"INFO: %lf\n",val);
+		phase = phase + phasestep; /* should be fmod by TWOPI, but seems to work without this */
+	}
+	fflush(stdout);
+}
+
+/****************************** RAND_INTS_WITH_FIXED_ENDS ****************************/
+
+void rand_ints_with_fixed_ends(void)
+{
+	int z, n, m, i, k, j, j1, j2, repets, fullperms, partperm, startval, finval;
+	int range, rangbot, arrsiz, endcnt, endval, allowed, checkpart, done = 0;
+	int *arr, *arr2, *perm;
+
+	repets = round(number[5]);
+	startval = round(number[3]);
+	finval   = round(number[4]);
+	j1 = round(number[1]);
+	j2 = round(number[2]);
+	range = abs(j2 - j1) + 1;
+	rangbot = (int)min(j1,j2);
+	arrsiz = range * repets;
+	ifactor = round(number[0]) - 2;
+	fullperms = ifactor / arrsiz;
+	partperm = ifactor - (fullperms * arrsiz);
+	if(partperm == 0) {
+		fullperms--;		/* The last set of vals has to be calculated separately */
+		partperm = arrsiz;	/* as, unlike others, it will have to be compared with the finval */
+	}
+
+	if((arr = (int *)malloc(arrsiz * sizeof(int)))==NULL) {
+		fprintf(stdout,"ERROR: Out of memory.\n");
+		fflush(stdout);
+		exit(1);
+	}
+	if((perm = (int *)malloc(arrsiz * sizeof(int)))==NULL) {
+		fprintf(stdout,"ERROR: Out of memory.\n");
+		fflush(stdout);
+		exit(1);
+	}
+	if((arr2 = (int *)malloc(repets * sizeof(int)))==NULL) {
+		fprintf(stdout,"ERROR: Out of memory.\n");
+		fflush(stdout);
+		exit(1);
+	}
+	n = 0;
+	for(j=0;j<repets;j++) {					/* fill array with REPET copies of values. */
+		z = rangbot;						/* this set can be permd AS A WHOLE, as repet adjacent copies of any val */
+		for(i=0;i<range;i++)				/* which might arise in perming this set, are allowed */
+			arr[n++] = z++;
+	}
+	endcnt = 0;							  	/* number of items repeated at end of previous perm */
+	endval = startval;						/* value (possibly repeated) at end of previous perm */
+											/* initially this is just the 'startval' fixed by the user */
+	allowed = repets - 1;					/* number of permissible repetitions of this val at start of NEW perm */
+	checkpart = arrsiz - repets;			/* items at end of array to test for repetitions */
+	n = 0;
+	fprintf(stdout,"INFO: %d\n",startval);	/* Output user-specified first value */
+	while(n < fullperms) {
+		do_repet_restricted_perm(arr,perm,arrsiz,allowed,endval);
+		j = 0;
+		for(m = 0;m <arrsiz;m++) {
+			k = arr[perm[m]];
+			fprintf(stdout,"INFO: %d\n",k);
+			if(m >= checkpart)				/* save last checkable stretch of perm */
+				arr2[j++] = k;
+		}
+		fflush(stdout);
+		j--;
+		endval = arr2[j--];					/* note the val at end of perm */
+		endcnt = 1;							/* and count it */
+		for(k = j; k>= 0; k--) {			
+			if(arr2[k] == endval)			/* check adjacent vals, for repetition of value: count */
+				endcnt++;
+			else							/* if no more repetitions, finish counting */
+				break;
+		}
+		allowed = repets - endcnt;			/* get number of permissible repets at start of next perm */
+		n++;
+	}
+	k = partperm - 1;	/* index of last item of next perm which will actually be outputted */
+	j = repets - 1;		/* How many items at end of partperm, other than item k, which need to be checked for value-repetition */
+	while(!done) {
+		do_repet_restricted_perm(arr,perm,arrsiz,allowed,endval);
+		for(n=k;n>=k - j;n--) {
+			if(arr[perm[n]] == finval) {	/* Check end vals of the-set-of-values-in-the-final-perm-which-will-actually-be-outputted */
+				if(allowed == 0) 			/* against 'finval', to avoid too many value-repetitions at end of output */
+					break;
+				else
+					allowed--;
+			} else {						
+				done = 1;
+				break;
+			}			
+		}
+	}
+	for(m = 0;m <partperm;m++) {
+		k = arr[perm[m]];
+		fprintf(stdout,"INFO: %d\n",k);
+	}
+	fprintf(stdout,"INFO: %d\n",finval);
+	fflush(stdout);
+}
+
+/****************************** RAND_ZIGS ****************************/
+
+void rand_zigs(void)
+{
+	int n, k, j, j1, j2, finval, range, rangbot, arrsiz, outvals, lastval, t, done;
+	int *arr, *perm;
+
+	outvals = round(number[0]);
+	j1 = round(number[1]);
+	j2 = round(number[2]);
+	finval = round(number[3]);
+	range = abs(j2 - j1) + 1;
+	rangbot = (int)min(j1,j2);
+	if(finval < rangbot || finval > (int)max(j1,j2)) {
+		fprintf(stdout,"ERROR: Final value specified does not lie within the range of values specified.\n");
+		fflush(stdout);
+		exit(1);
+	}
+	arrsiz = range;
+	if((arr = (int *)malloc(arrsiz * sizeof(int)))==NULL) {
+		fprintf(stdout,"ERROR: Out of memory.\n");
+		fflush(stdout);
+		exit(1);
+	}
+	if((perm = (int *)malloc(arrsiz * sizeof(int)))==NULL) {
+		fprintf(stdout,"ERROR: Out of memory.\n");
+		fflush(stdout);
+		exit(1);
+	}
+	k = rangbot;						/* this set can be permd AS A WHOLE, as repet adjacent copies of any val */
+	for(n=0;n<range;n++)				/* which might arise in perming this set, are allowed */
+		arr[n] = k++;
+	j = 0;
+	lastval = rangbot - 1;
+	done = 0;
+	while(j < outvals) {
+		for(n=0;n<arrsiz;n++) {
+			t = (int)(drand48() * (double)(n+1)); /* Do Perm */
+			if(t==n)
+				hhprefix(n,arrsiz,perm);
+			else
+				hhinsert(n,t,arrsiz,perm);
+		}
+		for(n=0;n<arrsiz;n++) {
+			if (lastval < arr[perm[n]])  {
+				k = lastval + 1;
+				while(k < arr[perm[n]]) {
+					fprintf(stdout,"INFO: %d\n",k);
+					if(++j >= outvals) {
+						lastval = k;
+						done = 1;
+						break;
+					}
+					k++;
+				}
+			} else if(lastval > arr[perm[n]]) {
+				k = lastval - 1;
+				while(k > arr[perm[n]]) {
+					fprintf(stdout,"INFO: %d\n",k);
+					if(++j >= outvals) {
+						lastval = k;
+						done = 1;
+						break;
+					}
+					k--;
+				}
+			} else {		/* next perm val can only be equal to previous at join of two different perms */
+				break;		/* in this case, get a different perm */
+			}
+			if(done) {
+				break;
+			}
+			lastval = arr[perm[n]];
+			fprintf(stdout,"INFO: %d\n",lastval);
+			j++;
+		}
+	}
+	if(lastval < finval) {
+		lastval++;
+		while(lastval <= finval) {
+			fprintf(stdout,"INFO: %d\n",lastval);
+			lastval++;
+		}
+	} else if(lastval > finval) {
+		lastval--;
+		while(lastval >= finval) {
+			fprintf(stdout,"INFO: %d\n",lastval);
+			lastval--;
+		}
+	}
+	fflush(stdout);
+}
+
+/************************** ELIMINATE_DUPLTEXT *************************/
+
+void eliminate_dupltext(void)
+{
+	int m,n,k;
+	for(n=0;n<stringscnt-1;n++) {
+		for(m=n+1;m<stringscnt;m++) {
+			if(!strcmp(strings[n],strings[m])) {
+				for(k = m;k < stringscnt-1; k++)
+					strings[k] = strings[k+1];
+				m--;
+				stringscnt--;
+			}
+		}
+	}
+	for(n=0; n < stringscnt;n++)
+		do_stringout(strings[n]);
+	fflush(stdout);
+}
+
+/************************** RANDOM_WARP *************************/
+
+void random_warp(void)
+{
+	int n, wcnt;
+	float *warpvals, *number2;
+	double lastsum, diff, warp, dummy;
+	FILE *fp;
+	char *p;
+	arraysize = 100;
+	if((warpvals = (float *)malloc(arraysize * sizeof(float)))==NULL) {
+		fprintf(stdout,"ERROR: Out of memory.\n");
+		fflush(stdout);
+		return;
+	}
+	if((fp = fopen(string,"r"))==NULL) {
+		sprintf(errstr,"Cannot open infile %s\n",string);
+		do_error();
+	}
+	wcnt = 0;
+	while(fgets(temp,20000,fp)!=NULL) {
+		p = temp;
+		while(strgetfloat(&p,&dummy)) {
+			warpvals[wcnt] = (float)dummy;
+			if(++wcnt >= arraysize) {
+				arraysize += BIGARRAY;
+				if((number2=(float *)malloc(arraysize*sizeof(float)))==NULL) {
+					sprintf(errstr,"Out of memory for more warp values at %d numbers\n",cnt);
+					do_error();
+				}
+				memcpy((void *)number2,(void *)warpvals,cnt * sizeof(float));
+				warpvals = number2;
+			}
+		}
+	}
+	fclose(fp);
+	if(wcnt ==0 || (wcnt & 1)) {
+		sprintf(errstr,"Invalid or missing warp data.\n");
+		do_error();
+	}
+	lastsum = number[0];
+	do_valout(lastsum);
+	for(n=1;n<cnt;n++) {
+		diff = number[n] - number[n-1];
+		warp = readbrk(warpvals,number[n],wcnt);
+		warp = (((drand48() * 2.0) - 1.0) * warp) + 1.0;
+		diff *= warp;
+		lastsum += diff;
+		do_valout(lastsum);
+	}
+}
+
+double readbrk(float *warpvals,double time,int wcnt)
+{
+	int n, got = 0;
+	double wlasttime = 0.0, wlastval=0.0, wthistime=0.0, wthisval=0.0, val;
+	double timeratio, valdiff;
+	for(n = 0; n< wcnt; n+= 2) {
+		if(warpvals[n] < time) {
+			wlasttime = warpvals[n]; 
+			wlastval  = warpvals[n+1]; 
+		} else {
+			wthistime = warpvals[n];
+			wthisval  = warpvals[n+1]; 
+			got = 1;
+			break;
+		}
+	}
+	if(!got)
+		return (double)warpvals[wcnt - 1];
+	valdiff   = wthisval  - wlastval;
+	timeratio = (time - wlasttime)/(wthistime - wlasttime);
+	val = (valdiff * timeratio) + wlastval;
+	return val;
+}
+

+ 1709 - 0
dev/tabedit/columns6.c

@@ -0,0 +1,1709 @@
+/*
+ * 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 <columns.h>
+#include <cdplib.h>
+#include <time.h>
+
+static void sort_set(double *set,int setcnt);
+static void do_search(double thisval,double error,int **adjusted);
+static void adjust_all_vals(double thisval,double gap,int n,int m);
+
+/************************************** COMPRESS_SEQUENCE ****************************************
+ *
+ * parameter is interval compression multiplier.
+ */
+
+void compress_sequence(int multi)
+{
+	int n;
+	int m, hdcnt = ifactor;
+	char temp[200];
+	double interval, nunote;
+	if(multi) {
+		sprintf(errstr,"%lf",number[0]);
+		for(n=1;n< hdcnt;n++) {
+			sprintf(temp,"  %lf",number[n]);
+			strcat(errstr,temp);
+		}
+		strcat(errstr,"\n");
+		fprintf(stdout,"INFO: %s\n",errstr);
+		for(n = 0,m = hdcnt;m < cnt;n++, m++)
+			number[n] = number[m];
+		cnt -= hdcnt;
+	}
+	if(multi) {
+		fprintf(stdout,"INFO: %d  %lf  %lf  %lf  %lf\n",(int)number[0],number[1],number[2],number[3],number[4]);
+		nunote = number[2];
+		for(n=5;n<cnt;n+=5) {
+			interval = (number[n+2] - number[n-3]) * factor;
+			nunote += interval;
+			fprintf(stdout,"INFO: %d  %lf  %lf  %lf  %lf\n",(int)number[n],number[n+1],nunote,number[n+3],number[n+4]);
+		}
+	} else {
+		for(n=0;n<cnt;n+=3)
+			fprintf(stdout,"INFO: %lf  %lf  %lf\n",number[n],number[n+1] * factor,number[n+2]);
+	}
+	fflush(stdout);
+}
+
+/************************************** TRANSPOSE_SEQUENCE ****************************************
+ *
+ * parameter is transposition in semitones.
+ */
+
+void transpose_sequence(int multi)
+{
+	int n;
+	int m, hdcnt = ifactor;
+	char temp[200];
+	if(multi) {
+		sprintf(errstr,"%lf",number[0]);
+		for(n=1;n< hdcnt;n++) {
+			sprintf(temp,"  %lf",number[n]);
+			strcat(errstr,temp);
+		}
+		strcat(errstr,"\n");
+		fprintf(stdout,"INFO: %s\n",errstr);
+		for(n = 0,m = hdcnt;m < cnt;n++, m++)
+			number[n] = number[m];
+		cnt -= hdcnt;
+	}
+	if(multi) {
+		for(n=0;n<cnt;n+=5)
+			fprintf(stdout,"INFO: %d  %lf  %lf  %lf  %lf\n",(int)number[n],number[n+1],number[n+2] + factor,number[n+3],number[n+4]);
+	} else {
+		for(n=0;n<cnt;n+=3)
+			fprintf(stdout,"INFO: %lf  %lf  %lf\n",number[n],number[n+1] + factor,number[n+2]);
+	}
+	fflush(stdout);
+}
+
+/************************************** P_INVERTSET_SEQUENCE *****************************************/
+
+void p_invertset_sequence(int multi)
+{
+	double  *set;
+	int setcnt, n, gotit, q;
+	int m, hdcnt = ifactor;
+	char temp[200];
+	if(multi) {
+		sprintf(errstr,"%lf",number[0]);
+		for(n=1;n< hdcnt;n++) {
+			sprintf(temp,"  %lf",number[n]);
+			strcat(errstr,temp);
+		}
+		strcat(errstr,"\n");
+		fprintf(stdout,"INFO: %s\n",errstr);
+		for(n = 0,m = hdcnt;m < cnt;n++, m++)
+			number[n] = number[m];
+		cnt -= hdcnt;
+	}
+	if((set = (double *)malloc(cnt * sizeof(double)))==NULL) {
+		fprintf(stdout,"ERROR: Insufficient memory to store pitch set.\n");
+		fflush(stdout);
+		exit(1);
+	}
+	setcnt = 0;
+	if(multi) {
+		for(n=2;n<cnt;n+=5) {
+			gotit = 0;
+			for(q = 0; q < setcnt; q++) {
+				if(flteq(number[n],set[q])) {
+					gotit = 1;
+					break;
+				}
+			}
+			if(!gotit)
+				set[setcnt++] = number[n];
+		}
+		sort_set(set,setcnt);
+
+		for(n=2;n<cnt;n+=5) {
+			for(q=0;q<setcnt;q++) {
+				if(flteq(number[n],set[q])) {
+					number[n] = set[setcnt - 1 - q];
+					break;
+				}
+			}
+		}
+		for(n=0;n<cnt;n+=5) 
+			fprintf(stdout,"INFO: %d  %lf  %lf  %lf  %lf\n",(int)number[n],number[n+1],number[n+2],number[n+3],number[n+4]);
+	} else {
+		for(n=1;n<cnt;n+=3) {
+			gotit = 0;
+			for(q = 0; q < setcnt; q++) {
+				if(flteq(number[n],set[q])) {
+					gotit = 1;
+					break;
+				}
+			}
+			if(!gotit)
+				set[setcnt++] = number[n];
+		}
+		sort_set(set,setcnt);
+
+		for(n=1;n<cnt;n+=3) {
+			for(q=0;q<setcnt;q++) {
+				if(flteq(number[n],set[q])) {
+					number[n] = set[setcnt - 1 - q];
+					break;
+				}
+			}
+		}
+		for(n=0;n<cnt;n+=3) 
+			fprintf(stdout,"INFO: %lf  %lf  %lf\n",number[n],number[n+1],number[n+2]);
+	}
+	fflush(stdout);
+}
+
+/************************************** P_EXPANDSET_SEQUENCE *****************************************
+ *
+ * parameter is set expansion multiplier.
+ */
+
+void p_expandset_sequence(int multi)
+{
+	double  *set=NULL, transpos;
+	int setcnt, n, gotit, q, qn, qq, qoct;
+	int m, hdcnt = ifactor;
+	int lastsetpos=0, lastnusetpos=0, thissetpos, setstep;
+	char temp[200];
+	if(multi) {
+		sprintf(errstr,"%lf",number[0]);
+		for(n=1;n< hdcnt;n++) {
+			sprintf(temp,"  %lf",number[n]);
+			strcat(errstr,temp);
+		}
+		strcat(errstr,"\n");
+		fprintf(stdout,"INFO: %s\n",errstr);
+		for(n = 0,m = hdcnt;m < cnt;n++, m++)
+			number[n] = number[m];
+		cnt -= hdcnt;
+	}
+	if(factor <= 1.0) {
+		fprintf(stdout,"ERROR: Set expansion must be > 1\n");
+		fflush(stdout);
+		exit(1);
+	}
+	ifactor = (int)round(factor + 0.5);
+	if((set = (double *)malloc((cnt * ifactor) * sizeof(double)))==NULL) {
+		fprintf(stdout,"ERROR: Insufficient memory to store pitch set.\n");
+		fflush(stdout);
+		exit(1);
+	}
+	setcnt = 0;
+	if(multi) {
+		for(n=2;n<cnt;n+=5) {
+			gotit = 0;
+			for(q = 0; q < setcnt; q++) {
+				if(flteq(number[n],set[q])) {
+					gotit = 1;
+					break;
+				}
+			}
+			if(!gotit)
+				set[setcnt++] = number[n];
+		}
+		sort_set(set,setcnt);
+		fprintf(stdout,"INFO: %d  %lf  %lf  %lf  %lf\n",(int)number[0],number[1],number[2],number[3],number[4]);
+		for(q=0;q<setcnt;q++) {
+			if(flteq(number[2],set[q])) {				/* find which set-member this is */
+				lastsetpos = q;
+				lastnusetpos = q;
+				break;
+			}
+		}
+		for(n=7;n<cnt;n+=5) {
+			for(q=0;q<setcnt;q++) {
+				if(flteq(number[n],set[q])) {				/* find which set-member this is */
+					thissetpos = q;
+					setstep = thissetpos - lastsetpos;
+					setstep = (int)round(setstep * factor);
+					qn = lastnusetpos + setstep;
+					lastsetpos = thissetpos;
+					lastnusetpos = qn;
+					if(qn >= setcnt) {						/* if beyond existing set */			
+						qq = qn%setcnt;						/* cyclically find appropriate set member */
+						qoct = qn/setcnt;
+						transpos = 12.0 * qoct;
+						number[n] = set[qq] + transpos;
+					} else if(qn < 0) {						/* if below existing set */			
+						qoct = 0;							/* simil */
+						while(qn < 0) {
+							qn += setcnt;
+							qoct++;
+						}
+						transpos = -(12.0 * qoct);
+						number[n] = set[qn] + transpos;
+					} else
+						number[n] = set[qn];
+					break;
+				}
+			}
+		}
+		for(n=5;n<cnt;n+=5) 
+			fprintf(stdout,"INFO: %d  %lf  %lf  %lf  %lf\n",(int)number[n],number[n+1],number[n+2],number[n+3],number[n+4]);
+	} else {
+		for(n=1;n<cnt;n+=3) {
+			gotit = 0;
+			for(q = 0; q < setcnt; q++) {
+				if(flteq(number[n],set[q])) {
+					gotit = 1;
+					break;
+				}
+			}
+			if(!gotit)
+				set[setcnt++] = number[n];
+		}
+		sort_set(set,setcnt);
+		for(n=1;n<cnt;n+=3) {
+			for(q=0;q<setcnt;q++) {
+				if(flteq(number[n],set[q])) {				/* find which set-member this is */
+					qn = (int)round((q+1) * factor) - 1;	/* expand set-position */
+					if(qn >= setcnt) {						/* if beyond existing set */			
+						qq = qn%setcnt;						/* cyclically find appropriate set member */
+						qoct = qn/setcnt;
+						transpos = 12.0 * qoct;
+						number[n] = set[qq] + transpos;
+					} else
+						number[n] = set[qn];
+					break;
+				}
+			}
+		}
+		for(n=0;n<cnt;n+=3) 
+			fprintf(stdout,"INFO: %lf  %lf  %lf\n",number[n],number[n+1],number[n+2]);
+	}
+	fflush(stdout);
+}
+
+/************************************** P_INVERT_SEQUENCE *****************************************/
+
+void p_invert_sequence(int multi)
+{
+	int n;
+	double adjust;
+	int m, hdcnt = ifactor;
+	char temp[200];
+	if(multi) {
+		sprintf(errstr,"%lf",number[0]);
+		for(n=1;n< hdcnt;n++) {
+			sprintf(temp,"  %lf",number[n]);
+			strcat(errstr,temp);
+		}
+		strcat(errstr,"\n");
+		fprintf(stdout,"INFO: %s\n",errstr);
+		for(n = 0,m = hdcnt;m < cnt;n++, m++)
+			number[n] = number[m];
+		cnt -= hdcnt;
+	}
+
+	if(multi) {
+		adjust = 2 * number[2];
+		for(n=0;n<cnt;n+=5)
+			fprintf(stdout,"INFO: %d  %lf  %lf  %lf  %lf\n",(int)number[n],number[n+1],adjust - number[n+2],number[n+3],number[n+4]);
+	} else {
+		adjust = 2 * number[1];
+		for(n=0;n<cnt;n+=3) 
+			fprintf(stdout,"INFO: %lf  %lf  %lf\n",number[n],adjust - number[n+1],number[n+2]);
+	}
+	fflush(stdout);
+}
+
+/************************************** T_REVERSE_SEQUENCE ****************************************/
+
+void t_reverse_sequence(int multi)		
+{
+	double totaldur;
+	int tend, n, te;
+	int m, hdcnt = ifactor;
+	char temp[200];
+	if(multi) {
+		sprintf(errstr,"%lf",number[0]);
+		for(n=1;n< hdcnt;n++) {
+			sprintf(temp,"  %lf",number[n]);
+			strcat(errstr,temp);
+		}
+		strcat(errstr,"\n");
+		fprintf(stdout,"INFO: %s\n",errstr);
+		for(n = 0,m = hdcnt;m < cnt;n++, m++)
+			number[n] = number[m];
+		cnt -= hdcnt;
+	}
+	totaldur = 0.0;
+	tend = cnt - 4;
+
+	if(multi) {
+		for(n=0,te = tend;n<cnt;n+=5, te-=5) {
+			fprintf(stdout,"INFO: %d  %lf  %lf  %lf  %lf\n",(int)number[n],totaldur,number[n+2],number[n+3],number[n+4]);
+			totaldur += number[te] - number[te - 5];
+		}
+	} else {
+		for(n=0,te = tend;n<cnt;n+=3, te-=3) {
+			fprintf(stdout,"INFO: %lf  %lf  %lf\n",totaldur,number[n+1],number[n+2]);
+			totaldur += number[te] - number[te - 3];
+		}
+	}
+	fflush(stdout);
+}
+
+/************************************** P_REVERSE_SEQUENCE ****************************************/
+
+void p_reverse_sequence(int multi)		
+{
+	int n, pe;
+	int pend;
+	int m, hdcnt = ifactor;
+	char temp[200];
+	if(multi) {
+		sprintf(errstr,"%lf",number[0]);
+		for(n=1;n< hdcnt;n++) {
+			sprintf(temp,"  %lf",number[n]);
+			strcat(errstr,temp);
+		}
+		strcat(errstr,"\n");
+		fprintf(stdout,"INFO: %s\n",errstr);
+		for(n = 0,m = hdcnt;m < cnt;n++, m++)
+			number[n] = number[m];
+		cnt -= hdcnt;
+	}
+	pend = cnt-3;
+	if(multi) {
+		for(n=0, pe = pend;n<cnt;n+=5, pe -= 5)
+			fprintf(stdout,"INFO: %d  %lf  %lf  %lf  %lf\n",(int)number[n],number[n+1],number[pe],number[n+3],number[n+4]);
+	} else {
+		for(n=0, pe = pend;n<cnt;n+=3, pe -= 3)
+			fprintf(stdout,"INFO: %lf  %lf  %lf\n",number[n],number[pe],number[n+2]);
+	}
+	fflush(stdout);
+}
+
+/************************************** A_REVERSE_SEQUENCE ****************************************/
+
+void a_reverse_sequence(int multi)		
+{
+	int n, ae;
+	int m, hdcnt = ifactor;
+	int aend = cnt - 2;
+	char temp[200];
+	if(multi) {
+		sprintf(errstr,"%lf",number[0]);
+		for(n=1;n< hdcnt;n++) {
+			sprintf(temp,"  %lf",number[n]);
+			strcat(errstr,temp);
+		}
+		strcat(errstr,"\n");
+		fprintf(stdout,"INFO: %s\n",errstr);
+		for(n = 0,m = hdcnt;m < cnt;n++, m++)
+			number[n] = number[m];
+		cnt -= hdcnt;
+	}
+	if(multi) {
+		for(n=0, ae = aend;n<cnt;n+=5, ae -= 5)
+			fprintf(stdout,"INFO: %d  %lf  %lf  %lf  %lf\n",(int)number[n],number[n+1],number[n+2],number[ae],number[n+4]);
+	} else {
+		for(n=0, ae = cnt-1;n<cnt;n+=3, ae -= 3)
+			fprintf(stdout,"INFO: %lf  %lf  %lf\n",number[n],number[n+1],number[ae]);
+	}
+	fflush(stdout);
+}
+
+/************************************** PA_REVERSE_SEQUENCE ***************************************/
+
+void pa_reverse_sequence(int multi)		
+{
+	int n, pe;
+	int pend;
+	int m, hdcnt = ifactor;
+	char temp[200];
+	if(multi) {
+		sprintf(errstr,"%lf",number[0]);
+		for(n=1;n< hdcnt;n++) {
+			sprintf(temp,"  %lf",number[n]);
+			strcat(errstr,temp);
+		}
+		strcat(errstr,"\n");
+		fprintf(stdout,"INFO: %s\n",errstr);
+		for(n = 0,m = hdcnt;m < cnt;n++, m++)
+			number[n] = number[m];
+		cnt -= hdcnt;
+	}
+	pend = cnt-3;
+	if(multi) {
+		for(n=0, pe = pend;n<cnt;n+=5, pe -= 5)
+			fprintf(stdout,"INFO: %d  %lf  %lf  %lf  %lf\n",(int)number[n],number[n+1],number[pe],number[pe+1],number[n+4]);
+	} else {
+		for(n=0, pe = pend;n<cnt;n+=3, pe -= 3)
+			fprintf(stdout,"INFO: %lf  %lf  %lf\n",number[n],number[pe],number[pe+1]);
+	}
+	fflush(stdout);
+}
+
+/************************************** TP_REVERSE_SEQUENCE ***************************************/
+
+void tp_reverse_sequence(int multi)		
+{
+	double totaldur;
+	int tend, n, te;
+	int m, hdcnt = ifactor;
+	char temp[200];
+	if(multi) {
+		sprintf(errstr,"%lf",number[0]);
+		for(n=1;n< hdcnt;n++) {
+			sprintf(temp,"  %lf",number[n]);
+			strcat(errstr,temp);
+		}
+		strcat(errstr,"\n");
+		fprintf(stdout,"INFO: %s\n",errstr);
+		for(n = 0,m = hdcnt;m < cnt;n++, m++)
+			number[n] = number[m];
+		cnt -= hdcnt;
+	}
+	totaldur = 0.0;
+	tend = cnt-4;
+	if(multi) {
+		for(n=0,te = tend;n<cnt;n+=5, te-=5) {
+			fprintf(stdout,"INFO: %d  %lf  %lf  %lf  %lf\n",(int)number[n],totaldur,number[te+1],number[n+3],number[n+4]);
+			totaldur += number[te] - number[te - 5];
+		}
+	} else {
+		for(n=0,te = tend;n<cnt;n+=3, te-=3) {
+			fprintf(stdout,"INFO: %lf  %lf  %lf\n",totaldur,number[te+1],number[n+2]);
+			totaldur += number[te] - number[te - 3];
+		}
+	}
+	fflush(stdout);
+}
+
+/************************************** TA_REVERSE_SEQUENCE ***************************************/
+
+void ta_reverse_sequence(int multi)		
+{
+	double totaldur;
+	int tend, n, te;
+	int m, hdcnt = ifactor;
+	char temp[200];
+	if(multi) {
+		sprintf(errstr,"%lf",number[0]);
+		for(n=1;n< hdcnt;n++) {
+			sprintf(temp,"  %lf",number[n]);
+			strcat(errstr,temp);
+		}
+		strcat(errstr,"\n");
+		fprintf(stdout,"INFO: %s\n",errstr);
+		for(n = 0,m = hdcnt;m < cnt;n++, m++)
+			number[n] = number[m];
+		cnt -= hdcnt;
+	}
+	totaldur = 0.0;
+	tend = cnt-4;
+	if(multi) {
+		for(n=0,te = tend;n<cnt;n+=5, te-=5) {
+			fprintf(stdout,"INFO: %d  %lf  %lf  %lf  %lf\n",(int)number[n],totaldur,number[n+2],number[te+2],number[n+4]);
+			totaldur += number[te] - number[te - 5];
+		}
+	} else {
+		for(n=0,te = tend;n<cnt;n+=3, te-=3) {
+			fprintf(stdout,"INFO: %lf  %lf  %lf\n",totaldur,number[n+1],number[te+2]);
+			totaldur += number[te] - number[te - 3];
+		}
+	}
+	fflush(stdout);
+}
+
+/************************************** TPA_REVERSE_SEQUENCE **************************************/
+
+void tpa_reverse_sequence(int multi)		
+{
+	double totaldur;
+	int tend, te, n;
+	int m, hdcnt = ifactor;
+	char temp[200];
+	if(multi) {
+		sprintf(errstr,"%lf",number[0]);
+		for(n=1;n< hdcnt;n++) {
+			sprintf(temp,"  %lf",number[n]);
+			strcat(errstr,temp);
+		}
+		strcat(errstr,"\n");
+		fprintf(stdout,"INFO: %s\n",errstr);
+		for(n = 0,m = hdcnt;m < cnt;n++, m++)
+			number[n] = number[m];
+		cnt -= hdcnt;
+	}
+	totaldur = 0.0;
+	tend = cnt-4;
+	if(multi) {
+		for(n = 0,te = tend;te >= 0;te-=5,n+=5) {
+			fprintf(stdout,"INFO: %d  %lf  %lf  %lf  %lf\n",(int)number[n],totaldur,number[te+1],number[te+2],number[n+4]);
+			totaldur += number[te] - number[te - 5];
+		}
+	} else {
+		for(te = tend;te >= 0;te-=3) {
+			fprintf(stdout,"INFO: %lf  %lf  %lf\n",totaldur,number[te+1],number[te+2]);
+			totaldur += number[te] - number[te - 3];
+		}
+	}
+	fflush(stdout);
+}
+
+/************************************** LOOP_SEQUENCE **************************************
+ *
+ * params are loopcnt and lastdur.
+ */
+
+void loop_sequence(int multi)		
+{
+	int n, m, loopcnt = (int)factor;
+	double lastdur = thresh, totaldur, basetime;
+	int hdcnt = ifactor;
+	char temp[200];
+	if(multi) {
+		sprintf(errstr,"%lf",number[0]);
+		for(n=1;n< hdcnt;n++) {
+			sprintf(temp,"  %lf",number[n]);
+			strcat(errstr,temp);
+		}
+		strcat(errstr,"\n");
+		fprintf(stdout,"INFO: %s\n",errstr);
+		for(n = 0,m = hdcnt;m < cnt;n++, m++)
+			number[n] = number[m];
+		cnt -= hdcnt;
+		totaldur = number[cnt-4] + lastdur;
+	} else {
+		totaldur = number[cnt-3] + lastdur;
+	}
+	if(lastdur <= 0.0) {
+		fprintf(stdout,"ERROR: final event duration is <= zero\n");
+		fflush(stdout);
+		exit(1);
+	}
+	if(loopcnt < 2) {
+		fprintf(stdout,"ERROR: Loopcnt is <= 1\n");
+		fflush(stdout);
+		exit(1);
+	}
+	basetime = 0.0;
+	for(n = 0; n<loopcnt; n++) {
+		if(multi) {
+			for(m=0;m < cnt; m+=5)
+				fprintf(stdout,"INFO: %d  %lf  %lf  %lf  %lf\n",(int)number[m],number[m+1] + basetime,number[m+2],number[m+3],number[m+4]);
+		} else {
+			for(m=0;m < cnt; m+=3)
+				fprintf(stdout,"INFO: %lf  %lf  %lf\n",number[m] + basetime,number[m+1],number[m+2]);
+		}
+		basetime += totaldur;
+	}
+	fflush(stdout);
+}
+
+/************************************** ABUT_SEQUENCES **************************************
+ *
+ * Read two tables, as strings, like 'jj'
+ */
+
+void abut_sequences(int multi)
+{
+	int n, m, hdcnt;
+	double lasttime, time;
+	char temp[264];
+	if(factor <= 0.0) {
+		fprintf(stdout,"ERROR: final event duration is less than or equal to zero\n");
+		fflush(stdout);
+		exit(1);
+	}
+	if(multi) {
+		hdcnt = ifactor;
+		sprintf(errstr,"%lf",number[0]);
+		for(n=1;n< hdcnt;n++) {
+			sprintf(temp,"  %lf",number[n]);
+			strcat(errstr,temp);
+		}
+		strcat(errstr,"\n");
+ 		fprintf(stdout,"INFO: %s\n",errstr);
+		for(n = 0,m = hdcnt;m < cnt;n++, m++)
+			number[n] = number[m];
+		cnt -= hdcnt;
+		firstcnt -= hdcnt;
+
+		for(n = 0; n < firstcnt; n+= 5)
+			fprintf(stdout,"INFO: %d  %lf  %lf  %lf  %lf\n",(int)number[n],number[n+1],number[n+2],number[n+3],number[n+4]);
+		lasttime = number[n-4];
+		lasttime += factor;
+		for(n = firstcnt + hdcnt; n < cnt; n+= 5) {
+			time = number[n+1] + lasttime;
+			fprintf(stdout,"INFO: %d  %lf  %lf  %lf  %lf\n",(int)number[n],time,number[n+2],number[n+3],number[n+4]);
+		}
+	} else {
+		for(n = 0; n < cnt; n+= 3)
+			fprintf(stdout,"INFO: %s  %s  %s\n",strings[n],strings[n+1],strings[n+2]);
+		lasttime = atof(strings[n-3]);
+		lasttime += factor;
+		for(n = cnt; n < stringscnt; n+= 3) {
+			time = atof(strings[n]) + lasttime;
+			sprintf(temp,"%lf",time);
+			fprintf(stdout,"INFO: %s  %s  %s\n",temp,strings[n+1],strings[n+2]);
+		}
+	}
+	fflush(stdout);
+}
+
+/************************************** SORT_SET **************************************/
+
+void sort_set(double *set,int setcnt)
+{
+	int n, m;
+	double temp;
+	for(n=0;n<setcnt-1;n++) {
+		for(m = n; m<setcnt; m++) {
+			if(set[m] < set[n]) {
+				temp = set[n];
+				set[n] = set[m];
+				set[m] = temp;
+			}
+		}
+	}
+}
+
+/************************************** uptempo_sequence ****************************************
+ *
+ * parameter is tempo multiplier.
+ */
+
+void uptempo_sequence(int multi)		
+{
+	int n;
+	int m, hdcnt = ifactor;
+	char temp[200];
+	if(multi) {
+		sprintf(errstr,"%lf",number[0]);
+		for(n=1;n< hdcnt;n++) {
+			sprintf(temp,"  %lf",number[n]);
+			strcat(errstr,temp);
+		}
+		strcat(errstr,"\n");
+		fprintf(stdout,"INFO: %s\n",errstr);
+		for(n = 0,m = hdcnt;m < cnt;n++, m++)
+			number[n] = number[m];
+		cnt -= hdcnt;
+	}
+	if(multi) {
+		for(n=0;n<cnt;n+=5)
+			fprintf(stdout,"INFO: %d  %lf  %lf  %lf  %lf\n",(int)number[n],number[n+1] * factor,number[n+2],number[n+3],number[n+4]);
+	} else {
+		for(n=0;n<cnt;n+=3)
+			fprintf(stdout,"INFO: %lf  %lf  %lf\n",number[n] * factor,number[n+1],number[n+2]);
+	}
+	fflush(stdout);
+}
+
+/************************************** ACCEL_SEQUENCE ****************************************
+ *
+ * parameter is multiplier of final event-time, thresh is curve of accel.
+ */
+
+void accel_sequence(int multi)		
+{
+	int n;
+	double accel_step = (1.0/factor) - 1.0, lasttime;
+	double convertor, frac, accel, time, dur;
+	int m, hdcnt = ifactor;
+	char temp[200];
+	if(multi) {
+		sprintf(errstr,"%lf",number[0]);
+		for(n=1;n< hdcnt;n++) {lasttime = number[cnt-3];
+			sprintf(temp,"  %lf",number[n]);
+			strcat(errstr,temp);
+		}
+		strcat(errstr,"\n");
+		fprintf(stdout,"INFO: %s\n",errstr);
+		for(n = 0,m = hdcnt;m < cnt;n++, m++)
+			number[n] = number[m];
+		cnt -= hdcnt;
+		lasttime = number[cnt-4];
+	} else {
+		lasttime = number[cnt-3];
+	}
+	convertor = 1.0/lasttime;
+	if(multi) {
+		for(n=0;n<cnt;n+=5) {
+			frac = pow(number[n+1] * convertor,thresh);
+			accel = 1.0 + (accel_step * frac);
+			time = number[n+1] * accel;
+			dur = number[n+4] * accel;
+			fprintf(stdout,"INFO: %d  %lf  %lf  %lf  %lf\n",(int)number[n],time,number[n+2],number[n+3],dur);
+		}
+	} else {
+		for(n=0;n<cnt;n+=3) {
+			frac = pow(number[n] * convertor,thresh);
+			accel = 1.0 + (accel_step * frac);
+			time = number[n] * accel;
+			fprintf(stdout,"INFO: %lf  %lf  %lf\n",time,number[n+1],number[n+2]);
+		}
+	}
+	fflush(stdout);
+}
+
+/************************************** MEAN_TEMPO *****************************************/
+
+void mean_tempo()		
+{
+	factor = (double)(60 * (cnt-1))/(number[cnt-1] - number[0]);
+	factor = (round(factor * 100.0))/100.0;
+	fprintf(stdout,"WARNING: Mean Tempo is %.2lf (assuming times are approx evenly spaced)\n",factor);
+	fflush(stdout);
+}
+
+/************************************** TIME_TO_CROTCHETS *****************************************/
+
+void time_to_crotchets(int beatvals) {
+	double crotchet = factor;
+	double semibrev = 4 * crotchet;
+	double minim = 2 * crotchet;
+	double quaver = crotchet / 2;	
+	double semiquav = crotchet / 4;
+	double tripquav = crotchet / 3;
+	double tripsemiquav = crotchet / 6;
+	double demisemiquav = crotchet / 8;
+	double trip	= minim / 3;
+	int n, m;
+	int **adjusted;
+	if ((adjusted = (int **)malloc(cnt * sizeof(int *)))==NULL) {
+		fprintf(stdout,"ERROR: Insufficient memory\n");
+		fflush(stdout);
+		exit(1);
+	}
+	for(n=0;n<cnt;n++) {
+		if ((adjusted[n] = (int *)malloc(cnt * sizeof(int)))==NULL) {
+			fprintf(stdout,"ERROR: Insufficient memory\n");
+			fflush(stdout);
+			exit(1);
+		}
+		for(m=0;m<cnt;m++)
+			adjusted[n][m] = 0;
+	}
+	do_search(semibrev,tripsemiquav,adjusted);
+	do_search(minim,tripsemiquav,adjusted);
+	do_search(crotchet,tripsemiquav,adjusted);
+	do_search(tripquav,tripsemiquav/2,adjusted);
+	do_search(trip,tripsemiquav/2,adjusted);
+	do_search(quaver,demisemiquav,adjusted);
+	do_search(semiquav,tripsemiquav/2,adjusted);
+
+	if(beatvals) {
+		for(n=1;n<cnt; n++)
+			number[n-1] = number[n] - number[n-1];
+		cnt--;
+	}
+	for(n=0;n<cnt;n++) {
+		number[n] /= crotchet;
+		number[n] = (round(number[n] * 1000))/1000.0;
+	}
+	for(n=0;n<cnt;n++)
+		fprintf(stdout,"INFO: %lf\n",number[n]);
+	fflush(stdout);
+}
+
+void do_search(double thisval,double error,int **adjusted) {
+	int n, m;
+	double up = thisval + error;
+	double dn = thisval - error;
+	double gap;
+	for(n=0; n<cnt-1; n++) {
+		for(m=n+1; m<cnt; m++) {
+			if(adjusted[n][m])
+				continue;
+			gap = number[m] - number[n];
+			if(gap > dn) {
+				if(gap < up) {
+					adjust_all_vals(thisval,gap,n,m);
+					adjusted[n][m] = 1;
+				} else
+					break;
+			}
+		}
+	}
+}
+
+void adjust_all_vals(double thisval,double gap,int n,int m) {
+	
+	int k;
+	double thisgap;
+	double adjust_within = thisval/gap;
+	double discrep_beyond = thisval - gap;
+	number[m] = number[n] + thisval;
+	for(k = m+1; k < cnt; k++)
+		number[k] += discrep_beyond;
+	for(k = n+1; k < m; k++) {
+		thisgap = number[k] - number[n];
+		number[k] = number[n] + (thisgap * adjust_within);
+	}
+}
+
+/************************************** ROTATE_LIST *****************************************/
+
+void rotate_list(int reversed)
+{
+	int n;
+	if(reversed) {
+		for(n=1;n < stringscnt; n++)
+			fprintf(stdout,"INFO: %s\n",strings[n]);
+		fprintf(stdout,"INFO: %s\n",strings[0]);
+	} else {
+		fprintf(stdout,"INFO: %s\n",strings[stringscnt - 1]);
+		for(n=0;n < stringscnt-1; n++)
+			fprintf(stdout,"INFO: %s\n",strings[n]);
+	}
+	fflush(stdout);
+}	
+
+/************************************** SPLICE_POS *****************************************/
+
+#define SHSECSIZE 256
+
+void splice_pos(void)
+{
+	double splicelen = (number[cnt]+ .5)/1000.0;
+	int srate  = round(number[cnt+1]);
+	int chans  = round(number[cnt+2]);
+	int chcnt  = round(number[cnt+3]);
+	int splen = round(splicelen * srate) * chans;
+	int seccnt, k1, k2;
+	int n;
+	if(((seccnt = splen / SHSECSIZE) * SHSECSIZE) < splen)
+		seccnt++;
+	splen = seccnt * SHSECSIZE;
+	splen /= chcnt;
+	for(n=0;n<cnt;n++) {
+		if((k1 = round(number[n]) - splen) < 0) {
+			fprintf(stdout,"ERROR: Splice falls before zero.\n");
+			exit(1);
+		}
+	}
+	for(n=0;n<cnt;n++) {
+		k1 = round(number[n]) - splen;
+		k2 = round(number[n]) + splen;
+		fprintf(stdout,"INFO: %d  %d\n",k1,k2);
+	}
+	fflush(stdout);
+}
+
+/************************************** WARP_TIMES *****************************************/
+
+void time_warp()
+{
+	int m, n;
+	double thistime, nexttime, lasttime = 0.0, thisval, nextval, step, frac, val, sum, gap;
+	m = firstcnt;
+	for(n=0;n<firstcnt;n++) {
+		if(n==0) {
+			if(!(flteq(number[n],0.0))) {
+				fprintf(stdout,"ERROR: Invalid 1st value %lf in list of times (must be ZERO)\n",number[n]);
+				exit(1);
+			}
+			number[n] = 0.0;
+			lasttime = number[n];
+		} else if(number[n] <= lasttime) {
+			fprintf(stdout,"ERROR: Times, in list of times, must be in increasing order\n");
+			exit(1);
+		}
+	}	
+	for(m=firstcnt+1;m<cnt;m+=2) {
+		if(number[m] < FLTERR) {
+			fprintf(stdout,"ERROR: Invalid value %lf in warping file (must be > 0)\n",number[m]);
+			exit(1);
+		}
+	}
+	fprintf(stdout,"INFO: %lf\n",0.0);
+	sum = 0.0;
+	m = firstcnt;
+	for(n=1;n<firstcnt;n++) {
+		while(number[m] <= number[n]) {
+			if((m += 2) >= cnt)
+				break;
+		}
+		if(m < cnt) {
+			nexttime = number[m];
+			nextval  = number[m+1];
+			thistime = number[m-2];
+			thisval  = number[m-1];
+			step = nexttime - thistime;
+			frac = (number[n] - thistime)/step;
+			val = ((nextval - thisval) * frac) + thisval;
+		} else {
+			val = number[cnt-1];
+		}
+		gap = number[n] - number[n-1];
+		val *= gap;
+		sum += val;
+		fprintf(stdout,"INFO: %lf\n",sum);
+	}
+	fflush(stdout);
+}
+
+/************************************** LIST_WARP *****************************************/
+
+void list_warp()
+{
+	int m, n;
+	int sizz = firstcnt-1;
+	double index, thistime, nexttime, lasttime, thisval, nextval, step, frac, val;
+	m = firstcnt;
+
+	if(!flteq(number[firstcnt],0.0)) {
+		fprintf(stdout,"ERROR: First time in warping file must be ZERO\n");
+		exit(1);
+	}
+	number[firstcnt] = 0.0;
+	lasttime = number[cnt-2];
+	for(m=firstcnt;m<cnt;m+=2)
+		number[m] /= lasttime;
+	m = firstcnt;
+	for(n=0;n<firstcnt;n++) {
+		index = (double)n/(double)sizz;
+		while(number[m] <= index) {
+			if((m += 2) >= cnt)
+				break;
+		}
+		if(m < cnt) {
+			nexttime = number[m];
+			nextval  = number[m+1];
+			thistime = number[m-2];
+			thisval  = number[m-1];
+			step = nexttime - thistime;
+			frac = (index - thistime)/step;
+			val = ((nextval - thisval) * frac) + thisval;
+		} else
+			val = number[cnt-1];
+
+		fprintf(stdout,"INFO: %lf\n",number[n] * val);
+	}
+	fflush(stdout);
+}
+
+/************************************** BRKWARP_TIMES *****************************************/
+
+void brktime_warp()
+{
+	int m, n;
+	double thistime, nexttime, thisval, nextval, step, frac, val, gap, sum;
+
+	for(m=firstcnt+1;m<cnt;m+=2) {
+		if(number[m] < FLTERR) {
+			fprintf(stdout,"ERROR: Invalid value %lf in warping file (must be > 0)\n",number[m]);
+			exit(1);
+		}
+	}
+	if(!flteq(number[0],0.0)) {
+		fprintf(stdout,"ERROR: Breakpoint file to BE warped must begin at time ZERO\n");
+		exit(1);
+	}
+	number[0] = 0.0;
+	fprintf(stdout,"INFO: %lf  %lf\n",number[0], number[1]);
+	sum = 0.0;
+	m = firstcnt;
+	for(n=2;n<firstcnt;n+=2) {
+		while(number[m] <= number[n]) {
+			if((m += 2) >= cnt)
+				break;
+		}
+		if(m < cnt) {
+			nexttime = number[m];
+			nextval  = number[m+1];
+			thistime = number[m-2];
+			thisval  = number[m-1];
+			step = nexttime - thistime;
+			frac = (number[n] - thistime)/step;
+			val = ((nextval - thisval) * frac) + thisval;
+		} else {
+			val = number[cnt-1];
+		}
+		gap = number[n] - number[n-2];
+		val *= gap;
+		sum += val;
+		fprintf(stdout,"INFO: %lf  %lf\n",sum, number[n+1]);
+	}
+	fflush(stdout);
+}
+
+/************************************** SEQWARP_TIMES *****************************************/
+
+void seqtime_warp()
+{
+	int m, n, OK = 1;
+	double thistime, nexttime, thisval, nextval, step, frac, val, gap, sum, lasttime;
+	if(((firstcnt/3) * 3) != firstcnt)
+		OK = 0;
+	else if(!flteq(number[0],0.0)) 
+		OK = 0;
+	else {
+		number[0] = 0.0;
+		lasttime = number[0];
+		for(n=3;n<firstcnt;n+=3) {
+			if(number[n] <= lasttime) {
+				OK = 0;
+				break;
+			}
+			lasttime = number[n];
+		}
+	}
+	if(!OK) {
+		fprintf(stdout,"ERROR: First file is not a valid sequnce file.\n");
+		exit(1);
+	}
+	m = firstcnt;
+	for(m=firstcnt+1;m<cnt;m+=2) {
+		if(number[m] < FLTERR) {
+			fprintf(stdout,"ERROR: Invalid value %lf in warping file (must be > 0)\n",number[m]);
+			exit(1);
+		}
+	}
+	if(!flteq(number[0],0.0)) {
+		fprintf(stdout,"ERROR: Breakpoint file to BE warped must begin at time ZERO\n");
+		exit(1);
+	}
+	number[0] = 0.0;
+	fprintf(stdout,"INFO: %lf  %lf  %lf\n",number[0],number[1],number[2]);
+	sum = 0.0;
+	m = firstcnt;
+	for(n=3;n<firstcnt;n+=3) {
+		while(number[m] <= number[n]) {
+			if((m += 2) >= cnt)
+				break;
+		}
+		if(m < cnt) {
+			nexttime = number[m];
+			nextval  = number[m+1];
+			thistime = number[m-2];
+			thisval  = number[m-1];
+			step = nexttime - thistime;
+			frac = (number[n] - thistime)/step;
+			val = ((nextval - thisval) * frac) + thisval;
+		} else {
+			val = number[cnt-1];
+		}
+		gap = number[n] - number[n-3];
+		val *= gap;
+		sum += val;
+		fprintf(stdout,"INFO: %lf  %lf  %lf\n",sum, number[n+1], number[n+2]);
+	}
+	fflush(stdout);
+}
+
+/************************************** BRKVAL_WARP *****************************************/
+
+void brkval_warp()
+{
+	int m, n;
+	double thistime, nexttime, thisval, nextval, step, frac, val;
+	if(!flteq(number[0],0.0)) {
+		fprintf(stdout,"ERROR: Breakpoint file to BE warped must begin at time ZERO\n");
+		exit(1);
+	}
+	if(!flteq(number[firstcnt],0.0)) {
+		fprintf(stdout,"ERROR: Warping file must begin at time ZERO\n");
+		exit(1);
+	}
+	m = firstcnt;
+	for(n=2;n<firstcnt;n+=2) {
+		while(number[m] <= number[n]) {
+			if((m += 2) >= cnt)
+				break;
+		}
+		if(m < cnt) {
+			nexttime = number[m];
+			nextval  = number[m+1];
+			thistime = number[m-2];
+			thisval  = number[m-1];
+			step = nexttime - thistime;
+			frac = (number[n] - thistime)/step;
+			val = ((nextval - thisval) * frac) + thisval;
+		} else
+			val = number[cnt-1];
+
+		fprintf(stdout,"INFO: %lf  %lf\n",number[n], number[n+1] * val);
+	}
+	fflush(stdout);
+}
+
+/************************************** DUPLICATE_LIST_AT_STEP *****************************************/
+
+void duplicate_list_at_step()
+{
+	int n, m;
+	double base = 0.0;
+	double step = number[cnt+1];
+	ifactor = round(number[cnt]);
+	step = number[cnt-1] - number[0] + step;
+	for(m=0;m<ifactor;m++) {
+		for(n=0;n<cnt;n++)
+			fprintf(stdout,"INFO: %lf\n",number[n] + base);
+		base += step;
+	}
+	fflush(stdout);
+}
+
+/************************************ TW_PSEUDO_EXP ************************************/
+
+void tw_pseudo_exp()
+{
+	double bottime = number[0];
+	double toptime = number[1];
+	double botval  = number[2];
+	double topval  = number[3];
+	double timefrac = 0.5, valfrac  = 0.333333333333, step;
+	int valbase = ifactor+1;
+	int div, n, index;
+	int mask = 1, span;
+	cnt = ifactor;
+	if(topval < botval)
+		valfrac *= 2.0;
+	while(mask < (cnt>>1)) {
+		if(cnt & mask) {
+			fprintf(stdout,"ERROR: Number of steps must be a multiple of 2.\n");
+			fflush(stdout);
+			exit(1);
+		}
+		mask <<= 1;
+	}	
+	free(number);
+	if((number = (double *)malloc((cnt+1) * 2 * sizeof(double)))==NULL) {
+		fprintf(stdout,"ERROR: Insufficient memory to store interpolated values.\n");
+		fflush(stdout);
+		exit(1);
+	}
+	number[0]	= bottime;	
+	number[cnt]	= toptime;	
+	number[cnt+1]	  = botval;	
+	number[(cnt*2)+1] = topval;	
+
+	div = 2;
+	span = cnt/2;
+	while(div <= cnt) {
+		n = 1;
+		while(n < div) {
+			index = (cnt * n)/div;						/* ODD denominators, factor of 2 numerators */
+			step = number[index+span] - number[index-span];	/* i.e. 1/2 : 1/4,3/4 : 1/8,3/8,5/8,7/8 etc */
+			step *= timefrac;
+			number[index] = number[index-span] + step;
+			step = number[valbase+index+span] - number[valbase+index-span];
+			step *= valfrac;
+			number[valbase+index] = number[valbase+index-span] + step;
+			n += 2;
+		}
+		div *= 2;
+		span /= 2;
+	}
+	for(n=0; n<= cnt;n++)
+		fprintf(stdout,"INFO: %lf  %lf\n",number[n],number[valbase+n]); 
+	fflush(stdout);
+}
+
+/****************************** REVERSE_TIME_INTERVALS2 ******************************/
+
+void reverse_time_intervals2(void)
+{
+	int n;
+	double k = number[0];
+	fprintf(stdout,"INFO: %lf\n",k);
+	for(n = cnt-1;n>=1;n--) {
+		k += (number[n] - number[n-1]);
+		fprintf(stdout,"INFO: %lf\n",k);
+	}
+	fflush(stdout);
+}
+
+/****************************** INTERP_N_VALS ******************************/
+
+void interp_n_vals(void)
+{
+	int n, m, subcnt = cnt - 1;
+	double k, difdiv, diff;
+	if(ifactor < 1) {
+		fprintf(stdout,"ERROR: Invalid number (%d) of interpolated values\n",ifactor);
+		fflush(stdout);
+		exit(1);
+	}
+	ifactor++;
+	difdiv = (double)ifactor;
+	for(n = 0;n< subcnt;n++) {
+		k = number[n];
+		diff = (number[n+1] - k)/difdiv;
+		for(m=0;m<ifactor;m++) {
+			fprintf(stdout,"INFO: %lf\n",k);
+			k += diff;
+		}
+	}
+	fprintf(stdout,"INFO: %lf\n",number[n]);
+	fflush(stdout);
+}
+
+/************************************** GENERAL *****************************************/
+
+#ifdef NOTDEF
+/*RWD May 2005 lets keepo to one definition in sfsys */
+void
+initrand48()
+{
+	srand(time((time_t *)0));
+}
+
+double
+drand48()
+{
+	return (double)rand()/(double)RAND_MAX;
+}
+#endif
+
+/**************************** WARPED_TIMES *****************************/
+
+void warped_times(int isdiff)
+{
+	int j, k, m, n, lastn, numcnt = cnt - firstcnt, itemp;
+	double endtime, endval, frac, val = 0.0, thistime, timediff=0.0, valdiff=0.0, sum, temp;
+	double timestep = (double)128/48000.0;
+	/* This is default window length for standard PVOC analysis under CDP, at srate 48000 (windows 1024 samps: decimation 8)*/
+	/* However, the timestep, so long as sufficiently small, is not critical, except for very long time stretches */
+	double *vals = (double *)exmalloc(numcnt*sizeof(double));
+	int *perm = (int *)exmalloc(numcnt*sizeof(int));
+	int *perm2 = (int *)exmalloc(numcnt*sizeof(int));
+	for(n = 0;n < numcnt;n++)
+		perm[n] = n;
+	for(k = 0,n = firstcnt; n < cnt-1; n++,k++) {	/* SORT NUMBERS TO ASCending ORDER, AND NOTE PERMUTATION OF POSITIONS */
+		m = n+1;
+		j = k+1;
+		while(m  < cnt) {
+			if(number[m] < number[n]) {
+				temp = number[m];
+				number[m] = number[n];
+				number[n] = temp;
+				itemp = perm[j];
+				perm[j] = perm[k];
+				perm[k] = itemp;
+			}
+			m++;
+			j++;
+		}
+	}
+	for(n=0;n<cnt;n++) {			/* 'INVERT' THE POSITION PERM */
+		for(m=0;m<cnt;m++) {
+			if(perm[m] == n) {
+				perm2[n] = m;
+				break;
+			}
+		}
+	}
+	perm = perm2;
+	endtime = number[firstcnt-2];
+	endval  = number[firstcnt-1];
+	thistime = 0.0;
+	sum = 0.0;
+	n = 0;
+	k = 0;
+	for(m=firstcnt;m<cnt;m++) {
+		while(thistime < number[m]) {
+			if(thistime >= endtime) {
+				val = endval;
+			} else if(thistime <= number[0]) {
+				val = number[1];
+			} else {
+				lastn = n;
+				while(thistime > number[n])
+					n += 2;
+				if(n != lastn) {
+					timediff = (number[n] - number[n-2]);
+					valdiff  = (number[n+1] - number[n-1]);
+				}
+				frac = (thistime - number[n-2])/timediff;
+				val =  (valdiff * frac) + number[n-1];
+			}
+			sum += val;
+			thistime += timestep;
+		}
+		val = sum * timestep;
+		if(isdiff)
+			vals[k++] = val - number[m];
+		else
+			vals[k++] = val;
+	}
+	for(n=0;n<numcnt;n++)
+		fprintf(stdout,"INFO: %lf\n",vals[perm[n]]);
+
+	fflush(stdout);
+}
+
+/**************************** CUMULADD *****************************/
+
+void cumuladd(void)
+{
+	int n;
+	double upstep = number[cnt];
+	fprintf(stdout,"INFO: %lf\n",number[0]);
+	for(n=1;n<cnt;n++) {
+		fprintf(stdout,"INFO: %lf\n",number[n] + upstep);
+		upstep += number[cnt];
+	}
+	fflush(stdout);
+}
+
+/**************************** TW_PSUEDOPAN *****************************/
+
+void tw_psuedopan(void)
+{
+	double inner_width = number[0], outer_width = number[1];
+	double startpos    = number[2], time_propor = number[3];
+	double bakfrth_dur = number[4], duration    = number[5];
+	int leftwards = round(number[6]);
+	double time = 0;
+	double *vals;
+	double large_tstep, small_tstep;
+	double  left_pos, far_left_pos, right_pos, far_right_pos;
+	double  dist_from_left, prop_dist;
+	double nexttimestep = -1.0;
+	int n, dostop = 0, cycle_point, valcnt = (int)floor(duration/bakfrth_dur) + 3;
+	valcnt *= 12;
+	if((vals = (double *)malloc(valcnt * sizeof(double)))==NULL) {
+		fprintf(stdout,"ERROR: Insufficient memory to store pan data.\n");
+		fflush(stdout);
+		exit(1);
+	}
+	small_tstep = bakfrth_dur * time_propor;
+	large_tstep = bakfrth_dur - small_tstep;
+	small_tstep /= 4.0;	
+	large_tstep /= 2.0;
+	left_pos = -inner_width;
+	far_left_pos = -outer_width;
+	right_pos = inner_width;
+	far_right_pos = outer_width;
+	if(flteq(startpos,far_left_pos)) {
+		nexttimestep = small_tstep;
+		cycle_point = 0;
+	} else if(flteq(startpos,left_pos)) {
+		if(leftwards == 0) {
+			nexttimestep = large_tstep;
+			cycle_point = 1;
+		} else {
+			nexttimestep = small_tstep;
+			cycle_point = 5;
+		}
+	} else if(flteq(startpos,right_pos)) {
+		if(leftwards == 0) {
+			nexttimestep = small_tstep;
+			cycle_point = 2;
+		} else {
+			nexttimestep = large_tstep;
+			cycle_point = 4;
+		}
+	} else if(flteq(startpos,far_right_pos)) {
+			nexttimestep = small_tstep;
+			cycle_point = 3;
+	} else if(startpos < left_pos) {
+		dist_from_left = startpos - far_left_pos;
+		prop_dist = dist_from_left/(left_pos - far_left_pos);
+		if(leftwards == 0) {
+			cycle_point = 0;
+			nexttimestep = small_tstep * (1.0 - prop_dist);
+		} else {
+			cycle_point = 5;
+			nexttimestep = small_tstep * prop_dist;
+		}
+	} else if(startpos < right_pos) {
+		dist_from_left = startpos -  left_pos;
+		prop_dist = dist_from_left/(right_pos - left_pos);
+		if(leftwards == 0) {
+			cycle_point = 1;
+			nexttimestep = large_tstep * (1.0 - prop_dist);
+		} else {
+			cycle_point = 4;
+			nexttimestep = large_tstep * prop_dist;
+		}
+	} else {
+		dist_from_left = startpos -  right_pos;
+		prop_dist = dist_from_left/(far_right_pos - right_pos);
+		if(leftwards == 0) {
+			cycle_point = 2;
+			nexttimestep = small_tstep * (1.0 - prop_dist);
+		} else {
+			cycle_point = 3;
+			nexttimestep = small_tstep * prop_dist;
+		}
+	}
+
+	n = 0;
+	if(n + 12 >= valcnt) {
+		fprintf(stdout,"ERROR: Internal error calculating memory required.\n");
+		fflush(stdout);
+		exit(1);
+	}
+	switch(cycle_point) {
+	case(0):
+		vals[n++] = time;
+		vals[n++] = startpos;
+		time += nexttimestep;
+		nexttimestep = -1.0;
+		if(time >= duration)
+			dostop = 1;
+		/* fall thro */
+	case(1):
+		vals[n++] = time;
+		if(dostop) {
+			dostop++;
+			break;
+		}
+		if(nexttimestep > 0.0) {
+			vals[n++] = startpos;
+			time += nexttimestep;
+			nexttimestep = -1.0;
+		} else {
+			vals[n++] = left_pos;
+			time += large_tstep;
+		}
+		if(time >= duration)
+			dostop = 1;
+		/* fall thro */
+	case(2):
+		vals[n++] = time;
+		if(dostop) {
+			dostop++;
+			break;
+		}
+		if(nexttimestep > 0.0) {
+			vals[n++] = startpos;
+			time += nexttimestep;
+			nexttimestep = -1.0;
+		} else {
+			vals[n++] = right_pos;
+			time += small_tstep;
+		}
+		if(time >= duration)
+			dostop = 1;
+		/* fall thro */
+	case(3):
+		vals[n++] = time;
+		if(dostop) {
+			dostop++;
+			break;
+		}
+		if(nexttimestep > 0.0) {
+			vals[n++] = startpos;
+			time += nexttimestep;
+			nexttimestep = -1.0;
+		} else {
+			vals[n++] = far_right_pos;
+			time += small_tstep;
+		}
+		if(time >= duration)
+			dostop = 1;
+		/* fall thro */
+	case(4):
+		vals[n++] = time;
+		if(dostop) {
+			dostop++;
+			break;
+		}
+		if(nexttimestep > 0.0) {
+			vals[n++] = startpos;
+			time+= nexttimestep;
+			nexttimestep = -1.0;
+		} else {
+			vals[n++] = right_pos;
+			time += large_tstep;
+		}
+		if(time >= duration)
+			dostop = 1;
+		/* fall thro */
+	case(5):
+		vals[n++] = time;
+		if(dostop) {
+			dostop++;
+			break;
+		}
+		if(nexttimestep > 0.0) {
+			vals[n++] = startpos;
+			time+= nexttimestep;
+			nexttimestep = -1.0;
+		} else {
+			vals[n++] = left_pos;
+			time += small_tstep;
+		}
+		if(time >= duration)
+			dostop = 1;
+		break;
+	}
+	if(dostop < 2) {
+		for (;;) {
+			if(n + 12 >= valcnt) {
+				fprintf(stdout,"ERROR: Internal error calculating memory required.\n");
+				fflush(stdout);
+				exit(1);
+			}
+			vals[n++] = time;
+			vals[n++] = far_left_pos;
+			if(dostop)
+				break;
+			time += small_tstep;
+			if(time >= duration)
+				dostop = 1;
+
+			vals[n++] = time;
+			vals[n++] = left_pos;
+			if(dostop)
+				break;
+			time += large_tstep;
+			if(time >= duration)
+				dostop = 1;
+
+			vals[n++] = time;
+			vals[n++] = right_pos;
+			if(dostop)
+				break;
+			time += small_tstep;
+			if(time >= duration)
+				dostop = 1;
+
+			vals[n++] = time;
+			vals[n++] = far_right_pos;
+			if(dostop)
+				break;
+			time += small_tstep;
+			if(time >= duration)
+				dostop = 1;
+
+			vals[n++] = time;
+			vals[n++] = right_pos;
+			if(dostop)
+				break;
+			time += large_tstep;
+			if(time >= duration)
+				dostop = 1;
+
+			vals[n++] = time;
+			vals[n++] = left_pos;
+			if(dostop)
+				break;
+			time += small_tstep;
+			if(time >= duration)
+				dostop = 1;
+		}
+	}
+	valcnt = n;
+	for(n = 0;n < valcnt; n +=2) {
+		fprintf(stdout,"INFO: %lf   %lf\n",vals[n],vals[n+1]);
+	}
+	fflush(stdout);
+}
+
+/**************************** SINJOIN *****************************/
+
+void sinjoin(char c)
+{
+	double startval = number[0], endval = number[1];
+	double starttime = number[2], endtime = number[3];
+	int n, pointcnt = (int)round(number[4]), inverse = 0;
+	double val = 0.0, valdiff = endval - startval;
+	double timediff = endtime - starttime;
+	double timestep = timediff/(double)pointcnt;
+	double startrad = 0.0;
+	double nstep_cosin = (PI/(double)pointcnt);
+	double nstep_sin = (PI/(2.0 * (double)pointcnt));
+	if((c == 'x' && valdiff < 0.0) || (c=='v' && valdiff > 0.0)) {
+		inverse = 1;
+		nstep_sin = -nstep_sin;
+		startrad = PI/2.0;
+	} else if(c=='c')
+		startrad = PI;
+
+	fprintf(stdout,"INFO: %lf  %lf\n",starttime,startval);
+	for(n = 1; n< pointcnt;n++) {
+		switch(c) {
+		case('c'):
+			startrad += nstep_cosin;
+			val = (cos(startrad) + 1.0) / 2.0;
+			break;
+		case('v'):
+		case('x'):
+			startrad += nstep_sin;
+			val = sin(startrad);
+			if(inverse)
+				val = 1.0 - val;
+			break;
+		}
+		val *= valdiff;
+		val += startval;
+		starttime += timestep;
+		fprintf(stdout,"INFO: %lf  %lf\n",starttime,val);
+	}
+	fprintf(stdout,"INFO: %lf  %lf\n",endtime,endval);
+	fflush(stdout);
+}
+
+/************************************** BRKTIME_OWARP *****************************************/
+
+void brktime_owarp()
+{
+	int m, n;
+	double thistime, nexttime, thisval, nextval, step, frac, val, gap, sum;
+	for(m=firstcnt+1;m<cnt;m+=2) {
+		if(number[m] < FLTERR) {
+			fprintf(stdout,"ERROR: Invalid value %lf in warping file (must be > 0)\n",number[m]);
+			exit(1);
+		}
+	}
+	if(!flteq(number[0],0.0)) {
+		fprintf(stdout,"ERROR: Breakpoint file to BE warped must begin at time ZERO\n");
+		exit(1);
+	}
+	number[0] = 0.0;
+	fprintf(stdout,"INFO: %lf  %lf\n",number[0], number[1]);
+	sum = 0.0;
+	n = 2;
+	m = firstcnt;
+	for(;;) {
+		while(number[m] <= sum) {
+			if((m += 2) >= cnt)
+				break;
+		}
+		if(m >= cnt)
+			val = number[cnt-1];
+		else {
+			nexttime = number[m];
+			nextval  = number[m+1];
+			thistime = number[m-2];
+			thisval  = number[m-1];
+			step = nexttime - thistime;
+			frac = (sum - thistime)/step;
+			val = ((nextval - thisval) * frac) + thisval;
+		}
+		gap = number[n] - number[n-2];
+		val *= gap;
+		sum += val;
+		fprintf(stdout,"INFO: %lf  %lf\n",sum, number[n+1]);
+		if((n += 2) >= firstcnt)
+			break;
+	}
+	fflush(stdout);
+}

+ 245 - 0
dev/tabedit/getcol.c

@@ -0,0 +1,245 @@
+/*
+ * 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
+ *
+ */
+
+
+
+/*
+ * get Nth column from a file of columned data
+ * (skipping M lines at start of file)
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <math.h>
+#include <string.h>
+
+#define PROG 	 "GETCOL"
+#define ENDOFSTR '\0'
+
+FILE 	*fp1, *fpout;
+char	*skip_column(char *,int,char *);
+char	*skip_column_wanted(char *,int,char *);
+void 	usage(void), logo(void);
+
+int		ignore_s_and_e = 0, ignore_c = 0;
+int		sloom = 0;
+int		sloombatch = 0;
+const char* cdp_version = "7.1.0";
+
+int main(int argc,char *argv[])
+{   
+	char temp[2000], *p, *q;
+	int n, skip=0, column, cnt=0;
+
+	if(argc==2 && (strcmp(argv[1],"--version") == 0)) {
+		fprintf(stdout,"%s\n",cdp_version);
+		fflush(stdout);
+		return 0;
+	}
+/* VERSION 3 */
+	if(argc < 2)
+		usage();
+	if(!strcmp(argv[1],"#")) {
+		sloom = 1;
+		argv++;
+		argc--;
+	} else if (!strcmp(argv[1],"##")) {
+		p = argv[0];
+		argc--;
+		argv++;
+		argv[0] = p;
+		sloombatch = 1;
+	}
+
+
+
+
+	if(!strcmp(argv[argc-1],"-e")) {
+		ignore_s_and_e = 1;
+		argc--;
+	} else 	if(!strcmp(argv[argc-1],"-ec")) {
+		ignore_c = 1;
+		argc--;
+	}
+	if(argc<4 || argc>5)
+		usage();
+	if((fp1 = fopen(argv[1],"r"))==NULL) {
+		fprintf(stdout,"ERROR: Cannot open file '%s'\n",argv[1]);
+		fflush(stdout);
+		usage();
+	}
+	if((fpout = fopen(argv[2],"w"))==NULL) {
+		fprintf(stdout,"ERROR: Cannot open file '%s'\n",argv[2]);
+		fflush(stdout);
+		usage();
+	}
+	if(sscanf(argv[3],"%d",&column)!=1) {
+		fprintf(stdout,"ERROR: Cannot read column value.\n");
+		fflush(stdout);
+		usage();
+	}
+	if(column<1) {
+		fprintf(stdout,"ERROR: Column value cannot be less than 1.\n");
+		fflush(stdout);
+		usage();
+	}
+	column--;
+	if(argc==5 && sscanf(argv[4],"%d",&skip)!=1) {
+		fprintf(stdout,"ERROR: Cannot read skip value.\n");
+		fflush(stdout);
+		usage();
+	}
+	for(n=0;n<skip;n++) {
+		if(fgets(temp,200,fp1)!=temp) {
+			fprintf(stdout,"ERROR: Failed to get skippable line %d in file '%s'\n",
+			n+1,argv[1]);
+			fflush(stdout);
+			exit(1);
+		}
+		q = temp;				/* IGNORE EMPTY LINES */
+		p = temp;
+		while(*p != ENDOFSTR) {
+			if(isspace(*p))
+				q++;
+			p++;
+		}
+		if(p==q)
+			n--;
+	}
+	while(fgets(temp,2000,fp1)!=NULL) {
+		cnt++;
+		p = temp;
+/*RWD*/	while(isspace(*p)) p++;
+/*and*/	if(*p=='\n' || *p==ENDOFSTR){
+			if(!sloom && !sloombatch)
+				fputs("\n",fpout);
+			else
+				fprintf(stdout,"INFO: \n");
+			continue;
+		}
+		if(ignore_s_and_e && (!strcmp(temp,"e\n") || !strcmp(temp,"e") || !strcmp(temp,"s\n") || !strncmp(temp,";",1)))
+			continue;
+		if(ignore_c && !strncmp(temp,";",1))
+			continue;
+		for(n=0;n<column;n++) {
+			if(*p==ENDOFSTR) {
+				fprintf(stdout,"ERROR: Not enough columns in line %d.\n",cnt);
+				fflush(stdout);
+				exit(1);
+			}
+			p = skip_column(p,cnt,argv[1]);
+		}
+		q = p;
+		if(*p==ENDOFSTR) {
+			fprintf(stdout,"ERROR: Not enough columns in line %d.\n",cnt);
+			fflush(stdout);
+			exit(1);
+		}
+		p = skip_column_wanted(p,cnt,argv[1]);
+		if(*p==ENDOFSTR) {
+			p--;	/* DELETE NEWLINE */
+			if(*p!='\n')
+				p++;
+		}
+		*p = ENDOFSTR;
+		if(!sloom && !sloombatch) {
+			fputs(q,fpout);
+			fputs("\n",fpout);
+		} else
+			fprintf(stdout,"INFO: %s\n",q);
+	}
+	fflush(stdout);
+	return 0;
+}
+
+/******************************** USAGE *****************************/
+
+
+void usage(void)
+{
+	if(!sloom && !sloombatch) {
+		logo();
+		fprintf(stderr,"USAGE : getcol infile outfile colno [skiplines] [-e]\n\n");
+		fprintf(stderr,"skiplines  Ignores this number of lines at start of file.\n");
+		fprintf(stderr,"-e         Ignores lines with a single 'e' or 's' (as in CSound scores)\n");
+		fprintf(stderr,"           and comment lines starting with ';'\n");
+		fprintf(stderr,"           (skipped lines should still be counted).\n");
+	}
+	exit(1);
+}
+
+/*************************** SKIP_COLUMN **************************/
+
+char *skip_column(char *p,int cnt,char *argv)
+{
+	if(*p==ENDOFSTR) {
+		fprintf(stdout,"ERROR: Not enough columns in line %d file %s\n",cnt,argv);
+		fflush(stdout);
+		exit(0);
+	}
+ 	while(!isspace(*p)) {
+		p++;
+		if(*p==ENDOFSTR)
+			return(p);
+	}
+	while(isspace(*p)) {
+		p++;
+		if(*p==ENDOFSTR)
+			return(p);
+   }
+   return(p);
+}
+
+/*************************** SKIP_COLUMN_WANTED **************************/
+
+char *skip_column_wanted(char *p,int cnt,char *argv)
+{
+	if(*p==ENDOFSTR) {
+		fprintf(stdout,"ERROR: Not enough columns in line %d file %s\n",cnt,argv);
+		fflush(stdout);
+		exit(0);
+	}
+ 	while(!isspace(*p++)) {
+		if(*p==ENDOFSTR)
+			return(p);
+	}
+	return(p);
+}
+
+/******************************** LOGO() **********************************/
+
+void logo(void)
+{   
+	printf("\t    ***************************************************\n");
+	printf("\t    *            COMPOSERS DESKTOP PROJECT            *\n");
+	printf("\t                    %s $Revision: 1.2 $\n",PROG);
+	printf("\t    *                                                 *\n");
+	printf("\t    *   get Nth column from a file of columned data   *\n");
+	printf("\t    *      (skipping M lines at start of file).       *\n");
+	printf("\t    *                                                 *\n");
+	printf("\t    *                by TREVOR WISHART                *\n");
+	printf("\t    ***************************************************\n\n");
+}
+

+ 359 - 0
dev/tabedit/putcol.c

@@ -0,0 +1,359 @@
+/*
+ * 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
+ *
+ */
+
+
+
+/*
+ * Insert a column of figures, in a textfile,
+ * into an existing file
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+#include <math.h>
+
+FILE *fp2, *fp1, *fpout;
+
+#define PROG 	"PUTCOL"
+#define NEW_COL_SPACE (128)
+
+#define ENDOFSTR '\0'
+#define NEWLINE  '\n'
+#define	TAB	 '\t'
+
+void 	usage(void), logo(void);
+char 	*skip_column(char *,int,char *);
+int 	sloom = 0;
+int 	sloombatch = 0;
+
+int		ignore_s_and_e = 0, ignore_c = 0;
+
+char	errstr[400];
+const char* cdp_version = "7.1.0";
+
+int main(int argc,char *argv[])
+{
+	char temp[400], temp2[400], *p, *q, c;
+	int n, skip = 0, column, cnt=0, replace = 0, end_col = 0, keep = 1, outlinecnt, newlen;
+	char **line = (char **)0;
+	if(argc==2 && (strcmp(argv[1],"--version") == 0)) {
+		fprintf(stdout,"%s\n",cdp_version);
+		fflush(stdout);
+		return 0;
+	}
+	if(argc < 2)
+		usage();
+	if(!strcmp(argv[1],"#")) {
+		sloom = 1;
+		argv++;
+		argc--;
+	} else if (!strcmp(argv[1],"##")) {
+		p = argv[0];
+		argc--;
+		argv++;
+		argv[0] = p;
+		sloombatch = 1;
+	}
+	if(!strcmp(argv[argc-1],"-e")) {
+		ignore_s_and_e = 1;
+		argc--;
+	}
+	if(!strcmp(argv[argc-1],"-ec")) {
+		ignore_c = 1;
+		argc--;
+	}
+	if(argc<6 || argc>7)
+		usage();
+
+	if(!sloom) {
+		if(!strcmp(argv[3],argv[2]) || !strcmp(argv[3],argv[1])) {
+			fprintf(stdout,"ERROR: Cannot use same file for input and ouput.\n");
+			fflush(stdout);
+			usage();
+		}
+		if((fpout = fopen(argv[3],"w"))==NULL) {
+			fprintf(stdout,"ERROR: Cannot open file '%s'\n",argv[3]);
+			fflush(stdout);
+			usage();
+		}
+	}
+	if((fp1 = fopen(argv[1],"r"))==NULL) {
+		fprintf(stdout,"ERROR: Cannot open file '%s'\n",argv[1]);
+		fflush(stdout);
+		usage();
+	}
+	if((fp2 = fopen(argv[2],"r"))==NULL) {
+		fprintf(stdout,"ERROR: Cannot open file '%s'\n",argv[2]);
+		fflush(stdout);
+		usage();
+	}
+	if(sscanf(argv[4],"%d",&column)!=1) {
+		fprintf(stdout,"ERROR: Cannot read column value.\n");
+		fflush(stdout);
+		usage();
+	}
+	if(column<1) {
+		fprintf(stdout,"ERROR: Column value cannot be less than 1.\n");
+		fflush(stdout);
+		usage();
+	}
+	column--;
+	if(argc==7 && sscanf(argv[6],"%d",&skip)!=1) {
+		fprintf(stdout,"ERROR: Cannot read skip value.\n");
+		fflush(stdout);
+		usage();
+	}
+	if(skip<0) {
+		skip = -skip;
+		keep = 0;
+	}
+	if(*argv[5]++!='-') {
+		fprintf(stdout,"ERROR: Unknown parameter %s.\n",--argv[5]);
+		fflush(stdout);
+		usage();
+	}
+	switch(*argv[5]) {
+	case('r'): replace = 1; break;
+	case('i'):	break;
+	default:
+		fprintf(stdout,"ERROR: Unknown flag -%c\n",*argv[5]);
+		fflush(stdout);
+		usage();
+	}
+	outlinecnt = 0;
+	if(skip > 0) {
+		if(keep) {
+			if((line = (char **)malloc(skip * sizeof(char *)))==NULL) {
+				fprintf(stdout,"ERROR: Out of memory\n");
+				fflush(stdout);
+			}			
+		}
+		for(n=0;n<skip;n++) {
+			if(fgets(temp,400,fp2)!=temp) {
+				fprintf(stdout,"ERROR: Failed to get skippable line %d in file '%s'\n",n+1,argv[1]);
+				fflush(stdout);
+				exit(1);
+			}
+			if(keep) {
+				if((line[outlinecnt] = (char *)malloc((strlen(temp)+2) * sizeof(char)))==NULL) {
+					fprintf(stdout,"ERROR: Out of memory\n");
+					fflush(stdout);
+				}			
+				line[outlinecnt][0] = ENDOFSTR;
+				strcat(line[outlinecnt],temp);
+				outlinecnt++;
+			}
+		}
+	}
+	while(fgets(temp,400,fp2)!=NULL) {
+/*RWD*/ p = temp;
+/*RWD*/ while(isspace(*p)) p++;
+/*and*/	if(*p=='\n' || *p == ENDOFSTR){
+			if((line = (char **)realloc((char *)line,(outlinecnt+1) * sizeof(char *)))==NULL) {
+				fprintf(stdout,"ERROR: Out of memory\n");
+				fflush(stdout);
+			}			
+			if((line[outlinecnt] = (char *)malloc(2 * sizeof(char)))==NULL) {
+				fprintf(stdout,"ERROR: Out of memory\n");
+				fflush(stdout);
+			}			
+			line[outlinecnt][0] = ENDOFSTR;
+			outlinecnt++;
+			continue;
+		}
+		if((ignore_s_and_e && (!strcmp(temp,"e\n") || !strcmp(temp,"e") || !strcmp(temp,"s\n") || !strncmp(temp,";",1)))
+		|| (ignore_c && !strncmp(temp,";",1))) {
+			if(line==(char **)0) {
+				if((line = (char **)malloc((outlinecnt+1) * sizeof(char *)))==NULL) {
+					fprintf(stdout,"ERROR: Out of memory\n");
+					fflush(stdout);
+				}			
+			} else {
+				if((line = (char **)realloc((char *)line,(outlinecnt+1) * sizeof(char *)))==NULL) {
+					fprintf(stdout,"ERROR: Out of memory\n");
+					fflush(stdout);
+				}			
+			}
+			if((line[outlinecnt] = (char *)malloc((strlen(temp)+2) * sizeof(char)))==NULL) {
+				fprintf(stdout,"ERROR: Out of memory\n");
+				fflush(stdout);
+			}			
+			line[outlinecnt][0] = ENDOFSTR;
+			strcat(line[outlinecnt],temp);
+			outlinecnt++;
+			continue;
+		}
+		cnt++;
+		end_col = 0;
+		q = p;
+		for(n=0;n<column;n++) {
+			if(*p==ENDOFSTR) {
+				fprintf(stdout,"ERROR: Not enough columns in line %d in origfile.\n",cnt);
+				fflush(stdout);
+				exit(1);
+			}
+			p = skip_column(p,cnt,argv[1]);
+		}
+		if(*p==ENDOFSTR) {
+			if(replace) {
+				fprintf(stdout,"ERROR: Not enough columns in line %d in origfile.\n",cnt);
+				fflush(stdout);
+				exit(1);
+			} else {
+				p--;	/* HANG ONTO NEWLINE */
+				if(*p != NEWLINE)
+					p++;
+				end_col = 1;		
+			}	
+		}
+		c = *p;
+		*p = ENDOFSTR;
+		if(line==(char **)0) {
+			if((line = (char **)malloc((outlinecnt+1) * sizeof(char *)))==NULL) {
+				fprintf(stdout,"ERROR: Out of memory\n");
+				fflush(stdout);
+			}			
+		} else {
+			if((line = (char **)realloc((char *)line,(outlinecnt+1) * sizeof(char *)))==NULL) {
+				fprintf(stdout,"ERROR: Out of memory\n");
+				fflush(stdout);
+			}			
+		}
+		if((line[outlinecnt] = (char *)malloc((strlen(temp)+2+NEW_COL_SPACE) * sizeof(char)))==NULL) {
+			fprintf(stdout,"ERROR: Out of memory\n");
+			fflush(stdout);
+		}			
+		line[outlinecnt][0] = ENDOFSTR;
+		strcat(line[outlinecnt],temp);
+		if(end_col)
+			strcat(line[outlinecnt],"\t");
+		*p = c;
+		if(replace) {
+			p = skip_column(p,cnt,argv[1]);
+			if(*p==ENDOFSTR) {
+				p--;		/* KEEP NEWLINE !!! */
+				if(*p != NEWLINE)
+					p++;
+				end_col = 1;
+			}
+		}
+		strcpy(temp2,p);
+   		if(fgets(temp,400,fp1)==NULL) {
+			fprintf(stdout,"ERROR: No more vals in file %s at line %d\n",argv[1],cnt);
+			fflush(stdout);
+			break;
+		}
+		p = temp + strlen(temp);
+		p--;	/* DELETE NEWLINE */
+		if(*p != NEWLINE)
+			p++;
+		if(!end_col)
+			*p++ = TAB;
+		*p = ENDOFSTR;
+		strcat(temp,temp2);
+		newlen = strlen(line[outlinecnt]) + strlen(temp) + 2;
+		if((line[outlinecnt] = (char *)realloc((char *)line[outlinecnt],newlen * sizeof(char)))==NULL) {
+			fprintf(stdout,"ERROR: Memory problem.\n");
+			fflush(stdout);
+		}			
+		strcat(line[outlinecnt],temp);
+		outlinecnt++;
+	}
+	if(sloom) {
+		if((fpout = fopen(argv[3],"w"))==NULL) {
+			fprintf(stdout,"ERROR: Cannot reopen file '%s'\n",argv[3]);
+			fflush(stdout);
+			usage();
+		}
+	}
+	for(n=0;n<outlinecnt;n++) {
+		if(!sloom && !sloombatch) {
+			strcat(line[n],"\n");
+			fputs(line[n],fpout);
+		} else 
+			fprintf(stdout,"INFO: %s\n",line[n]);
+	}
+	fflush(stdout);
+	fclose(fp2);
+	fclose(fp1);
+	return 0;
+}
+
+/******************************** USAGE *****************************/
+
+void usage(void)
+{
+	if(!sloom) {
+		logo();
+		fprintf(stderr,"USAGE : putcol columnfile intofile outfile colno -r|-i [[-]skiplines] [-e]\n\n");
+		fprintf(stderr,"COLUMNFILE  File with NEW column.\n");
+		fprintf(stderr,"INTOFILE    File INTO which the new column goes.\n");
+		fprintf(stderr,"OUTFILE     Resultant file.\n");
+		fprintf(stderr,"COLNO       POSITION of the column to be added.\n");
+		fprintf(stderr,"-r          REPLACE original column.\n");
+		fprintf(stderr,"-i          INSERT new column amongst original columns.\n");
+		fprintf(stderr,"SKIPLINES   SKIP OVER skiplines before inserting column.\n");
+	    fprintf(stderr,"-SKIPLINES  THROW AWAY skiplines: then insert column.\n");
+		fprintf(stderr,"-e          Ignore lines which contain only 'e' or 's'.\n");
+		fprintf(stderr,"            and comment lines starting with ';'\n");
+		fprintf(stderr,"            (skipped lines should still be counted).\n");
+	}
+	exit(1);
+}
+
+/*************************** SKIP_COLUMN **************************/
+
+char *skip_column(char *p,int cnt,char *argv)
+{  
+	if(*p==ENDOFSTR) {
+		fprintf(stdout,"ERROR: Not enough columns in line %d file %s\n",cnt,argv);
+		fflush(stdout);
+		exit(0);
+	}
+	while(!isspace(*p)) {
+		p++;
+		if(*p==ENDOFSTR)  return(p);
+	}
+	while(isspace(*p)) {
+		p++;
+		if(*p==ENDOFSTR)  return(p);
+   }
+   return(p);
+}
+
+/******************************** LOGO() **********************************/
+
+void logo(void)
+{   printf("\t    ***************************************************\n");
+	printf("\t    *           COMPOSERS DESKTOP PROJECT             *\n");
+	printf("\t                    %s $Revision: 1.3 $	\n",PROG);
+	printf("\t    *                                                 *\n");
+	printf("\t    *    Insert a column of figures, in a textfile,   *\n");
+	printf("\t    *              into an existing file.             *\n");
+	printf("\t    *                                                 *\n");
+	printf("\t    *                by TREVOR WISHART                *\n");
+	printf("\t    ***************************************************\n\n");
+}

+ 1742 - 0
dev/tabedit/vectors.c

@@ -0,0 +1,1742 @@
+/*
+ * 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
+ *
+ */
+
+
+
+/* Manipulate 2 columns of numbers (vectors) */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <string.h>
+#include <ctype.h>
+#include <osbind.h>
+#include <time.h>
+
+#define PROG	"VECTORS"
+
+#define BIGARRAY      200
+#define FLTERR        0.000002
+#define ENDOFSTR	'\0'
+
+#include <sfsys.h>
+#ifdef unix
+#define round lround
+#endif
+
+
+int  	strgetfloat(char **,double  *);
+double 	miditohz(double);
+char 	*exmalloc(int), *exrealloc(char *,int);
+void	logo(void), usage(void), help(void);
+void 	read_flags(int,int,char *[]);
+int 	do_infile(char *,double **), do_outfile(char *);
+void 	check_usage(int argc,char *argv[]), truncate_vectors(void);
+void 	do_add(void), 	     do_subtract(void),   do_multiply(void), do_mean(void);
+void	do_divide(void),     do_overwrite(void),  do_insert(void);
+void 	do_interleave(void), do_power(void),	  do_randadd(void);
+void 	do_patterned_interleave(void);
+void 	do_randmult(void),   do_randscat(void),   do_substitute(void);
+void 	do_quantise(void),	do_squeezed_pan(void);
+void 	quantise_sort(double *scti,int *scatcnt);
+void 	conjoina(void);
+void 	conjoinb(void);
+void 	conjoin_sort(void);
+void	do_max(void);
+void	do_min(void);
+
+void	do_keep(void);
+void	do_del(void);
+void 	compare(void);
+void 	del_copys(void);
+void 	insert_non_dupls(void);
+void 	partition_col(int atpos,int partition_outcol);
+void 	do_keep_in_spans(int is_del);
+void	do_del_in_spans(void);
+void	do_keep_cycles(int do_keep);
+void 	do_matches(void);
+void 	do_morph(void);
+void 	do_morphseq(void);
+
+static void do_error(void);
+static void do_valout(double val);
+static int do_stringfile(char *argv,char ***stringptr);
+
+double other_param;
+double *other_params;
+char **string0, **string1;
+
+int	cnt = 0, cnt2, arraysize = BIGARRAY, ifactor, flagstart;
+double 	*number1, *number2, *diffs, scatter, factor, errorbnd = FLTERR;
+FILE 	*fp = NULL;
+char 	flag = 0, errstr[400];
+int	ro = 0;
+int sloom = 0;
+int sloombatch = 0;
+const char* cdp_version = "7.1.0";
+
+int main(int argc,char *argv[])
+{
+	char *p;
+	fp = stdout;
+	if(argc==2 && (strcmp(argv[1],"--version") == 0)) {
+		fprintf(stdout,"%s\n",cdp_version);
+		fflush(stdout);
+		return 0;
+	}
+	if(argc < 2) {
+		fprintf(stdout,"ERROR: Invalid command\n");
+		fflush(stdout);
+		usage();
+	}
+	if(!strcmp(argv[1],"#")) {
+		sloom = 1;
+		argv++;
+		argc--;
+	} else if (!strcmp(argv[1],"##")) {
+		p = argv[0];
+		argc--;
+		argv++;
+		argv[0] = p;
+		sloombatch = 1;
+	}
+	check_usage(argc,argv);
+	if(sloom)
+		flagstart = 3;
+	initrand48();
+	read_flags(flagstart,argc,argv);
+	if(flag == 'I' && ro == 'P') {
+		if(((string0 = (char **)exmalloc(arraysize * sizeof(char *)))==NULL)
+			|| ((string1 = (char **)exmalloc(arraysize * sizeof(char *)))==NULL)) {
+			sprintf(errstr,"Memory allocation failed.\n");
+			do_error();
+		}
+		if((cnt  = do_stringfile(argv[1],&string0)) < 1) {
+			fprintf(stdout,"ERROR: No numeric data in 1st column.\n");
+			fflush(stdout);
+			exit(1);
+		}
+		if((cnt2 = do_stringfile(argv[2],&string1)) < 1) {
+			fprintf(stdout,"ERROR: No numeric data in 2nd column.\n");
+			fflush(stdout);
+			exit(1);
+		}
+	} else {
+		if(((number1 = (double *)exmalloc(arraysize * sizeof(double)))==NULL)
+			|| ((number2 = (double *)exmalloc(arraysize * sizeof(double)))==NULL)) {
+			sprintf(errstr,"Memory allocation failed.\n");
+			do_error();
+		}
+		if((cnt  = do_infile(argv[1],&number1)) < 1) {
+			fprintf(stdout,"ERROR: No numeric data in 1st column.\n");
+			fflush(stdout);
+			exit(1);
+		}
+		if((cnt2 = do_infile(argv[2],&number2)) < 1) {
+			fprintf(stdout,"ERROR: No numeric data in 2nd column.\n");
+			fflush(stdout);
+			exit(1);
+		}
+	}
+	if((flag == 'C' || flag == 'y') && (cnt != cnt2)) {
+		fprintf(stdout,"ERROR: Columns are not of the same length.\n");
+		fflush(stdout);
+		exit(1);
+	}
+	if(flag != 'l' && flag != 'K' && flag != 'k' && flag != 'M' && !(flag=='I' && ro=='P'))
+		truncate_vectors();
+	switch(flag) {
+	case('a'): do_add();		break;
+	case('A'): do_mean();		break;
+	case('b'): do_max();		break;
+	case('B'): do_min();		break;
+	case('d'): do_divide();		break;
+	case('i'): do_insert();		break;
+	case('m'): do_multiply();	break;
+	case('M'):
+		switch(ro) {
+		case('O'):do_morph();		break;
+		case('o'):do_morphseq();	break;
+		default:  do_matches();		break;
+		}
+		break;
+	case('o'): do_overwrite();	break;
+	case('p'):
+		switch(ro) {
+		case('y'): partition_col(1,1);		break;		/* partition, at given positions in outcol, the input col*/
+		case('n'): partition_col(0,1);		break;		/* partition, at other than given positions, the input col */
+		case('Y'): partition_col(1,0);		break;		/* partition, at given positions in incol, the output col*/
+		case('N'): partition_col(0,0);		break;		/* partition, at other than given positions, the output col */
+		}
+		break;
+	case('q'): do_quantise();	break;
+	case('s'): do_subtract();	break;
+	case('C'): compare();		break;
+	case('I'):
+		switch(ro) {
+		case(ENDOFSTR): do_interleave();	break;
+		case('P'):		do_patterned_interleave();	break;
+		}
+		break;
+	case('P'): do_power();		break;
+	case('S'): do_substitute();	break;
+	case('l'):
+		switch(ro) {
+		case('a'): conjoina();		break;
+		case('b'): conjoinb();		break;
+		case('s'): conjoin_sort();	break;
+		}
+		break;
+	case('K'):
+		switch(ro) {
+		case('k'): do_keep();			break;
+		case('d'): do_del();			break;
+		case('K'): do_keep_in_spans(0);	break;
+		case('D'): do_keep_in_spans(1);	break;
+		case('c'): del_copys();			break;
+		case('S'): insert_non_dupls();	break;
+		}
+		break;
+	case('k'):
+		switch(ro) {
+		case('k'): do_keep_cycles(1);	break;
+		case('d'): do_keep_cycles(0);	break;
+		}
+		break;
+	case('R'):
+		switch(ro) {
+		case('a'): do_randadd();	break;
+		case('m'): do_randmult();	break;
+		case('s'): do_randscat();	break;
+		}
+		break;
+	case('y'):
+		switch(ro) {
+		case('z'): do_squeezed_pan();	break;
+		}
+		break;
+	}
+	fflush(stdout);
+	return 0;
+}
+
+/************************ CHECK_USAGE *************************/
+
+void check_usage(int argc,char *argv[])
+{
+	if(argc==2 && !strncmp(argv[1],"-h",2))
+		help();
+	switch(argc) {
+	case(8):
+		flagstart = argc-4;
+		break;
+	case(6):
+		flagstart = argc-2;
+		if(!do_outfile(argv[3])) {
+			fprintf(stdout,"ERROR: Don't understand.\n");
+			fflush(stdout);
+			usage();
+		}
+		break;
+	case(5):
+		flagstart = argc-1;
+		if(!do_outfile(argv[3])) {
+			flagstart--;
+		}
+		break;
+	case(4):
+		flagstart = argc-1;
+		break;
+	case(2):
+		if(!strncmp(argv[1],"-h",2))
+		help();
+	default:
+		usage();
+	}
+}
+
+/**************************STRGETFLOAT **************************
+ * takes a pointer TO A POINTER to a string. If it succeeds in finding 
+ * a float it returns the float value (*val), and it's new position in the
+ * string (*str).
+ */
+
+int  strgetfloat(char **str,double *val)
+{
+	char *p, *q, *end;
+	double numero;
+	int	point, valid;
+	for(;;) {
+		point = 0;
+			p = *str;
+		while(isspace(*p))
+			p++;
+	 	q = p;	
+		if(!isdigit(*p) && *p != '.' && *p!='-')
+			return(0);
+		if(*p == '.'|| *p == '-') {
+			if(*p == '-')
+				p++;
+			else {
+				point++;
+				p++;
+			}
+		}
+		for(;;) {
+			if(*p == '.') {
+				if(point)
+					return(0);
+				else {
+					point++;
+					p++;
+					continue;
+				}
+			}
+			if(isdigit(*p)) {
+				p++;
+				continue;
+			} else {
+				if(!isspace(*p) && *p!='\0')
+					return(0);
+				else {
+					end = p;
+					p = q;
+					valid = 0;
+					while(p!=end) {
+						if(isdigit(*p))
+					  		valid++;
+						p++;
+					}
+					if(valid) {
+			 			if(sscanf(q,"%lf",&numero)!=1)
+							return(0);
+						*val = numero;
+						*str = end;
+						return(1);
+					}
+					return(0);
+				}
+			}
+	 	}
+	}
+	return(0);				/* NOTREACHED */
+}
+
+/****************************** USAGE ****************************/
+
+void usage(void)
+{
+	if(!sloom && !sloombatch) {
+		logo(); 
+		fprintf(stdout,"USAGE: vectors column1 column2 [outfile] -flag [-eERROR]\n\n");
+		fprintf(stdout,"\tcolumnN  textfile containing list of numbers.\n");
+		fprintf(stdout,"\toutfile  receives output as text (Default: screen)\n");
+		fprintf(stdout,"\tflag     determines operation.\n");
+		fprintf(stdout,"\t         use 'vectors -h' to see flags.\n");
+		fprintf(stdout,"\t-e       ERROR is acceptable error in checking equality of numbers.\n");
+		fprintf(stdout,"\t         (Default: %lf).\n",FLTERR);
+		fflush(stdout);
+	}
+	exit(1);
+}
+
+/****************************** HELP *******************************/
+
+void help(void)
+{
+	fprintf(stdout,
+	"---------------------- flags for VECTORS -----------------------\n");
+	fprintf(stdout,"-a   ADD         add column1 val to column2 val.\n");
+	fprintf(stdout,"-d   DIVIDE      divide column1 val by column2 val.\n");
+	fprintf(stdout,"-q   QUANTISE    quantise column1 vals onto set of (ascending) vals in column2.\n");
+	fprintf(stdout,"-o@  OVERWRITE   overwrite 1st & every @th val in column1 with column2 val.\n");
+	fprintf(stdout,"-i@  INSERT      insert column2 vals at start & after every @th item\n");
+	fprintf(stdout,"                 of column1.\n");
+	fprintf(stdout,"-m   MULTIPLY    multiply column1 val by column2 val.\n");
+	fprintf(stdout,"-s   SUBTRACT    subtract column2 val from column1 val.\n");
+	fprintf(stdout,"-C   COMPARE     compare vals in column1 & column2.\n");
+	fprintf(stdout,"-C@  COMPARE     within error range @.\n");
+	fprintf(stdout,"-I   INTERLEAVE  column 2 vals with column 1 vals.\n");
+	fprintf(stdout,"-IP x1 x2 x3 x4  Patterned Interleave, between x1 & x2 vals col1,\n");
+	fprintf(stdout,"                 then between x3 & x4 vals col2, etc\n");
+	fprintf(stdout,"-P   POWER       raise column1 vals (must be >=0) to powers in column2.\n");
+	fprintf(stdout,"-Ra  RANDADD     add to column1 val a randval btwn +-val in column2.\n");
+	fprintf(stdout,"-Rm  RANDMULT    multiply column1 val by randval between 0 and column2 val.\n");
+	fprintf(stdout,"-Rs  RANDSCATTER random scatter (ascending) column1 vals\n");
+	fprintf(stdout,"                 by degree of scatter(0-1) in column2.\n");
+	fprintf(stdout,"-S@  SUBSTITUTE  substitute any val @ in column1 by next val in column2.\n");
+	fflush(stdout);
+	exit(1);
+}
+
+/********************** DO_OUTFILE *****************************/
+
+int do_outfile(char *argv)
+{
+	if(*argv=='-')
+		return(0);
+	if((fp = fopen(argv,"w"))==NULL) {
+		if(!sloom && !sloombatch)
+			fprintf(stderr,"Cannot open file %s to write.\n",argv);
+		else {
+			fprintf(stdout,"ERROR: Cannot open file %s to write.\n",argv);
+			fflush(stdout);
+		}
+		usage();
+	}
+	return(1);
+}
+
+/******************************** EXMALLOC ****************************/
+
+char *exmalloc(int n)
+{
+	char *p;
+	if((p = (char *)malloc(n))==NULL) {
+		sprintf(errstr,"ERROR: memory allocation failed.\n");
+		do_error();
+	}
+	return(p);
+}
+
+/********************************** READ_FLAGS *************************/
+
+void read_flags(int flagstart,int argc,char *argv[])
+{
+	char dummy;
+
+	int bas = flagstart, k;
+
+	while(flagstart < argc) {
+		if(sloom) {
+			if(flagstart == bas) {
+				if(*argv[flagstart]++!='-') {
+					fprintf(stdout,"ERROR: Cannot interpret program mode\n");
+					fflush(stdout);
+					usage();
+				}
+				if(sscanf(argv[flagstart]++,"%c",&dummy)!=1) {
+					fprintf(stdout,"ERROR: Cannot interpret program mode\n");
+					fflush(stdout);
+					usage();
+				}
+			} else {
+				if(argc < 8)
+					dummy = 'z';
+			} 
+		} else {
+			if(*argv[flagstart]++!='-') {
+				fprintf(stdout,"ERROR: Cannot read flag '%s'.\n",--argv[flagstart]);
+				fflush(stdout);
+				usage();
+			}
+			if(sscanf(argv[flagstart]++,"%c",&dummy)!=1) {
+				fprintf(stdout,"ERROR: Cannot read flag '%s'\n",argv[flagstart]-2);
+				fflush(stdout);
+				usage();
+			}
+		}
+		switch(dummy) {
+		case('C'):
+			flag = dummy;
+			ro = (int)*argv[flagstart];
+			if(ro == ENDOFSTR)
+				factor = 0;
+			else if(sscanf(argv[flagstart],"%lf",&factor)!=1) {
+				fprintf(stdout,"ERROR: Cannot read error range.\n");
+				fflush(stdout);
+				usage();
+			}
+			break;
+		case('M'):
+			flag = dummy;
+			ro = (int)*argv[flagstart];
+			if((ro == 'o') || (ro == 'O')) {
+				argv[flagstart]++;
+				dummy = (int)*argv[flagstart];
+				if(dummy == ENDOFSTR) {
+					fprintf(stdout,"ERROR: Cannot read start entry of morph.\n");
+					fflush(stdout);
+					usage();
+				}
+				if(sscanf(argv[flagstart],"%lf",&factor)!=1) {
+					fprintf(stdout,"ERROR: Cannot read start entry of morph.\n");
+					fflush(stdout);
+					usage();
+				}
+			} else {
+				if(ro == ENDOFSTR) {
+					fprintf(stdout,"ERROR: Cannot read item to match.\n");
+					fflush(stdout);
+					usage();
+				}
+				if(sscanf(argv[flagstart],"%lf",&factor)!=1) {
+					fprintf(stdout,"ERROR: Cannot read item to match.\n");
+					fflush(stdout);
+					usage();
+				}
+			}
+			break;
+		case('d'): case('s'): case('m'): case('a'): case('A'):
+		case('P'): case('q'): case('b'): case('B'):
+			flag = dummy;
+			break;
+		case('R'):
+			flag = dummy;
+			ro = (int)*argv[flagstart];
+			switch(ro) {
+			case('a'): case('m'): case('s'):
+				break;
+			default:
+				if(!sloom) {
+					fprintf(stdout,"ERROR: Unknown flag %s.\n",argv[flagstart]-2);
+					fflush(stdout);
+				} else {
+					fprintf(stdout,"ERROR: Unknown program mode.\n");
+					fflush(stdout);
+				}
+				usage();
+			}
+			break;
+		case('k'):
+			flag = dummy;
+			ro = (int)*argv[flagstart]++;
+			switch(ro) {
+			case('k'):	case('d'):
+				if(sscanf(argv[flagstart],"%d",&ifactor)!=1) {
+					fprintf(stdout,"ERROR: Cannot read cycle count.\n");
+					fflush(stdout);
+					usage();
+				}
+				break;
+			default:
+				fprintf(stdout,"ERROR: Unknown program mode.\n");
+				fflush(stdout);
+				usage();
+			}
+			break;
+		case('K'):
+			flag = dummy;
+			ro = (int)*argv[flagstart];
+			switch(ro) {
+			case('k'):	case('d'):	case('K'):	case('D'):	case('c'):	case('S'):
+				break;
+			default:
+				if(!sloom) {
+					fprintf(stdout,"ERROR: Unknown flag %s.\n",argv[flagstart]-2);
+					fflush(stdout);
+				} else {
+					fprintf(stdout,"ERROR: Unknown program mode.\n");
+					fflush(stdout);
+				}
+				usage();
+			}
+			break;
+		case('l'):
+			flag = dummy;
+			ro = (int)*argv[flagstart];
+			switch(ro) {
+			case('a'): 	case('b'):	case('s'):
+				break;
+			default:
+				fprintf(stdout,"ERROR: Unknown program mode.\n");
+				fflush(stdout);
+				usage();
+			}
+			break;
+		case('p'):
+			flag = dummy;
+			ro = (int)*argv[flagstart]++;
+			switch(ro) {
+			case('n'): 	case('y'):	case('N'): 	case('Y'):
+				if(sscanf(argv[flagstart],"%lf",&factor)!=1) {
+					fprintf(stdout,"ERROR: Cannot read parameter value.\n");
+					fflush(stdout);
+					usage();
+				}
+				errorbnd = 0.0;
+				break;
+			default:
+				fprintf(stdout,"ERROR: Unknown program mode.\n");
+				fflush(stdout);
+				usage();
+			}
+			break;
+		case('S'): case('i'): case('o'): case('c'):
+			flag = dummy;
+			if(sscanf(argv[flagstart],"%lf",&factor)!=1) {
+				if(!sloom) {
+					fprintf(stdout,"Cannot read numerical value with flag 'S'|'i'|'o'|'c'.\n");
+					fflush(stdout);
+				} else {
+					fprintf(stdout,"ERROR: Cannot read parameter value.\n");
+					fflush(stdout);
+				}
+				usage();
+			}
+			ifactor = round(factor);
+			break;
+		case('y'):
+			if(flagstart == bas) {
+				flag = dummy;
+				ro = (int)*argv[flagstart];
+				switch(ro) {
+				case('z'):
+					if((other_params = (double *)malloc(4 * sizeof(double)))==NULL) {
+						fprintf(stdout,"ERROR: Out of memory.\n");
+						fflush(stdout);
+						exit(1);
+					}
+					break;
+				default:
+					fprintf(stdout,"ERROR: Unknown program mode.\n");
+					fflush(stdout);
+					usage();
+				}
+			} else {
+				k = flagstart - bas - 1;
+				if(sscanf(argv[flagstart],"%lf",other_params+k)!=1) {
+					fprintf(stdout,"ERROR: Cannot read parameter %d\n",k+1);
+					fflush(stdout);
+					usage();
+				}
+			}
+			break;
+		case('I'):
+			if(flagstart == bas) {
+				flag = dummy;
+				ro = (int)*argv[flagstart]++;
+				switch(ro) {
+				case(ENDOFSTR):
+					break;
+				case('P'):
+					if((other_params = (double *)malloc(4 * sizeof(double)))==NULL) {
+						fprintf(stdout,"ERROR: Out of memory.\n");
+						fflush(stdout);
+						exit(1);
+					}
+					break;
+				default:
+					fprintf(stdout,"ERROR: Unknown program mode.\n");
+					fflush(stdout);
+					usage();
+				}
+			} else {
+				k = flagstart - bas - 1;
+				if(sscanf(argv[flagstart],"%lf",other_params+k)!=1) {
+					fprintf(stdout,"ERROR: Cannot read parameter %d\n",k+1);
+					fflush(stdout);
+					usage();
+				}
+			}
+			break;
+		case('e'):
+			if(!sloom) {
+				if(sscanf(argv[flagstart],"%lf",&errorbnd)!=1) {
+					fprintf(stdout,"ERROR: Cannot read error bound with flag 'e'.\n");
+					fflush(stdout);
+					usage();
+				}
+				if(errorbnd <= 0.0) {
+					fprintf(stdout,"ERROR: Error bound impossible.\n");
+					fflush(stdout);
+					usage();
+				}
+				break;
+			}
+			/* fall thro */
+		default:
+			if(!sloom) {
+				fprintf(stdout,"Unknown flag %s.\n",--argv[flagstart]);
+				fflush(stdout);
+				usage();
+			} else {
+				if(sscanf(argv[flagstart],"%lf",&other_param)!=1) {
+					fprintf(stdout,"ERROR: Unknown program parameter '%s'.\n",argv[flagstart]);
+					fflush(stdout);
+					usage();
+				}
+				if(flag == 'S' || flag == 'p')
+					errorbnd = other_param;
+				if(flag == 'M')
+					ifactor = round(other_param);
+			}
+		}
+		flagstart++;
+	}
+	if(flag==0) {
+		if(!sloom) {
+			fprintf(stdout,"ERROR: No action specified.\n");
+			fflush(stdout);
+		} else {
+			fprintf(stdout,"ERROR: No program mode specified.\n");
+			fflush(stdout);
+		}
+		usage();
+	}
+}
+
+/************************* DO_INFILE ***************************/
+
+int do_infile(char *argv,double **number)
+{
+	int ccnt = 0;
+	char *p, temp[200];
+	FILE *fpi;
+	arraysize = BIGARRAY;
+	if((fpi = fopen(argv,"r"))==NULL) {
+		fprintf(stdout,"ERROR: Cannot open infile %s\n",argv);
+		fflush(stdout);
+		usage();
+	}
+	while(fgets(temp,200,fpi)!=NULL) {
+	p = temp;
+	while(strgetfloat(&p,&((*number)[ccnt]))) {
+		if(++ccnt >= arraysize) {
+			arraysize += BIGARRAY;
+			*number = (double *)exrealloc((char *)*number,arraysize*sizeof(double));
+		}
+	}
+	}
+	*number=(double *)exrealloc((char *)*number,ccnt*sizeof(double));
+	fclose(fpi);
+	return(ccnt);
+}
+
+/************************* DO_STRINGFILE ***************************/
+
+int do_stringfile(char *argv,char ***stringptr)
+{
+	int ccnt = 0;
+	char temp[200];
+	FILE *fpi;
+	arraysize = BIGARRAY;
+	if((fpi = fopen(argv,"r"))==NULL) {
+		fprintf(stdout,"ERROR: Cannot open infile %s\n",argv);
+		fflush(stdout);
+		usage();
+	}
+	while(fgets(temp,200,fpi)!=NULL) {
+		if(((*stringptr)[ccnt] = (char *)malloc(strlen(temp)+1)) == NULL) {
+			fprintf(stdout,"ERROR: No more memory for strings\n");
+			fflush(stdout);
+			exit(1);
+		}
+		strcpy((*stringptr)[ccnt],temp);
+		if(++ccnt >= arraysize) {
+			arraysize += BIGARRAY;
+			if((*stringptr = (char **)exrealloc((char *)*stringptr,arraysize*sizeof(char *)))== NULL) {
+				fprintf(stdout,"ERROR: No more memory for strings\n");
+				fflush(stdout);
+				exit(1);
+			}
+		}
+	}
+	fclose(fpi);
+	return(ccnt);
+}
+
+/**************************** FLTEQ *******************************/
+
+int flteq(double f1,double f2,double errorbnd)
+{
+	double upperbnd, lowerbnd;
+	upperbnd = f2 + errorbnd;		
+	lowerbnd = f2 - errorbnd;		
+	if((f1>upperbnd) || (f1<lowerbnd))
+		return(0);
+	return(1);
+}
+
+/******************************** LOGO **********************************/
+
+void logo(void)
+{	
+	printf("\t    ***************************************************\n");
+	printf("\t    *           COMPOSERS DESKTOP PROJECT             *\n");
+	printf("\t                   %s $Revision: 1.1 $\n",PROG);
+	printf("\t    *                                                 *\n");
+	printf("\t    *     Manipulate 2 columns of numbers (vectors)   *\n");
+	printf("\t    *                                                 *\n");
+	printf("\t    *                by TREVOR WISHART                *\n");
+	printf("\t    ***************************************************\n\n");
+}
+
+/***************************** EXREALLOC *****************************/
+
+char *exrealloc(char *p,int k)
+{
+	char *q;
+	if((q = malloc(k))==NULL) {
+		sprintf(errstr,"ERROR: reallocation of memory failed.\n");
+		do_error();
+	}
+	memcpy(q,p,k);
+/*	
+	if((q = realloc(p,k))==NULL) {
+		sprintf(errstr,"ERROR: reallocation of memory failed.\n");
+		do_error();
+	}
+*/
+	return(q);
+}
+
+/******************************** DO_ADD ****************************/
+
+void do_add(void)
+{
+	int n;
+	for(n=0;n<cnt;n++)
+		do_valout(number1[n]+number2[n]);
+}
+
+/******************************** DO_MEAN ****************************/
+
+void do_mean(void)
+{
+	int n;
+	for(n=0;n<cnt;n++)
+		do_valout((number1[n]+number2[n])/2.0);
+}
+
+/******************************** DO_MAX ****************************/
+
+void do_max(void)
+{
+	int n;
+	for(n=0;n<cnt;n++)
+		do_valout(max(number1[n],number2[n]));
+}
+
+/******************************** DO_MIN ****************************/
+
+void do_min(void)
+{
+	int n;
+	for(n=0;n<cnt;n++)
+		do_valout(min(number1[n],number2[n]));
+}
+
+/******************************** DO_SUBTRACT ****************************/
+
+void do_subtract(void)
+{
+	int n;
+	for(n=0;n<cnt;n++)
+		do_valout(number1[n]-number2[n]);
+}
+
+/******************************** DO_MULTIPLY ****************************/
+
+void do_multiply(void)
+{
+	int n;
+	for(n=0;n<cnt;n++)
+		do_valout(number1[n]*number2[n]);
+}
+
+/******************************** DO_DIVIDE ****************************/
+
+void do_divide(void)
+{
+	int n;
+	for(n=0;n<cnt;n++) {
+		if(flteq(number2[n],0.0,FLTERR)) {
+			if(!sloom) {
+				fprintf(fp,"INF\n");
+				fflush(stdout);
+			} else {
+				sprintf(errstr,"Division by zero encountered at item %d in 2nd column: Impossible\n",n+1);
+				do_error();
+			}
+		} else
+			do_valout(number1[n]/number2[n]);
+	}
+}
+
+/******************************** DO_OVERWRITE ****************************/
+
+void do_overwrite(void)
+{
+	int n, m = -1, k = 1;
+	for(n=0;n<cnt;n++) {
+		if(n%ifactor)
+			do_valout(number1[n]);
+		else {
+			if(k) {
+				if(++m >= cnt2) {
+					fprintf(stdout,"WARNING: Out of values in column2\n");
+					fflush(stdout);
+					k = 0;
+				} else
+					do_valout(number2[m]);
+			}
+		}
+	}	
+}
+
+/******************************** DO_INSERT ****************************/
+
+void do_insert(void)
+{
+	int n, m = -1, k = 1;
+	for(n=0;n<cnt;n++) {
+		if(k && !(n%ifactor)) {
+			if(++m >= cnt2) {
+				fprintf(stdout,"WARNING: Out of values in column2\n");
+				fflush(stdout);
+				k = 0;
+			} else
+				do_valout(number2[m]);
+		}
+		do_valout(number1[n]);
+	}
+}
+
+/******************************** DO_INTERLEAVE ****************************/
+
+void do_interleave(void)
+{
+	int n;
+	for(n=0;n<cnt;n++) {
+		if(!sloom) {
+			fprintf(fp,"%lf\n",number1[n]);
+			fprintf(fp,"%lf\n",number2[n]);
+			fflush(stdout);
+		} else {
+			fprintf(stdout,"INFO: %lf\n",number1[n]);
+			fprintf(stdout,"INFO: %lf\n",number2[n]);
+		}
+	}
+}
+
+/******************************** DO_INTERLEAVE ****************************/
+
+void do_patterned_interleave(void)
+{
+	int n, outcnt[2], incnt[2], range[2], lims[4], which = 0, thiscnt;
+	char **strs[2];
+	strs[0] = string0;
+	strs[1] = string1;
+	incnt[0] = cnt;
+	incnt[1] = cnt2;
+	outcnt[0] = 0;
+	outcnt[1] = 0;
+	for(n=0;n<4;n++) {
+		lims[n] = round(other_params[n]);
+		if(lims[n] < 0) {
+			fprintf(stdout,"ERROR: Parameter %d is less than zero: Cannot proceed\n",n+1);
+			fflush(stdout);
+			exit(1);
+		}
+	}
+	n = lims[2];		/* change order of params from 01,23 -> 02,13 */
+	lims[2] = lims[1];	/* so bottom of ranges are 0 and 1 */
+	lims[1] = n;
+
+	range[0] = lims[2] - lims[0];	/* drand over range 0 2, followed by floor, gives ... */
+	range[1] = lims[3] - lims[1];	/* nums in range 0to0.999 -> 0, nums in range 1to1.999 ->1, and val 2.0 only -> 2 */
+									/* so vanishingly small probability of generating 2.0 */
+	range[0]++;						/* adding 1 to range, makes equally probable 0,1,or2 will be generated */
+	range[1]++;						/* with vanishingly small probability of generating 3.0 (outside range) */				
+	for(;;) {								
+		thiscnt = (int)(floor(drand48() * range[which]));
+		if(thiscnt > range[which])	/* safety only : vanishingly small probability of generating number outside range */
+			thiscnt--;					
+		thiscnt +=  lims[which];
+		for(n = 0;n < thiscnt; n++) {
+			if(outcnt[which] >= incnt[which])
+				return;
+			if(!sloom)
+				fprintf(fp,"%s\n",strs[which][outcnt[which]++]);
+			else
+				fprintf(fp,"INFO: %s\n",strs[which][outcnt[which]++]);
+			fflush(stdout);
+		}
+		which = !which;
+	}
+}
+
+/******************************** DO_POWER ****************************/
+
+void do_power(void)
+{
+	int n, is_neg;
+	double output;
+	for(n=0;n<cnt;n++) {
+		is_neg = 0;
+		if(number1[n]<0.0) {
+			number1[n] = -number1[n];
+			is_neg = 1;
+		}
+		output = pow(number1[n],number2[n]);
+		if(is_neg)
+			output = -output;
+		do_valout(output);
+	}
+}
+
+/******************************** DO_RANDADD ****************************/
+
+void do_randadd(void)
+{
+	int n;
+	double sum;
+	for(n=0;n<cnt;n++) {
+		sum =  ((drand48() * 2.0) - 1.0) * number2[n];
+		do_valout(number1[n] + sum);
+	}
+}
+
+/******************************** DO_RANDMULT ****************************/
+
+void do_randmult(void)
+{
+	int n;
+	double sum;
+	for(n=0;n<cnt;n++) {
+		sum = drand48() * number2[n];
+		do_valout(number1[n] * sum);
+	}
+}
+
+/******************************** DO_RANDSCAT ****************************/
+
+void do_randscat(void)
+{
+	int n;
+	double *diffs, scatter;
+	if(number2[0]<0.0 || number2[0]>1.0) {
+		sprintf(errstr,"1st nuber in 2nd column (%lf) is out of range for this option.\n",number2[0]);
+		do_error();
+		}		
+	diffs = (double *)exmalloc((cnt-1)*sizeof(double));
+	for(n=0;n<cnt-1;n++) {
+	 	diffs[n] = number1[n+1] - number1[n];
+		if(number2[n]<0.0 || number2[n]>1.0) {
+			sprintf(errstr,"COLUMN2[%d] = %lf is out of range for this option.\n",n+1,number2[n]);
+			do_error();
+		}
+		diffs[n] /= 2.0;
+	}		
+	for(n=1;n<cnt-1;n++) {
+	scatter = ((drand48() * 2.0) - 1.0) * number2[n-1];
+	if(scatter > 0.0)
+		number1[n] += diffs[n] * scatter;
+	else
+		number1[n] += diffs[n-1] * scatter;
+	}
+	for(n=0;n<cnt;n++)
+		do_valout(number1[n]);
+}
+
+
+/******************************** DO_SUBSTITUTE ****************************/
+
+void do_substitute(void)
+{
+	int n, m = 0;
+	for(n=0;n<cnt;n++) {
+		if(flteq(number1[n],factor,errorbnd)) {
+			number1[n] = number2[m];
+			if(++m >= cnt2) {
+				fprintf(stdout,"WARNING: out of numbers in column2\n");
+				fflush(stdout);
+				break;
+			}
+		}
+	}
+	for(n=0;n<cnt;n++)
+		do_valout(number1[n]);
+}
+
+/******************************** DO_QUANTISE ****************************/
+
+void do_quantise(void)
+{
+	int n, m;
+
+	quantise_sort(number2,&cnt2);
+	for(n=0;n<cnt;n++) {
+		m = 0;
+		while(number1[n] > number2[m]) {
+			if(++m>=cnt2)
+			break;
+		}
+		if(m==0)	{ number1[n] = number2[0]; 	 continue; }
+		if(m==cnt2) { number1[n] = number2[cnt2-1]; continue; }
+		if(number2[m]-number1[n]<number1[n]-number2[m-1])
+			number1[n] = number2[m];
+		else
+			number1[n] = number2[m-1];
+	}
+	for(n=0;n<cnt;n++)
+		do_valout(number1[n]);
+}
+
+/*************************** TRUNCATE_VECTORS ************************/
+
+void truncate_vectors(void)
+{
+	int cntdiff;
+	if(flag!='S' && flag!='q' && flag!='i'&& flag!='o') {
+		if((cntdiff = cnt2 - cnt)>0) {
+			if(!sloom && !sloombatch)
+				fprintf(stdout,"column2 > column1 : truncating column2.\n");
+			else
+				fprintf(stdout,"WARNING: column2 > column1 : truncating column2.\n");
+			fflush(stdout);
+		} else if(cntdiff<0)  {
+			if(!sloom && !sloombatch)
+				fprintf(stdout,"column1 > column2 : truncating column1.\n");
+			else
+				fprintf(stdout,"WARNING: column1 > column2 : truncating column1.\n");
+			fflush(stdout);
+			cnt = cnt2;
+		}	
+	}
+}
+
+/*********************** QUANTISE_SORT *******************************
+ * 
+ * Sort set of doubles into ascending order.
+ */
+
+void quantise_sort(double *scti,int *scatcnt)
+{
+	double sct;
+	int n, m;
+	for(n=0;n<((*scatcnt)-1);n++) {
+		for(m=n+1;m<(*scatcnt);m++) {
+			if(*(scti+m)<*(scti+n)) {
+				sct 	  = *(scti+m);
+				*(scti+m) = *(scti+n);
+				*(scti+n) = sct;
+			}
+		}
+	}
+	for(n=0;n<((*scatcnt)-1);n++) {
+		if(flteq(*(scti+n+1),*(scti+n),FLTERR)) {
+			for(m = n; m < ((*scatcnt)-1); m++)
+				*(scti+m) = *(scti+m+1);
+			(*scatcnt)--;
+			n--;
+		}
+	}
+}
+
+/******************************** CONJOINA ****************************/
+
+void conjoina(void)
+{
+	int n;
+	for(n=0;n<cnt;n++)
+		fprintf(stdout,"INFO: %lf\n",number1[n]);
+	for(n=0;n<cnt2;n++)
+		fprintf(stdout,"INFO: %lf\n",number2[n]);
+}
+
+/******************************** CONJOINB ****************************/
+
+void conjoinb(void)
+{
+	int n;
+	for(n=0;n<cnt2;n++)
+		fprintf(stdout,"INFO: %lf\n",number2[n]);
+	for(n=0;n<cnt;n++)
+		fprintf(stdout,"INFO: %lf\n",number1[n]);
+}
+
+/******************************** CONJOIN_SORT ****************************/
+
+void conjoin_sort(void)
+{
+	int n = 0,m = 0, done = 0;
+	while(!done) {
+		if(number1[n] <= number2[m]) {
+			fprintf(stdout,"INFO: %lf\n",number1[n]);
+			if(++n >= cnt)
+				done = 1;
+		} else {
+			fprintf(stdout,"INFO: %lf\n",number2[m]);
+			if(++m >= cnt2)
+				done = 1;
+		}
+	}				/* Either 1 list is unfinished, or neither list is unfinished */
+					/* so print elements in whichever list is still unfinished */
+	while(n < cnt) {
+		fprintf(stdout,"INFO: %lf\n",number1[n]);
+		n++;
+	}
+	while(m < cnt2) {
+		fprintf(stdout,"INFO: %lf\n",number2[m]);
+		m++;
+	}
+	fflush(stdout);
+}
+
+/******************************** DO_KEEP ****************************/
+
+void do_keep(void)
+{
+	int n, i, warned = 0;
+	for(n=0;n<cnt2;n++) {
+		i = (int)(round(number2[n]));
+		if(i < 1) {
+			fprintf(stdout,"ERROR: There is no such position as %lf (%d)\n",number2[n],i);
+			fflush(stdout);
+			exit(1);
+		}		
+		i--;
+		if(i < cnt)
+			fprintf(stdout,"INFO: %lf\n",number1[i]);
+		else if(!warned) {
+			fprintf(stdout,"WARNING: There is no such position as %lf (%d)\n",number2[n],i);
+			fflush(stdout);
+			warned = 1;
+		}
+	}
+	fflush(stdout);
+}
+
+/******************************** DO_DEL ****************************/
+
+void do_del(void)
+{
+	int n, m, elimcnt, i, j, *delpos, warned = 0;
+	if((delpos = (int *)malloc(cnt2 * sizeof(int)))==NULL) {
+		fprintf(stdout,"ERROR: Out of memory.\n");
+		fflush(stdout);
+		exit(1);
+	}
+	elimcnt = 0;
+	for(n=0;n<cnt2;n++) {
+		i = (int)(round(number2[n]));
+		if(i < 1) {
+			fprintf(stdout,"ERROR: There is no such position as %lf (%d)\n",number2[n],i);
+			fflush(stdout);
+			exit(1);
+		}		
+		i--;
+		if(i < cnt)
+			delpos[elimcnt++] = i;
+		else if(!warned) {
+			fprintf(stdout,"WARNING: There is no such position as %lf (%d)\n",number2[n],i);
+			fflush(stdout);
+			warned = 1;
+		}
+	}
+	for(n=0;n<elimcnt-1;n++) {						/* eliminate duplicates */
+		for(m=n+1;m<elimcnt;m++) {
+			if(delpos[m] == delpos[n]) {	/* if values are equal */
+				i = m;
+				j = m+1;
+				while(j < elimcnt) {		/* If there are vals beyond here, shuffle down to eliminate delpos[m] */
+					delpos[i] = delpos[j];
+					i++;
+					j++;
+				}
+				elimcnt--;					/* total number of items reduced by 1 */
+				m--;						/* comparison cnt stays where it is */
+			}
+		}
+	}
+	for(n=0;n<elimcnt-1;n++) {						/* sort into ascending order */
+		for(m=n+1;m<elimcnt;m++) {
+			if(delpos[m] < delpos[n]) {
+				i		  = delpos[m];
+				delpos[m] = delpos[n];
+				delpos[n] = i;
+			}
+		}
+	}
+	i = 0;
+	for(n=0;n<cnt;n++) {					/* print all values not listed for elimination */
+		if(i < elimcnt) {
+			if(n != delpos[i])
+				fprintf(stdout,"INFO: %lf\n",number1[n]);
+			else
+				i++;
+		} else
+			fprintf(stdout,"INFO: %lf\n",number1[n]);
+	}
+	fflush(stdout);
+}
+
+/******************************** COMPARE ****************************/
+
+void compare(void)
+{
+	int n;
+	double upbnd, lobnd;
+	if(factor == 0) {
+		for(n = 0;n<cnt;n++) {
+			if(number1[n] != number2[n]) {
+				if(!sloom && !sloombatch)
+					fprintf(stdout,"Columns differ at item %d.\n",n+1);
+				else
+					fprintf(stdout,"WARNING: Columns differ at item %d.\n",n+1);
+				fflush(stdout);
+				exit(1);
+			}
+		}		
+		if(!sloom && !sloombatch)
+			fprintf(stdout,"Columns are the same.\n");
+		else
+			fprintf(stdout,"WARNING: Columns are the same.\n");
+	} else {
+		for(n = 0;n<cnt;n++) {
+			upbnd = number1[n] + factor;
+			lobnd = number1[n] - factor;
+			if(number2[n] > upbnd || number2[n] < lobnd) {
+				if(!sloom && !sloombatch)
+					fprintf(stdout,"Columns differ by more than permitted error at item %d.\n",n+1);
+				else
+					fprintf(stdout,"WARNING: Columns differ by more than permitted error at item %d.\n",n+1);
+				fflush(stdout);
+				exit(1);
+			}
+		}		
+		if(!sloom && !sloombatch)
+			fprintf(stdout,"Columns are equivalent within error range %lf\n",factor);
+		else
+			fprintf(stdout,"WARNING: Columns are equivalent within error range %lf\n",factor);
+	}
+	fflush(stdout);
+}
+
+/******************************** DEL_COPYS ****************************/
+
+void del_copys(void)
+{
+	int n, m, dupl;
+	for(n=0;n<cnt;n++) {
+		dupl = 0;
+		for(m=0;m<cnt2;m++) {
+			if(flteq(number1[n],number2[m],FLTERR)) {
+				dupl = 1;				
+				break;
+			}
+		}
+		if(!dupl)
+			fprintf(stdout,"INFO: %lf\n",number1[n]);
+	}
+	fflush(stdout);
+}
+
+/******************************** INSERT_NON_DUPLS ****************************/
+
+void insert_non_dupls(void)
+{
+	int n, m, k, dupl;
+	double temp;
+	if((number1 = (double *)realloc((char *)number1,(cnt + cnt2) * sizeof(double))) == NULL) {
+		fprintf(stdout,"ERROR: Out of memory.\n");
+		fflush(stdout);
+		exit(1);
+	}
+	k = cnt;
+	for(m=0;m<cnt2;m++) {
+		dupl = 0;
+		for(n=0;n<cnt;n++) {
+			if(flteq(number1[n],number2[m],FLTERR)) {
+				dupl = 1;				
+				break;
+			}
+		}
+		if(!dupl)
+			number1[k++] = number2[m];
+	}
+	cnt = k;
+	for(n=0;n<cnt-1;n++) {
+		for(m = n; m<cnt; m++) {
+			if(number1[m] < number1[n]) {
+				temp = number1[n];
+				number1[n] = number1[m];
+				number1[m] = temp;
+			}
+		}
+	}
+	for(n=0;n<cnt;n++)
+		fprintf(stdout,"INFO: %lf\n",number1[n]);
+	fflush(stdout);
+}
+
+/******************************** INSERT_NON_DUPLS ****************************/
+
+void partition_col(int atpos,int partition_incol)
+{
+	double *numbera, *numberb;
+	int n;
+	if(partition_incol) {
+		numbera = number2;
+		numberb = number1;
+	} else {
+		numbera = number1;
+		numberb = number2;
+	}
+	if(atpos) {
+		for(n = 0;n < cnt;n++) {
+			if(flteq(numbera[n],factor,errorbnd))
+				fprintf(stdout,"INFO: %lf\n",numberb[n]);
+		}
+	} else {
+		for(n = 0;n < cnt;n++) {
+			if(!flteq(numbera[n],factor,errorbnd))
+				fprintf(stdout,"INFO: %lf\n",numberb[n]);
+		}
+	}
+	fflush(stdout);
+}
+
+/******************************** DO_KEEP_IN_SPANS ****************************/
+
+void do_keep_in_spans(int is_del)
+{
+	int n,m;
+	double lo, hi;
+	if((cnt2<2) || (cnt2&1)) {
+		fprintf(stdout,"ERROR: Values in column two are not paired correctly.\n");
+		fflush(stdout);
+		exit(1);
+	}		
+	if(!cnt) {
+		fprintf(stdout,"ERROR: No Values in column one.\n");
+		fflush(stdout);
+		exit(1);
+	}		
+	lo = number1[0];
+	for(n=1;n<cnt;n++) {
+		if(number1[n] < lo) {
+			fprintf(stdout,"ERROR: Values in column one are not in ascending order.\n");
+			fflush(stdout);
+			exit(1);
+		}
+		lo = number1[n];		
+	}
+	lo = number2[0];
+	for(n=1;n<cnt2;n++) {
+		if(number2[n] < lo) {
+			fprintf(stdout,"ERROR: Values in column two are not in ascending order.\n");
+			fflush(stdout);
+			exit(1);
+		}		
+		lo = number2[n];		
+	}
+	n = 0;
+	m = 0;
+	lo = number2[m++];	
+	hi = number2[m++];	
+ 	switch(is_del) {
+	case(0):
+		do {
+			if(number1[n] < lo)								/* If below value pair range, ignore */
+				;
+			else if(number1[n] <= hi)						/* If within value pair range, print */
+				fprintf(stdout,"INFO: %lf\n",number1[n]);
+			else if(m >= cnt2)								/* if above value pair range */
+				break;										/* if there are no more pairs, finished */
+			else {
+				lo = number2[m++];							/* else, get next pair */
+				hi = number2[m++];	
+			}
+			n++;
+		} while(n < cnt);
+		break;
+	case(1):
+		do {
+			if(number1[n] < lo)								/* If below value pair range, print */
+				fprintf(stdout,"INFO: %lf\n",number1[n]);
+			else if(number1[n] <= hi)						/* If within value pair range, ignore */
+				;
+			else if(m >= cnt2)								/* if above value pair range */
+				break;										/* if there are no more pairs, finished with pairs */
+			else {
+				lo = number2[m++];							/* else, get next pair */
+				hi = number2[m++];						
+				n--;										/* but stay where we are in input numbers */
+			}
+			n++;
+		} while(n < cnt);
+
+		while(n < cnt)										/* If any vals above last pair, print */
+			fprintf(stdout,"INFO: %lf\n",number1[n++]);
+		break;
+	}
+	fflush(stdout);
+}
+
+/******************************** DO_KEEP_CYCLES ****************************/
+
+void do_keep_cycles(int do_keep)
+{
+	int n, j, m, k;
+	int OK = 0, diff, *pos;
+
+	pos = (int *)exmalloc(cnt2 * sizeof(int));
+	for(n=0;n<cnt2;n++) {
+		if((pos[n] = (int)round(number2[n])) < 1) {
+			fprintf(stdout,"ERROR: List positions below 1 do not exist.\n");
+			fflush(stdout);
+			exit(1);
+		}		
+		if(pos[n] > ifactor) {
+			fprintf(stdout,"ERROR: Position %d is outside the cycle length (%d).\n",pos[n],ifactor);
+			fflush(stdout);
+			exit(1);
+		}		
+		if(n > 0) {
+			if((diff = pos[n] - pos[n-1]) < 1) {
+				fprintf(stdout,"ERROR: Positions must be in ascending order.\n");
+				fflush(stdout);
+				exit(1);
+			}		
+			else if(!OK && (diff > 1))		/* if no previous step is greater than 1 */
+				OK = 1;						/* if this step is > 1, set as OK */
+		}
+	}
+	if(!OK && (pos[0] == 1) && (pos[n-1] == ifactor)) {
+		if(do_keep)
+			fprintf(stdout,"ERROR: All items will be retained.\n");
+		else
+			fprintf(stdout,"ERROR: All items will be deleted.\n");
+		fflush(stdout);
+		exit(1);
+	}
+	for(n=0;n<cnt2;n++)
+		pos[n]--;
+
+	if(do_keep) {
+		for(n=0;n<cnt;n+=ifactor) {			/* KEEP */
+			j = 0;
+			for(m=n+pos[0],k=pos[0];k<ifactor;k++,m++) {
+				if(m >= cnt)
+					break;
+				if(k == pos[j]) {
+					fprintf(stdout,"INFO: %lf\n",number1[m]);
+					if(++j >= cnt2)
+						break;
+				}
+			}
+		}
+	} else {
+		for(n=0;n<cnt;n+=ifactor) {			/* DELETE */
+			j = 0;
+			for(m=n,k=0;k<ifactor;k++,m++) {
+				if(m >= cnt)
+					break;
+				if(j < cnt2) {
+					if(k != pos[j])
+						fprintf(stdout,"INFO: %lf\n",number1[m]);
+					else
+						j++;
+				} else {
+					fprintf(stdout,"INFO: %lf\n",number1[m]);
+				}
+			}
+		}
+	}
+	fflush(stdout);
+}				
+
+/******************************** DO_MATCHES ****************************/
+
+void do_matches(void) {
+
+	int n, m, k;
+	for(n=0;n<cnt;n++) {
+		if(flteq(number1[n],factor,FLTERR)) {
+			for(k=0,m=n;k<ifactor;m++,k++)
+				fprintf(stdout,"INFO: %lf\n",number2[m]);
+		}
+	}
+	fflush(stdout);
+}
+
+/******************************** DO_ERROR ****************************/
+
+void do_error(void) {
+	if(!sloom && !sloombatch)
+		fprintf(stderr,"%s\n",errstr);
+	else {
+		fprintf(stdout,"ERROR: %s\n",errstr);
+		fflush(stdout);
+	}
+	exit(1);
+}
+
+/******************************** DO_VALOUT ****************************/
+
+void do_valout(double val) {
+	if(!sloom && !sloombatch)
+		fprintf(fp,"%lf\n",val);
+	else
+		fprintf(stdout,"INFO: %lf\n",val);
+}
+
+/******************************** DO_SQUEEZED_PAN ****************************/
+
+void do_squeezed_pan(void) {
+	int n, neg = 1;
+	double time_shoulder = other_params[0];
+	double start_panpos  = other_params[1];
+	double end_panpos    = other_params[2];
+	double end_pantime   = other_params[3];
+	double lastime;
+	double pan_subedj;
+
+	if(time_shoulder < 0.0) {
+		fprintf(stdout,"ERROR: half lingertime (%lf) cannot be less than zero.\n",time_shoulder);
+		fflush(stdout);
+		exit(1);
+	}
+	if(number1[0] < 0.0) {
+		fprintf(stdout,"ERROR: First time value less than zero encountered.\n");
+		fflush(stdout);
+		exit(1);
+	} else if(number1[0] <= time_shoulder) {
+		fprintf(stdout,"ERROR: First time (%lf) is too close to zero for half-lingertime %lf\n",number1[0],time_shoulder);
+		fflush(stdout);
+		exit(1);
+	}
+	lastime = number1[0];
+	for(n = 1; n < cnt; n++) {
+		if(number1[n] <= lastime + (2 * time_shoulder)) {
+			fprintf(stdout,"ERROR: Too small time step encountered (between %lf and %lf).\n",number1[n],lastime);
+			fflush(stdout);
+			exit(1);
+		}
+	}
+	if(end_pantime - time_shoulder <= number1[cnt-1]) {
+		fprintf(stdout,"ERROR: Too small time step encountered before end pantime (%lf to %lf).\n",number1[cnt -1],end_pantime);
+		fflush(stdout);
+		exit(1);
+	}
+	if(flteq(number1[0],0.0,FLTERR))
+		fprintf(stdout,"INFO: 0.0  %lf\n",number2[0]);
+	else {
+		pan_subedj = number2[0] * (7.5/9.0); 
+		fprintf(stdout,"INFO: 0.0  %lf\n",start_panpos);
+		fprintf(stdout,"INFO: %lf  %lf\n",number1[0] - time_shoulder,pan_subedj);
+		fprintf(stdout,"INFO: %lf  %lf\n",number1[0],number2[0]);
+		fprintf(stdout,"INFO: %lf  %lf\n",number1[0] + time_shoulder,pan_subedj);
+	}
+	if(number2[0] > 0.0)
+		neg = -1;
+	for(n = 1; n < cnt; n++) {
+		number2[n] *= neg;
+		pan_subedj = number2[n] * (7.5/9.0); 
+		fprintf(stdout,"INFO: %lf  %lf\n",number1[n] - time_shoulder,pan_subedj);
+		fprintf(stdout,"INFO: %lf  %lf\n",number1[n],number2[n]);
+		fprintf(stdout,"INFO: %lf  %lf\n",number1[n] + time_shoulder,pan_subedj);
+		lastime = number1[n];
+		neg = -neg;
+	}
+	fprintf(stdout,"INFO: %lf  %lf\n",end_pantime,end_panpos);
+	fflush(stdout);
+}	
+
+/************************************** GENERAL *****************************************/
+
+#ifdef NOTDEF
+
+void
+initrand48()
+{
+	srand(time((time_t *)0));
+}
+
+double
+drand48()
+{
+	return (double)rand()/(double)RAND_MAX;
+}
+#endif
+/******************************** DO_MORPHSEQ ****************************/
+
+void do_morphseq(void) {
+
+	int n = 0, morphcnt;
+	int minlen = min(cnt,cnt2);
+	int startmorph = (int)round(factor) - 1;
+	int endmorph = ifactor - 1;
+	int morphlen = endmorph - startmorph + 1;
+	double last1val, last2val, outval, diff1, diff2, trudiff;
+	while(n <= startmorph) {
+		fprintf(stdout,"INFO: %lf\n",number1[n]);
+		n++;
+	}
+	n--;
+	last1val = number1[n];
+	last2val = number2[n];
+	outval   = number1[n];
+	n++;
+	morphcnt = 1;
+	while(n <= endmorph) {
+		diff1 = number1[n] - last1val;
+		diff2 = number2[n] - last2val;
+		last1val = number1[n];
+		last2val = number2[n];
+		trudiff = ((diff2 - diff1) * ((double)morphcnt/(double)morphlen)) + diff1;
+		outval += trudiff;
+		fprintf(stdout,"INFO: %lf\n",outval);
+		morphcnt++;
+		n++;
+	}
+	while(n < minlen) {
+		diff2 = number2[n] - last2val;
+		last2val = number2[n];
+		outval += diff2;
+		fprintf(stdout,"INFO: %lf\n",outval);
+		n++;
+	}
+	fflush(stdout);
+}
+
+/******************************** DO_MORPH ****************************/
+
+void do_morph(void) {
+
+	int n = 0, morphcnt;
+	int minlen = min(cnt,cnt2);
+	int startmorph = (int)round(factor) - 1;
+	int endmorph = ifactor - 1;
+	int morphlen = endmorph - startmorph + 1;
+	while(n <= startmorph) {
+		fprintf(stdout,"INFO: %lf\n",number1[n]);
+		n++;
+	}
+	morphcnt = 1;
+	while(n < endmorph) {
+		fprintf(stdout,"INFO: %lf\n",((number2[n] - number1[n]) * ((double)morphcnt/(double)morphlen)) + number1[n]);
+		morphcnt++;
+		n++;
+	}
+	while(n < minlen) {
+		fprintf(stdout,"INFO: %lf\n",number2[n]);
+		n++;
+	}
+	fflush(stdout);
+}
+

+ 20 - 0
dev/texture/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(texture main.c ap_texture.c texperm.c texture1.c
+                       texture2.c texture3.c texture4.c texture5.c texprepro.c) 
+
+target_link_libraries(texture cdp2k sfsys ${EXTRA_LIBRARIES})
+my_install(texture)
+

+ 891 - 0
dev/texture/ap_texture.c

@@ -0,0 +1,891 @@
+/*
+ * 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
+ *
+ */
+/* 03/2020: TW/RWD: corrected usage message argument lists */
+
+/* floatsam version: no changes */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <structures.h>
+#include <cdpmain.h>
+#include <tkglobals.h>
+#include <pnames.h>
+#include <texture.h>
+#include <processno.h>
+#include <modeno.h>
+#include <globcon.h>
+#include <logic.h>
+#include <filetype.h>
+#include <mixxcon.h>
+#include <flags.h>
+#include <speccon.h>
+#include <arrays.h>
+#include <special.h>
+#include <formants.h>
+#include <sfsys.h>
+#include <osbind.h>
+
+#include <srates.h>
+
+/********************************************************************************************/
+/********************************** FORMERLY IN pconsistency.c ******************************/
+/********************************************************************************************/
+
+static int  texture_pconsistency(dataptr dz);
+
+/********************************************************************************************/
+/********************************** FORMERLY IN specialin.c *********************************/
+/********************************************************************************************/
+
+static int  get_the_notedatafile(char *filename,dataptr dz);
+
+/***************************************************************************************/
+/****************************** FORMERLY IN aplinit.c **********************************/
+/***************************************************************************************/
+
+/***************************** ESTABLISH_BUFPTRS_AND_EXTRA_BUFFERS **************************/
+
+int establish_bufptrs_and_extra_buffers(dataptr dz)
+{
+    /*int is_spec = FALSE;*/
+    dz->bptrcnt = 0;
+    dz->bufcnt  = 0;
+    switch(dz->process) {
+    case(SIMPLE_TEX):
+    case(TIMED):
+    case(GROUPS):
+    case(TGROUPS):
+    case(DECORATED):
+    case(PREDECOR): 
+    case(POSTDECOR):
+    case(ORNATE):
+    case(PREORNATE):
+    case(POSTORNATE):
+    case(MOTIFS):
+    case(TMOTIFS):
+    case(MOTIFSIN):
+    case(TMOTIFSIN):
+        dz->extra_bufcnt = 0;   dz->bufcnt = 1;
+        break;
+    default:
+        sprintf(errstr,"Unknown program type [%d] in establish_bufptrs_and_extra_buffers()\n",dz->process);
+        return(PROGRAM_ERROR);
+    }
+    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(SIMPLE_TEX):
+    case(TIMED):
+    case(GROUPS):
+    case(TGROUPS):
+    case(DECORATED):
+    case(PREDECOR): 
+    case(POSTDECOR):
+    case(ORNATE):
+    case(PREORNATE):
+    case(POSTORNATE):
+    case(MOTIFS):
+    case(TMOTIFS):
+    case(MOTIFSIN):
+    case(TMOTIFSIN):
+        dz->array_cnt = 1; dz->iarray_cnt = 6; 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(SIMPLE_TEX):
+    case(TIMED):
+    case(GROUPS):
+    case(TGROUPS):
+    case(DECORATED):
+    case(PREDECOR):
+    case(POSTDECOR):
+    case(ORNATE):
+    case(PREORNATE):
+    case(POSTORNATE):
+    case(MOTIFS):
+    case(TMOTIFS):
+    case(MOTIFSIN):
+    case(TMOTIFSIN):
+        setup_process_logic(ONE_OR_MANY_SNDFILES,   UNEQUAL_SNDFILE,    SNDFILE_OUT,    dz);
+        break;
+    default:
+        sprintf(errstr,"Unknown process: assign_process_logic()\n");
+        return(PROGRAM_ERROR);
+        break;
+    }
+    if(dz->has_otherfile) {
+        switch(dz->input_data_type) {
+        case(ALL_FILES):
+        case(TWO_SNDFILES):
+        case(SNDFILE_AND_ENVFILE):
+        case(SNDFILE_AND_BRKFILE):
+        case(SNDFILE_AND_UNRANGED_BRKFILE):
+        case(SNDFILE_AND_DB_BRKFILE):
+            break;
+        case(MANY_SNDFILES):
+            if(dz->process==INFO_TIMELIST)
+                break;
+            /* fall thro */
+        default:
+            sprintf(errstr,"Most processes accepting files with different properties\n"
+                           "can only take 2 sound infiles.\n");
+            return(PROGRAM_ERROR);
+        }
+    }
+    return(FINISHED);
+}
+
+/***************************** SET_LEGAL_INFILE_STRUCTURE **************************
+ *
+ * Allows 2nd infile to have different props to first infile.
+ */
+
+void set_legal_infile_structure(dataptr dz)
+{
+    switch(dz->process) {
+    default:
+        dz->has_otherfile = FALSE;
+        break;
+    }
+}
+
+/***************************************************************************************/
+/****************************** FORMERLY IN internal.c *********************************/
+/***************************************************************************************/
+
+/****************************** SET_LEGAL_INTERNALPARAM_STRUCTURE *********************************/
+
+int set_legal_internalparam_structure(int process,int mode,aplptr ap)
+{
+    int exit_status = FINISHED;
+    switch(process) {
+    case(SIMPLE_TEX):   case(TIMED):    case(GROUPS):   case(TGROUPS):
+    case(DECORATED):    case(PREDECOR): case(POSTDECOR):
+    case(ORNATE):       case(PREORNATE):case(POSTORNATE):
+    case(MOTIFS):       case(TMOTIFS):  case(MOTIFSIN): case(TMOTIFSIN):
+                        exit_status = set_internalparam_data("iiidddi",ap);         break;
+    default:
+        sprintf(errstr,"Unknown process in set_legal_internalparam_structure()\n");
+        return(PROGRAM_ERROR);
+    }
+    return(exit_status);
+}
+
+/********************************************************************************************/
+/********************************** FORMERLY IN specialin.c *********************************/
+/********************************************************************************************/
+
+/********************** READ_SPECIAL_DATA ************************/
+
+int read_special_data(char *str,dataptr dz)
+{
+/*  int exit_status = FINISHED;*/
+    aplptr ap = dz->application;
+    switch(ap->special_data) {
+    case(TEX_NOTEDATA):         return get_the_notedatafile(str,dz);
+    default:
+        sprintf(errstr,"Unknown special_data type: read_special_data()\n");
+        return(PROGRAM_ERROR);
+    }
+    return(FINISHED);   /* NOTREACHED */
+}
+
+/***************************** GET_THE_NOTEDATAFILE ****************************/
+
+int get_the_notedatafile(char *filename,dataptr dz)
+{
+    if((dz->fp = fopen(filename,"r"))==NULL) {
+        sprintf(errstr,"Failed to open notedata file %s\n",filename);
+        return(DATA_ERROR);
+    }
+    return(FINISHED);
+}
+
+/********************************************************************************************/
+/********************************** FORMERLY IN preprocess.c ********************************/
+/********************************************************************************************/
+
+/****************************** PARAM_PREPROCESS *********************************/
+
+int param_preprocess(dataptr dz)
+{
+/*  int exit_status = FINISHED;*/
+
+    switch(dz->process) {
+    case(SIMPLE_TEX):   case(TIMED):    case(GROUPS):   case(TGROUPS):
+    case(DECORATED):    case(PREDECOR): case(POSTDECOR):
+    case(ORNATE):       case(PREORNATE):case(POSTORNATE):
+    case(MOTIFS):       case(TMOTIFS):  case(MOTIFSIN): case(TMOTIFSIN):
+         return texture_preprocess(dz);
+    default:
+        sprintf(errstr,"PROGRAMMING PROBLEM: Unknown process in param_preprocess()\n");
+        return(PROGRAM_ERROR);
+    }
+    return(FINISHED);   /* NOTREACHED */
+}
+
+/********************************************************************************************/
+/********************************** FORMERLY IN procgrou.c **********************************/
+/********************************************************************************************/
+
+/**************************** GROUCHO_PROCESS_FILE ****************************/
+
+int groucho_process_file(dataptr dz)   /* FUNCTIONS FOUND IN PROCESS.C */
+{   
+    int exit_status = FINISHED;
+
+    switch(dz->process) {
+    case(SIMPLE_TEX):   case(TIMED):    case(GROUPS):   case(TGROUPS):
+    case(DECORATED):    case(PREDECOR): case(POSTDECOR):
+    case(ORNATE):       case(PREORNATE):case(POSTORNATE):
+    case(MOTIFS):       case(MOTIFSIN): case(TMOTIFS):  case(TMOTIFSIN):
+        if((exit_status = make_texture(dz))<0)
+            return(exit_status);
+        if((exit_status = produce_texture_sound(dz))<0)
+            return(exit_status);
+        break;
+    default:
+        sprintf(errstr,"Unknown case in process_file()\n");
+        return(PROGRAM_ERROR);
+    }
+    return(FINISHED);
+}
+
+/********************************************************************************************/
+/********************************** FORMERLY IN pconsistency.c ******************************/
+/********************************************************************************************/
+
+/****************************** CHECK_PARAM_VALIDITY_AND_CONSISTENCY *********************************/
+
+int check_param_validity_and_consistency(dataptr dz)
+{
+/*  int exit_status = FINISHED;*/
+    handle_pitch_zeros(dz);
+    switch(dz->process) {
+    case(SIMPLE_TEX): case(TIMED):      case(GROUPS):   case(TGROUPS):
+    case(DECORATED):  case(PREDECOR):   case(POSTDECOR):
+    case(ORNATE):     case(PREORNATE):  case(POSTORNATE):
+    case(MOTIFS):     case(TMOTIFS):    case(MOTIFSIN): case(TMOTIFSIN):
+                        return texture_pconsistency(dz);
+    }
+    return(FINISHED);
+}
+
+/***************************** PREPARE_TEXTURE_PARAMETERS ****************************/
+
+int texture_pconsistency(dataptr dz)
+{
+    double *p, *end;
+    int OK = TRUE;
+    if(dz->brksize[TEXTURE_INSLO]) {
+        p = dz->brk[TEXTURE_INSLO] + 1;
+        end = dz->brk[TEXTURE_INSLO] + (dz->brksize[TEXTURE_INSLO] * 2);
+        while(p < end) {
+            if(*p  > (double)dz->infilecnt) {
+                OK = FALSE;
+                break;
+            }
+            p += 2;
+        }
+    } else if(dz->iparam[TEXTURE_INSLO] > dz->infilecnt)
+        OK  = FALSE;
+    if(!OK) {
+        sprintf(errstr,"FIRST SND-IN-LIST TO USE > count of files entered: cannot proceed.\n");
+        return(DATA_ERROR);
+    }
+    OK = TRUE;
+    if(dz->brksize[TEXTURE_INSHI]) {
+        p = dz->brk[TEXTURE_INSHI] + 1;
+        end = dz->brk[TEXTURE_INSHI] + (dz->brksize[TEXTURE_INSHI] * 2);
+        while(p < end) {
+            if(*p  > (double)dz->infilecnt) {
+                OK = FALSE;
+                break;
+            }
+            p += 2;
+        }
+    } else if(dz->iparam[TEXTURE_INSHI] > dz->infilecnt)
+        OK  = FALSE;
+    if(!OK) {
+        sprintf(errstr,"LAST SND-IN-LIST TO USE > count of files entered: cannot proceed.\n");
+        return(DATA_ERROR);
+    }
+    return(FINISHED);
+}
+
+
+
+/********************************************************************************************/
+/********************************** FORMERLY IN buffers.c ***********************************/
+/********************************************************************************************/
+
+/**************************** ALLOCATE_LARGE_BUFFERS ******************************/
+
+int allocate_large_buffers(dataptr dz)
+{
+    switch(dz->process) {
+    case(SIMPLE_TEX):
+    case(TIMED):        case(GROUPS):       case(TGROUPS):
+    case(DECORATED):    case(PREDECOR):     case(POSTDECOR):
+    case(ORNATE):       case(PREORNATE):    case(POSTORNATE):
+    case(MOTIFS):       case(TMOTIFS):      case(MOTIFSIN): 
+    case(TMOTIFSIN):
+        return create_sndbufs(dz);
+    default:
+        sprintf(errstr,"Unknown program no. in allocate_large_buffers()\n");
+        return(PROGRAM_ERROR);
+    }
+    return(FINISHED);   /* NOTREACHED */
+}
+
+/********************************************************************************************/
+/********************************** FORMERLY IN cmdline.c ***********************************/
+/********************************************************************************************/
+
+int get_process_no(char *prog_identifier_from_cmdline,dataptr dz)
+{
+    if     (!strcmp(prog_identifier_from_cmdline,"simple"))         dz->process = SIMPLE_TEX;
+    else if(!strcmp(prog_identifier_from_cmdline,"grouped"))        dz->process = GROUPS;
+    else if(!strcmp(prog_identifier_from_cmdline,"motifs"))         dz->process = MOTIFS;
+    else if(!strcmp(prog_identifier_from_cmdline,"motifsin"))       dz->process = MOTIFSIN;
+    else if(!strcmp(prog_identifier_from_cmdline,"decorated"))      dz->process = DECORATED;
+    else if(!strcmp(prog_identifier_from_cmdline,"predecor"))       dz->process = PREDECOR;
+    else if(!strcmp(prog_identifier_from_cmdline,"postdecor"))      dz->process = POSTDECOR;
+    else if(!strcmp(prog_identifier_from_cmdline,"ornate"))         dz->process = ORNATE;
+    else if(!strcmp(prog_identifier_from_cmdline,"preornate"))      dz->process = PREORNATE;
+    else if(!strcmp(prog_identifier_from_cmdline,"postornate"))     dz->process = POSTORNATE;
+    else if(!strcmp(prog_identifier_from_cmdline,"timed"))          dz->process = TIMED;
+    else if(!strcmp(prog_identifier_from_cmdline,"tgrouped"))       dz->process = TGROUPS;
+    else if(!strcmp(prog_identifier_from_cmdline,"tmotifs"))        dz->process = TMOTIFS;
+    else if(!strcmp(prog_identifier_from_cmdline,"tmotifsin"))      dz->process = TMOTIFSIN;
+    else {
+        sprintf(errstr,"Unknown program identification string '%s'\n",prog_identifier_from_cmdline);
+        return(USAGE_ONLY);
+    }
+
+    return FINISHED;
+}
+
+/********************************************************************************************/
+/********************************** FORMERLY IN usage.c *************************************/
+/********************************************************************************************/
+
+/******************************** USAGE1 ********************************/
+
+int usage1(void)
+{
+    fprintf(stdout, /* HAs to use fprintf because of kbhit */
+    "\n"
+    "USAGE:\ntexture NAME (mode) infile (infile2..etc) outfile notedata params:\n"
+    "\n"
+    "\nwhere NAME can be any one of\n"
+    "\n"
+    "\tTEXTURE MADE FROM ONE OR SEVERAL SOUND FILES\n"
+    "\n"
+    "simple   grouped    decorated    ornate       motifs\n"
+    "                    predecor     preornate    motifsin\n"
+    "                    postdecor    postornate\n"
+    "\n"
+    "\tTIMED TEXTURES MADE FROM ONE OR SEVERAL SOUND FILES\n"
+    "\n"
+    "timed     tmotifs   tmotifsin   tgrouped\n"
+    "\n"
+    "ORNAMENTS & MOTIFS   have user-specified pitch-shapes.\n"
+    "DECORATIONS & GROUPS have random pitch-shapes.\n"
+    "\n"
+    "Type 'texture simple' for more info on simple texture option.... etc.\n"
+    "\n"
+#ifdef IS_PC
+    "MORE??? ----- (hit keyboard)\n"
+    "\n");
+
+    while(!kbhit())
+        ;
+    if(kbhit()) {
+#else
+    "\n");
+#endif
+        fprintf(stdout,
+        "\n"
+        "*********************************************************************\n"
+        "SOME SPECIAL PARAMETER VALUES\n"
+        "*********************************************************************\n"
+        "GPSPACE: spatialisation of event-groups\n"
+        "\n"
+        "     0:still            1:scattered(default) 2:towards-texture-centre\n"
+        "     3:away-from-centre 4:follow-texmotion   5:contrary-to-motion\n"
+        "     4 & 5 only function if spatial position varies in time..\n"
+        "*********************************************************************\n"
+        "CONTOUR: amplitude contour of groups\n"
+        "\n"
+        "     0:mixed(default) 1:cresc     2:flat   3:decresc    4:c_or_fl\n"
+        "     5:c_or_d         6:d_or_fl  [7:directed_to_event   8:dir_or_flat]\n"
+        "*********************************************************************\n"
+        "CENTRING: how decoration pitches centre on decorated line pitches\n"
+        "\n"
+        "     0: centred(default) 1: above       2: below\n"
+        "     3: c_and_a          4: c_and_b     5: a_and_b     6: c_and_a_and_b\n"
+        "     In all cases except 0, pitchrange shifted to tally with line pitch\n\n"
+        "\n"
+        "*********************************************************************\n"
+        "       ALL OTHER PARAMS, except outdur, MAY VARY IN TIME.\n"
+        "*********************************************************************\n"
+        "\n"
+
+#ifdef IS_PC
+        "MORE??? ----- (hit keyboard)\n");
+    }
+    _getch();
+    while(!kbhit())
+        ;
+    if(kbhit()) {
+#else
+        "\n");
+#endif
+
+        fprintf(stdout,
+        "\n"
+        "*********************************************************************\n"
+        "HARMONIC SETS   use only the pitches specified.\n"
+        "\n"
+        "HARMONIC FIELDS duplicate the specified pitches in all 8vas.\n"
+        "*********************************************************************\n"
+        "NOTEDATA is in a textfile containing.....\n"
+        "*********************************************************************\n"
+        "     assumed MIDI 'pitch' of each input snd, specified on 1st line.\n"
+        "\n"
+        "   FOLLOWED BY, where ness,  NOTELIST(S), SPECIFIED THUS:-\n"
+        "\n"
+        "     #N (where N = no. of notes in notelist: follows by N lines of...)\n"
+        "     time(SECS)   infile_no    pitch(MIDI)    amp(MIDI)   dur(SECS)\n"
+        "\n"
+        "where times within motif must increase (or remain same, during chords)\n"
+        "*********************************************************************\n"
+        "NOTELISTS REPRESENT: IN THIS ORDER..\n"
+        "*********************************************************************\n"
+        "Notelist of notes in any timed, ornamented or decorated line in texture.\n"
+        "Notelist of notes in any harmonic field(s) or set(s) specified.\n"
+        "      (For more than one  hfield(hset),\n"
+        "      data should specify chords, placed at appropriae times.)\n"
+        "Notelist(s) of notes in any ornament(s) or motif(s) specified.\n"
+        "*********************************************************************\n");
+
+#ifdef IS_PC
+    }
+#endif
+    return(USAGE_ONLY);
+}
+
+/******************************** USAGE2 ********************************/
+
+int usage2(char *str)
+{
+    if(!strcmp(str,"simple")) {
+        fprintf(stdout,
+        "USAGE:\n"
+        "texture simple mode infile [infile2...] outfile notedata outdur packing scatter\n"
+        "   tgrid sndfirst sndlast  mingain maxgain  mindur maxdur  minpich maxpich omit\n"
+        "             [-aatten] [-pposition] [-sspread] [-rseed] [-w -c -p]\n"
+        "MODES:-\n"
+        "1)  ON A GIVEN HARMONIC-FIELD        3)  ON A GIVEN HARMONIC-SET\n"
+        "2)  ON CHANGING HARMONIC-FIELDS      4)  ON CHANGING HARMONIC-SETS\n"
+        "5)  NONE\n"
+        "notedata: infofile, insnd 'pitches',harmonic fields pitches etc.\n"
+        "outdur:           (min) duration of outfile\n"
+        "packing:          (average) time between event onsets.\n"  
+        "scatter:          randomisation of event-onsets (0 - %.0lf)\n"
+        "tgrid:            minstep(MS) quantised timegrid(for grp starttimes)(default 0)\n"
+        "sndfirst,sndlast: 1st,last snd to use,from list of insnds(range:1 - no.of snds)\n"
+        "mingain,maxgain:  minimum & maximum level of input events (1-127:default 64,64)\n"
+        "mindur,maxdur:    minimum & maximum duration of events in texture\n"
+        "minpich,maxpich:  minimum & maximum pitch (MIDI VALUE):\n"
+        "omit:             1 in \"omit\" events are silent.\n"
+        "                  less and less silent events as param increases.\n"
+        "                  at 64 (as at zero) NO events are silent.\n"
+        "atten:            overall attenuation of the output\n"
+        "position:         centre of output sound-image (0(Left) 1(Right): default 0.5)\n"
+        "spread:           spatial-spread of texture events (0 - 1(full-spread))\n"
+        "seed:             same seed-no: same output on rerun(dflt 0: differs each time)\n"
+        "-w:               always play whole input-sound (ignoring duration values).\n"
+        "-c:               Choose files cyclically in listed order (ignore 'sndfirst','last').\n"
+        "-p:               Random permute each cycle (only when -c flag set).\n",MAX_SCAT_TEXTURE);
+    } else if(!strcmp(str,"timed")) {
+        fprintf(stdout,
+        "TIMED TEXTURE:  USAGE:\n"
+        "texture timed mode infile [infile2...]  outfile  notedata     outdur skiptime\n"
+        "             sndfirst sndlast mingain maxgain mindur maxdur minpitch maxpitch\n"
+        "             [-aatten] [-pposition] [-sspread] [-rseed] [-w]\n"
+        "MODES:-\n"
+        "1)  ON A GIVEN HARMONIC-FIELD        3)  ON A GIVEN HARMONIC-SET\n"
+        "2)  ON CHANGING HARMONIC-FIELDS      4)  ON CHANGING HARMONIC-SETS\n"
+        "5)  NONE\n"
+        "notedata: infofile, insnd 'pitches',texture timing,harmonic fields pitches etc.\n"
+        "outdur:            (min) duration of outfile\n"
+        "skiptime:          time between repetitions of timing motif in notedata\n"
+        "sndfirst,sndlast:  1st,last snd to use,from list of insnds(range:1 - all)\n"
+        "mingain,maxgain:   min & max level of input events (1-127:default 64,64)\n"
+        "mindur,maxdur:     min & max duration of events in texture\n"
+        "minpitch,maxpitch: min & max pitch (MIDI VALUE)\n"
+        "atten:             overall attenuation of the output\n"
+        "position:          centre of output sound-image (0(Left) 1(Right):default 0.5)\n"
+        "spread:            spatial-spread of texture events (0 - 1(full-spread))\n"
+        "seed:             same seed-no: same output on rerun(dflt 0: differs each time)\n"
+        "-w:                always play whole input-sound (ignoring duration values).\n");
+    } else if(!strcmp(str,"grouped")) {
+        fprintf(stdout,
+        "TEXTURE OF EVENT-GROUPS: USAGE: texture grouped mode infile [infile2..] outfile\n"
+        "notedata outdur packing scatter tgrid\n"
+        "sndfirst sndlast mingain maxgain mindur maxdur minpitch maxpitch phgrid gpspace\n"
+        "gpsprange amprise contour gpsizelo gpsizehi gppaklo gppakhi gpranglo gpranghi\n"
+        "                   [-aatten] [-pposition] [-sspread] [-rseed] [-w] [-d] [-i]\n"
+        "MODES:-\n"
+        "1)ON HARMONIC-FIELD 2)CHANGING HFLDS 3)HARMONIC-SET 4)CHANGING HSETS 5)NONE\n"
+        "notedata:   infofile, 'pitch' of insnds, harmonic fields etc.\n"
+        "outdur:     (min) duration of outfile\n"
+        "packing:    (average) time between group onsets.\n"  
+        "scatter:    randomisation of event-onsets (0 - %.0lf)\n"
+        "tgrid:      minstep(MS) quantised timegrid(for grp starttimes)(default 0)\n"
+        "sndfirst,sndlast: 1st,last snd to use, from list of insnds(range:1 - all)\n"
+        "mingain,maxgain:  min & max level of input events (1-127:default 64,64)\n"
+        "mindur,maxdur:    min & max duration of events in texture\n"
+        "minpitch,maxpitch:min & max pitch (MIDI VALUE)\n"
+        "phgrid:     a timegrid (MS) applying WITHIN the groups\n"
+        "gpspace:    spatialisation of event-groups (Range 0-5: default 1)\n"
+        "gpsprange:  spatial range of event-groups (Range 0-1: default 1)\n"
+        "amprise:    amplitude change within groups: (0-127: default 0)\n"
+        "contour:    amplitude contour of groups (Range 0-6: default 0)\n"
+            /* NOTE : CARE all_types is 7 AND NOT 8 here */
+        "gpsizelo,gpsizehi:smallest,largest no. of events in groups\n"
+        "gppaklo,gppakhi:  shortest,longest time between event-onsets in groups (MS)\n"
+        "gpranglo,gpranghi:min,max pitchrange grps OR (hfields) no.of hf-notes range\n"
+        "atten:      overall attenuation of output\n"
+        "position:   centre of output sound-image (0(Left) 1(Right): default 0.5)\n"
+        "spread:     spatial-spread of texture events (0 - 1(full-spread))\n"
+        "seed:       same seed-no: same output on rerun(dflt 0: differs each time)\n"
+        "-w:         always play whole input-sound (ignore maxdur,mindur vals).\n"
+        "-d:         fixed timestep between groupnotes.\n"
+        "-i:         each group not confined to a fixed instr (default:fixed)\n",MAX_SCAT_TEXTURE);
+    } else if(!strcmp(str,"tgrouped")) {
+        fprintf(stdout,
+        "TIMED TEXTURE OF EVENT-GROUPS: USAGE: texture tgrouped mode infile [infile2..]\n"
+        "outfile notedata outdur skip sndfirst sndlast mingain maxgain mindur maxdur\n"
+        "minpitch maxpitch phgrid gpspace gpsprange amprise contour gpsizelo gpsizehi\n"
+        "gppacklo gppackhi gpranglo gpranghi\n"
+        "                   [-aatten] [-pposition] [-sspread] [-rseed] [-w] [-d] [-i]\n"
+        "MODES:-\n"
+        "1)  ON A GIVEN HARMONIC-FIELD        3)  ON A GIVEN HARMONIC-SET\n"
+        "2)  ON CHANGING HARMONIC-FIELDS      4)  ON CHANGING HARMONIC-SETS\n"
+        "5)  NONE\n"
+        "notedata: infofile, 'pitch' of insnds, timings for timed textures, hfields etc\n"
+        "outdur:           (min) duration of outfile\n"
+        "skip:             time between repetitions of timing motif in notedata\n"
+        "sndfirst,sndlast: 1st,last snd to use from list of insnds(range:1 - all)\n"
+        "mingain,maxgain:  min & max level of input events (1-127:default 64,64)\n"
+        "mindur,maxdur:    min & max duration of events in texture\n"
+        "minpitch,maxpitch:min & max pitch (MIDI VALUE)\n"
+        "phgrid:           timegrid (MS) applying WITHIN the groups\n"
+        "gpspace:          spatialisation of event-groups (Range 0-5: default 1)\n"
+        "gpsprange:        spatial range of event-groups (Range 0-1: default 1)\n"
+        "amprise:          amplitude change within groups: (0-127: default 0)\n"
+        "contour:          amplitude contour of groups (Range 0-6: default 0)\n"
+            /* NOTE : CARE all_types is 7 AND NOT 8 here */
+        "gpsizelo,gpsizehi:smallest & largest numbers of events in groups\n"
+        "gppacklo,gppackhi:shortest & longest time between event-onsets in groups (MS)\n"
+        "gpranglo,gpranghi:min,max pitchrange grps OR (hfields) no.of hf-notes range\n"
+        "atten:            overall attenuation of output\n"
+        "position:         centre of output sound-image (0(Left) 1(Right): default 0.5)\n"
+        "spread:           spatial-spread of texture events (0 - 1(full-spread))\n"
+        "seed:             same seed-no: same output on rerun(dflt 0: differs each time)\n"
+        "-w:               always play whole input-sound (ignoring duration values).\n"
+        "-d:                fixed timestep between groupnotes.\n"
+        "-i:               each group not confined to a fixed instr (default:fixed)\n");
+    } else if(!strcmp(str,"decorated") || !strcmp(str,"predecor") || !strcmp(str,"postdecor")) {
+        fprintf(stdout,
+        "TEXTURE WITH DECORATIONS:USAGE:texture decorated|predecor|postdecor mode infile\n"
+        "[infile2..] outfile notedata outdur skiptime sndfirst sndlast mingain maxgain\n"
+        "mindur maxdur phgrid gpspace gpsprange amprise contour gpsizlo gpsizhi\n"
+        "gppaklo gppakhi gpranglo gpranghi centring\n"
+        "              [-aatten] [-ppos] [-ssprd] [-rseed] [-w] [-d] [-i] [-h] [-e] [-k]\n"
+        "MODES:-\n"
+        "1)ON HARMONIC-FIELD 2)CHANGING HFLDS 3)HARMONIC-SET 4)CHANGING HSETS 5)NONE\n"
+        "notedata:         infofile, 'pitch' of insnds, decoration shape etc.\n"
+        "outdur:           (min) duration outfile\n"
+        "skiptime:         time between repets of motif-to-decorate in notedata\n"
+        "sndfirst,sndlast: 1st,last snd to use, from input snds (range 1 - all)\n"
+        "mingain,maxgain:  min & max gain on input events (MIDI)\n"
+        "mindur,maxdur:    min & max duration of events in texture\n"
+        "phgrid:           timegrid (MS) applying WITHIN decors\n"
+        "gpspace:          spatialisation decor-groups (Range 0-5: default 1)\n"
+        "gpsprange:        spatial range decor-groups (Range 0-1: default 1)\n"
+        "amprise:          amplitude change within decors: (0-127: default 0)\n"
+        "contour:          amplitude contour of decors (Range 0-8: default 0)\n"
+        "gpsizlo,gpsizhi:  smallest,largest no. events in decors\n"
+        "gppaklo,gppakhi:  shortest,longest time between event-onsets in decors(MS)\n"
+        "gpranglo,gpranghi:min,max pitchrange decors OR (hfields) no.of hf-notes range\n"
+        "centring:         how decor pitches centre on line pitches(Range 0-7:default 0)\n"
+        "atten:            overall attenuation of output\n"
+        "pos:              centre of output sound-image (-1(Left) 1(Right): default 0)\n"
+        "sprd:             spatial-spread of texture events (0 - 1(full-spread))\n"
+        "seed:             same seed-no: same output on rerun(dflt 0: differs each time)\n"
+        "-w: play all insnd(ignore min,maxdur) -h: dec TOPnote chord:(dflt:1st listed)\n"
+        "-d: fixed timestep btwn decornotes    -e: dec all notes of chords\n"
+        "-i: instrs vary in decor(dflt:fixed)  -k: discard orig line, after decor\n");
+    } else if(!strcmp(str,"ornate") || !strcmp(str,"preornate") || !strcmp(str,"postornate")) {
+        fprintf(stdout,
+        "TEXTURE WITH ORNAMENTS: USAGE:\n"
+        "texture ornate|preornate|postornate mode infile [infile2...] outfile notedata\n"
+        "outdur skiptime sndfirst sndlast   mingain maxgain  mindur maxdur\n"
+        "phgrid gpspace gpsprange  amprise  contour   multlo   multhi\n"
+        "          [-aatten] [-pposition] [-sspread] [-rseed] [-w] [-d] [-i] [-h] [-e]\n"
+        "MODES:-\n"
+        "1)ON HARMONIC-FIELD 2)CHANGING HFLDS 3)HARMONIC-SET 4)CHANGING HSETS 5)NONE\n"
+        "notedata:   infofile, 'pitch' of insnds, notes in ornaments, hfields etc.\n"
+        "outdur:           (min) duration of outfile\n"
+        "skiptime:         time between repetitions of motif-to-ornament in notedata\n"
+        "sndfirst,sndlast: 1st,last snd to use, from input snds (range 1 - all)\n"
+        "mingain,maxgain:  min & max level of input events (1-127:default 64,64)\n"
+        "mindur,maxdur:    min & max duration of events in texture\n"
+        "phgrid:           a timegrid (MS) applying WITHIN the ornaments\n"
+        "gpspace:          spatialisation of event-groups (Range 0-5: default 1)\n"
+        "gpsprange:        spatial range of event-groups (Range 0-1: default 1)\n"
+        "amprise:          amplitude change within ornaments: (0-127: default 0)\n"
+        "contour:          amplitude contour of groups (Range 0-8: default 0)\n"
+        "multlo, multhi:   min & max multiplier of total input duration of motif\n"
+        "atten:            overall attenuation of the output\n"
+        "position:         centre of output sound-image (0(Left) 1(Right):default 0.5)\n"
+        "spread:           spatial-spread of texture events (0 - 1(full-spread))\n"
+        "seed:             same seed-no: same output on rerun(dflt 0: differs each time)\n"
+        "-w:               always play whole input-sound (ignoring duration values).\n"
+        "-d:               ornament notes all have same duration as ornamented note\n"
+        "-i:               orns not confined to instr of ornd-note (default:same note)\n"
+        "-h:               orns on highest note of any chord:(default:1st note listed)\n"
+        "-e:               ornaments on all notes of any chord.\n");
+    } else if(!strcmp(str,"motifsin")) {        
+        fprintf(stdout,
+        "TEXTURE OF MOTIFS, FORCED ONTO A HARMONIC FIELD: USAGE:\n"
+        "texture motifsin mode infile [infile2..] outfile notedata outdur packing\n"
+        "scatter tgrid sndfirst sndlast mingain maxgain \n"
+        "minpitch maxpitch phgrid gpspace gpsprange amprise  contour multlo multhi\n"
+        "                [-aatten] [-pposition] [-sspread] [-rseed] [-w] [-d] [-i]\n"
+        "MODES:-\n"
+        "1) ON HARMONIC-FIELD 2) CHANGING HFLDS 3) HARMONIC-SET 4) CHANGING HSETS\n"
+        "notedata: infofile,'pitch' of insnds, timings for timed textures, hfields etc\n"
+        "outdur:             (min) duration of outfile\n"
+        "packing:            (average) time between motif onsets.\n"
+        "scatter:            randomisation of event-onsets (0 - %.0lf)\n"
+        "tgrid:              minstep(MS) quantised timegrid (for mtf starttimes)(dflt 0)\n"
+        "sndfirst,sndlast:   1st,last snd to use, from input snds (range 1 - all)\n"
+        "mingain,maxgain:    min & max level of input events (1-127:default 64,64)\n"
+        "minpitch,maxpitch:  min & max pitch (MIDI VALUE)\n"
+        "phgrid:             a timegrid (MS) applying WITHIN the motifs\n"
+        "gpspace:            spatialisation of event-groups (Range 0-5: default 1)\n"
+        "gpsprange:          spatial range of event-groups (Range 0-1: default 1)\n"
+        "amprise:            amplitude change within motifs: (0-127: default 0)\n"
+        "contour:            amplitude contour of groups (Range 0-6: default 0)\n"
+            /* NOTE : CARE all_types is 7 AND NOT 8 here */
+        "multlo, multhi:     min & max multiplier of total input duration of motif\n"
+        "atten:              overall attenuation of the output\n"
+        "position:           centre of output sound-image (0(Left) 1(Right):default 0.5)\n"
+        "spread:             spatial-spread of texture events (0 - 1(full-spread))\n"
+        "seed:             same seed-no: same output on rerun(dflt 0: differs each time)\n"
+        "-w:                 always play whole input-sound (ignoring duration values).\n"
+        "-d                  notes within any one motif all have same duration.\n"
+        "-i:                 motif not each confined to fixed instr (default:fixed)\n",MAX_SCAT_TEXTURE);
+    } else if(!strcmp(str,"tmotifsin")) {       
+        fprintf(stdout,
+        "TIMED TEXTURE OF MOTIFS, FORCED ONTO A HARMONIC FIELD: USAGE:\n"
+        "texture tmotifsin mode infile [infile2...] outfile notedata sndfirst sndlast\n"
+        "mingain maxgain minpich maxpich phgrid gpspace gpsprange\n"
+        "amprise contour multlo multhi [-aatten] [-ppos] [-sspread] [-rseed] [-w] [-d]\n"
+        "MODES:-\n"
+        "1) ON HARMONIC-FIELD 2) CHANGING HFLDS 3) HARMONIC-SET 4) CHANGING HSETS\n"
+        "notedata:    infofile, 'pitch' of insnds,motifs,texture timings,hfields etc..\n"
+        "outdur:           (min) duration of outfile\n"
+        "skiptime:         time between repetitions of timing motif in notedata\n"
+        "sndfirst,sndlast: 1st,last snd to use, from input snds (range 1 - all)\n"
+        "mingain,maxgain:  minimum & maximum level of input events (1-127:default 64,64)\n"
+        "minpich,maxpich:  min & max pitch (MIDI VALUE)\n"
+        "phgrid:           a timegrid (MS) applying WITHIN the motifs\n"
+        "gpspace:          spatialisation of event-groups (Range 0-5: default 1)\n"
+        "gpsprange:        spatial range of event-groups (Range 0-1: default 1)\n"
+        "amprise:          amplitude change within motifs: (0-127: default 0)\n"
+        "contour:          amplitude contour of groups (Range 0-6: default 0)\n"
+            /* NOTE : CARE all_types is 7 AND NOT 8 here */
+        "multlo, multhi:   min & max multiplier of total input duration of motif\n"
+        "atten:            overall attenuation of the output\n"
+        "pos:              centre of output sound-image (0(Left) 1(Right):default 0.5)\n"
+        "spread:           spatial-spread of texture events (0 - 1(full-spread))\n"
+        "seed:             same seed-no: same output on rerun(dflt 0: differs each time)\n"
+        "-w:               always play whole input-sound (ignoring duration values).\n"
+        "-d:               notes in any one motif all have same duration as timing note.\n"
+        "-i:               motifs not each confined to a fixed instrument (default: fixed)\n");
+    } else if(!strcmp(str,"motifs")) {      
+        fprintf(stdout,
+        "TEXTURE OF MOTIFS, (1ST NOTES ONLY, FORCED ONTO HARMONIC FIELD/SET, IF USED)\n"
+        "USAGE: texture motifs mode infile [infile2...] outfile notedata outdur packing\n"
+        "scatter tgrid sndfirst sndlast mingain maxgain minpich maxpich\n"
+        "phgrid gpspace gpsprange amprise contour multlo multhi\n"
+        "                 [-aatten] [-pposition] [-sspread] [-rseed] [-w] [-d]\n"
+        "MODES:-\n"
+        "1)ON HARMONIC-FIELD 2)CHANGING HFLDS 3)HARMONIC-SET 4)CHANGING HSETS 5)NONE\n"
+        "notedata: infofile, 'pitch' of insnds, timings for timed textures,hfields etc.\n"
+        "outdur:             (min) duration of outfile\n"
+        "packing:            (average) time between motif onsets.\n"
+        "scatter:            randomisation of event-onsets (0 - %.0lf)\n"
+        "tgrid:              minstep(MS) quantised timegrid (for mtf starttimes)(dflt 0)\n"
+        "sndfirst,sndlast:   1st,last snd to use, from input snds (range 1 - all)\n"
+        "mingain,maxgain:    min & max level of input events (1-127:default 64,64)\n"
+        "minpich,maxpich:    min & max pitch (MIDI VALUE)\n"
+        "phgrid:             a timegrid (MS) applying WITHIN the motifs\n"
+        "gpspace:            spatialisation of event-groups (Range 0-5: default 1)\n"
+        "gpsprange:          spatial range of event-groups (Range 0-1: default 1)\n"
+        "amprise:            amplitude change within motifs: (0-127: default 0)\n"
+        "contour:            amplitude contour of groups (Range 0-6: default 0)\n"
+            /* NOTE : CARE all_types is 7 AND NOT 8 here */
+        "multlo, multhi:     min & max multiplier of total input duration of motif\n"
+        "atten:              overall attenuation of the output\n"
+        "position:           centre of output sound-image (0(Left) 1(Right):default 0.5)\n"
+        "spread:             spatial-spread of texture events (0 - 1(full-spread))\n"
+        "seed:               same seed-no: same output on rerun(dflt 0: differs each time)\n"
+        "-w:                 always play whole input-sound (ignoring duration values).\n"
+        "-d                  notes of any one motif all have same duration.\n"
+        "-i:                 motif not each confined to fixed instr (default:fixed)\n",MAX_SCAT_TEXTURE);
+    } else if(!strcmp(str,"tmotifs")) {
+        fprintf(stdout,
+        "TIMED TEXTURE OF MOTIFS, THEMSELVES NOT FORCED ONTO HARMONIC FIELD: USAGE:\n"
+        "texture tmotifs mode infile [infile2...] outfile notedata outdur skip\n"
+        "sndfirst sndlast mingain maxgain minpitch maxpitch phgrid\n"
+        "gpspace gpsprange amprise contour multlo multhi\n"
+        "                    [-aatten] [-pposition] [-sspread] [-rseed] [-w] [-d]\n"
+        "MODES:-\n"
+        "1)ON HARMONIC-FIELD 2)CHANGING HFLDS 3)HARMONIC-SET 4)CHANGING HSETS 5)NONE\n"
+        "notedata:  infofile, 'pitch' of insnds,texture timings,motifs,hfields etc....\n"
+        "outdur:             (min) duration of outfile\n"
+        "skip:               time between repetitions of timing motif in notedata\n"
+        "sndfirst,sndlast:   1st,last snd to use, from input snds (range 1 - all)\n"
+        "mingain,maxgain:    min & max level of input events (1-127:default 64,64)\n"
+        "minpitch,maxpitch:  min & max pitch (MIDI VALUE)\n"
+        "phgrid:             a timegrid (MS) applying WITHIN the motifs\n"
+        "gpspace:            spatialisation of event-groups (Range 0-5: default 1)\n"
+        "gpsprange:          spatial range of event-groups (Range 0-1: default 1)\n"
+        "amprise:            amplitude change within motifs: (0-127: default 0)\n"
+        "contour:            amplitude contour of groups (Range 0-6: default 0)\n"
+            /* NOTE : CARE all_types is 7 AND NOT 8 here */
+        "multlo, multhi:     min & max multiplier of total input duration of motif\n"
+        "atten:              overall attenuation of the output\n"
+        "position:           centre of output sound-image (0(Left) 1(Right):default 0.5)\n"
+        "spread:             spatial-spread of texture events (0 - 1(full-spread))\n"
+        "seed:             same seed-no: same output on rerun(dflt 0: differs each time)\n"
+        "-w:                 always play whole input-sound (ignoring duration values).\n"
+        "-d:                 motif notes all have same duration as ornamented note\n"
+        "-i:                 motif not each confined to fixed instr (default:fixed)\n");
+    } else
+        fprintf(stdout,"Unknown option '%s'\n",str);
+    return(USAGE_ONLY);
+}
+
+/******************************** USAGE3 ********************************/
+
+int usage3(char *str1,char *str2)
+{
+    sprintf(errstr,"Insufficient parameters on command line.\n");
+    return(USAGE_ONLY);
+}
+
+/******************************** INNER_LOOP (redundant)  ********************************/
+
+int inner_loop
+(int *peakscore,int *descnt,int *in_start_portion,int *least,int *pitchcnt,int windows_in_buf,dataptr dz)
+{
+    return(FINISHED);
+}

+ 234 - 0
dev/texture/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
+ *
+ */
+/* floatsam version: no changes */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <structures.h>
+#include <tkglobals.h>
+#include <texture.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>
+
+char errstr[6000];
+
+/*extern*/ int sloom = 0;
+/*extern*/ int sloombatch = 0;
+/*extern*/ int anal_infiles = 0;
+/*extern*/ int is_converted_to_stereo = -1;
+const char* cdp_version = "8.0.1";
+
+/**************************************** MAIN *********************************************/
+
+int main(int argc,char *argv[])
+{
+    int exit_status;
+    dataptr dz = NULL;
+/*  char *special_data_string = NULL;*/
+    char **cmdline;
+    int  cmdlinecnt;
+    aplptr ap;
+    int *valid = NULL;
+    int is_launched = FALSE;
+    int  validcnt;
+
+    if(argc==2 && (strcmp(argv[1],"--version") == 0)) {
+        fprintf(stdout,"%s\n",cdp_version);
+        fflush(stdout);
+        return 0;
+    }
+                        /* CHECK FOR SOUNDLOOM */
+//TW UPDATE
+    if((sloom = sound_loom_in_use(&argc,&argv)) > 1) {
+        sloom = 0;
+        sloombatch = 1;
+    }
+
+    if(!sloom) {
+        if((exit_status = allocate_and_initialise_validity_flags(&valid,&validcnt))<0) {
+            print_messages_and_close_sndfiles(exit_status,is_launched,dz);
+            return(FAILED);
+        }
+    }
+
+    if(sflinit("cdp")){
+        sfperror("cdp: initialisation\n");
+        return(FAILED);
+    }
+
+                          /* SET UP THE PRINCIPLE DATASTRUCTURE */
+    if((exit_status = establish_datastructure(&dz))<0) {
+        print_messages_and_close_sndfiles(exit_status,is_launched,dz);
+        return(FAILED);
+    }
+                      
+    if(!sloom) {
+                              /* INITIAL CHECK OF CMDLINE DATA */
+        if((exit_status = make_initial_cmdline_check(&argc,&argv))<0) {
+            print_messages_and_close_sndfiles(exit_status,is_launched,dz);
+            return(FAILED);
+        }
+        cmdline    = argv;  /* GET PRE_DATA, ALLOCATE THE APPLICATION, CHECK FOR EXTRA INFILES */
+        cmdlinecnt = argc;
+        if((exit_status = get_process_and_mode_from_cmdline(&cmdlinecnt,&cmdline,dz))<0) {
+            print_messages_and_close_sndfiles(exit_status,is_launched,dz);
+            return(FAILED);
+        }       
+        if((exit_status = setup_particular_application(dz))<0) {
+            print_messages_and_close_sndfiles(exit_status,is_launched,dz);
+            return(FAILED);
+        }
+        if((exit_status = count_and_allocate_for_infiles(cmdlinecnt,cmdline,dz))<0) {
+            print_messages_and_close_sndfiles(exit_status,is_launched,dz);
+            return(FAILED);
+        }
+    } else {
+        if((exit_status = parse_tk_data(argc,argv,&cmdline,&cmdlinecnt,dz))<0) {    /* includes setup_particular_application()      */
+            exit_status = print_messages_and_close_sndfiles(exit_status,is_launched,dz);/* and cmdlinelength check = sees extra-infiles */
+            return(exit_status);         
+        }
+    }
+
+    ap = dz->application;
+
+/*********************************************************************************************************************
+       cmdline[0]                         2 vals                              ACTIVE         
+TK      (infile) (more-infiles) (outfile) (flag val) (formantsqksrch) (special) params  options   variant-params  flags
+CMDLINE (infile) (more-infiles) (outfile) (formants) (formantsqksrch) (special) params  POSSIBLY  POSSIBLY      POSSIBLY
+                                          1 val
+*********************************************************************************************************************/
+
+    if((exit_status = parse_infile_and_hone_type(cmdline[0],valid,dz))<0) {
+        print_messages_and_close_sndfiles(exit_status,is_launched,dz);
+        return(FAILED);
+    }
+
+    if((exit_status = setup_param_ranges_and_defaults(dz))<0) {
+        print_messages_and_close_sndfiles(exit_status,is_launched,dz);
+        return(FAILED);
+    }
+
+                    /* OPEN FIRST INFILE AND STORE DATA, AND INFORMATION, APPROPRIATELY */
+
+    if(dz->input_data_type!=NO_FILE_AT_ALL) {
+        if((exit_status = open_first_infile(cmdline[0],dz))<0) {
+            print_messages_and_close_sndfiles(exit_status,is_launched,dz);
+            return(FAILED);
+        }
+//TW UPDATE
+        cmdlinecnt--;
+        cmdline++;
+    }
+    
+/*********************************************************************************************************************
+        cmdline[0]                 2 vals                              ACTIVE
+TK      (more-infiles) (outfile) (flag val) (formantsqksrch) (special) params  options   variant-params  flags
+CMDLINE (more-infiles) (outfile) (formants) (formantsqksrch) (special) params  POSSIBLY  POSSIBLY         POSSIBLY
+                                   1 val
+*********************************************************************************************************************/
+
+    if((exit_status = handle_extra_infiles(&cmdline,&cmdlinecnt,dz))<0) {
+        print_messages_and_close_sndfiles(exit_status,is_launched,dz);
+        return(FAILED);
+    }
+
+/*********************************************************************************************************************
+        cmdline[0]    2                                 ACTIVE
+TK      (outfile) (flag val) (formantsqksrch) (special) params  options   variant-params  flags
+CMDLINE (outfile) (formants) (formantsqksrch) (special) params  POSSIBLY  POSSIBLY         POSSIBLY
+                      1
+*********************************************************************************************************************/
+
+    if((exit_status = handle_outfile(&cmdlinecnt,&cmdline,is_launched,dz))<0) {
+        print_messages_and_close_sndfiles(exit_status,is_launched,dz);
+        return(FAILED);
+    }
+
+/****************************************************************************************
+        cmdline[0]                             ACTIVE
+TK      (flag val) (formantsqksrch) (special) params  options   variant-params  flags
+CMDLINE (formants) (formantsqksrch) (special) params  POSSIBLY  POSSIBLY        POSSIBLY
+*****************************************************************************************/
+
+    if((exit_status = handle_formants(&cmdlinecnt,&cmdline,dz))<0) {
+        print_messages_and_close_sndfiles(exit_status,is_launched,dz);
+        return(FAILED);
+    }
+    if((exit_status = handle_formant_quiksearch(&cmdlinecnt,&cmdline,dz))<0) {
+        print_messages_and_close_sndfiles(exit_status,is_launched,dz);
+        return(FAILED);
+    }
+    if((exit_status = handle_special_data(&cmdlinecnt,&cmdline,dz))<0) {
+        print_messages_and_close_sndfiles(exit_status,is_launched,dz);
+        return(FAILED);
+    }
+ 
+/****************************************************************************************
+        cmdline[0]
+TK      active_params   options         variant-params  flags
+CMDLINE active_params   POSSIBLY        POSSIBLY        POSSIBLY
+*****************************************************************************************/
+
+    if((exit_status = read_parameters_and_flags(&cmdline,&cmdlinecnt,dz))<0) {
+        print_messages_and_close_sndfiles(exit_status,is_launched,dz);
+        return(FAILED);
+    }
+
+    if((exit_status = check_param_validity_and_consistency(dz))<0) {
+        print_messages_and_close_sndfiles(exit_status,is_launched,dz);
+        return(FAILED);
+    }
+
+    is_launched = TRUE;
+
+    if((exit_status = allocate_large_buffers(dz))<0){
+        print_messages_and_close_sndfiles(exit_status,is_launched,dz);
+        return(FAILED);
+    }
+    if((exit_status = param_preprocess(dz))<0){
+        print_messages_and_close_sndfiles(exit_status,is_launched,dz);
+        return(FAILED);
+    }
+    if((exit_status = groucho_process_file(dz))<0) {
+        print_messages_and_close_sndfiles(exit_status,is_launched,dz);
+        return(FAILED);
+    }
+    if((exit_status = complete_output(dz))<0) {
+        print_messages_and_close_sndfiles(exit_status,is_launched,dz);
+        return(FAILED);
+    }
+    exit_status = print_messages_and_close_sndfiles(FINISHED,is_launched,dz);
+    free(dz);
+    return(SUCCEEDED);
+}
+

BIN
dev/texture/prevsrc/prev-src.zip


+ 889 - 0
dev/texture/prevsrc/prev-src/ap_texture.c

@@ -0,0 +1,889 @@
+/*
+ * 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
+ *
+ */
+
+/* 03/2020: TW/RWD: corrected usage message argument lists */
+
+/* floatsam version: no changes */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <structures.h>
+#include <cdpmain.h>
+#include <tkglobals.h>
+#include <pnames.h>
+#include <texture.h>
+#include <processno.h>
+#include <modeno.h>
+#include <globcon.h>
+#include <logic.h>
+#include <filetype.h>
+#include <mixxcon.h>
+#include <flags.h>
+#include <speccon.h>
+#include <arrays.h>
+#include <special.h>
+#include <formants.h>
+#include <sfsys.h>
+#include <osbind.h>
+
+#include <srates.h>
+
+/********************************************************************************************/
+/********************************** FORMERLY IN pconsistency.c ******************************/
+/********************************************************************************************/
+
+static int  texture_pconsistency(dataptr dz);
+
+/********************************************************************************************/
+/********************************** FORMERLY IN specialin.c *********************************/
+/********************************************************************************************/
+
+static int  get_the_notedatafile(char *filename,dataptr dz);
+
+/***************************************************************************************/
+/****************************** FORMERLY IN aplinit.c **********************************/
+/***************************************************************************************/
+
+/***************************** ESTABLISH_BUFPTRS_AND_EXTRA_BUFFERS **************************/
+
+int establish_bufptrs_and_extra_buffers(dataptr dz)
+{
+    /*int is_spec = FALSE;*/
+    dz->bptrcnt = 0;
+    dz->bufcnt  = 0;
+    switch(dz->process) {
+    case(SIMPLE_TEX):
+    case(TIMED):
+    case(GROUPS):
+    case(TGROUPS):
+    case(DECORATED):
+    case(PREDECOR):
+    case(POSTDECOR):
+    case(ORNATE):
+    case(PREORNATE):
+    case(POSTORNATE):
+    case(MOTIFS):
+    case(TMOTIFS):
+    case(MOTIFSIN):
+    case(TMOTIFSIN):
+        dz->extra_bufcnt = 0;   dz->bufcnt = 1;
+        break;
+    default:
+        sprintf(errstr,"Unknown program type [%d] in establish_bufptrs_and_extra_buffers()\n",dz->process);
+        return(PROGRAM_ERROR);
+    }
+    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(SIMPLE_TEX):
+    case(TIMED):
+    case(GROUPS):
+    case(TGROUPS):
+    case(DECORATED):
+    case(PREDECOR):
+    case(POSTDECOR):
+    case(ORNATE):
+    case(PREORNATE):
+    case(POSTORNATE):
+    case(MOTIFS):
+    case(TMOTIFS):
+    case(MOTIFSIN):
+    case(TMOTIFSIN):
+        dz->array_cnt = 1; dz->iarray_cnt = 6; 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(SIMPLE_TEX):
+    case(TIMED):
+    case(GROUPS):
+    case(TGROUPS):
+    case(DECORATED):
+    case(PREDECOR):
+    case(POSTDECOR):
+    case(ORNATE):
+    case(PREORNATE):
+    case(POSTORNATE):
+    case(MOTIFS):
+    case(TMOTIFS):
+    case(MOTIFSIN):
+    case(TMOTIFSIN):
+        setup_process_logic(ONE_OR_MANY_SNDFILES,       UNEQUAL_SNDFILE,        SNDFILE_OUT,    dz);
+        break;
+    default:
+        sprintf(errstr,"Unknown process: assign_process_logic()\n");
+        return(PROGRAM_ERROR);
+        break;
+    }
+    if(dz->has_otherfile) {
+        switch(dz->input_data_type) {
+        case(ALL_FILES):
+        case(TWO_SNDFILES):
+        case(SNDFILE_AND_ENVFILE):
+        case(SNDFILE_AND_BRKFILE):
+        case(SNDFILE_AND_UNRANGED_BRKFILE):
+        case(SNDFILE_AND_DB_BRKFILE):
+            break;
+        case(MANY_SNDFILES):
+            if(dz->process==INFO_TIMELIST)
+                break;
+            /* fall thro */
+        default:
+            sprintf(errstr,"Most processes accepting files with different properties\n"
+                    "can only take 2 sound infiles.\n");
+            return(PROGRAM_ERROR);
+        }
+    }
+    return(FINISHED);
+}
+
+/***************************** SET_LEGAL_INFILE_STRUCTURE **************************
+ *
+ * Allows 2nd infile to have different props to first infile.
+ */
+
+void set_legal_infile_structure(dataptr dz)
+{
+    switch(dz->process) {
+    default:
+        dz->has_otherfile = FALSE;
+        break;
+    }
+}
+
+/***************************************************************************************/
+/****************************** FORMERLY IN internal.c *********************************/
+/***************************************************************************************/
+
+/****************************** SET_LEGAL_INTERNALPARAM_STRUCTURE *********************************/
+
+int set_legal_internalparam_structure(int process,int mode,aplptr ap)
+{
+    int exit_status = FINISHED;
+    switch(process) {
+    case(SIMPLE_TEX):       case(TIMED):    case(GROUPS):   case(TGROUPS):
+    case(DECORATED):        case(PREDECOR): case(POSTDECOR):
+    case(ORNATE):           case(PREORNATE):case(POSTORNATE):
+    case(MOTIFS):           case(TMOTIFS):  case(MOTIFSIN): case(TMOTIFSIN):
+        exit_status = set_internalparam_data("iiidddi",ap);                     break;
+    default:
+        sprintf(errstr,"Unknown process in set_legal_internalparam_structure()\n");
+        return(PROGRAM_ERROR);
+    }
+    return(exit_status);
+}
+
+/********************************************************************************************/
+/********************************** FORMERLY IN specialin.c *********************************/
+/********************************************************************************************/
+
+/********************** READ_SPECIAL_DATA ************************/
+
+int read_special_data(char *str,dataptr dz)
+{
+    /*      int exit_status = FINISHED;*/
+    aplptr ap = dz->application;
+    switch(ap->special_data) {
+    case(TEX_NOTEDATA):                     return get_the_notedatafile(str,dz);
+    default:
+        sprintf(errstr,"Unknown special_data type: read_special_data()\n");
+        return(PROGRAM_ERROR);
+    }
+    return(FINISHED);       /* NOTREACHED */
+}
+
+/***************************** GET_THE_NOTEDATAFILE ****************************/
+
+int get_the_notedatafile(char *filename,dataptr dz)
+{
+    if((dz->fp = fopen(filename,"r"))==NULL) {
+        sprintf(errstr,"Failed to open notedata file %s\n",filename);
+        return(DATA_ERROR);
+    }
+    return(FINISHED);
+}
+
+/********************************************************************************************/
+/********************************** FORMERLY IN preprocess.c ********************************/
+/********************************************************************************************/
+
+/****************************** PARAM_PREPROCESS *********************************/
+
+int param_preprocess(dataptr dz)
+{
+    /*      int exit_status = FINISHED;*/
+
+    switch(dz->process) {
+    case(SIMPLE_TEX):       case(TIMED):    case(GROUPS):   case(TGROUPS):
+    case(DECORATED):        case(PREDECOR): case(POSTDECOR):
+    case(ORNATE):           case(PREORNATE):case(POSTORNATE):
+    case(MOTIFS):           case(TMOTIFS):  case(MOTIFSIN): case(TMOTIFSIN):
+        return texture_preprocess(dz);
+    default:
+        sprintf(errstr,"PROGRAMMING PROBLEM: Unknown process in param_preprocess()\n");
+        return(PROGRAM_ERROR);
+    }
+    return(FINISHED);       /* NOTREACHED */
+}
+
+/********************************************************************************************/
+/********************************** FORMERLY IN procgrou.c **********************************/
+/********************************************************************************************/
+
+/**************************** GROUCHO_PROCESS_FILE ****************************/
+
+int groucho_process_file(dataptr dz)   /* FUNCTIONS FOUND IN PROCESS.C */
+{
+    int exit_status = FINISHED;
+
+    switch(dz->process) {
+    case(SIMPLE_TEX):       case(TIMED):    case(GROUPS):   case(TGROUPS):
+    case(DECORATED):        case(PREDECOR): case(POSTDECOR):
+    case(ORNATE):           case(PREORNATE):case(POSTORNATE):
+    case(MOTIFS):           case(MOTIFSIN): case(TMOTIFS):  case(TMOTIFSIN):
+        if((exit_status = make_texture(dz))<0)
+            return(exit_status);
+        if((exit_status = produce_texture_sound(dz))<0)
+            return(exit_status);
+        break;
+    default:
+        sprintf(errstr,"Unknown case in process_file()\n");
+        return(PROGRAM_ERROR);
+    }
+    return(FINISHED);
+}
+
+/********************************************************************************************/
+/********************************** FORMERLY IN pconsistency.c ******************************/
+/********************************************************************************************/
+
+/****************************** CHECK_PARAM_VALIDITY_AND_CONSISTENCY *********************************/
+
+int check_param_validity_and_consistency(dataptr dz)
+{
+    /*      int exit_status = FINISHED;*/
+    handle_pitch_zeros(dz);
+    switch(dz->process) {
+    case(SIMPLE_TEX): case(TIMED):          case(GROUPS):   case(TGROUPS):
+    case(DECORATED):  case(PREDECOR):       case(POSTDECOR):
+    case(ORNATE):     case(PREORNATE):      case(POSTORNATE):
+    case(MOTIFS):     case(TMOTIFS):        case(MOTIFSIN): case(TMOTIFSIN):
+        return texture_pconsistency(dz);
+    }
+    return(FINISHED);
+}
+
+/***************************** PREPARE_TEXTURE_PARAMETERS ****************************/
+
+int texture_pconsistency(dataptr dz)
+{
+    double *p, *end;
+    int OK = TRUE;
+    if(dz->brksize[TEXTURE_INSLO]) {
+        p = dz->brk[TEXTURE_INSLO] + 1;
+        end = dz->brk[TEXTURE_INSLO] + (dz->brksize[TEXTURE_INSLO] * 2);
+        while(p < end) {
+            if(*p  > (double)dz->infilecnt) {
+                OK = FALSE;
+                break;
+            }
+            p += 2;
+        }
+    } else if(dz->iparam[TEXTURE_INSLO] > dz->infilecnt)
+        OK  = FALSE;
+    if(!OK) {
+        sprintf(errstr,"FIRST SND-IN-LIST TO USE > count of files entered: cannot proceed.\n");
+        return(DATA_ERROR);
+    }
+    OK = TRUE;
+    if(dz->brksize[TEXTURE_INSHI]) {
+        p = dz->brk[TEXTURE_INSHI] + 1;
+        end = dz->brk[TEXTURE_INSHI] + (dz->brksize[TEXTURE_INSHI] * 2);
+        while(p < end) {
+            if(*p  > (double)dz->infilecnt) {
+                OK = FALSE;
+                break;
+            }
+            p += 2;
+        }
+    } else if(dz->iparam[TEXTURE_INSHI] > dz->infilecnt)
+        OK  = FALSE;
+    if(!OK) {
+        sprintf(errstr,"LAST SND-IN-LIST TO USE > count of files entered: cannot proceed.\n");
+        return(DATA_ERROR);
+    }
+    return(FINISHED);
+}
+
+
+
+/********************************************************************************************/
+/********************************** FORMERLY IN buffers.c ***********************************/
+/********************************************************************************************/
+
+/**************************** ALLOCATE_LARGE_BUFFERS ******************************/
+
+int allocate_large_buffers(dataptr dz)
+{
+    switch(dz->process) {
+    case(SIMPLE_TEX):
+    case(TIMED):            case(GROUPS):           case(TGROUPS):
+    case(DECORATED):        case(PREDECOR):         case(POSTDECOR):
+    case(ORNATE):           case(PREORNATE):        case(POSTORNATE):
+    case(MOTIFS):           case(TMOTIFS):          case(MOTIFSIN):
+    case(TMOTIFSIN):
+        return create_sndbufs(dz);
+    default:
+        sprintf(errstr,"Unknown program no. in allocate_large_buffers()\n");
+        return(PROGRAM_ERROR);
+    }
+    return(FINISHED);       /* NOTREACHED */
+}
+
+/********************************************************************************************/
+/********************************** FORMERLY IN cmdline.c ***********************************/
+/********************************************************************************************/
+
+int get_process_no(char *prog_identifier_from_cmdline,dataptr dz)
+{
+    if     (!strcmp(prog_identifier_from_cmdline,"simple"))         dz->process = SIMPLE_TEX;
+    else if(!strcmp(prog_identifier_from_cmdline,"grouped"))        dz->process = GROUPS;
+    else if(!strcmp(prog_identifier_from_cmdline,"motifs"))         dz->process = MOTIFS;
+    else if(!strcmp(prog_identifier_from_cmdline,"motifsin"))       dz->process = MOTIFSIN;
+    else if(!strcmp(prog_identifier_from_cmdline,"decorated"))      dz->process = DECORATED;
+    else if(!strcmp(prog_identifier_from_cmdline,"predecor"))       dz->process = PREDECOR;
+    else if(!strcmp(prog_identifier_from_cmdline,"postdecor"))      dz->process = POSTDECOR;
+    else if(!strcmp(prog_identifier_from_cmdline,"ornate"))         dz->process = ORNATE;
+    else if(!strcmp(prog_identifier_from_cmdline,"preornate"))      dz->process = PREORNATE;
+    else if(!strcmp(prog_identifier_from_cmdline,"postornate"))     dz->process = POSTORNATE;
+    else if(!strcmp(prog_identifier_from_cmdline,"timed"))                  dz->process = TIMED;
+    else if(!strcmp(prog_identifier_from_cmdline,"tgrouped"))               dz->process = TGROUPS;
+    else if(!strcmp(prog_identifier_from_cmdline,"tmotifs"))                dz->process = TMOTIFS;
+    else if(!strcmp(prog_identifier_from_cmdline,"tmotifsin"))              dz->process = TMOTIFSIN;
+    else {
+        sprintf(errstr,"Unknown program identification string '%s'\n",prog_identifier_from_cmdline);
+        return(USAGE_ONLY);
+    }
+
+    return FINISHED;
+}
+
+/********************************************************************************************/
+/********************************** FORMERLY IN usage.c *************************************/
+/********************************************************************************************/
+
+/******************************** USAGE1 ********************************/
+
+int usage1(void)
+{
+    fprintf(stdout, /* HAs to use fprintf because of kbhit */
+            "\n"
+            "USAGE:\ntexture NAME (mode) infile (infile2..etc) outfile notedata params:\n"
+            "\n"
+            "\nwhere NAME can be any one of\n"
+            "\n"
+            "\tTEXTURE MADE FROM ONE OR SEVERAL SOUND FILES\n"
+            "\n"
+            "simple   grouped    decorated    ornate       motifs\n"
+            "                    predecor     preornate    motifsin\n"
+            "                    postdecor    postornate\n"
+            "\n"
+            "\tTIMED TEXTURES MADE FROM ONE OR SEVERAL SOUND FILES\n"
+            "\n"
+            "timed     tmotifs   tmotifsin   tgrouped\n"
+            "\n"
+            "ORNAMENTS & MOTIFS   have user-specified pitch-shapes.\n"
+            "DECORATIONS & GROUPS have random pitch-shapes.\n"
+            "\n"
+            "Type 'texture simple' for more info on simple texture option.... etc.\n"
+            "\n"
+#ifdef IS_PC
+            "MORE??? ----- (hit keyboard)\n"
+            "\n");
+
+    while(!kbhit())
+        ;
+    if(kbhit()) {
+#else
+        "\n");
+#endif
+    fprintf(stdout,
+            "\n"
+            "*********************************************************************\n"
+            "SOME SPECIAL PARAMETER VALUES\n"
+            "*********************************************************************\n"
+            "GPSPACE: spatialisation of event-groups\n"
+            "\n"
+            "     0:still            1:scattered(default) 2:towards-texture-centre\n"
+            "     3:away-from-centre 4:follow-texmotion   5:contrary-to-motion\n"
+            "     4 & 5 only function if spatial position varies in time..\n"
+            "*********************************************************************\n"
+            "CONTOUR: amplitude contour of groups\n"
+            "\n"
+            "     0:mixed(default) 1:cresc     2:flat   3:decresc    4:c_or_fl\n"
+            "     5:c_or_d         6:d_or_fl  [7:directed_to_event   8:dir_or_flat]\n"
+            "*********************************************************************\n"
+            "CENTRING: how decoration pitches centre on decorated line pitches\n"
+            "\n"
+            "     0: centred(default) 1: above       2: below\n"
+            "     3: c_and_a          4: c_and_b     5: a_and_b     6: c_and_a_and_b\n"
+            "     In all cases except 0, pitchrange shifted to tally with line pitch\n\n"
+            "\n"
+            "*********************************************************************\n"
+            "       ALL OTHER PARAMS, except outdur, MAY VARY IN TIME.\n"
+            "*********************************************************************\n"
+            "\n"
+
+#ifdef IS_PC
+            "MORE??? ----- (hit keyboard)\n");
+}
+_getch();
+while(!kbhit())
+    ;
+if(kbhit()) {
+#else
+    "\n");
+#endif
+
+fprintf(stdout,
+        "\n"
+        "*********************************************************************\n"
+        "HARMONIC SETS   use only the pitches specified.\n"
+        "\n"
+        "HARMONIC FIELDS duplicate the specified pitches in all 8vas.\n"
+        "*********************************************************************\n"
+        "NOTEDATA is in a textfile containing.....\n"
+        "*********************************************************************\n"
+        "     assumed MIDI 'pitch' of each input snd, specified on 1st line.\n"
+        "\n"
+        "   FOLLOWED BY, where ness,  NOTELIST(S), SPECIFIED THUS:-\n"
+        "\n"
+        "     #N (where N = no. of notes in notelist: follows by N lines of...)\n"
+        "     time(SECS)   infile_no    pitch(MIDI)    amp(MIDI)   dur(SECS)\n"
+        "\n"
+        "where times within motif must increase (or remain same, during chords)\n"
+        "*********************************************************************\n"
+        "NOTELISTS REPRESENT: IN THIS ORDER..\n"
+        "*********************************************************************\n"
+        "Notelist of notes in any timed, ornamented or decorated line in texture.\n"
+        "Notelist of notes in any harmonic field(s) or set(s) specified.\n"
+        "      (For more than one  hfield(hset),\n"
+        "      data should specify chords, placed at appropriae times.)\n"
+        "Notelist(s) of notes in any ornament(s) or motif(s) specified.\n"
+        "*********************************************************************\n");
+
+#ifdef IS_PC
+}
+#endif
+return(USAGE_ONLY);
+}
+
+/******************************** USAGE2 ********************************/
+
+int usage2(char *str)
+{
+    if(!strcmp(str,"simple")) {
+        fprintf(stdout,
+                "USAGE:\n"
+                "texture simple mode infile [infile2...] outfile notedata outdur packing scatter\n"
+                "        tgrid sndfirst sndlast  mingain maxgain  mindur maxdur  minpich maxpich\n"
+                "             [-aatten] [-pposition] [-sspread] [-rseed] [-w -c -p]\n"
+                "MODES:-\n"
+                "1)  ON A GIVEN HARMONIC-FIELD        3)  ON A GIVEN HARMONIC-SET\n"
+                "2)  ON CHANGING HARMONIC-FIELDS      4)  ON CHANGING HARMONIC-SETS\n"
+                "5)  NONE\n"
+                "notedata: infofile, insnd 'pitches',harmonic fields pitches etc.\n"
+                "outdur:           (min) duration of outfile\n"
+                "packing:          (average) time between event onsets.\n"
+                "scatter:          randomisation of event-onsets (0 - %.0lf)\n"
+                "tgrid:            minstep(MS) quantised timegrid(for grp starttimes)(default 0)\n"
+                "sndfirst,sndlast: 1st,last snd to use,from list of insnds(range:1 - no.of snds)\n"
+                "mingain,maxgain:  minimum & maximum level of input events (1-127:default 64,64)\n"
+                "mindur,maxdur:    minimum & maximum duration of events in texture\n"
+                "minpich,maxpich:  minimum & maximum pitch (MIDI VALUE):\n"
+                "atten:            overall attenuation of the output\n"
+                "position:         centre of output sound-image (0(Left) 1(Right): default 0.5)\n"
+                "spread:           spatial-spread of texture events (0 - 1(full-spread))\n"
+                "seed:             same seed-no: same output on rerun(dflt 0: differs each time)\n"
+                "-w:               always play whole input-sound (ignoring duration values).\n"
+                "-c:               Choose files cyclically in listed order (ignore 'sndfirst','last').\n"
+                "-p:               Random permute each cycle (only when -c flag set).\n",MAX_SCAT_TEXTURE);
+    } else if(!strcmp(str,"timed")) {
+        fprintf(stdout,
+                "TIMED TEXTURE:  USAGE:\n"
+                "texture timed mode infile [infile2...]  outfile  notedata     outdur skiptime\n"
+                "             sndfirst sndlast mingain maxgain mindur maxdur minpitch maxpitch\n"
+                "             [-aatten] [-pposition] [-sspread] [-rseed] [-w]\n"
+                "MODES:-\n"
+                "1)  ON A GIVEN HARMONIC-FIELD        3)  ON A GIVEN HARMONIC-SET\n"
+                "2)  ON CHANGING HARMONIC-FIELDS      4)  ON CHANGING HARMONIC-SETS\n"
+                "5)  NONE\n"
+                "notedata: infofile, insnd 'pitches',texture timing,harmonic fields pitches etc.\n"
+                "outdur:            (min) duration of outfile\n"
+                "skiptime:          time between repetitions of timing motif in notedata\n"
+                "sndfirst,sndlast:  1st,last snd to use,from list of insnds(range:1 - all)\n"
+                "mingain,maxgain:   min & max level of input events (1-127:default 64,64)\n"
+                "mindur,maxdur:     min & max duration of events in texture\n"
+                "minpitch,maxpitch: min & max pitch (MIDI VALUE)\n"
+                "atten:             overall attenuation of the output\n"
+                "position:          centre of output sound-image (0(Left) 1(Right):default 0.5)\n"
+                "spread:            spatial-spread of texture events (0 - 1(full-spread))\n"
+                "seed:             same seed-no: same output on rerun(dflt 0: differs each time)\n"
+                "-w:                always play whole input-sound (ignoring duration values).\n");
+    } else if(!strcmp(str,"grouped")) {
+        fprintf(stdout,
+                "TEXTURE OF EVENT-GROUPS: USAGE: texture grouped mode infile [infile2..] outfile\n"
+                "notedata outdur packing scatter tgrid\n"
+                "sndfirst sndlast mingain maxgain mindur maxdur minpitch maxpitch phgrid gpspace\n"
+                "gpsprange amprise contour gpsizelo gpsizehi gppaklo gppakhi gpranglo gpranghi\n"
+                "                   [-aatten] [-pposition] [-sspread] [-rseed] [-w] [-d] [-i]\n"
+                "MODES:-\n"
+                "1)ON HARMONIC-FIELD 2)CHANGING HFLDS 3)HARMONIC-SET 4)CHANGING HSETS 5)NONE\n"
+                "notedata:   infofile, 'pitch' of insnds, harmonic fields etc.\n"
+                "outdur:     (min) duration of outfile\n"
+                "packing:    (average) time between group onsets.\n"
+                "scatter:    randomisation of event-onsets (0 - %.0lf)\n"
+                "tgrid:      minstep(MS) quantised timegrid(for grp starttimes)(default 0)\n"
+                "sndfirst,sndlast: 1st,last snd to use, from list of insnds(range:1 - all)\n"
+                "mingain,maxgain:  min & max level of input events (1-127:default 64,64)\n"
+                "mindur,maxdur:    min & max duration of events in texture\n"
+                "minpitch,maxpitch:min & max pitch (MIDI VALUE)\n"
+                "phgrid:     a timegrid (MS) applying WITHIN the groups\n"
+                "gpspace:    spatialisation of event-groups (Range 0-5: default 1)\n"
+                "gpsprange:  spatial range of event-groups (Range 0-1: default 1)\n"
+                "amprise:    amplitude change within groups: (0-127: default 0)\n"
+                "contour:    amplitude contour of groups (Range 0-6: default 0)\n"
+                /* NOTE : CARE all_types is 7 AND NOT 8 here */
+                "gpsizelo,gpsizehi:smallest,largest no. of events in groups\n"
+                "gppaklo,gppakhi:  shortest,longest time between event-onsets in groups (MS)\n"
+                "gpranglo,gpranghi:min,max pitchrange grps OR (hfields) no.of hf-notes range\n"
+                "atten:      overall attenuation of output\n"
+                "position:   centre of output sound-image (0(Left) 1(Right): default 0.5)\n"
+                "spread:     spatial-spread of texture events (0 - 1(full-spread))\n"
+                "seed:       same seed-no: same output on rerun(dflt 0: differs each time)\n"
+                "-w:         always play whole input-sound (ignore maxdur,mindur vals).\n"
+                "-d:             fixed timestep between groupnotes.\n"
+                "-i:         each group not confined to a fixed instr (default:fixed)\n",MAX_SCAT_TEXTURE);
+    } else if(!strcmp(str,"tgrouped")) {
+        fprintf(stdout,
+                "TIMED TEXTURE OF EVENT-GROUPS: USAGE: texture tgrouped mode infile [infile2..]\n"
+                "outfile notedata outdur skip sndfirst sndlast mingain maxgain mindur maxdur\n"
+                "minpitch maxpitch phgrid gpspace gpsprange amprise contour gpsizelo gpsizehi\n"
+                "gppacklo gppackhi gpranglo gpranghi\n"
+                "                   [-aatten] [-pposition] [-sspread] [-rseed] [-w] [-d] [-i]\n"
+                "MODES:-\n"
+                "1)  ON A GIVEN HARMONIC-FIELD        3)  ON A GIVEN HARMONIC-SET\n"
+                "2)  ON CHANGING HARMONIC-FIELDS      4)  ON CHANGING HARMONIC-SETS\n"
+                "5)  NONE\n"
+                "notedata: infofile, 'pitch' of insnds, timings for timed textures, hfields etc\n"
+                "outdur:           (min) duration of outfile\n"
+                "skip:             time between repetitions of timing motif in notedata\n"
+                "sndfirst,sndlast: 1st,last snd to use from list of insnds(range:1 - all)\n"
+                "mingain,maxgain:  min & max level of input events (1-127:default 64,64)\n"
+                "mindur,maxdur:    min & max duration of events in texture\n"
+                "minpitch,maxpitch:min & max pitch (MIDI VALUE)\n"
+                "phgrid:           timegrid (MS) applying WITHIN the groups\n"
+                "gpspace:          spatialisation of event-groups (Range 0-5: default 1)\n"
+                "gpsprange:        spatial range of event-groups (Range 0-1: default 1)\n"
+                "amprise:          amplitude change within groups: (0-127: default 0)\n"
+                "contour:          amplitude contour of groups (Range 0-6: default 0)\n"
+                /* NOTE : CARE all_types is 7 AND NOT 8 here */
+                "gpsizelo,gpsizehi:smallest & largest numbers of events in groups\n"
+                "gppacklo,gppackhi:shortest & longest time between event-onsets in groups (MS)\n"
+                "gpranglo,gpranghi:min,max pitchrange grps OR (hfields) no.of hf-notes range\n"
+                "atten:            overall attenuation of output\n"
+                "position:         centre of output sound-image (0(Left) 1(Right): default 0.5)\n"
+                "spread:           spatial-spread of texture events (0 - 1(full-spread))\n"
+                "seed:             same seed-no: same output on rerun(dflt 0: differs each time)\n"
+                "-w:               always play whole input-sound (ignoring duration values).\n"
+                "-d:                            fixed timestep between groupnotes.\n"
+                "-i:               each group not confined to a fixed instr (default:fixed)\n");
+    } else if(!strcmp(str,"decorated") || !strcmp(str,"predecor") || !strcmp(str,"postdecor")) {
+        fprintf(stdout,
+                "TEXTURE WITH DECORATIONS:USAGE:texture decorated|predecor|postdecor mode infile\n"
+                "[infile2..] outfile notedata outdur skiptime sndfirst sndlast mingain maxgain\n"
+                "mindur maxdur phgrid gpspace gpsprange amprise contour gpsizlo gpsizhi\n"
+                "gppaklo gppakhi gpranglo gpranghi centring\n"
+                "              [-aatten] [-ppos] [-ssprd] [-rseed] [-w] [-d] [-i] [-h] [-e] [-k]\n"
+                "MODES:-\n"
+                "1)ON HARMONIC-FIELD 2)CHANGING HFLDS 3)HARMONIC-SET 4)CHANGING HSETS 5)NONE\n"
+                "notedata:         infofile, 'pitch' of insnds, decoration shape etc.\n"
+                "outdur:           (min) duration outfile\n"
+                "skiptime:         time between repets of motif-to-decorate in notedata\n"
+                "sndfirst,sndlast: 1st,last snd to use, from input snds (range 1 - all)\n"
+                "mingain,maxgain:  min & max gain on input events (MIDI)\n"
+                "mindur,maxdur:    min & max duration of events in texture\n"
+                "phgrid:           timegrid (MS) applying WITHIN decors\n"
+                "gpspace:          spatialisation decor-groups (Range 0-5: default 1)\n"
+                "gpsprange:        spatial range decor-groups (Range 0-1: default 1)\n"
+                "amprise:          amplitude change within decors: (0-127: default 0)\n"
+                "contour:          amplitude contour of decors (Range 0-8: default 0)\n"
+                "gpsizlo,gpsizhi:  smallest,largest no. events in decors\n"
+                "gppaklo,gppakhi:  shortest,longest time between event-onsets in decors(MS)\n"
+                "gpranglo,gpranghi:min,max pitchrange decors OR (hfields) no.of hf-notes range\n"
+                "centring:         how decor pitches centre on line pitches(Range 0-7:default 0)\n"
+                "atten:            overall attenuation of output\n"
+                "pos:              centre of output sound-image (-1(Left) 1(Right): default 0)\n"
+                "sprd:             spatial-spread of texture events (0 - 1(full-spread))\n"
+                "seed:             same seed-no: same output on rerun(dflt 0: differs each time)\n"
+                "-w: play all insnd(ignore min,maxdur) -h: dec TOPnote chord:(dflt:1st listed)\n"
+                "-d: fixed timestep btwn decornotes    -e: dec all notes of chords\n"
+                "-i: instrs vary in decor(dflt:fixed)  -k: discard orig line, after decor\n");
+    } else if(!strcmp(str,"ornate") || !strcmp(str,"preornate") || !strcmp(str,"postornate")) {
+        fprintf(stdout,
+                "TEXTURE WITH ORNAMENTS: USAGE:\n"
+                "texture ornate|preornate|postornate mode infile [infile2...] outfile notedata\n"
+                "outdur skiptime sndfirst sndlast   mingain maxgain  mindur maxdur\n"
+                "phgrid gpspace gpsprange  amprise  contour   multlo   multhi\n"
+                "          [-aatten] [-pposition] [-sspread] [-rseed] [-w] [-d] [-i] [-h] [-e]\n"
+                "MODES:-\n"
+                "1)ON HARMONIC-FIELD 2)CHANGING HFLDS 3)HARMONIC-SET 4)CHANGING HSETS 5)NONE\n"
+                "notedata:   infofile, 'pitch' of insnds, notes in ornaments, hfields etc.\n"
+                "outdur:           (min) duration of outfile\n"
+                "skiptime:         time between repetitions of motif-to-ornament in notedata\n"
+                "sndfirst,sndlast: 1st,last snd to use, from input snds (range 1 - all)\n"
+                "mingain,maxgain:  min & max level of input events (1-127:default 64,64)\n"
+                "mindur,maxdur:    min & max duration of events in texture\n"
+                "phgrid:           a timegrid (MS) applying WITHIN the ornaments\n"
+                "gpspace:          spatialisation of event-groups (Range 0-5: default 1)\n"
+                "gpsprange:        spatial range of event-groups (Range 0-1: default 1)\n"
+                "amprise:          amplitude change within ornaments: (0-127: default 0)\n"
+                "contour:          amplitude contour of groups (Range 0-8: default 0)\n"
+                "multlo, multhi:   min & max multiplier of total input duration of motif\n"
+                "atten:            overall attenuation of the output\n"
+                "position:         centre of output sound-image (0(Left) 1(Right):default 0.5)\n"
+                "spread:           spatial-spread of texture events (0 - 1(full-spread))\n"
+                "seed:             same seed-no: same output on rerun(dflt 0: differs each time)\n"
+                "-w:               always play whole input-sound (ignoring duration values).\n"
+                "-d:               ornament notes all have same duration as ornamented note\n"
+                "-i:               orns not confined to instr of ornd-note (default:same note)\n"
+                "-h:               orns on highest note of any chord:(default:1st note listed)\n"
+                "-e:               ornaments on all notes of any chord.\n");
+    } else if(!strcmp(str,"motifsin")) {
+        fprintf(stdout,
+                "TEXTURE OF MOTIFS, FORCED ONTO A HARMONIC FIELD: USAGE:\n"
+                "texture motifsin mode infile [infile2..] outfile notedata outdur packing\n"
+                "scatter tgrid sndfirst sndlast mingain maxgain\n"
+                "minpitch maxpitch phgrid gpspace gpsprange amprise  contour multlo multhi\n"
+                "                [-aatten] [-pposition] [-sspread] [-rseed] [-w] [-d] [-i]\n"
+                "MODES:-\n"
+                "1) ON HARMONIC-FIELD 2) CHANGING HFLDS 3) HARMONIC-SET 4) CHANGING HSETS\n"
+                "notedata: infofile,'pitch' of insnds, timings for timed textures, hfields etc\n"
+                "outdur:             (min) duration of outfile\n"
+                "packing:            (average) time between motif onsets.\n"
+                "scatter:            randomisation of event-onsets (0 - %.0lf)\n"
+                "tgrid:              minstep(MS) quantised timegrid (for mtf starttimes)(dflt 0)\n"
+                "sndfirst,sndlast:   1st,last snd to use, from input snds (range 1 - all)\n"
+                "mingain,maxgain:    min & max level of input events (1-127:default 64,64)\n"
+                "minpitch,maxpitch:  min & max pitch (MIDI VALUE)\n"
+                "phgrid:             a timegrid (MS) applying WITHIN the motifs\n"
+                "gpspace:            spatialisation of event-groups (Range 0-5: default 1)\n"
+                "gpsprange:          spatial range of event-groups (Range 0-1: default 1)\n"
+                "amprise:            amplitude change within motifs: (0-127: default 0)\n"
+                "contour:            amplitude contour of groups (Range 0-6: default 0)\n"
+                /* NOTE : CARE all_types is 7 AND NOT 8 here */
+                "multlo, multhi:     min & max multiplier of total input duration of motif\n"
+                "atten:              overall attenuation of the output\n"
+                "position:           centre of output sound-image (0(Left) 1(Right):default 0.5)\n"
+                "spread:             spatial-spread of texture events (0 - 1(full-spread))\n"
+                "seed:             same seed-no: same output on rerun(dflt 0: differs each time)\n"
+                "-w:                 always play whole input-sound (ignoring duration values).\n"
+                "-d                  notes within any one motif all have same duration.\n"
+                "-i:                 motif not each confined to fixed instr (default:fixed)\n",MAX_SCAT_TEXTURE);
+    } else if(!strcmp(str,"tmotifsin")) {
+        fprintf(stdout,
+                "TIMED TEXTURE OF MOTIFS, FORCED ONTO A HARMONIC FIELD: USAGE:\n"
+                "texture tmotifsin mode infile [infile2...] outfile notedata sndfirst sndlast\n"
+                "mingain maxgain minpich maxpich phgrid gpspace gpsprange\n"
+                "amprise contour multlo multhi [-aatten] [-ppos] [-sspread] [-rseed] [-w] [-d]\n"
+                "MODES:-\n"
+                "1) ON HARMONIC-FIELD 2) CHANGING HFLDS 3) HARMONIC-SET 4) CHANGING HSETS\n"
+                "notedata:    infofile, 'pitch' of insnds,motifs,texture timings,hfields etc..\n"
+                "outdur:           (min) duration of outfile\n"
+                "skiptime:         time between repetitions of timing motif in notedata\n"
+                "sndfirst,sndlast: 1st,last snd to use, from input snds (range 1 - all)\n"
+                "mingain,maxgain:  minimum & maximum level of input events (1-127:default 64,64)\n"
+                "minpich,maxpich:  min & max pitch (MIDI VALUE)\n"
+                "phgrid:           a timegrid (MS) applying WITHIN the motifs\n"
+                "gpspace:          spatialisation of event-groups (Range 0-5: default 1)\n"
+                "gpsprange:        spatial range of event-groups (Range 0-1: default 1)\n"
+                "amprise:          amplitude change within motifs: (0-127: default 0)\n"
+                "contour:          amplitude contour of groups (Range 0-6: default 0)\n"
+                /* NOTE : CARE all_types is 7 AND NOT 8 here */
+                "multlo, multhi:   min & max multiplier of total input duration of motif\n"
+                "atten:            overall attenuation of the output\n"
+                "pos:              centre of output sound-image (0(Left) 1(Right):default 0.5)\n"
+                "spread:           spatial-spread of texture events (0 - 1(full-spread))\n"
+                "seed:             same seed-no: same output on rerun(dflt 0: differs each time)\n"
+                "-w:               always play whole input-sound (ignoring duration values).\n"
+                "-d:               notes in any one motif all have same duration as timing note.\n"
+                "-i:               motifs not each confined to a fixed instrument (default: fixed)\n");
+    } else if(!strcmp(str,"motifs")) {
+        fprintf(stdout,
+                "TEXTURE OF MOTIFS, (1ST NOTES ONLY, FORCED ONTO HARMONIC FIELD/SET, IF USED)\n"
+                "USAGE: texture motifs mode infile [infile2...] outfile notedata outdur packing\n"
+                "scatter tgrid sndfirst sndlast mingain maxgain minpich maxpich\n"
+                "phgrid gpspace gpsprange amprise contour multlo multhi\n"
+                "                 [-aatten] [-pposition] [-sspread] [-rseed] [-w] [-d]\n"
+                "MODES:-\n"
+                "1)ON HARMONIC-FIELD 2)CHANGING HFLDS 3)HARMONIC-SET 4)CHANGING HSETS 5)NONE\n"
+                "notedata: infofile, 'pitch' of insnds, timings for timed textures,hfields etc.\n"
+                "outdur:             (min) duration of outfile\n"
+                "packing:            (average) time between motif onsets.\n"
+                "scatter:            randomisation of event-onsets (0 - %.0lf)\n"
+                "tgrid:              minstep(MS) quantised timegrid (for mtf starttimes)(dflt 0)\n"
+                "sndfirst,sndlast:   1st,last snd to use, from input snds (range 1 - all)\n"
+                "mingain,maxgain:    min & max level of input events (1-127:default 64,64)\n"
+                "minpich,maxpich:    min & max pitch (MIDI VALUE)\n"
+                "phgrid:             a timegrid (MS) applying WITHIN the motifs\n"
+                "gpspace:            spatialisation of event-groups (Range 0-5: default 1)\n"
+                "gpsprange:          spatial range of event-groups (Range 0-1: default 1)\n"
+                "amprise:            amplitude change within motifs: (0-127: default 0)\n"
+                "contour:            amplitude contour of groups (Range 0-6: default 0)\n"
+                /* NOTE : CARE all_types is 7 AND NOT 8 here */
+                "multlo, multhi:     min & max multiplier of total input duration of motif\n"
+                "atten:              overall attenuation of the output\n"
+                "position:           centre of output sound-image (0(Left) 1(Right):default 0.5)\n"
+                "spread:             spatial-spread of texture events (0 - 1(full-spread))\n"
+                "seed:               same seed-no: same output on rerun(dflt 0: differs each time)\n"
+                "-w:                 always play whole input-sound (ignoring duration values).\n"
+                "-d                  notes of any one motif all have same duration.\n"
+                "-i:                 motif not each confined to fixed instr (default:fixed)\n",MAX_SCAT_TEXTURE);
+    } else if(!strcmp(str,"tmotifs")) {
+        fprintf(stdout,
+                "TIMED TEXTURE OF MOTIFS, THEMSELVES NOT FORCED ONTO HARMONIC FIELD: USAGE:\n"
+                "texture tmotifs mode infile [infile2...] outfile notedata outdur skip\n"
+                "sndfirst sndlast mingain maxgain minpitch maxpitch phgrid\n"
+                "gpspace gpsprange amprise contour multlo multhi\n"
+                "                    [-aatten] [-pposition] [-sspread] [-rseed] [-w] [-d]\n"
+                "MODES:-\n"
+                "1)ON HARMONIC-FIELD 2)CHANGING HFLDS 3)HARMONIC-SET 4)CHANGING HSETS 5)NONE\n"
+                "notedata:  infofile, 'pitch' of insnds,texture timings,motifs,hfields etc....\n"
+                "outdur:             (min) duration of outfile\n"
+                "skip:               time between repetitions of timing motif in notedata\n"
+                "sndfirst,sndlast:   1st,last snd to use, from input snds (range 1 - all)\n"
+                "mingain,maxgain:    min & max level of input events (1-127:default 64,64)\n"
+                "minpitch,maxpitch:  min & max pitch (MIDI VALUE)\n"
+                "phgrid:             a timegrid (MS) applying WITHIN the motifs\n"
+                "gpspace:            spatialisation of event-groups (Range 0-5: default 1)\n"
+                "gpsprange:          spatial range of event-groups (Range 0-1: default 1)\n"
+                "amprise:            amplitude change within motifs: (0-127: default 0)\n"
+                "contour:            amplitude contour of groups (Range 0-6: default 0)\n"
+                /* NOTE : CARE all_types is 7 AND NOT 8 here */
+                "multlo, multhi:     min & max multiplier of total input duration of motif\n"
+                "atten:              overall attenuation of the output\n"
+                "position:           centre of output sound-image (0(Left) 1(Right):default 0.5)\n"
+                "spread:             spatial-spread of texture events (0 - 1(full-spread))\n"
+                "seed:             same seed-no: same output on rerun(dflt 0: differs each time)\n"
+                "-w:                 always play whole input-sound (ignoring duration values).\n"
+                "-d:                 motif notes all have same duration as ornamented note\n"
+                "-i:                 motif not each confined to fixed instr (default:fixed)\n");
+    } else
+        fprintf(stdout,"Unknown option '%s'\n",str);
+    return(USAGE_ONLY);
+}
+
+/******************************** USAGE3 ********************************/
+
+int usage3(char *str1,char *str2)
+{
+    sprintf(errstr,"Insufficient parameters on command line.\n");
+    return(USAGE_ONLY);
+}
+
+/******************************** INNER_LOOP (redundant)  ********************************/
+
+int inner_loop
+(int *peakscore,int *descnt,int *in_start_portion,int *least,int *pitchcnt,int windows_in_buf,dataptr dz)
+{
+    return(FINISHED);
+}

+ 236 - 0
dev/texture/prevsrc/prev-src/main.c

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

+ 194 - 0
dev/texture/prevsrc/prev-src/texperm.c

@@ -0,0 +1,194 @@
+/*
+ * Copyright (c) 1983-2013 Trevor Wishart and Composers Desktop Project Ltd
+ * http://www.trevorwishart.co.uk
+ * http://www.composersdesktop.com
+ *
+ This file is part of the CDP System.
+
+ The CDP System is free software; you can redistribute it
+ and/or modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The CDP System is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the CDP System; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA
+ *
+ */
+
+
+
+/* floatsam version: no changes */
+#include <stdio.h>
+#include <stdlib.h>
+#include <structures.h>
+#include <tkglobals.h>
+#include <texture.h>
+#include <globcon.h>
+#include <arrays.h>
+
+#include <osbind.h>
+
+static void rndpermm(int k,int pindex,int **permm,dataptr dz);
+static void insert(int m,int t,int pindex,int **permm,dataptr dz);
+static void prefix(int m,int pindex,int **permm,dataptr dz);
+static void shuflup(int k,int pindex, int **permm,dataptr dz);
+
+/******************************** DOPERM *********************************
+ *
+ * Either deliver next item in a permuted set, or (if set exhausted)
+ * generate a randon permutation of the set and deliver its first
+ * element.
+ *
+ * (1)  If this permset does not have the same length as the last...
+ * (2)    Set a new permset length.
+ * (3)    If a permset already exists (i.e. this is not first)
+ *        Free the permset space, and malloc a new space of correct size,
+ * (4)    Create a random permutation of elements into the permset.
+ * (5)    Set the pointer-to-the-set to 0.
+ * (6)    Set the size of the previous perm (which will be this one,
+ *        next time!) to this permset size.
+ * (6a) Whether or not a new perm set has been set up...
+ * (7)    Get the value of the next item in the current permset,
+ *        incrementing the set pointer in the process.
+ * (8)    If this has the same value as the previous-one-output-from-doperm
+ *        increment the repetition counter.
+ * (9)    Otherwise set the repetition counter to 1.
+ * (10)   If the set pointer has run beyond the permset.
+ * (11)     reset the pointer to 0.
+ * (12)     generate a new random perm (of same length).
+ * (13) Continue this process if the number of permissible repetitions
+ *      is exceeded.
+ * (14) Set the value for lastpermval, for next call.
+ * (15) Return the value.
+ */
+
+int doperm(int k,int pindex,int *val,dataptr dz)
+{
+    int i, OK;
+    int **permm = dz->tex->perm;
+    if(pindex >= PERMCNT) {
+        sprintf(errstr,"doperm(): Perm index %d too big (max = %d)\n",pindex,PERMCNT);
+        return(PROGRAM_ERROR);
+    }
+    if(k <= 1) {
+        if(k>=0) {
+            *val = 0;
+            return(FINISHED);
+        } else {
+            sprintf(errstr,"doperm(): Invalid perm count %d\n",k);
+            return(PROGRAM_ERROR);
+        }
+    }
+    if((k*dz->iparray[TXRPT][pindex])!=dz->iparray[TXLASTPERMLEN][pindex]) {        /* 1 */
+        dz->iparray[TXPERMLEN][pindex] = (int)(k * dz->iparray[TXRPT][pindex]); /* 2 */
+        if(permm[pindex]   != (int *)0)                                                                                 /* 3 */
+            free(permm[pindex]);
+        if((permm[pindex] = (int *)malloc(dz->iparray[TXPERMLEN][pindex] * sizeof(int)))==NULL) {
+            sprintf(errstr,"INSUFFICIENT MEMORY for permutation %d\n",pindex+1);
+            return(MEMORY_ERROR);
+        }
+        rndpermm(k,pindex,permm,dz);                                                                                    /* 4 */
+        dz->iparray[TXPERMINDEX][pindex]   = 0;                                                                 /* 5 */
+        dz->iparray[TXLASTPERMLEN][pindex] = dz->iparray[TXPERMLEN][pindex];    /* 6 */
+    }
+    do {                                            /* 6a */
+        OK = 1;
+        i = *(permm[pindex] + (dz->iparray[TXPERMINDEX][pindex]++));                    /* 7 */
+        if(i==dz->iparray[TXLASTPERMVAL][pindex]) {                                                             /* 8 */
+            dz->iparray[TXREPETCNT][pindex]++;
+            if(dz->iparray[TXREPETCNT][pindex]>dz->iparray[TXRPT][pindex]) {
+                dz->iparray[TXREPETCNT][pindex] = dz->iparray[TXRPT][pindex];
+                OK = 0;
+            }
+        } else {
+            dz->iparray[TXREPETCNT][pindex]=1;
+        }
+        if(dz->iparray[TXPERMINDEX][pindex]>=dz->iparray[TXPERMLEN][pindex]) {  /* 10 */
+            dz->iparray[TXPERMINDEX][pindex] = 0;                                                           /* 11 */
+            rndpermm(k,pindex,permm,dz);                                                                            /* 12 */
+        }
+    }while(!OK);                                                                                                                            /* 13 */
+    dz->iparray[TXLASTPERMVAL][pindex] = i;                                                                         /* 14 */
+    *val = i;
+    return(FINISHED);                                                                                                                       /* 15 */
+}
+
+/*************************** RNDPERMM *******************************
+ *
+ * Produce a permutation of k objects and store it in permutation-store
+ * number 'pindex'.
+ *
+ * (1)  permlen is the number of objects (k) times the number of repetitions
+ *          permitted (rpt[pindex]) = N.
+ * (2)  This is the efficient algorithm for distributing N objects into
+ *              a random perm.
+ * (3)  As we really only have k objects, we take the value%rpt in each
+ *              permutation location.
+ *              e.g. 3 objects repeated 3 times would give us a random perm of
+ *              nine objects such as
+ *              5 6 2 8 3 0 1 7 4
+ *              applying %3 to this we get
+ *              2 0 2 2 0 0 1 1 1
+ *              i.e. a perm of 3 objects with no more than 3 consecutive repets
+ *              of any one object!!
+ */
+
+void rndpermm(int k,int pindex,int **permm,dataptr dz)
+{
+    int n, t;
+    for(n=0;n<dz->iparray[TXPERMLEN][pindex];n++) {         /* 1 */
+        t = (int)(drand48() * (double)(n+1));           /* 2 */
+        if(t==n) {
+            prefix(n,pindex,permm,dz);
+        } else {
+            insert(n,t,pindex,permm,dz);
+        }
+    }
+    for(n=0;n<dz->iparray[TXPERMLEN][pindex];n++)           /* 3 */
+        *(permm[pindex]+n) = (int)(*(permm[pindex]+n) % k);
+}
+
+/***************************** INSERT **********************************
+ *
+ * Insert the value m AFTER the T-th element in permm[pindex].
+ */
+
+void insert(int m,int t,int pindex,int **permm,dataptr dz)
+{
+    shuflup(t+1,pindex,permm,dz);
+    *(permm[pindex]+t+1) = m;
+}
+
+/***************************** PREFIX ************************************
+ *
+ * Insert the value m at start of the permutation permm[pindex].
+ */
+
+void prefix(int m,int pindex,int **permm,dataptr dz)
+{
+    shuflup(0,pindex,permm,dz);
+    *permm[pindex] = m;
+}
+
+/****************************** SHUFLUP ***********************************
+ *
+ * move set members in permm[pindex] upwards, starting from element k.
+ */
+
+void shuflup(int k,int pindex, int **permm,dataptr dz)
+{
+    int n, *i;
+    int z = dz->iparray[TXPERMLEN][pindex] - 1;
+    i = permm[pindex] + z;
+    for(n = z;n > k;n--) {
+        *i = *(i-1);
+        i--;
+    }
+}

+ 1527 - 0
dev/texture/prevsrc/prev-src/texprepro.c

@@ -0,0 +1,1527 @@
+/*
+ * Copyright (c) 1983-2013 Trevor Wishart and Composers Desktop Project Ltd
+ * http://www.trevorwishart.co.uk
+ * http://www.composersdesktop.com
+ *
+ This file is part of the CDP System.
+
+ The CDP System is free software; you can redistribute it
+ and/or modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The CDP System is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the CDP System; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA
+ *
+ */
+
+
+
+/* floatsam version */
+#include <stdio.h>
+#include <stdlib.h>
+#include <memory.h>
+#include <structures.h>
+#include <tkglobals.h>
+#include <globcon.h>
+#include <processno.h>
+#include <modeno.h>
+#include <arrays.h>
+#include <texture.h>
+#include <ctype.h>
+#include <sfsys.h>
+#include <osbind.h>
+#include <cdpmain.h>
+
+#if defined unix || defined __GNUC__
+#define round(x) lround((x))
+#endif
+
+#define SQUASH    (2.0) /* non-linearity factor */
+#define MAXPOSCNT (512) /* max no. of spatial positions between lspkrs */
+
+static int  initialise_texture_structure(dataptr dz);
+static int  set_up_and_fill_insample_buffers(insamptr **insound,dataptr dz);
+static int  setup_texflag(texptr tex,dataptr dz);
+static int  adjust_some_input_params(dataptr dz);
+static int  preset_some_internal_texture_params(dataptr dz);
+static int  install_unused_texture_flags(int *total_flags,int unused_flags,dataptr dz);
+static int  install_the_internal_flags(int total_flags,int internal_flags,dataptr dz);
+static int  get_the_notedata(texptr tex,dataptr dz);
+static int  extend_timeset(dataptr dz);
+static int  generate_timeset(dataptr dz);
+static int  do_prespace(motifptr tset,dataptr dz);
+static int  get_sample_pitches(FILE *fp,dataptr dz);
+static int  get_motifs(FILE *fp,int *motifcnt,dataptr dz);
+static int  motifchek(motifptr thismotif);
+static void convert_cmdline_instrnos_to_internal_representation(dataptr dz);
+static int  check_max_transpos_compatible_with_splicelen(dataptr dz);
+static int  set_amptype_params(dataptr dz);
+static int  set_decor_pitchposition_params(dataptr dz);
+static void copy_note(noteptr thisnote,noteptr orignote);
+static int  add_motif_to_end_of_motiflist(motifptr *new,dataptr dz);
+static int  scatter_and_quantise_tset_times(double *lasttime,noteptr *thisnote,dataptr dz);
+static int  pre_space(noteptr thisnote,dataptr dz);
+static int  getpos(double thistime,double *position,dataptr dz);
+static int  spread_and_set_cpos(double *position,double given_position,double spread,dataptr dz);
+static int  chekrang(double *val);
+static int  read_a_note_from_notedata_file
+(noteptr thisnote,int noteno,int motifno,double *lasttime,dataptr dz);
+static int  generate_tset_times(double *thistime,noteptr *thisnote,dataptr dz);
+static int  un_link_note(noteptr thisnote);
+static int  new_motif(motifptr *thismotif);
+static int  unlink_last_motif(motifptr thismotif);
+static void subtract_one_from_brkvals(int paramno,dataptr dz);
+static int  bigscatter(noteptr *thisnote,double thistime,double timestep,double scatter,double *lasttime,dataptr dz);
+static int  get_data_item(char *q,char **p,double *val);
+static int  init_note(noteptr *thisnote);
+static void put_znote(noteptr thisnote);
+static int  assign_timeset_hfset_motifsets(dataptr dz);
+static int  massage_params(dataptr dz);
+static int  init_motifs(dataptr dz);
+
+/************************* TEXTURE_PREPROCESS ****************************
+ *
+ * (1)  Establish the bitflag which characterises the texture process.
+ * (2)  For consistency across all texture processes, all unused flags are mallocd.
+ *              This ensures that the numbering of the INTERNAL flags is consistent across all applics.
+ * (3)  Convert some input parameters to form used internally, and check some against insnd lengths.
+ */
+
+int texture_preprocess(dataptr dz)
+{
+    int exit_status;
+    int total_flags, unused_flags, n;
+    unsigned int texflag;
+
+    initialise_random_sequence(IS_TEX_RSEED,TEXTURE_SEED,dz);
+    if((exit_status = initialise_texture_structure(dz))<0)
+        return(exit_status);
+
+    if((exit_status = set_up_and_fill_insample_buffers(&(dz->tex->insnd),dz))<0)
+        return(exit_status);
+
+    if((exit_status = initperm(&(dz->tex->perm),dz))<0)
+        return(exit_status);
+
+    if((exit_status = setup_texflag(dz->tex,dz))<0)                                         /* 1 */
+        return(exit_status);
+
+    texflag = dz->tex->txflag;
+
+    if((exit_status = adjust_some_input_params(dz))<0)
+        return(exit_status);
+
+    if((exit_status = preset_some_internal_texture_params(dz))<0)
+        return(exit_status);
+    /* 2 */
+    unused_flags = TOTAL_POSSIBLE_USER_FLAGS - dz->application->vflag_cnt;
+
+    if((exit_status = install_unused_texture_flags(&total_flags,unused_flags,dz))<0)
+        return(exit_status);
+
+    if((exit_status = install_the_internal_flags(total_flags,INTERNAL_FLAGS_CNT,dz))<0)
+        return(exit_status);
+
+    if((exit_status = get_the_notedata(dz->tex,dz))<0)
+        return(exit_status);
+
+    if((exit_status = assign_timeset_hfset_motifsets(dz))<0)
+        return(exit_status);
+
+    if((exit_status = massage_params(dz))<0)                                                        /* 3 */
+        return(exit_status);
+    if(texflag & ORN_DEC_OR_TIMED) {
+        if((exit_status = extend_timeset(dz))<0)                                                /* 7 */
+            return(exit_status);
+    } else {
+        if((exit_status = generate_timeset(dz))<0)                                              /* 8 */
+            return(exit_status);
+    }
+    if((exit_status = do_prespace(dz->tex->timeset,dz))<0)
+        return(exit_status);
+
+    if(dz->process == SIMPLE_TEX && dz->vflag[CYCLIC_TEXFLAG]) {
+        if(dz->infilecnt < 2)
+            dz->vflag[CYCLIC_TEXFLAG] = 0;
+        else if (dz->vflag[PERM_TEXFLAG]) {
+            if((dz->peakno = (int *)malloc(dz->infilecnt * sizeof(int))) == NULL) {
+                sprintf(errstr,"Insufficient memory for clyclic permutations of input files.\n");
+                return(MEMORY_ERROR);
+            }
+            if((dz->lastpeakno = (int *)malloc(dz->infilecnt * sizeof(int))) == NULL) {
+                sprintf(errstr,"Insufficient memory for clyclic permutations of input files.\n");
+                return(MEMORY_ERROR);
+            }
+            for(n=0;n<dz->infilecnt;n++) {
+                dz->peakno[n] = n;
+                dz->lastpeakno[n] = n;
+            }
+        }
+    }
+    /* create stereo outfile here! */
+    /* RWD 4:2002  now we can open outfile with corect params! */
+    //TW UPDATE to use stereo input means that dz->infile->channels must be retained for now
+    //TW Open outfile later (texture5.c)
+    return(FINISHED);
+}
+
+/*********************** INITIALISE_TEXTURE_STRUCTURE ******************************/
+
+int initialise_texture_structure(dataptr dz)
+{
+    int n;
+    if((dz->tex = (texptr)malloc(sizeof(struct textural)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY for texture structure.\n");
+        return(MEMORY_ERROR);
+    }
+
+    dz->tex->txflag     = 0;
+    dz->tex->motifhead  = (motifptr)0;
+    dz->tex->insnd      = (insamptr *)0;
+    dz->tex->timeset    = (motifptr)0;
+    dz->tex->hfldmotif  = (motifptr)0;
+    dz->tex->phrase     = (motifptr *)0;
+    dz->tex->perm       = (int **)0;
+    dz->tex->dectypstor = 0;
+    dz->tex->dectypcnt      = 0;
+    dz->tex->amptypstor = 0;
+    dz->tex->amptypcnt  = 0;
+    dz->tex->phrasecnt  = 0;
+    dz->tex->ampdirectd = FALSE;
+
+    if((dz->tex->insnd      = (insamptr *)malloc(dz->infilecnt * sizeof(insamptr)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY for texture insound structure.\n");
+        return(MEMORY_ERROR);
+    }
+    for(n=0;n<dz->infilecnt;n++) {
+        dz->tex->insnd[n] = (insamptr)0;
+        if((dz->tex->insnd[n]= (insamptr)malloc(sizeof(struct insample)))==NULL) {
+            sprintf(errstr,"INSUFFICIENT MEMORY for texture insound[%d] structure.\n",n+1);
+            return(MEMORY_ERROR);
+        }
+    }
+    return(FINISHED);
+}
+
+/************************** SET_UP_AND_FILL_INSAMPLE_BUFFERS ****************************
+ *
+ * 1) Set buffer pointer to zero, until it has been malloced.
+ *        This make freeing of tex structure possible.
+ */
+
+int set_up_and_fill_insample_buffers(insamptr **insound,dataptr dz)
+{
+    int n;
+    int samps_read;
+    int thisbufsize;
+    int wrap_around_samps = 1;
+    for(n=0;n<dz->infilecnt;n++) {
+        ((*insound)[n])->buffer = /*(float *)0*/NULL;                                   /* 1 */
+        thisbufsize = dz->insams[n];
+        thisbufsize += wrap_around_samps;
+        if((((*insound)[n])->buffer  = (float *)malloc(thisbufsize * sizeof(float)))==NULL) {
+            sprintf(errstr,"INSUFFICIENT MEMORY for texture insound buffer pointer %d.\n",n+1);
+            return(MEMORY_ERROR);
+        }
+        memset((char *)((*insound)[n])->buffer,0,thisbufsize * sizeof(float));
+        if((samps_read = fgetfbufEx(((*insound)[n])->buffer,thisbufsize,dz->ifd[n],0)) < 0) {
+            sprintf(errstr,"Can't read sndfile %d to buffer: set_up_and_fill_insample_buffers()\n",n+1);
+            return(SYSTEM_ERROR);
+        }
+        if(samps_read != dz->insams[n]) {
+            sprintf(errstr,"Error reading sndfile %d to buf: set_up_and_fill_insample_buffers()\n",n+1);
+            return(PROGRAM_ERROR);
+        }
+    }
+    return(FINISHED);
+}
+
+/***************************** SETUP_TEXFLAG ****************************/
+
+int setup_texflag(texptr tex,dataptr dz)
+{
+    tex->txflag = 0;
+    switch(dz->process) {
+    case(SIMPLE_TEX): break;
+    case(GROUPS):     tex->txflag |= IS_GROUPS;                                                                                                         break;
+    case(DECORATED):  tex->txflag |= IS_DECOR;                                                                                                              break;
+    case(PREDECOR):   tex->txflag |= IS_DECOR;      tex->txflag |= ISPRE_DECORORN;                                          break;
+    case(POSTDECOR):  tex->txflag |= IS_DECOR;      tex->txflag |= ISPOST_DECORORN;                                     break;
+    case(ORNATE):     tex->txflag |= IS_ORNATE;                                                                                                         break;
+    case(PREORNATE):  tex->txflag |= IS_ORNATE; tex->txflag |= ISPRE_DECORORN;                                              break;
+    case(POSTORNATE): tex->txflag |= IS_ORNATE; tex->txflag |= ISPOST_DECORORN;                                         break;
+    case(MOTIFS):     tex->txflag |= IS_MOTIFS;                                                                                                         break;
+    case(MOTIFSIN):   tex->txflag |= IS_MOTIFS; tex->txflag |= MOTIF_IN_HF;                                             break;
+    case(TIMED):                                                                                                                    tex->txflag |= ISTIMED; break;
+    case(TGROUPS):    tex->txflag |= IS_GROUPS;                                                             tex->txflag |= ISTIMED; break;
+    case(TMOTIFS):    tex->txflag |= IS_MOTIFS;                                                             tex->txflag |= ISTIMED; break;
+    case(TMOTIFSIN):  tex->txflag |= IS_MOTIFS; tex->txflag |= MOTIF_IN_HF; tex->txflag |= ISTIMED; break;
+    default:
+        sprintf(errstr,"Unknown process in setup_texflag()\n");
+        return(PROGRAM_ERROR);
+    }
+    switch(dz->mode) {
+    case(TEX_NEUTRAL):      break;
+    case(TEX_HFIELD):       tex->txflag |= ISHARM;                                                                                                                  break;
+    case(TEX_HFIELDS):      tex->txflag |= ISHARM;                                                  tex->txflag |= ISMANY_HFLDS;    break;
+    case(TEX_HSET):         tex->txflag |= ISHARM;  tex->txflag |= IS_HS;                                                                   break;
+    case(TEX_HSETS):        tex->txflag |= ISHARM;  tex->txflag |= IS_HS;   tex->txflag |= ISMANY_HFLDS;    break;
+    default:
+        sprintf(errstr,"Unknown mode in setup_texflag()\n");
+        return(PROGRAM_ERROR);
+    }
+    return(FINISHED);
+}
+
+/************************** ADJUST_SOME_INPUT_PARAMS ****************************
+ *
+ * (1)  dz->vflag[WHICH_CHORDNOTE] internally carries all 3 vals (first,highest,every).
+ *
+ * (2)  Gprange, in cases with Hfields, is an integer count of HF-field notes to use.
+ */
+
+int adjust_some_input_params(dataptr dz)
+{
+    int texflag = dz->tex->txflag;
+    if((texflag & IS_ORN_OR_DEC) && dz->vflag[FORCE_EVERY]==TRUE)
+        dz->vflag[WHICH_CHORDNOTE] = DECOR_EVERY;                                               /* 1 */
+
+    if((texflag & IS_DEC_OR_GRP) && (texflag & ISHARM)) {                           /* 2 */
+        dz->is_int[TEX_GPRANGLO] = TRUE;
+        dz->is_int[TEX_GPRANGHI] = TRUE;
+        dz->iparam[TEX_GPRANGLO] = round(dz->param[TEX_GPRANGLO]);
+        dz->iparam[TEX_GPRANGHI] = round(dz->param[TEX_GPRANGHI]);
+    }
+    return(FINISHED);
+}
+
+/***************************** PRESET_SOME_INTERNAL_TEXTURE_PARAMS ****************************/
+
+int preset_some_internal_texture_params(dataptr dz)
+{
+    int cnt = 0;
+    dz->iparam[SPINIT]    = 0;       cnt++; /* ALL CLUMPS */
+    dz->iparam[SPCNT]     = 0;       cnt++;
+    dz->iparam[DIRECTION] = 0;       cnt++;
+    dz->param[CPOS]       = 0.5; cnt++; /* for safety only */       /* SPATIALISATION */
+    dz->param[TPOSITION]  = 0.5; cnt++; /* for safety only */
+    dz->param[THISSPRANGE]= 1.0; cnt++; /* full range */
+    /*dz->iparam[TEX_MAXOUT]= 0.0;   cnt++; *//* min value */
+    dz->param[TEX_MAXOUT] = 0.0;   cnt++;             /*RWD*/
+    if(cnt != dz->application->internal_param_cnt) {
+        sprintf(errstr,"preset_some_internal_texture_params() has false count\n");
+        return(PROGRAM_ERROR);
+    }
+    dz->itemcnt = 0;
+    return(FINISHED);
+}
+
+/***************************** INSTALL_UNUSED_TEXTURE_FLAGS ****************************/
+
+int install_unused_texture_flags(int *total_flags,int unused_flags,dataptr dz)
+{
+    int n;
+    *total_flags = dz->application->vflag_cnt + unused_flags;
+    if(unused_flags > 0) {
+        if((dz->vflag  =
+            (char *)realloc(dz->vflag,(*total_flags) * sizeof(char)))==NULL) {
+            sprintf(errstr,"INSUFFICIENT MEMORY for internal flags.\n");
+            return(MEMORY_ERROR);
+        }
+        for(n=0;n<unused_flags;n++) {
+            switch(n) {
+            case(4):        dz->vflag[2] = FALSE;   break;
+            case(3):        dz->vflag[3] = FALSE;   break;
+            case(2):        dz->vflag[4] = FALSE;   break;
+            case(1):        dz->vflag[5] = FALSE;   break;
+            case(0):        dz->vflag[6] = FALSE;   break;
+            }
+        }
+    }
+    return(FINISHED);
+}
+
+/***************************** INSTALL_THE_INTERNAL_FLAGS ****************************/
+
+int install_the_internal_flags(int total_flags,int internal_flags,dataptr dz)
+{
+    /* THESE FLAGS ARE NOT AVAILABLE TO USER : but they are used in the code */
+    total_flags += internal_flags;
+    if((dz->vflag  =
+        (char *)realloc(dz->vflag,total_flags * sizeof(char)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY to reallocate internal flags.\n");
+        return(MEMORY_ERROR);
+    }
+    dz->iparam[DECCENTRE] = FALSE;
+    return(FINISHED);
+}
+
+/***************************** GET_THE_NOTEDATA ****************************/
+
+int get_the_notedata(texptr tex,dataptr dz)
+{
+    int exit_status;
+    unsigned int texflag = tex->txflag;
+    int motifcnt, expected_motifcnt = 0;
+
+    if(dz->fp==NULL) {
+        sprintf(errstr,"notedata fileptr not initialised: get_the_notedata()\n");
+        return(PROGRAM_ERROR);
+    }
+    if((exit_status = get_sample_pitches(dz->fp,dz))<0) {
+        sprintf(errstr,"Insufficient pitch values in notedata file.\n");
+        return(DATA_ERROR);
+    }
+    if((exit_status = get_motifs(dz->fp,&motifcnt,dz))<0)
+        return(exit_status);
+    if(texflag & ORN_DEC_OR_TIMED)  expected_motifcnt++;    /* Line to work on */
+    if(texflag & ISHARM)                    expected_motifcnt++;    /* HF data                 */
+    if(texflag & IS_ORN_OR_MTF)             expected_motifcnt++;    /* Ornmnts or mtfs */
+
+    if(texflag & IS_ORN_OR_MTF)     {
+        if(motifcnt < expected_motifcnt) {
+            sprintf(errstr,"Insufficient motifs in notedata file.\n");
+            return(DATA_ERROR);
+        }
+    } else {
+        if(motifcnt!=expected_motifcnt) {
+            sprintf(errstr,"Incorrect number [%d] of motifs in notedata file (expected %d).\n",
+                    motifcnt,expected_motifcnt);
+            return(DATA_ERROR);
+        }
+    }
+    return(FINISHED);
+}
+
+/**************************** EXTEND_TIMESET *******************************/
+
+int extend_timeset(dataptr dz)
+{
+    int exit_status;
+    int origcnt = 0, n;
+    noteptr startnote = dz->tex->motifhead->firstnote;
+    noteptr orignote, thisnote  = startnote;
+    double *timediff;
+
+    if(startnote==(noteptr)0) {
+        sprintf(errstr,"Problem in note timings: extend_timeset()\n");
+        return(PROGRAM_ERROR);
+    }
+    while(thisnote!=(noteptr)0) {
+        if(thisnote->ntime > dz->param[TEXTURE_DUR]) {
+            delete_notes_here_and_beyond(thisnote);
+            return(FINISHED);
+        }
+        thisnote = thisnote->next;
+        origcnt++;
+    }
+
+    if((timediff = (double *)malloc(origcnt * sizeof(double)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY for timegaps array.\n");
+        return(MEMORY_ERROR);
+    }
+    n = 1;
+    thisnote = startnote;
+    while(thisnote->next !=(noteptr)0) {
+        thisnote = thisnote->next;
+        timediff[n++] = thisnote->ntime - thisnote->last->ntime;
+    }
+    if(dz->brksize[TEXTURE_SKIP]) {
+        if((exit_status = read_value_from_brktable(thisnote->ntime,TEXTURE_SKIP,dz))<0) {
+            free(timediff);
+            return(exit_status);
+        }
+    }
+    timediff[0] = dz->param[TEXTURE_SKIP];
+    n = 0;
+    orignote = startnote;
+
+    for(;;) {
+        if(thisnote->ntime > dz->param[TEXTURE_DUR] && timediff[n] > 0.0)
+            break;
+        if((exit_status = make_new_note(&thisnote))<0) {
+            free(timediff);
+            return(exit_status);
+        }
+        copy_note(thisnote,orignote);
+        thisnote->ntime = (float)(thisnote->last->ntime + timediff[n]);
+        if(++n>=origcnt) {
+            if(dz->brksize[TEXTURE_SKIP]) {
+                if((exit_status = read_value_from_brktable(thisnote->ntime,TEXTURE_SKIP,dz))<0) {
+                    free(timediff);
+                    return(exit_status);
+                }
+                timediff[0] = dz->param[TEXTURE_SKIP];
+            }
+            n = 0;
+            orignote = startnote;
+        } else
+            orignote = orignote->next;
+    }
+    dz->brksize[TEXTURE_SKIP] = 0;  /* prevent future reads */
+    free(timediff);
+    return(FINISHED);
+}
+
+
+/*********************************************************************
+ *
+ * (1)  Generating the tset (set of timed values on or around which the
+ *              texture is to be generated).
+ */
+/************************** GENERATE_TIMESET ******************************
+ *
+ * (A)  Zero all other parameters besides time.
+ */
+
+int generate_timeset(dataptr dz)
+{
+    int exit_status;
+    double lasttime, thistime = 0.0;
+    noteptr thisnote;
+    motifptr tset;
+    if((exit_status = add_motif_to_end_of_motiflist(&(dz->tex->timeset),dz))<0)
+        return(exit_status);
+    tset =  dz->tex->timeset;
+    if((thisnote = tset->firstnote)==(noteptr)0) {
+        sprintf(errstr,"Failure to find 1st note in motif: generate_timeset()\n");
+        return(PROGRAM_ERROR);
+    }
+    put_znote(thisnote);                    /* A */
+    thisnote->ntime = (float)thistime;
+    if(dz->brksize[TEXTURE_PACK]) {
+        if((exit_status = read_value_from_brktable(thistime,TEXTURE_PACK,dz))<0)
+            return(exit_status);
+    }
+    thistime += dz->param[TEXTURE_PACK];
+    while(thistime<dz->param[TEXTURE_DUR]) {
+        if((exit_status = generate_tset_times(&thistime,&thisnote,dz))<0)
+            return(exit_status);
+        put_znote(thisnote);                            /* A */
+    }
+    thisnote = tset->firstnote;
+    lasttime = thisnote->ntime;
+    thisnote = thisnote->next;
+    while(thisnote!=(noteptr)0) {
+        if((exit_status = scatter_and_quantise_tset_times(&lasttime,&thisnote,dz))<0)
+            return(exit_status);
+    }
+    dz->brksize[TEXTURE_PACK]  = 0; /* set these brktables to appear empty, so no read attempts later */
+    dz->brksize[TEXTURE_SCAT]  = 0;
+    dz->brksize[TEXTURE_TGRID] = 0;
+    return(FINISHED);
+}
+
+/***************************** DO_PRESPACE ******************************
+ *
+ * Spatialise the time set, prior to output phase&/or ornamentation.
+ */
+
+int do_prespace(motifptr tset,dataptr dz)
+{
+    int exit_status;
+    noteptr thisnote = tset->firstnote;
+    while(thisnote!=(noteptr)0) {
+        if((exit_status = pre_space(thisnote,dz))<0)
+            return(exit_status);
+        thisnote = thisnote->next;
+    }
+    return(FINISHED);
+}
+
+/**************************** GET_SAMPLE_PITCHES *****************************/
+
+int get_sample_pitches(FILE *fp,dataptr dz)
+{
+    int exit_status;
+    /* TW AUGUST 2006: 200--> 2000 */
+    char temp[2000], *q;
+    int pitchcnt = 0;
+    double *p;
+    int got_all_pitches = FALSE;
+    /* TW AUGUST 2006: 200--> 2000 */
+    while(!got_all_pitches && (fgets(temp,2000,fp)!=NULL)) {
+        q = temp;
+        p = &(((dz->tex->insnd)[pitchcnt])->pitch);
+        while((exit_status = get_float_from_within_string(&q,p))==TRUE) {
+            if(++pitchcnt >= dz->infilecnt) {
+                got_all_pitches = TRUE;
+                break;
+            }
+            p = &(((dz->tex->insnd)[pitchcnt])->pitch);
+        }
+        if(exit_status==FALSE)
+            return(DATA_ERROR);
+    }
+    if(!got_all_pitches)
+        return(DATA_ERROR);
+    return(FINISHED);
+}
+
+/**************************** GET_MOTIFS *****************************
+ *
+ * Read data from an ascii file to notelist.
+ */
+
+int get_motifs(FILE *fp,int *motifcnt,dataptr dz)
+{
+    int exit_status;
+    motifptr thismotif;
+    noteptr thisnote;
+    char *p, temp[200];
+    double lasttime = 0.0;
+    int datalen, noteno, motifno = 0;
+    if((exit_status = init_motifs(dz))<0)               /* 8 */
+        return(exit_status);
+    thismotif = dz->tex->motifhead;
+    while(fgets(temp,200,fp)!=NULL) {
+        p = temp;
+        while(isspace(*p))
+            p++;
+        if(*p==ENDOFSTR)
+            continue;
+        if(*p!=TEXTURE_SEPARATOR) {
+            //TW UPDATE
+            sprintf(errstr,"'%c' missing before datacount in notedata file: motif %d (or more notes listed than indicated by %cN)\n"
+                    "check datalen is correct\n",TEXTURE_SEPARATOR,motifno+1,TEXTURE_SEPARATOR);
+            return(DATA_ERROR);
+        }
+        p++;
+        if(!isdigit(*p) || sscanf(p,"%d",&datalen)!=1) {
+            sprintf(errstr,"No datalength given: motif %d\n",motifno+1);
+            return(DATA_ERROR);
+        }
+        if(datalen <= 0) {
+            sprintf(errstr,"Invalid data length %d in notedata: motif %d\n",datalen,motifno+1);
+            return(DATA_ERROR);
+        }
+        motifno++;
+        thisnote = thismotif->firstnote;
+        for(noteno=1;noteno<=datalen;noteno++) {
+            if((exit_status = read_a_note_from_notedata_file(thisnote,noteno,motifno,&lasttime,dz))<0)
+                return(exit_status);
+            if(exit_status==CONTINUE) {
+                noteno--;
+                continue;
+            }
+            if((exit_status = make_new_note(&thisnote))<0)
+                return(exit_status);
+        }
+        if((exit_status = un_link_note(thisnote))<0)
+            return(exit_status);
+        if((exit_status = new_motif(&thismotif))<0)
+            return(exit_status);
+    }
+    *motifcnt = motifno;
+    if(motifno > 0)
+        return unlink_last_motif(thismotif);
+    return(FINISHED);
+}
+
+/************************** MOTIFCHEK ********************************
+ *
+ * Check we've not run out of motifs.
+ */
+
+int motifchek(motifptr thismotif)
+{
+    if(thismotif == (motifptr)0) {
+        sprintf(errstr,"motifchek(): Insufficient motifs: even though correctly counted.\n");
+        return(PROGRAM_ERROR);
+    }
+    return(FINISHED);
+}
+
+/***************************** CONVERT_CMDLINE_INSTRNOS_TO_INTERNAL_REPRESENTATION ****************************/
+
+void convert_cmdline_instrnos_to_internal_representation(dataptr dz)
+{
+    if(dz->brksize[TEXTURE_INSLO])
+        subtract_one_from_brkvals(TEXTURE_INSLO,dz);
+    else
+        dz->iparam[TEXTURE_INSLO]--;
+
+    if(dz->brksize[TEXTURE_INSHI])
+        subtract_one_from_brkvals(TEXTURE_INSHI,dz);
+    else
+        dz->iparam[TEXTURE_INSHI]--;
+}
+
+/***************************** CHECK_MAX_TRANSPOS_COMPATIBLE_WITH_SPLICELEN ****************************/
+
+int check_max_transpos_compatible_with_splicelen(dataptr dz)
+{
+    int n, exit_status;
+    double max_maxpitch, max_minpitch, max_transpospitch, maxupshift, upratio, minlen;
+    double min_sndlength = (TEXTURE_SPLICELEN + TEXTURE_SAFETY) * MS_TO_SECS * (double)dz->infile->srate;
+    dz->frametime = TEXTURE_SPLICELEN;
+
+    if(dz->brksize[TEXTURE_MAXPICH]) {
+        if((exit_status = get_maxvalue_in_brktable(&max_maxpitch,TEXTURE_MAXPICH,dz))<0)
+            return(exit_status);
+    } else
+        max_maxpitch = dz->param[TEXTURE_MAXPICH];
+
+    if(dz->brksize[TEXTURE_MINPICH]) {
+        if((exit_status = get_maxvalue_in_brktable(&max_minpitch,TEXTURE_MINPICH,dz))<0)
+            return(exit_status);
+    } else
+        max_minpitch = dz->param[TEXTURE_MINPICH];
+
+    max_transpospitch = max(max_minpitch,max_maxpitch);
+
+    dz->zeroset = 0;        /* use as flag re splicelen change */
+    for(n=0;n<dz->infilecnt;n++) {
+        maxupshift = max_transpospitch - ((dz->tex->insnd)[n])->pitch;
+        upratio    = pow(2.0,(maxupshift/SEMITONES_PER_OCTAVE));
+        minlen     = (double)dz->insams[n]/upratio;
+        if(minlen < min_sndlength) {
+            dz->frametime = 2.0;
+            min_sndlength = (dz->frametime + TEXTURE_SAFETY) * MS_TO_SECS * (double)dz->infile->srate;
+            if(minlen < min_sndlength) {
+                dz->frametime = 1.0;
+                min_sndlength = (dz->frametime + TEXTURE_SAFETY) * MS_TO_SECS * (double)dz->infile->srate;
+                if(minlen < min_sndlength) {
+                    sprintf(errstr,"sndfile %d [%.3lf secs] too short for max upward transposition [ratio %.2lf].\n",
+                            n+1,(double)dz->insams[n]/(double)dz->infile->srate,upratio);
+                    return(DATA_ERROR);
+                }
+            }
+        }
+    }
+    return(FINISHED);
+}
+
+/************************* SET_AMPTYPE_PARAMS *******************************/
+
+int set_amptype_params(dataptr dz)
+{   int mask = 1, n;
+    dz->tex->amptypcnt  = 0;
+    dz->tex->amptypstor = 0;
+    switch(dz->iparam[TEX_AMPCONT]) {
+    case(IS_MIXED):                          dz->tex->amptypstor |= 1;      dz->tex->amptypstor |= 2;                                                       break;
+    case(IS_CRESC):                                                                                 dz->tex->amptypstor |= 2;                                                       break;
+    case(IS_FLAT):                           dz->tex->amptypstor |= 1;                                                                                                              break;
+    case(IS_DECRESC):                                                                                                                                 dz->tex->amptypstor |= 4;     break;
+    case(IS_FLAT_AND_CRESC):         dz->tex->amptypstor |= 1;      dz->tex->amptypstor |= 2;                                                       break;
+    case(IS_CRESC_AND_DECRESC):                                                             dz->tex->amptypstor |= 2; dz->tex->amptypstor |= 4;     break;
+    case(IS_FLAT_AND_DECRESC):       dz->tex->amptypstor |= 1;                                                        dz->tex->amptypstor |= 4;     break;
+
+    case(IS_DIRECTIONAL):            dz->tex->ampdirectd = TRUE;    dz->tex->amptypcnt = 1;                                                 break;
+    case(IS_DIREC_OR_FLAT):          dz->tex->ampdirectd = TRUE;    dz->tex->amptypcnt = 2;                                                 break;
+    default:
+        sprintf(errstr,"Unknown case in set_amptype_params()\n");
+        return(PROGRAM_ERROR);
+    }
+    if(dz->tex->amptypstor > 0) {
+        for(n=0;n<3;n++) {
+            if(mask & dz->tex->amptypstor)
+                dz->tex->amptypcnt++;
+            mask <<= 1;
+        }
+    }
+    return(FINISHED);
+}
+
+/************************* SET_DECOR_PITCHPOSITION_PARAMS ******************************/
+
+int set_decor_pitchposition_params(dataptr dz)
+{
+    int n, mask = 1;
+    dz->tex->dectypstor = 0;
+    dz->tex->dectypcnt  = 0;
+    switch(dz->iparam[TEX_DECPCENTRE]) {
+    case(DEC_CENTRED): dz->tex->dectypstor |= 1;                                                                                                            break;
+    case(DEC_ABOVE):                                                         dz->tex->dectypstor |= 2;                                                              break;
+    case(DEC_BELOW):                                                                                                                dz->tex->dectypstor |= 4;       break;
+    case(DEC_C_A):     dz->tex->dectypstor |= 1; dz->tex->dectypstor |= 2;                                                          break;
+    case(DEC_C_B):     dz->tex->dectypstor |= 1;                                                    dz->tex->dectypstor |= 4;       break;
+    case(DEC_A_B):                                                           dz->tex->dectypstor |= 2;      dz->tex->dectypstor |= 4;       break;
+    case(DEC_C_A_B):   dz->tex->dectypstor |= 1; dz->tex->dectypstor |= 2;  dz->tex->dectypstor |= 4;       break;
+    default:
+        sprintf(errstr,"Unknown case in set_decor_pitchposition_params()\n");
+        return(PROGRAM_ERROR);
+    }
+    if(dz->tex->dectypstor > 0) {
+        for(n=0;n<3;n++) {
+            if(mask & dz->tex->dectypstor)
+                dz->tex->dectypcnt++;
+            mask <<= 1;
+        }
+    }
+    return(FINISHED);
+}
+
+/********************** DELETE_NOTES_HERE_AND_BEYOND *******************************
+
+void delete_notes_here_and_beyond(noteptr startnote)
+{
+        noteptr here = startnote;
+        if(here==(noteptr)0)
+                return;
+        while(here->next!=(noteptr)0)
+                here=here->next;
+        while(here!=startnote) {
+                here=here->last;
+                free(here->next);
+        }
+        if(startnote->last!=(noteptr)0)
+                startnote->last->next = (noteptr)0;
+        free(startnote);
+}
+****/
+
+/********************** MAKE_NEW_NOTE ****************************
+ *
+ * Create new link in note list.
+ */
+
+int make_new_note(noteptr *thisnote)
+{
+    if(((*thisnote)->next = (noteptr)malloc(sizeof(struct nnote)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY for a further note store.\n");
+        return(MEMORY_ERROR);
+    }
+    (*thisnote)->next->last = *thisnote;
+    *thisnote = (*thisnote)->next;
+    (*thisnote)->next = (noteptr)0;
+    return(FINISHED);
+}
+
+/**************************** COPY_NOTE *******************************/
+
+void copy_note(noteptr thisnote,noteptr orignote)
+{
+    thisnote->ntime = orignote->ntime;
+    thisnote->amp   = orignote->amp;
+    thisnote->pitch = orignote->pitch;
+    thisnote->dur   = orignote->dur;
+    thisnote->instr = orignote->instr;
+    thisnote->spacepos = orignote->spacepos;
+    thisnote->motioncentre = orignote->motioncentre;
+}
+
+/************************** ADD_MOTIF_TO_END_OF_MOTIFLIST ******************************
+ *
+ * Create new motif at end of list.
+ */
+
+int add_motif_to_end_of_motiflist(motifptr *new,dataptr dz)
+{
+    int exit_status;
+    motifptr here = dz->tex->motifhead;
+    while(here->next!=(motifptr)0)
+        here = here->next;
+    if((exit_status =  new_motif(&here))<0)
+        return(exit_status);
+    *new = here;
+    return(FINISHED);
+}
+
+/************************* SCATTER_AND_QUANTISE_TSET_TIMES ******************************/
+
+int scatter_and_quantise_tset_times(double *lasttime,noteptr *thisnote,dataptr dz)
+{
+    int exit_status;
+    double thistime = (*thisnote)->ntime;                   /* 1 */
+    double timestep = thistime - *lasttime;                 /* 2 */
+    *lasttime = thistime;                                                   /* 2a */
+    if(dz->brksize[TEXTURE_SCAT]) {
+        if((exit_status = read_value_from_brktable(thistime,TEXTURE_SCAT,dz))<0)
+            return(exit_status);
+    }
+    if(dz->param[TEXTURE_SCAT]>1.0) {                               /* 3a */
+        //TW UPDATE (original code error)
+        if((exit_status = bigscatter(thisnote,thistime,timestep,dz->param[TEXTURE_SCAT],lasttime,dz))<0)
+            return(exit_status);
+    } else {
+        if(!flteq(dz->param[TEXTURE_SCAT],0.0))                         /* 4 */
+            thistime -= (float)(drand48() * dz->param[TEXTURE_SCAT] * timestep);
+
+        if(dz->param[TEXTURE_TGRID]>0.0)
+            thistime  = quantise(thistime,dz->param[TEXTURE_TGRID]);        /* 6 */
+        (*thisnote)->ntime = (float)thistime;
+    }
+    *thisnote = (*thisnote)->next;
+    return(FINISHED);                               /* 8a */
+}
+
+/************************** PRE_SPACE ********************************
+ *
+ * Store spatial data in the tsetnote spacepos and motioncentre.
+ */
+
+int pre_space(noteptr thisnote,dataptr dz)
+{
+    int exit_status;
+    double position;
+    if((exit_status = getpos((double)thisnote->ntime,&position,dz))<0)
+        return(exit_status);
+    thisnote->spacepos     = (float)position;
+    thisnote->motioncentre = (float)dz->param[CPOS];
+    return(FINISHED);
+}
+
+/************************** GETPOS ****************************
+ *
+ * Calculate spatial position of event from it's time.
+ */
+
+int getpos(double thistime,double *position,dataptr dz)
+{
+    int exit_status;
+    if(dz->brksize[TEXTURE_POS] && (exit_status = read_value_from_brktable(thistime,TEXTURE_POS,dz))<0)
+        return(exit_status);
+    if(dz->brksize[TEXTURE_SPRD] && (exit_status = read_value_from_brktable(thistime,TEXTURE_SPRD,dz))<0)
+        return(exit_status);
+    if(dz->param[TEXTURE_SPRD] > 0.0) {
+        if((exit_status = spread_and_set_cpos(position,dz->param[TEXTURE_POS],dz->param[TEXTURE_SPRD],dz))<0)
+            return(exit_status);
+    } else {
+        /* NOV 1997--> */
+        dz->param[CPOS] = dz->param[TEXTURE_POS];
+        /* <--NOV 1997 */
+        *position       = dz->param[TEXTURE_POS];
+    }
+    return(FINISHED);
+}
+
+/***************************** SPREAD_AND_SET_CPOS *****************************/
+
+int spread_and_set_cpos(double *position,double given_position,double spread,dataptr dz)
+{
+    int exit_status;
+    int        posno, spswitch;
+    int    poscnt,hposcnt;
+    double hspread,spacing, closeness, squash;
+
+    /* total stereospace has MAXPOSCNT positions: calc no. & spacing of positions available at given spread */
+    poscnt  = round(spread * (double)MAXPOSCNT);
+    hposcnt = poscnt/2;
+    hspread = spread/(double)2.0;
+    if(hposcnt != 0)
+        spacing = hspread/(double)hposcnt;
+    else {
+        /* bandwidth effectively zero: return given position */
+        dz->param[CPOS] = given_position;
+        *position       = given_position;
+        return(FINISHED);
+    }
+    /* randomly select leftwards/rightwards of the given position */
+    if((exit_status = doperm(2,PM_SPACE,&spswitch,dz))<0)
+        return(exit_status);
+    if(!spswitch)
+        spswitch = -1;
+
+    /* randomly chose a pos (to left or right) around centre pos */
+    posno  = round(drand48() * hposcnt);
+    posno *= spswitch;
+
+    /* calculate warping coefficient to avoid position-spread leaking over edges of stereo-space */
+    if(spread>(double)1.0/SQUASH)
+        squash = (double)1.0/spread;
+    else
+        squash = SQUASH;
+
+    /* If (position+spread) leaks to right of stereo-space : squeeze position */
+    if(given_position>=0.5 && (given_position + spread) > 1.0) {
+        closeness = (given_position - 0.5)/(double)0.5;
+        dz->param[CPOS] = given_position - (hspread*pow(closeness,squash));
+        /* If (position+spread) leaks to left of stereo-space : squeeze position */
+    } else if(given_position<0.5 && given_position < spread) {
+        closeness = (0.5 - given_position)/(double)0.5;
+        dz->param[CPOS] = given_position + (hspread*pow(closeness,squash));
+    } else
+        dz->param[CPOS] = given_position;
+
+    /* generate true position, around central position */
+    *position = dz->param[CPOS] + ((double)posno * spacing);
+    return chekrang(position);
+}
+
+/*************************** CHEKRANG **************************
+ *
+ * Check variable lies within range 0.0 to 1.0.
+ */
+
+int chekrang(double *val)
+{
+    if(flteq(*val,1.0))
+        *val = 1.0;
+    if(flteq(*val,0.0))
+        *val = 0.0;
+    if(*val<0.0 || *val>1.0) {
+        sprintf(errstr,"value [%f] outside range 0-1: chekrang()\n",*val);
+        return(PROGRAM_ERROR);
+    }
+    return(FINISHED);
+}
+
+/************************** READ_A_NOTE_FROM_NOTEDATA_FILE ********************************/
+
+int read_a_note_from_notedata_file(noteptr thisnote,int noteno,int motifno,double *lasttime,dataptr dz)
+{
+    int exit_status;
+    unsigned int texflag = dz->tex->txflag;
+    char temp[200], *p, *q;
+    double val;
+    int start;
+    if(dz->fp==NULL) {
+        sprintf(errstr,"Note datafile descriptor not initialised: read_a_note_from_notedata_file()\n");
+        return(PROGRAM_ERROR);
+    }
+    if(fgets(temp,200,dz->fp)==NULL){
+        sprintf(errstr,"Note data line for note %d, motif %d missing in notedatafile\n",noteno,motifno);
+        return(DATA_ERROR);
+    }
+    p =temp;
+    while(isspace(*p))
+        p++;
+    q = p;
+    if(*q==ENDOFSTR)
+        return(CONTINUE);
+    if((exit_status = get_data_item(q,&p,&val))<0) {
+        sprintf(errstr,"No time data for note %d, motif %d in notedatafile\n",noteno,motifno);
+        return(DATA_ERROR);
+    }
+    if(exit_status==FINISHED) {
+        sprintf(errstr,"No data after time for note %d, motif %d in notedatafile\n",noteno,motifno);
+        return(DATA_ERROR);
+    }
+    thisnote->ntime = (float)val;
+    if((noteno > 1) && (*lasttime > thisnote->ntime)) {
+        sprintf(errstr,"Notes in reverse time order: notedata file : motif %d: notes %d & %d\n",
+                motifno,noteno,noteno-1);
+        return(DATA_ERROR);
+    }
+    *lasttime = thisnote->ntime;
+    p++;
+    q = p;
+    if((exit_status = get_data_item(q,&p,&val))<0) {
+        sprintf(errstr,"No instr_no for note %d, motif %d in notedatafile\n",noteno,motifno);
+        return(DATA_ERROR);
+    }
+    if(exit_status==FINISHED) {
+        sprintf(errstr,"No data after instr_no for note %d, motif %d in notedatafile\n",noteno,motifno);
+        return(DATA_ERROR);
+    }
+    //instr_no = round(val);
+
+    p++;
+    q = p;
+    if((exit_status = get_data_item(q,&p,&val))<0) {
+        sprintf(errstr,"No pitch data for note %d, motif %d in notedatafile\n",noteno,motifno);
+        return(DATA_ERROR);
+    }
+    if(exit_status==FINISHED) {
+        sprintf(errstr,"No data after pitch for note %d, motif %d in notedatafile\n",noteno,motifno);
+        return(DATA_ERROR);
+    }
+    thisnote->pitch = (float)val;
+
+    /* NEEDS TESTING FOR MIDIRANGE: EXCEPT IN TIMING SET CASE */
+    if(!(texflag & ISTIMED) || motifno!=1) {
+        if(val < MIDIMIN || val > MIDIMAX) {
+            sprintf(errstr,"pitch value [%lf] out of range (%d to %d): motif %d: note %d\n",
+                    val,MIDIMIN,MIDIMAX,motifno,noteno);
+            return(DATA_ERROR);
+        }
+    }
+    p++;
+    q = p;
+    if((exit_status = get_data_item(q,&p,&val))<0) {
+        sprintf(errstr,"No amplitude data for note %d, motif %d in notedatafile\n",noteno,motifno);
+        return(DATA_ERROR);
+    }
+    if(exit_status==FINISHED) {
+        sprintf(errstr,"No data after amp for note %d, motif %d in notedatafile\n",noteno,motifno);
+        return(DATA_ERROR);
+    }
+    thisnote->amp = (float)val;
+    /* 1999 THIS NEEDS TESTING FOR MIDIRANGE EXCEPT IN TIMING SET CASE */
+    if(!(texflag & ISTIMED) || motifno!=1) {
+        if(val < MIDIMIN || val > MIDIMAX) {
+            sprintf(errstr,"amplitude value [%lf] out of range (%d to %d): motif %d: note %d\n",
+                    val,MIDIMIN,MIDIMAX,motifno,noteno);
+            return(DATA_ERROR);
+        }
+    }
+    p++;
+    q = p;
+    if((exit_status = get_data_item(q,&p,&val))<0) {
+        sprintf(errstr,"No duration data for note %d, motif %d in notedatafile\n",noteno,motifno);
+        return(DATA_ERROR);
+    }
+    thisnote->dur = (float)val;
+    if(texflag & IS_ORN_OR_MTF) {
+        if(texflag & IS_ORNATE) {
+            start = 2;
+        } else {
+            start = 1;
+            if(texflag & ISTIMED)
+                start++;
+        }
+        if(texflag & ISHARM)
+            start++;
+        if(motifno >= start) {
+            if(val <= FLTERR) {
+                sprintf(errstr,"Duration value [%lf] is too small: motif %d: note %d\n",val,motifno,noteno);
+                return(DATA_ERROR);
+            }
+        }
+    } else {
+        thisnote->dur = 1.0f;   /* default ; redundant */
+    }
+    return(FINISHED);
+}
+
+/***************************** GENERATE_TSET_TIMES **********************************
+ *
+ * Store time initially as SECONDS.
+ *
+ * (1)  Create location for a new note.
+ * (2)  Go to that new note.
+ * (3)  Store the current time at this note.
+ * (4)  Find note-density at this time, and generate time of next event.
+ * (5)  Return nextnote.
+ */
+
+int generate_tset_times(double *thistime,noteptr *thisnote,dataptr dz)
+{
+    int exit_status;
+    if((exit_status = make_new_note(thisnote))<0)
+        return(exit_status);                                            /* 1 */
+    (*thisnote)->ntime = (float)(*thistime);                        /* 3 */
+    if(dz->brksize[TEXTURE_PACK]) {
+        if((exit_status = read_value_from_brktable(*thistime,TEXTURE_PACK,dz))<0)
+            return(exit_status);
+    }
+    *thistime  += dz->param[TEXTURE_PACK];                  /* 4 */
+    return(FINISHED);                                                               /* 5 */
+}
+
+/********************** UN_LINK_NOTE ******************************
+ *
+ * Deletes empty address space at end of notelist.
+ */
+
+int un_link_note(noteptr thisnote)
+{
+    if(thisnote->last==(noteptr)0) {
+        sprintf(errstr,"Problem in un_link_note()\n");
+        return(PROGRAM_ERROR);
+    }
+    thisnote = thisnote->last;
+    free(thisnote->next);
+    thisnote->next = (noteptr)0;
+    return(FINISHED);
+}
+
+/************************ NEW_MOTIF *****************************
+ *
+ * Set up next motif in a list of musical-motifs.
+ * Set up location of first note of this motif.
+ */
+
+int new_motif(motifptr *thismotif)
+{
+    int exit_status;
+    motifptr newmotif;
+    noteptr  thisnote;
+
+    if((newmotif = (motifptr)malloc(sizeof (struct motif)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY to store next motif.\n");
+        return(MEMORY_ERROR);
+    }
+    (*thismotif)->next = newmotif;
+    newmotif->last = *thismotif;
+    newmotif->next = (motifptr)0;
+    if((exit_status = init_note(&thisnote))<0)
+        return(exit_status);
+    thisnote->next = (noteptr)0;
+    thisnote->last = (noteptr)0;
+    newmotif->firstnote = thisnote;
+    *thismotif = newmotif;
+    return(FINISHED);
+}
+
+/********************** UNLINK_LAST_MOTIF ******************************
+ *
+ * Deletes empty address space at end of motiflist.
+ */
+
+int unlink_last_motif(motifptr thismotif)
+{
+    if(thismotif->last==(motifptr)0) {
+        sprintf(errstr,"Problem in unlink_last_motif()\n");
+        return(PROGRAM_ERROR);
+    }
+    thismotif = thismotif->last;
+    free(thismotif->next);
+    thismotif->next = (motifptr)0;
+    return(FINISHED);
+}
+
+/**************************** SUBTRACT_ONE_FROM_BRKVALS ****************************/
+
+void subtract_one_from_brkvals(int paramno,dataptr dz)
+{
+    double *p = dz->brk[paramno] + 1;
+    double *pend = dz->brk[paramno] + (dz->brksize[paramno] * 2);
+    while(p < pend) {
+        *p -= 1.0;
+        p += 2;
+    }
+}
+
+/************************ BIGSCATTER *************************************
+ *
+ * (1)  The number of time-points to be randomly scattered as a group is
+ *      scatcnt.
+ * (1a) Base time is the time from which these new scattered times are offset.
+ * (2)  Save the current position in note list as 'here'.
+ * (3)  Go forward in note list until there are scatcnt notes inclusive
+ *      between here and there, or until list runs out.
+ * (3a) If the list runs out, modify scatcnt accordingly.
+ * (4)  Note the (original) time of the last of these events. This will
+ *      be returned as the new 'lasttime' for the next cycle of the
+ *      program.
+ * (5)  Make the time-step include the total duration of all these
+ *      events.
+ * (5a) Generate a set of times AT RANDOM within this large timestep,
+        sort them and store them.
+        * (6)  Replace existing times by scattered times, relative to basetime.
+        * (6a) Convert to MIDitime.
+        * (6b) Quantise if necessary.
+        * (7)  Replace the last time.
+        * (9)  Return the last note we worked on.
+        */
+
+int bigscatter(noteptr *thisnote,double thistime,double timestep,double scatter,double *lasttime,dataptr dz)
+{
+    int n, scatcnt = round(scatter);                /* 1 */
+    double *sct, *scti;
+    double basetime = thistime - timestep;  /* 1a */
+    noteptr here  = *thisnote;                              /* 2 */
+    noteptr there = *thisnote;                              /* 2 */
+    if((scti = (double *)malloc(scatcnt * sizeof(double)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY for scattering structure.\n");
+        return(MEMORY_ERROR);
+    }
+    sct = scti;
+    for(n=0;n < scatcnt-1; n++) {                   /* 3 */
+        if(there->next==(noteptr)0) {
+            scatcnt = n+1;                                  /* 3a */
+            break;
+        }
+        there = there->next;
+    }
+    *lasttime = there->ntime;                               /* 4 */
+    timestep += *lasttime - thistime;               /* 5 */
+    for(n= 0;n<scatcnt;n++)                                 /* 5a */
+        *sct++ = drand48() * timestep;
+    upsort(scti,scatcnt);
+    sct = scti;
+    while(here!=there) {                                    /* 6 */
+        thistime = basetime + (*sct++);
+        if(dz->param[TEXTURE_TGRID]>0.0)
+            thistime  = quantise(thistime,dz->param[TEXTURE_TGRID]);        /* 6b */
+        here->ntime = (float)thistime;
+        here = here->next;
+    }
+    thistime = basetime + *sct;                             /* 7 */
+    if(dz->param[TEXTURE_TGRID]>0.0)
+        thistime  = quantise(thistime,dz->param[TEXTURE_TGRID]);
+    there->ntime = (float)thistime;
+    free(scti);
+    *thisnote = there;
+    return(FINISHED);                                       /* 9 */
+}
+
+/************************** QUANTISE *************************************
+ *
+ * Quantise time point onto a grid.
+ */
+
+double quantise(double thistime,double timegrid)
+{
+    int gridpoint;
+    timegrid *= MS_TO_SECS;
+    gridpoint = round(thistime/timegrid);
+    return((double)gridpoint * timegrid);
+}
+
+/************************* GET_DATA_ITEM ****************************/
+
+int get_data_item(char *q,char **p,double *val)
+{
+    int exit_status = CONTINUE;
+    if(*q==ENDOFSTR)
+        return(DATA_ERROR);
+    while(isspace(**p)) {
+        (*p)++;
+        if(**p == ENDOFSTR)
+            return(DATA_ERROR);
+    }
+    if(**p==TEXTURE_SEPARATOR)
+        return(DATA_ERROR);
+    while(!isspace(**p) && **p!=ENDOFSTR) {
+        (*p)++;
+    }
+    if(**p==ENDOFSTR)
+        exit_status = FINISHED;
+    **p = ENDOFSTR;
+    if(sscanf(q,"%lf",val)!=1)
+        return(DATA_ERROR);
+    return(exit_status);
+}
+
+/************************* INIT_NOTE ****************************
+ *
+ * Initialise notelist.
+ */
+
+int init_note(noteptr *thisnote)
+{
+    if((*thisnote = (noteptr)malloc(sizeof(struct nnote)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY for another note.\n");
+        return(MEMORY_ERROR);
+    }
+    (*thisnote)->next = (noteptr)0;
+    (*thisnote)->last = (noteptr)0;
+    return(FINISHED);
+}
+
+/********************** UPSORT *******************************
+ *
+ * Sort set of doubles into ascending order.
+ */
+
+void upsort(double *scti,int scatcnt)
+{
+    double sct;
+    int n, m;
+    for(n=0;n<(scatcnt-1);n++) {
+        for(m=n+1;m<scatcnt;m++) {
+            if(*(scti+m)<*(scti+n)) {
+                sct       = *(scti+m);
+                *(scti+m) = *(scti+n);
+                *(scti+n) = sct;
+            }
+        }
+    }
+}
+
+/*********************** PUT_ZNOTE ********************************
+ *
+ * Put zero values in all parameters except time.
+ */
+
+void put_znote(noteptr thisnote)
+{
+    thisnote->amp   = 0.0f;
+    thisnote->pitch  = 0.0f;
+    thisnote->dur   = 0.0f;
+    thisnote->instr = 0;
+    thisnote->spacepos = 0.0f;
+    thisnote->motioncentre = 0.0f;
+}
+
+/************************* ASSIGN_TIMESET_HFSET_MOTIFSETS ******************************
+ *
+ * Assign appropriate pointers to input motifs.
+ *
+ * (1)  If it's a timed texture, indicate first motif in list as that
+ *              which defines the set of times (tset).
+ *              Similarly, if texture is ornamented or decorated, point to first
+ *              motif as that to BE ornamented or decorated (tset).
+ * (2)  If the texture restricted to HF(s) or HS(s), indicate next motif
+ *              as the HF-set (hfldmotif). It may be read in different ways (as HF, as
+ *              HS, or as time-varying of either type) at a later time.
+ * (3)  If texture consists of motifs, or is to use specific ornaments...
+ * (4)  count the number of motifs remaining.
+ * (5)  Set up the array of phrases to point to the appropriate motifs.
+ */
+
+int assign_timeset_hfset_motifsets(dataptr dz)
+{
+    int exit_status;
+    unsigned int texflag = dz->tex->txflag;
+    motifptr here, thismotif = dz->tex->motifhead;
+    int n;
+    dz->tex->phrasecnt = 0;
+    if(texflag & ORN_DEC_OR_TIMED) {
+        if((exit_status = motifchek(thismotif))<0)
+            return(exit_status);
+        dz->tex->timeset = thismotif;                                   /* 1 */
+        thismotif = thismotif->next;
+    }
+    if(texflag & ISHARM) {                                                          /* 2 */
+        if((exit_status = motifchek(thismotif))<0)
+            return(exit_status);
+        dz->tex->hfldmotif = thismotif;
+        thismotif = thismotif->next;
+    }
+    if((texflag & IS_ORNATE) || (texflag & IS_MOTIFS)) {    /* 3 */
+        if((exit_status = motifchek(thismotif))<0)
+            return(exit_status);
+        here = thismotif;
+        while(thismotif!=(motifptr)0) {                                 /* 4 */
+            dz->tex->phrasecnt++;
+            thismotif = thismotif->next;
+        }                                                                                               /* 5 */
+        if((dz->tex->phrase = (motifptr *)malloc(dz->tex->phrasecnt * sizeof(motifptr)))==NULL) {
+            sprintf(errstr,"INSUFFICIENT MEMORY for phrase array.\n");
+            return(MEMORY_ERROR);
+        }
+        thismotif = here;
+        n = -1;
+        while(thismotif!=(motifptr)0) {
+            dz->tex->phrase[++n] = thismotif;
+            thismotif = thismotif->next;
+        }
+    }
+    return(FINISHED);
+}
+
+/***************************** MASSAGE_PARAMS ****************************/
+
+int massage_params(dataptr dz)
+{
+    int exit_status;
+    unsigned int texflag = dz->tex->txflag;
+    convert_cmdline_instrnos_to_internal_representation(dz);
+    if((exit_status = check_max_transpos_compatible_with_splicelen(dz))<0)
+        return(exit_status);
+    if(texflag & IS_CLUMPED) {
+        if((exit_status = set_amptype_params(dz))<0)
+            return(exit_status);
+    }
+    if(texflag & IS_DECOR) {
+        if((exit_status = set_decor_pitchposition_params(dz))<0)
+            return(exit_status);
+    }
+    return(FINISHED);
+}
+
+/************************* INIT_MOTIFS *****************************
+ *
+ * Set up head item of a list of musical-motifs.
+ * Set up location of first note of first motif.
+ */
+
+int init_motifs(dataptr dz)
+{
+    int exit_status;
+    noteptr thisnote;
+    if((dz->tex->motifhead = (motifptr)malloc(sizeof (struct motif)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY to store any motifs.\n");
+        return(MEMORY_ERROR);
+    }
+    dz->tex->motifhead->next  = (motifptr)0;
+    dz->tex->motifhead->last  = (motifptr)0;
+    if((exit_status = init_note(&thisnote))<0)
+        return(exit_status);
+    dz->tex->motifhead->firstnote = thisnote;
+    thisnote->next = (noteptr)0;
+    thisnote->last = (noteptr)0;
+    return(FINISHED);
+}
+
+/******************************** INITPERM *********************************
+ *
+ * Establish storage space for permutation parameters.
+ *
+ * (1)  create pointers to the items within the permuted sets.          Initialise to zero.
+ * (2)  Create storage for current length of each perm.                         Initialise to zero.
+ * (3)  Create storage for previous length of each perm.                        Initialise to -1 (impossible).
+ *              If new perm different length to old, space for permuted elements will need to be re-malloced.
+ * (4)  Create pointers to storage areas for each permuted set.         Initialise to point nowhere.
+ *              These will be malloced when the size of each set-to-permute is known.
+ * (5)  Create storage for previous outputed val in each perm.          Initialise to -1 (impossible).
+ *              This is useful at permutation boundaries, when a particular element may be repeated more
+ *              than permitted no. of times if there's no check. These constants allow no. of repets to be counted.
+ * (6)  Create counter of current no. of consecutive repets of an element in each of the (output) perms.
+ *              Initialise to 0, though this is arbitrary, as repetcnt should always be set on any call of do_perm.
+ * (7)  Create storage for max no. of allowed consecutive repets of an element in each perm-set.
+ *              Initialise to 1, which is the default if no info is given to the contrary.
+ */
+
+int initperm(int ***permm,dataptr dz)
+{
+    int n;
+    if((dz->iparray[TXPERMINDEX] = (int *)malloc(PERMCNT * sizeof(int)))==NULL) {   /* 1 */
+        sprintf(errstr,"INSUFFICIENT MEMORY for permutation indeces.\n");
+        return(MEMORY_ERROR);
+    }
+    for(n=0;n<PERMCNT;n++)
+        dz->iparray[TXPERMINDEX][n] = 0;
+
+    if((dz->iparray[TXPERMLEN] = (int *)malloc(PERMCNT * sizeof(int)))==NULL) {   /* 2 */
+        sprintf(errstr,"INSUFFICIENT MEMORY for permutation lengths.\n");
+        return(MEMORY_ERROR);
+    }
+    for(n=0;n<PERMCNT;n++)
+        dz->iparray[TXPERMLEN][n] = 0;
+
+    if((dz->iparray[TXLASTPERMLEN] = (int *)malloc(PERMCNT * sizeof(int)))==NULL) {   /* 3 */
+        sprintf(errstr,"INSUFFICIENT MEMORY for last permutation lengths.\n");
+        return(MEMORY_ERROR);
+    }
+    for(n=0;n<PERMCNT;n++)
+        dz->iparray[TXLASTPERMLEN][n] = -1;
+
+    if((*permm = (int **)malloc(PERMCNT * sizeof(int *)))==NULL) {   /* 4 */
+        sprintf(errstr,"INSUFFICIENT MEMORY for permutations.\n");
+        return(MEMORY_ERROR);
+    }
+
+    for(n=0;n<PERMCNT;n++)
+        (*permm)[n] = (int *)0;
+
+    if((dz->iparray[TXLASTPERMVAL] = (int *)malloc(PERMCNT * sizeof(int)))==NULL) {   /* 5 */
+        sprintf(errstr,"INSUFFICIENT MEMORY for last permutation values.\n");
+        return(MEMORY_ERROR);
+    }
+    for(n=0;n<PERMCNT;n++)
+        dz->iparray[TXLASTPERMVAL][n] = -1;
+
+    if((dz->iparray[TXREPETCNT] = (int *)malloc(PERMCNT * sizeof(int)))==NULL) {   /* 6 */
+        sprintf(errstr,"INSUFFICIENT MEMORY for permutation repetition counts.\n");
+        return(MEMORY_ERROR);
+    }
+    for(n=0;n<PERMCNT;n++)
+        dz->iparray[TXREPETCNT][n] = 1;
+
+    if((dz->iparray[TXRPT] = (int *)malloc(PERMCNT * sizeof(int)))==NULL) {   /* 7 */
+        sprintf(errstr,"INSUFFICIENT MEMORY for permutation repetitions.\n");
+        return(MEMORY_ERROR);
+    }
+    /* THESE ARE THE DEFAULT NUMBER OF REPETITIONS-OF-AN-ENTITY ALLOWED IN A PERM */
+    dz->iparray[TXRPT][PM_SPACE]  = SPACE_REPETS;
+    dz->iparray[TXRPT][PM_PITCH]  = PITCH_REPETS;
+    dz->iparray[TXRPT][PM_AMP]    = AMP_REPETS;
+    dz->iparray[TXRPT][PM_DUR]    = DUR_REPETS;
+    dz->iparray[TXRPT][PM_INSNO]  = INSNO_REPETS;
+    dz->iparray[TXRPT][PM_GPRANG] = GPRANG_REPETS;
+    dz->iparray[TXRPT][PM_GPSIZE] = GPSIZE_REPETS;
+    dz->iparray[TXRPT][PM_GPDENS] = GPDENS_REPETS;
+    dz->iparray[TXRPT][PM_GPCNTR] = GPCNTR_REPETS;
+    dz->iparray[TXRPT][PM_GPPICH] = GPPICH_REPETS;
+    dz->iparray[TXRPT][PM_ORNPOS] = ORNPOS_REPETS;
+    dz->iparray[TXRPT][PM_GPSPAC] = GPSPAC_REPETS;
+    dz->iparray[TXRPT][PM_ORIENT] = ORIENT_REPETS;
+    dz->iparray[TXRPT][PM_DECABV] = DECABV_REPETS;
+    dz->iparray[TXRPT][PM_MULT]   = MULT_REPETS;
+    dz->iparray[TXRPT][PM_WHICH]  = WHICH_REPETS;
+    dz->iparray[TXRPT][PM_GPPICH2]= GPPICH2_REPETS;
+    return(FINISHED);
+}

+ 223 - 0
dev/texture/prevsrc/prev-src/texture1.c

@@ -0,0 +1,223 @@
+/*
+ * Copyright (c) 1983-2013 Trevor Wishart and Composers Desktop Project Ltd
+ * http://www.trevorwishart.co.uk
+ * http://www.composersdesktop.com
+ *
+ This file is part of the CDP System.
+
+ The CDP System is free software; you can redistribute it
+ and/or modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The CDP System is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the CDP System; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA
+ *
+ */
+
+
+
+/* floatsam version: no changes */
+#include <stdio.h>
+#include <stdlib.h>
+#include <structures.h>
+#include <tkglobals.h>
+#include <globcon.h>
+#include <processno.h>
+#include <modeno.h>
+#include <arrays.h>
+#include <texture.h>
+#include <cdpmain.h>
+
+#include <sfsys.h>
+
+/********************* GETTING DATA VALUES VIA RAND PERMUTATIONS *************/
+
+
+
+static int  delete_all_other_motifs(motifptr thismotif,dataptr dz);
+static int  delete_motifs_before(motifptr thismotif,dataptr dz);
+static int  delete_motifs_beyond(motifptr thismotif);
+
+/***************************** TEXTURE 1 ********************************
+ * (1)  Generating random permutations of sets of values, and delivering
+ *              the next value from one of these.
+ * (2)  Scattering values within a range.
+ */
+
+/*************************** MAKE_TEXTURE *********************************/
+
+int make_texture(dataptr dz)
+{
+    int exit_status;
+    unsigned int texflag = dz->tex->txflag;
+    display_virtual_time(0,dz);
+    if(texflag & ISHARM) {
+        if(texflag & IS_CLUMPED) {
+            if((exit_status = do_clumped_hftexture(dz))<0)
+                return(exit_status);
+        } else {
+            if((exit_status = do_simple_hftexture(dz))<0)
+                return(exit_status);
+        }
+    } else {
+        if((exit_status = do_texture(dz))<0)
+            return(exit_status);
+    }
+    if((exit_status = delete_all_other_motifs(dz->tex->timeset,dz))<0)
+        return(exit_status);
+    return(FINISHED);
+}
+
+/****************************** GETVALUE **********************************
+ *
+ * Get value of a parameter, either from table, or fixed value.
+ */
+
+int getvalue(int paramhi,int paramlo,double thistime,int z,double *val,dataptr dz)
+{
+    int exit_status;
+    double range;
+    int is_swap = 0;
+    if(dz->is_int[paramhi] || dz->is_int[paramlo]) {
+        sprintf(errstr,"getvalue() called on integer parameter %d or %d\n",paramhi,paramlo);
+        return(PROGRAM_ERROR);
+    }
+    if(dz->brk[paramhi]) {
+        if((exit_status = read_value_from_brktable(thistime,paramhi,dz))<0)
+            return(exit_status);
+    }
+    if(dz->brk[paramlo]) {
+        if((exit_status = read_value_from_brktable(thistime,paramlo,dz))<0)
+            return(exit_status);
+    }
+    if((range = dz->param[paramhi] - dz->param[paramlo])<0.0) {
+        swap(&dz->param[paramhi],&dz->param[paramlo]);
+        range = -range;
+        is_swap = 1;
+    }
+    if(flteq(range,0.0)) {
+        *val = dz->param[paramhi];
+        if(is_swap)
+            swap(&dz->param[paramhi],&dz->param[paramlo]);
+        return(FINISHED);
+    }
+    if((exit_status = pscatx(range,dz->param[paramlo],z,val,dz))<0)
+        return(exit_status);
+    if(is_swap)
+        swap(&dz->param[paramhi],&dz->param[paramlo]);
+    return(FINISHED);
+}
+
+/****************************** IGETVALUE **********************************
+ *
+ * Get integer value of a parameter, either from table, or fixed value.
+ */
+
+int igetvalue(int paramhi,int paramlo,double thistime,int z,int *ival,dataptr dz)
+{
+    int   exit_status;
+    int  irange;
+    int   a, is_swap = 0;
+
+    if(!dz->is_int[paramhi] || !dz->is_int[paramlo]) {
+        sprintf(errstr,"igetvalue() called on non-integer parameter %d or %d\n",paramhi,paramlo);
+        return(PROGRAM_ERROR);
+    }
+    if(dz->brk[paramhi]) {
+        if((exit_status = read_value_from_brktable(thistime,paramhi,dz))<0)
+            return(exit_status);
+    }
+    if(dz->brk[paramlo]) {
+        if((exit_status = read_value_from_brktable(thistime,paramlo,dz))<0)
+            return(exit_status);
+    }
+
+    if((irange = dz->iparam[paramhi] - dz->iparam[paramlo])<0) {
+        iiswap(&dz->iparam[paramhi],&dz->iparam[paramlo]);
+        irange = -irange;
+        is_swap = 1;
+    }
+    if(irange==0) {
+        *ival = (int)dz->iparam[paramlo];
+        if(is_swap)
+            iiswap(&dz->iparam[paramhi],&dz->iparam[paramlo]);
+        return(FINISHED);
+        /* OCT 1997 replace ****
+           } else if((exit_status = doperm(irange,z,&a,dz))<0)
+        */
+        /* BY */
+    } else if((exit_status = doperm(irange+1,z,&a,dz))<0)
+        /* because the range of an integer variable between(say) 3 & 7 is INCLUSIVELY 5, not 7-3) */
+        return(exit_status);
+    a = (int)(a + dz->iparam[paramlo]);
+    *ival = a;
+    if(is_swap)
+        iiswap(&dz->iparam[paramhi],&dz->iparam[paramlo]);
+    return(FINISHED);
+}
+
+/*************************** DELETE_ALL_OTHER_MOTIFS **********************************
+ *
+ * Deletes all other motifs in motif list.
+ */
+
+int delete_all_other_motifs(motifptr thismotif,dataptr dz)
+{
+    int exit_status;
+    motifptr here = thismotif->next;
+    if((exit_status = delete_motifs_before(thismotif,dz))<0)
+        return(exit_status);
+    if(here!=(motifptr)0) {
+        if((exit_status = delete_motifs_beyond(here))<0)
+            return(exit_status);
+    }
+    dz->tex->motifhead = thismotif;
+    return(exit_status);
+}
+
+/********************** DELETE_MOTIFS_BEYOND ******************************
+ *
+ * Deletes motif-space from this space onwards.
+ */
+
+int delete_motifs_beyond(motifptr thismotif)
+{
+    motifptr start = thismotif;
+    while(thismotif->next!=(motifptr)0)
+        thismotif = thismotif->next;
+    while(thismotif!=start) {
+        thismotif = thismotif->last;
+        free(thismotif->next);
+    }
+    thismotif->next = (motifptr)0;
+    return(FINISHED);
+}
+
+/*********************** DELETE_MOTIFS_BEFORE ***************************
+ *
+ * Kill all motifs BEFORE this one in the motif list.
+ */
+
+int delete_motifs_before(motifptr thismotif,dataptr dz)
+{
+    motifptr here = dz->tex->motifhead;
+    while(here!=thismotif) {
+        if((here = here->next)==(motifptr)0) {
+            sprintf(errstr,"Problem in delete_motifs_before()\n");
+            return(PROGRAM_ERROR);
+        }
+        delete_notes_here_and_beyond(here->last->firstnote);
+        free(here->last);
+        here->last = (motifptr)0;
+    }
+    dz->tex->motifhead = thismotif;
+    return(FINISHED);
+}

+ 520 - 0
dev/texture/prevsrc/prev-src/texture2.c

@@ -0,0 +1,520 @@
+/*
+ * Copyright (c) 1983-2013 Trevor Wishart and Composers Desktop Project Ltd
+ * http://www.trevorwishart.co.uk
+ * http://www.composersdesktop.com
+ *
+ This file is part of the CDP System.
+
+ The CDP System is free software; you can redistribute it
+ and/or modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The CDP System is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the CDP System; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA
+ *
+ */
+
+
+
+/* floatsam version: no changes */
+#include <stdio.h>
+#include <stdlib.h>
+#include <structures.h>
+#include <tkglobals.h>
+#include <globcon.h>
+#include <processno.h>
+#include <modeno.h>
+#include <arrays.h>
+#include <texture.h>
+#include <cdpmain.h>
+#include <sfsys.h>
+#include <osbind.h>
+
+/***************************** GENERATING TEXTURES WITH NO HFIELD(S) ******************************/
+
+static int  setup_motif_params
+(noteptr phrasenote,double tsettime,double *thisamp,double ampstep,double *phraseamp,
+ int phrno,double rangemult,noteptr thisnote,noteptr tsetnote,
+ double multiplier,double timeadjust,dataptr dz);
+static void gen_orn_pitch(noteptr thisnote,noteptr tsetnote,noteptr phrasenote,
+                          float phrlpitch,float phrfirstpitch,dataptr dz);
+static void gen_mtf_pitch(noteptr thisnote,noteptr tsetnote,noteptr phrasenote,float phrfirstpitch);
+static int  dec_centre(double tsetpitch,float *val,int gpsize,double gprlow,double gprange,dataptr dz);
+static int  pscat(double range,double bottom,int pindex,double *val,dataptr dz);
+static int  initialise_phrases
+(int **phrnotecnt,double **phraseamp,double **phrange,noteptr **phrlastnote,dataptr dz);
+static int  do_ev_pch
+(double *thispitch,double thistime,double *pptop,double *ppbot,dataptr dz);
+static int  get_gpparams
+(double thistime,double thispitch,unsigned char dectypecnt,double *gprange,double *gprlow,int *gpsize,
+ double *gpdense,double pptop,double ppbot,unsigned char dectypestor,int mingrpsize,dataptr dz);
+static int orientrange
+(double thispitch,double pptop, double ppbot,double *gprange, double *gprlow,
+ unsigned char dectypestor,unsigned char dectypecnt,dataptr dz);
+static void squeezrange(double thispitch,double *gprange,double *gprlow, double pptop, double ppbot);
+
+/**************************** DO_TEXTURE *****************************/
+
+int do_texture(dataptr dz)
+{
+    int exit_status;
+    noteptr tsetnote = dz->tex->timeset->firstnote;
+    unsigned int texflag     = dz->tex->txflag;
+    unsigned char dectypestor = dz->tex->dectypstor;
+    unsigned char dectypecnt  = dz->tex->dectypcnt;
+    unsigned char amptypestor = dz->tex->amptypstor;
+    unsigned char amptypecnt  = dz->tex->amptypcnt;
+    int ampdirected           = dz->tex->ampdirectd;
+    motifptr tset                     = dz->tex->timeset;
+    motifptr *phrase                  = dz->tex->phrase;
+    int phrcount                      = dz->tex->phrasecnt;
+    int *phrnotecnt=NULL;
+    double *phraseamp=NULL, *phrange=NULL;
+    noteptr thisnote=NULL, nextnote=NULL, phrasenote=NULL, nextevent=NULL, *phrlastnote=NULL, *shadow=NULL;
+    float phrlpitch=0.0, phrfirstpitch=0.0;
+    unsigned char thisinstr, amptype=0;
+    double  tsettime=0.0, thistime=0.0, thispitch=0.0, ampstep=0.0, thepitch=0.0, thisamp=0.0, thisdur=0.0;
+    double  rangemult=0.0, gpdense=0.0, gprange=0.0, gprlow=0.0, multiplier=0.0;
+    double timeadjust = 0.0; /* default */
+    int phrno=0, n=0, shadowsize=0, gpsize=0, mingrpsize = 0;
+    double pptop=0.0, ppbot=0.0;
+    int shadindex = 0;
+
+    dz->iparam[SPINIT] = 0;
+    if(texflag & IS_CLUMPED) {
+        if((dz->tex->phrasecnt > 0)
+           && (exit_status = initialise_phrases(&phrnotecnt,&phraseamp,&phrange,&phrlastnote,dz))<0)
+            return(exit_status);
+
+        if(texflag & IS_GROUPS)
+            mingrpsize = 1;
+
+        if((exit_status= make_shadow(tset,&shadowsize,&shadow))<0)
+            return(exit_status);
+
+        if(texflag & IS_DECOR) {
+            setup_decor(&pptop,&ppbot,&shadindex,&tsetnote,dz);
+        } else if(texflag & IS_MOTIFS)  {
+            if((exit_status = set_motifs(phrcount,phrase,phrnotecnt,phraseamp,phrange,phrlastnote))<0)
+                return(exit_status);
+        } else if(texflag & IS_ORNATE) {
+            if((exit_status = set_motifs(phrcount,phrase,phrnotecnt,phraseamp,phrange,phrlastnote))<0)
+                return(exit_status);
+            if(dz->vflag[WHICH_CHORDNOTE]==DECOR_HIGHEST)
+                tsetnote = gethipitch(tsetnote,&shadindex);
+        }
+    }
+
+    while(tsetnote!=(noteptr)0) {
+        tsettime  = (double)tsetnote->ntime;
+        thistime  = tsettime;
+        if((exit_status = read_values_from_all_existing_brktables(thistime,dz))<0)
+            return(exit_status);
+        if(texflag & IS_DECOR)
+            thispitch = tsetnote->pitch;
+        if(texflag & IS_ORN_OR_MTF) {
+            if((exit_status =
+                setup_motif_or_ornament(thistime,&multiplier,&phrno,&phrasenote,phrase,dz))<0)
+                return(exit_status);
+        }
+        if(!(texflag & IS_ORN_OR_DEC)) {
+            if((exit_status = do_ev_pch(&thispitch,thistime,&pptop,&ppbot,dz))<0)
+                return(exit_status);
+            tsetnote->pitch = (float)thispitch;
+        }
+        if((exit_status = do_amp_instr_dur(&thisamp,&thisinstr,&thisdur,tsetnote,thistime,dz))<0)
+            return(exit_status);
+        if(texflag & IS_CLUMPED) {
+            if(texflag & IS_MOTIFS) {
+                if((exit_status = getmtfdur(tsetnote,phrasenote,&thisdur,multiplier,dz))<0)
+                    return(exit_status);
+                tsetnote->dur = (float)thisdur;
+            }
+            if(texflag & IS_ORN_OR_MTF) {
+                gpsize = phrnotecnt[phrno];
+                phrfirstpitch = phrasenote->pitch;
+            } else {
+                if((exit_status = get_gpparams(thistime,thispitch,dectypecnt,
+                                               &gprange,&gprlow,&gpsize,&gpdense,pptop,ppbot,dectypestor,mingrpsize,dz))<0)
+                    return(exit_status);
+            }
+            if(texflag & IS_DECOR) {
+                if((exit_status = position_and_size_decoration(&thistime,tsettime,gpdense,&gpsize,dz))<0)
+                    return(exit_status);
+            } else
+                gpsize--;
+            if(texflag & IS_ORNATE) {
+                phrlpitch = (phrlastnote[phrno])->pitch;
+                if((exit_status = setup_ornament
+                    (&timeadjust,&thistime,&gpsize,phrlastnote,multiplier,&phrasenote,phrno,dz))<0)
+                    return(exit_status);
+            }
+            if(!(texflag & IS_DECOR))
+                nextnote = tsetnote->next;
+            if(gpsize>0) {                                          /* 3b */
+                if(texflag & IS_ORN_OR_MTF) {
+                    if((exit_status = orn_or_mtf_amp_setup
+                        (ampdirected,phrange,phrno,thisamp,gpsize,&rangemult,&ampstep,&amptype,amptypestor,amptypecnt,dz))<0)
+                        return(exit_status);
+                }
+                if(texflag & IS_MOTIFS) {
+                    if((exit_status = set_motif_amp
+                        (tsetnote,&thisamp,gpsize,ampstep,phrasenote,rangemult,phraseamp,phrno,amptype))<0)
+                        return(exit_status);
+                } else if(texflag & IS_ORNATE) {
+                    if((exit_status = set_ornament_amp
+                        (phraseamp,phrlastnote,&thisamp,phrasenote,phrno,tsetnote,ampstep,rangemult,gpsize,dz))<0)
+                        return(exit_status);
+                } else if(texflag & IS_GROUPS) {
+                    if((exit_status = set_group_amp
+                        (tsetnote,&thisamp,&amptype,&ampstep,gpsize,amptypecnt,amptypestor,dz))<0)
+                        return(exit_status);
+                } else if(texflag & IS_DECOR) {
+                    if((exit_status = set_decor_amp
+                        (ampdirected,&thisamp,&ampstep,gpsize,&amptype,amptypecnt,amptypestor,dz))<0)
+                        return(exit_status);
+                }
+                if(dz->iparam[TEX_GPSPACE]!=IS_STILL) {
+                    if((exit_status = init_group_spatialisation(tsetnote,shadindex,shadow,shadowsize,dz))<0)
+                        return(exit_status);
+                }
+                thisnote  = tsetnote;
+                if(texflag & IS_DECOR)
+                    nextnote = tsetnote->next;
+                else if(texflag & IS_ORNATE) {
+                    if(!dz->vflag[IS_PRE])
+                        phrasenote = phrasenote->next;
+                }
+                if(texflag & IS_ORN_OR_DEC)
+                    nextevent = getnextevent_to_decorate(tsetnote,&shadindex,dz);
+                for(n=0;n<gpsize;n++) {
+                    if((exit_status = make_new_note(&thisnote))<0)
+                        return(exit_status);
+                    if(texflag & IS_DEC_OR_GRP) {
+                        if((exit_status = set_group_params
+                            (tsetnote,thisnote,gpdense,ampstep,&thisamp,&thistime,thisdur,dz))<0)
+                            return(exit_status);
+                        if((exit_status = do_grp_ins(tsetnote->instr,&(thisnote->instr),dz))<0)
+                            return(exit_status);
+                        thisnote->motioncentre = tsetnote->motioncentre;
+                        if(texflag & IS_DECOR) {
+                            if((exit_status = dec_centre
+                                (thispitch,&(thisnote->pitch),gpsize,gprlow,gprange,dz))<0)
+                                return(exit_status);
+                        } else {
+                            if((exit_status = pscat(gprange,gprlow,PM_GPPICH,&thepitch,dz))<0)
+                                return(exit_status);
+                            thisnote->pitch = (float)thepitch;
+                        }
+                        thisnote->ntime  = (float)thistime;
+                    } else {
+                        if((exit_status = check_next_phrasenote_exists(&phrasenote,texflag,dz))<0)
+                            return(exit_status);
+                        if((exit_status = setup_motif_params(phrasenote,thistime,&thisamp,ampstep,phraseamp,phrno,
+                                                             rangemult,thisnote,tsetnote,multiplier,timeadjust,dz))<0)
+                            return(exit_status);
+                        if(texflag & IS_MOTIFS) {
+                            gen_mtf_pitch(thisnote,tsetnote,phrasenote,phrfirstpitch);
+                        } else {
+                            gen_orn_pitch(thisnote,tsetnote,phrasenote,phrlpitch,phrfirstpitch,dz);
+                            phrasenote = phrasenote->next;
+                        }
+                    }
+                    if((exit_status = setspace(tsetnote,thisnote,gpsize,dz))<0)
+                        return(exit_status);
+                }
+                thisnote->next = nextnote;
+                if(nextnote!=(noteptr)0)
+                    nextnote->last = thisnote;
+                if(texflag & IS_ORN_OR_DEC)
+                    tsetnote = nextevent;
+
+            } else if(texflag & IS_ORN_OR_DEC)
+                tsetnote = getnextevent_to_decorate(tsetnote,&shadindex,dz);
+
+        } else
+            tsetnote = tsetnote->next;
+
+        if(texflag & IS_MTF_OR_GRP) {
+            tsetnote = nextnote;
+            shadindex++;
+        }
+    }
+    if((texflag & IS_DECOR) && dz->vflag[DISCARD_ORIGLINE]) {
+        if((exit_status = erase_shadow(shadowsize,shadow,tset))<0)
+            return(exit_status);
+    }
+    if(texflag & IS_CLUMPED)
+        return arrange_notes_in_timeorder(tset);
+    return(FINISHED);
+}
+
+/**************************** SETUP_MOTIF_PARAMS ****************************/
+
+int setup_motif_params
+(noteptr phrasenote,double tsettime,double *thisamp,double ampstep,double *phraseamp, int phrno,
+ double rangemult,noteptr thisnote,noteptr tsetnote,double multiplier,double timeadjust,dataptr dz)
+{
+    double notetime, ampdif;
+    notetime = getnotetime(phrasenote,tsettime,multiplier,timeadjust,dz);
+    *thisamp  += ampstep;
+    ampdif    =(phraseamp[phrno] - phrasenote->amp)*rangemult;/* e */
+    return do_mtf_params(thisnote,*thisamp,phrasenote,tsetnote,ampdif,notetime,multiplier,dz);
+}
+
+/**************************** GEN_ORN_PITCH ****************************/
+
+void gen_orn_pitch
+(noteptr thisnote,noteptr tsetnote,noteptr phrasenote,float phrlpitch,float phrfirstpitch,dataptr dz)
+{
+    if(dz->vflag[IS_PRE])
+        thisnote->pitch = (float)(tsetnote->pitch + phrasenote->pitch - phrlpitch);
+    else
+        thisnote->pitch = (float)(tsetnote->pitch + phrasenote->pitch - phrfirstpitch);
+}
+
+/**************************** GEN_MTF_PITCH ****************************/
+
+void gen_mtf_pitch(noteptr thisnote,noteptr tsetnote,noteptr phrasenote,float phrfirstpitch)
+{
+    thisnote->pitch = (float)(tsetnote->pitch + phrasenote->pitch - phrfirstpitch);
+    thisnote->pitch = (float)octadjust((double)thisnote->pitch);
+}
+
+/************************* DEC_CENTRE ******************************
+ *
+ * Centre a decoration on the decorated pitch.
+ *
+ * (1)  For groupsize 1 or 2, k=1
+ *              For groupsize 3 or 4, k=2
+ *              For groupsize 5 or 6, k=3 etc
+ * (2)  Scatter pitches as normally.
+ * (3)  If range is NOT one-sided, proceed..otherwise return in normal way.
+ * (4)  Find ratio of upper half of range to lower.
+ * (5)  Find distance from decorated note.
+ * (6)  Save the current value of allowed repetitions.
+ *              THese are number of times a note occurs above the decorated pitch,
+ *              before it can do so again (same for below).
+ * (7)  If the allowed repetitions are bigger than k, replace it by k.
+ *              This means that if we allow 3 repetitions but there are only
+ *              1,2,3 or 4 notes, we force, 1 repetition for 2 notes, 2 repetitions
+ *              for 3 or 4 notes etc. but allow 3 repetitions for 5,6 etc notes.
+ * (8)  Select above or below decorated pitch.
+ * (9)  If meant to be above note, but is below it, put note in other
+ *              half of range, with appropriate adjustment for relative sizes
+ *              of half-ranges.
+ * (10) If meant to be below note, but is above it, put note in other
+ *              half of range, with appropriate adjustment for relative sizes
+ *              of half-ranges.
+ * (11) Restore the repetcnt value!!
+ */
+
+int dec_centre(double tsetpitch,float *val,int gpsize,double gprlow,double gprange,dataptr dz)
+{
+    int exit_status;
+    double a, q, w, gprhi = gprlow + gprange, ulratio;
+    int s, save, k = (gpsize+1)/2;                                                          /* 1 */
+    if((exit_status = pscat(gprange,gprlow,PM_GPPICH,&a,dz))<0) /* 2 */
+        return(exit_status);
+    if((w=tsetpitch-gprlow)>FLTERR && !flteq(tsetpitch,gprhi)) {/* 3 */
+        ulratio = (gprhi-tsetpitch)/w;                                                  /* 4 */
+        q       = a-tsetpitch;                                                                  /* 5 */
+        save    = dz->iparray[TXREPETCNT][PM_DECABV];                   /* 6 */
+        if(dz->iparray[TXREPETCNT][PM_DECABV]>k)                                /* 7 */
+            dz->iparray[TXREPETCNT][PM_DECABV] = k;
+        if((exit_status = doperm((int)2,PM_DECABV,&s,dz))<0)                    /* 8 */
+            return(exit_status);
+        if(s && q<0.0)                                                                                  /* 9 */
+            a = tsetpitch - (q*ulratio);
+        if(!s && q>0.0)                                                                                 /* 10 */
+            a = tsetpitch - (q/ulratio);
+        dz->iparray[TXREPETCNT][PM_DECABV] = save;                              /* 11 */
+        if(a<MIDIBOT || a>MIDITOP) {
+            sprintf(errstr,"TEXTURE: Problem in dec_centre()\n");
+            return(PROGRAM_ERROR);
+        }
+    }
+    *val = (float)a;
+    return(FINISHED);
+}
+
+/***************************** PSCAT ************************************
+ *
+ * A weighted version of pscatx().
+ *
+ * Select a random value within 'range', by permuting one of BANDCNT UNequal
+ * ranges, and selecting a random value within the chosen range. The upper
+ * and lower band are half as wide as the inner 3 bands, ensuring that
+ * values within these outer bands are squeezed into a narrow-range-of-values
+ * near the boundaries of the total range.
+ */
+
+int pscat(double range,double bottom,int pindex,double *val,dataptr dz)
+{
+    int exit_status;
+    double bandbottom, bandwidth, x;
+    int k;
+    if((exit_status = doperm((int)BANDCNT,pindex,&k,dz))<0)
+        return(exit_status);
+    bandwidth = range/(double)LAYERCNT;
+    switch(k) {
+    case(0):
+        bandbottom = 0.0;
+        break;
+    case(BANDCNT-1):
+        bandbottom = (LAYERCNT-1) * bandwidth;
+        break;
+    default:
+        bandbottom = bandwidth + ((double)((k-1) * 2) * bandwidth);
+        bandwidth *= 2.0;
+        break;
+    }
+    x  = (drand48() * bandwidth);
+    x += bandbottom;
+    *val = x + bottom;
+    return(FINISHED);
+}
+
+/**************************** INITIALISE_PHRASES *******************************/
+
+int initialise_phrases(int **phrnotecnt,double **phraseamp,double **phrange,noteptr **phrlastnote,dataptr dz)
+{
+    if((*phrnotecnt = (int *)malloc(dz->tex->phrasecnt * sizeof(int)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY for phrase notecnt array.\n");
+        return(MEMORY_ERROR);
+    }
+    if((*phraseamp = (double *)malloc(dz->tex->phrasecnt * sizeof(double)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY for phrase amplitude array.\n");
+        return(MEMORY_ERROR);
+    }
+    if((*phrange = (double *)malloc(dz->tex->phrasecnt * sizeof(double)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY for phrase range array.\n");
+        return(MEMORY_ERROR);
+    }
+    if((*phrlastnote = (noteptr *)malloc(dz->tex->phrasecnt * sizeof(noteptr)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY for phrase lastnote array.\n");
+        return(MEMORY_ERROR);
+    }
+    return(FINISHED);
+}
+
+/********************** DO_EV_PCH *******************************
+ *
+ * Set pitch of event (not group etc.).
+ */
+
+int do_ev_pch
+(double *thispitch,double thistime,double *pptop,double *ppbot,dataptr dz)
+{
+    int exit_status;
+    if((exit_status = getvalue(TEXTURE_MAXPICH,TEXTURE_MINPICH,thistime,PM_PITCH,thispitch,dz))<0)
+        return(exit_status);
+    if(*thispitch > MIDITOP || *thispitch < MIDIBOT) {
+        sprintf(errstr,"TEXTURE: pitch [%.1f] out of midirange at time %.2f\n",*thispitch,thistime);
+        return(DATA_ERROR);
+    }
+    *pptop = dz->param[TEXTURE_MAXPICH];
+    *ppbot = dz->param[TEXTURE_MINPICH];
+    return(FINISHED);
+}
+
+/************************** GET_GPPARMAS **************************
+ *
+ * Get the parameters for a group of notes.
+ *
+ * (1)  Get gprange in normal way.
+ * (2)  Don't adjust range.
+ * (3)  For decorations, the range may be oriented, above, below
+ *              or centred on the initial note. So range is adjusted here.
+ */
+
+int get_gpparams(double thistime,double thispitch,unsigned char dectypecnt,
+                 double *gprange,double *gprlow,int *gpsize,double *gpdense,double pptop,double ppbot,
+                 unsigned char dectypestor,int mingrpsize,dataptr dz)
+{
+    int exit_status;
+    if((exit_status = getvalue(TEX_GPRANGHI,TEX_GPRANGLO,thistime,PM_GPRANG,gprange,dz))<0)
+        return(exit_status);                                                                                            /* 1 */
+    if(!dectypecnt)
+        squeezrange(thispitch,gprange,gprlow,pptop,ppbot);
+    else {
+        if((exit_status = orientrange
+            (thispitch,pptop,ppbot,gprange,gprlow,dectypestor,dectypecnt,dz))<0)/* 3 */
+            return(exit_status);
+    }
+    if((exit_status = igetvalue(TEX_GPSIZEHI,TEX_GPSIZELO,thistime,PM_GPSIZE,gpsize,dz))<0)
+        return(PROGRAM_ERROR);
+
+    if(*gpsize < mingrpsize) {
+        sprintf(errstr,"Impossible GROUP SIZE value [%d]\n",*gpsize);
+        return(PROGRAM_ERROR);
+    }
+    return get_density_val(thistime,gpdense,dz);
+}
+
+/***************************  ORIENTRANGE ******************************
+ *
+ */
+
+int orientrange
+(double thispitch,double pptop, double ppbot,double *gprange, double *gprlow,
+ unsigned char dectypestor,unsigned char dectypecnt,dataptr dz)
+{
+    int exit_status;
+    unsigned char dectype;
+    double top;
+    int k;
+    if((exit_status = doperm((int)dectypecnt,PM_ORIENT,&k,dz))<0)
+        return(exit_status);
+    if((exit_status = gettritype(k,dectypestor,&dectype))<0)
+        return(exit_status);
+    switch(dectype) {
+    case(0):                        /* centred range */
+        squeezrange(thispitch,gprange,gprlow,pptop,ppbot);
+        dz->vflag[DECCENTRE] = TRUE;
+        break;
+    case(1):                        /* range above note */
+        top      = min((thispitch + *gprange),pptop);
+        *gprlow  = max((top - *gprange),ppbot);
+        *gprange = top - *gprlow;
+        dz->vflag[DECCENTRE] = FALSE;
+        break;
+    case(2):                        /* range below note */
+        top      = thispitch;
+        *gprlow  = max((top - *gprange),ppbot);
+        *gprange = top - *gprlow;
+        dz->vflag[DECCENTRE] = FALSE;
+        break;
+    default:
+        sprintf(errstr,"TEXTURE: Problem in orientrange()\n");
+        return(PROGRAM_ERROR);
+    }
+    return(FINISHED);
+}
+
+/***************************  SQUEEZRANGE ******************************
+ *
+ * Adjust range to lie within texture limits.
+ *
+ * (2)  Top of range is at current pitch plus half range. If this is
+ *      above current top-of-texture range (pptop) move top down.
+ * (3)  Bottom of range is gprange below top. If this is below
+ *      bottom-of-texture range (ppbot), move gprangelo up.
+ * (4)  Recalculate the true gprange within true limits.
+ */
+
+void squeezrange(double thispitch,double *gprange,double *gprlow, double pptop, double ppbot)
+{
+    double top;
+    top     = min((thispitch + (*gprange/2.0)),pptop);              /* 2 */
+    *gprlow  = max((top-*gprange),ppbot);                                   /* 3 */
+    *gprange = top - *gprlow;                                                               /* 4 */
+}

+ 2362 - 0
dev/texture/prevsrc/prev-src/texture3.c

@@ -0,0 +1,2362 @@
+/*
+ * Copyright (c) 1983-2013 Trevor Wishart and Composers Desktop Project Ltd
+ * http://www.trevorwishart.co.uk
+ * http://www.composersdesktop.com
+ *
+ This file is part of the CDP System.
+
+ The CDP System is free software; you can redistribute it
+ and/or modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The CDP System is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the CDP System; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA
+ *
+ */
+
+
+
+/* floatsam version: no changes */
+#include <stdio.h>
+#include <stdlib.h>
+#include <float.h>
+#include <structures.h>
+#include <tkglobals.h>
+#include <globcon.h>
+#include <processno.h>
+#include <modeno.h>
+#include <arrays.h>
+#include <texture.h>
+#include <cdpmain.h>
+
+#include <sfsys.h>
+#include <osbind.h>
+
+#if defined unix || defined __GNUC__
+#define round(x) lround((x))
+#endif
+
+#define CHARBITSIZE (8)         /* number of bits in a char                  */
+
+struct ffit {                           /* Structure for FIT of motif to HS  */
+    float transpose;
+    float fit;
+    struct ffit *next;
+    struct ffit *last;
+};
+
+typedef struct ffit *fitptr;
+
+/***************************** GENERATING TEXTURES WITH HFIELD(S) ******************************/
+/* RWD Feb 2014: now in sfsys,h, differently! */
+#ifdef MAXINT
+# undef MAXINT
+#endif
+#define MAXINT (2147483647)
+
+static int set_hfmotifs(double *hs,motifptr *phrase,int *phrnotecnt,double *phraseamp,
+                        double *phrange, noteptr *phrlastnote,int *endhsindex,int **hfphrase,
+                        int hsnotecnt,fitptr fithead,double **notestor,dataptr dz);
+static int gethfphrase
+(double *hs,double **notestor,int z,double lopitch,double hipitch,int **hfphrase,
+ int hsnotecnt,int *phrnotecnt,motifptr *phrase,fitptr fithead);
+static int shrink_to_hs
+(int z,int hsnotecnt,double hipitch,double lopitch,double hstop,double hsbot,
+ double *hs, int *hfphrase,motifptr *phrase,int *phrnotecnt);
+static int findhfphrase
+(int z,double *hs,double hstop,int hsnotecnt,double lopitch,
+ double origlo,motifptr *phrase,int **hfphrase,int *phrnotecnt,fitptr fithead,double **notestor);
+static int getmtfindeces
+(double transpose,int z,int hsnotecnt,double *hs,motifptr *phrase,int *phrnotecnt,int **hfphrase);
+static int get_fit(double *notestor,fitptr thisfit,double lopitch,double origlo,int z,
+                   int hsnotecnt,int *phrnotecnt,double *hs,fitptr *newfit);
+static int put_fit(fitptr thisfit,double transval,double fitval,fitptr *newfit);
+static int best_fit(fitptr fithead,double *transpose);
+static void free_fitlist(fitptr fithead);
+static double hfadjust(double thispitch,double *hs,int x1,int x2,int texflag,int hsnotecnt);
+static int convert_pitch_to_nearest_hset_pitch(double thispitch,double *hs,int hsnotecnt);
+static int hfadj2(int hsi,int hfnotecnt,int hsnotecnt);
+static int setup_hfield(noteptr thisnote,double **hs,int *hsnotecnt,double **hf,int *hfnotecnt,int texflag);
+static int get_next_hfield
+(double **hf,double **hs,double inputtime,int *hf_cnt,int *hs_cnt,int *hfnotecnt,
+ noteptr *thishfnote,double *thishftime,double *nexthftime,int hfdatacnt,int *hsnotecnt,
+ noteptr *thishsnote,double *thishstime,double *nexthstime,double *hft,int texflag);
+static int setup_motif_note
+(double thisamp,int thisinstr,double thisdur,noteptr tsetnote,noteptr phrasenote,
+ double *thispitch,double thistime,int *hsindex,int hsnotecnt,double *hs,
+ double *pptop,double *ppbot,int *shadindex,char *shadbits,double multiplier,dataptr dz);
+static int setup_group_note
+(double thisamp,int thisinstr,double thisdur,noteptr tsetnote,
+ double *thispitch,double thistime,int *hsindex,int hsnotecnt,double *hs,
+ double *pptop,double *ppbot,int *shadindex,char *shadbits,dataptr dz);
+static int setup_ornamentation
+(int *starthsi,int *endhsi,noteptr *nextevent,noteptr tsetnote,noteptr *phrasenote,
+ int *shadindex, int *endhsindex,int *hfphrase,int phrno,dataptr dz);
+static int generate_motifin_note_pitch
+(int n,int hsindex,int starthsindex,int hsnotecnt,double thispitch,
+ int *hfphrase,noteptr *thisnote,double *hs,int texflag);
+static int generate_motif_note_pitch
+(noteptr tsetnote,noteptr phrasenote,double phrfirstnote,noteptr thisnote);
+static int generate_ornament_note_pitch
+(int n,double *hs, int hsi, int endhsi,int starthsi,noteptr *thisnote,noteptr *phrasenote,
+ int *hfphrase,int hfnotecnt,int hsnotecnt,dataptr dz);
+static int do_ev_hfpch
+(double thistime,int *hsindex,double *val,
+ int hsnotecnt,double *hs,double *pptop,double *ppbot,dataptr dz);
+static int getp_as_index
+(double thistime,int *val,int hsnotecnt,double *hs,double *pptop,double *ppbot,dataptr dz);
+static int init_shadbits(int shadowsize,int *shshsize,char **shadbits);
+static int geths(noteptr thisnote,double **hs,int *hsnotecnt);
+static int gethf(noteptr thisnote,double **hf,int *hfnotecnt);
+static int gen_hs(double **hf,double **hs, int *hsnotecnt, int hfnotecnt);
+static int chekrepeat(noteptr thisnote,double lastpitch);
+static void set_shadbit(int k,char *shadbits);
+static int      geths_lobnd(double thispitch,double *hs,int hsnotecnt);
+static int      gethfnote(double thispitch,double *hf,int *hfnotecnt);
+static int      setmtfparams
+(noteptr thisnote,double thisamp,noteptr phrasenote,noteptr tsetnote,double ampdif,
+ double notetime,int gpsize,double multiplier,dataptr dz);
+static int      initialise_hfphrases
+(int ***hfphrase,int **endhsindex,int **phrnotecnt,double **phraseamp,double **phrange,
+ noteptr **phrlastnote,dataptr dz);
+static int      readhftimes(noteptr firstnote, int *hfdatacnt,double **hft);
+static int      init_fits(fitptr *thisfit);
+static int      get_hfgpparams(double thistime,double thispitch,double *hs,int hsnotecnt,
+                               int *gpsize,int *hfrange,int *hfgpranglo,int *hfgpranghi,
+                               double *gprange,double *gpdense,int mingrpsize,
+                               double *gprlow, int dectypecnt,unsigned char dectypestor,dataptr dz);
+static int      generate_group_note(noteptr thisnote,noteptr testnote,double thistime,
+                                    int hfrange,int hfgpranglo,double *hs,int *hsindex,int gpsize,dataptr dz);
+static int      generate_decor_note(noteptr thisnote,noteptr tsetnote,
+                                    double thispitch,double thistime,int hfrange,int hfgpranghi,int hfgpranglo,
+                                    double *hs,int *hsindex,int hsnotecnt,double gprlow,double gprange,int gpsize,dataptr dz);
+static void del_ghosts(int shshsize,char *shadbits,noteptr *shadow,int shadowsize,motifptr tset);
+static int  geths_hibnd(double thispitch,int hsnotecnt,double *hs);
+static int  geths_above(double thispitch,double *hs,int hsnotecnt);
+static int  fit_unlink(fitptr thisfit);
+static int  new_fit(fitptr thisfit,fitptr *newfit);
+static int      getnexths(double **hs,double inputtime,int *hs_cnt,int *hsnotecnt,noteptr *thishsnote,
+                          double *thishstime,double *nexthstime,int hfdatacnt,double *hft);
+static int      getnexthf(double **hf,double **hs, int *hsnotecnt,double inputtime,int *hf_cnt,
+                          int *hfnotecnt,noteptr *thishfnote,double *thishftime,double *nexthftime,int hfdatacnt,double *hft);
+static int      hfscat(int prange,int pbottom,int permindex,int *val,dataptr dz);
+static int      gethsnote(double thispitch,double *thishs,int *hsnotecnt);
+static void hfsqueezrange
+(double thispitch,int *hfrange,int *hfgpranghi,int *hfgpranglo,int hsnotecnt,double *hs);
+static int  hforientrange(double thispitch,int *hfrange,int *hfgpranghi,int *hfgpranglo,
+                          int hsnotecnt,double *hs,int dectypecnt,unsigned char dectypestor,dataptr dz);
+static int  dec_hfcentre(double tsetpitch,double *hs,int hsnotecnt,
+                         int hfrange,int hfgpranghi,int hfgpranglo,double gprlow,double gprange,int gpsize,
+                         double *val,dataptr dz);
+static int  hfscatx(int prange,int pbottom,int permindex,int *val,dataptr dz);
+static int  get_first_hs(noteptr thisnote,double **hs,int *hsnotecnt);
+static int  get_first_hf(noteptr thisnote,double **hf,int *hfnotecnt);
+static int  setup_first_hfield
+(noteptr thisnote,double **hs,int *hsnotecnt,double **hf,int *hfnotecnt,int texflag);
+static int octeq(double a,double b);
+
+/**************************** DO_SIMPLE_HFTEXTURE ****************************/
+
+int do_simple_hftexture(dataptr dz)
+{
+    int exit_status;
+    unsigned int texflag     = dz->tex->txflag;
+    motifptr tset                     = dz->tex->timeset;
+    motifptr hfmotif                  = dz->tex->hfldmotif;
+    int hsindex;
+    noteptr tsetnote = tset->firstnote;
+    noteptr nextnote;
+    double thistime, thispitch, lastpitch = -1.0;
+    noteptr thishfnote = hfmotif->firstnote;
+    noteptr thishsnote = hfmotif->firstnote;
+    double thishftime,nexthftime,thishstime,nexthstime,thisamp,thisdur;
+    unsigned char thisinstr;
+    int hf_cnt = 1, hfnotecnt = 0;
+    int hs_cnt = 1, hsnotecnt = 0;
+    int hfdatacnt = 0;
+    double *hft, pptop, ppbot;
+    double *hs = (double *)0, *hf = (double *)0;
+    dz->iparam[SPINIT] = 0;
+
+    if((exit_status = readhftimes(hfmotif->firstnote,&hfdatacnt,&hft))<0)
+        return(exit_status);
+    thishftime = nexthftime = thishstime = nexthstime = hft[0];
+
+    if(texflag & ISMANY_HFLDS) {
+        if((exit_status = setup_first_hfield(hfmotif->firstnote,&hs,&hsnotecnt,&hf,&hfnotecnt,texflag))<0)
+            return(exit_status);
+    } else {
+        if((exit_status = setup_hfield(hfmotif->firstnote,&hs,&hsnotecnt,&hf,&hfnotecnt,texflag))<0)
+            return(exit_status);
+    }
+    while(tsetnote!=(noteptr)0) {                               /* 3 */
+        /*repeated  = */(void) chekrepeat(tsetnote,lastpitch);
+        lastpitch = tsetnote->pitch;
+        thistime  = (double)tsetnote->ntime;        /* 5 */
+        if((exit_status = read_values_from_all_existing_brktables(thistime,dz))<0)
+            return(exit_status);
+        if(texflag & ISMANY_HFLDS) {
+            if((exit_status = get_next_hfield(&hf,&hs,thistime,&hf_cnt,&hs_cnt,
+                                              &hfnotecnt,&thishfnote,&thishftime,&nexthftime,hfdatacnt,
+                                              &hsnotecnt,&thishsnote,&thishstime,&nexthstime,hft,texflag))<0)
+                return(exit_status);
+        }
+        if((exit_status = do_amp_instr_dur(&thisamp,&thisinstr,&thisdur,tsetnote,thistime,dz))<0)
+            return(exit_status);
+        if((exit_status = do_ev_hfpch(thistime,&hsindex,&thispitch,hsnotecnt,hs,&pptop,&ppbot,dz))<0)
+            return(exit_status);
+        tsetnote->pitch = (float)thispitch;
+        if(exit_status == CONTINUE) {
+            nextnote = tsetnote->next;
+            del_note(tsetnote,tset);
+            tsetnote = nextnote;
+        } else
+            tsetnote = tsetnote->next;
+    }
+    if(tset->firstnote==(noteptr)0) {
+        sprintf(errstr,"The harmonic set specified does not tally with the range.\n");
+        return(DATA_ERROR);
+    }
+    return(FINISHED);
+}
+
+/**************************** DO_CLUMPED_HFTEXTURE ****************************/
+
+int do_clumped_hftexture(dataptr dz)
+{
+    int exit_status;
+    unsigned int texflag     = dz->tex->txflag;
+    unsigned char dectypestor = dz->tex->dectypstor;
+    unsigned char dectypecnt  = dz->tex->dectypcnt;
+    unsigned char amptypestor = dz->tex->amptypstor;
+    unsigned char amptypecnt  = dz->tex->amptypcnt;
+    int ampdirected           = dz->tex->ampdirectd;
+    motifptr tset                     = dz->tex->timeset;
+    motifptr hfmotif                  = dz->tex->hfldmotif;
+    motifptr *phrase                  = dz->tex->phrase;
+    int **hfphrase = NULL;
+    int *endhsindex=NULL, *phrnotecnt=NULL;
+    double *phraseamp=NULL, *phrange=NULL;
+    unsigned char amptype = 0;
+    fitptr fithead = NULL;
+    noteptr tsetnote = tset->firstnote;
+    noteptr thisnote=NULL, nextnote=NULL, phrasenote=NULL, nextevent=NULL, *shadow=NULL;
+    double thispitch = 0.0, lastpitch = -1.0, ampstep = 0.0, ampdif = 0.0, notetime = 0.0, thisamp = 0.0, thisdur = 0.0;
+    unsigned char thisinstr;
+    double phrfirstnote = 0.0, thistime = 0.0, rangemult = 0.0, gprlow = 0.0;
+    double timeadjust = 0.0; /* default */
+    noteptr thishfnote = hfmotif->firstnote;
+    noteptr thishsnote = hfmotif->firstnote;
+    noteptr *phrlastnote = NULL;
+    double thishftime = 0.0,nexthftime = 0.0,thishstime = 0.0,nexthstime = 0.0,tsettime = 0.0;
+    int hf_cnt = 1, hfnotecnt = 0, mingrpsize = 0, shadindex = 0, shadowsize=0;
+    double gprange = 0.0,gpdense = 0.0,multiplier = 0.0;
+    double *notestor=NULL;
+    int hfgpranglo=0,hfgpranghi=0;
+    int hs_cnt = 1, hsnotecnt = 0;
+    int hfdatacnt = 0, hfrange = 0, gpsize,shshsize = 0;
+    int phrno = 0, n=0,  hsindex=0, starthsindex=0, hfchanged=0;
+    int hsi=0, starthsi = 0, endhsi=0;
+    char *shadbits = NULL;
+    double *hft=NULL, pptop=0.0, ppbot=0.0;
+    double *hs = (double *)0, *hf = (double *)0;
+
+    if((dz->tex->phrasecnt > 0) && (exit_status = initialise_hfphrases
+                                    (&hfphrase,&endhsindex,&phrnotecnt,&phraseamp,&phrange,&phrlastnote,dz))<0)
+        return(exit_status);
+    dz->iparam[SPINIT] = 0;
+    if(texflag & IS_GROUPS)
+        mingrpsize = 1;
+
+    if((exit_status = readhftimes(hfmotif->firstnote,&hfdatacnt,&hft))<0)
+        return(exit_status);
+    thishftime = nexthftime = thishstime = nexthstime = hft[0];
+
+    if((exit_status = make_shadow(tset,&shadowsize,&shadow))<0)
+        return(exit_status);
+
+    if((texflag & MOTIF_IN_HF) || (texflag & IS_ORNATE)) {
+        if((exit_status = init_fits(&fithead))<0)
+            return(exit_status);
+    }
+    if(texflag & IS_DECOR)
+        setup_decor(&pptop,&ppbot,&shadindex,&tsetnote,dz);
+    else {
+        if((exit_status = init_shadbits(shadowsize,&shshsize,&shadbits))<0)
+            return(exit_status);
+    }
+    if(texflag & ISMANY_HFLDS) {
+        if((exit_status = setup_first_hfield(hfmotif->firstnote,&hs,&hsnotecnt,&hf,&hfnotecnt,texflag))<0)
+            return(exit_status);
+    } else {
+        if((exit_status = setup_hfield(hfmotif->firstnote,&hs,&hsnotecnt,&hf,&hfnotecnt,texflag))<0)
+            return(exit_status);
+    }
+    if((texflag & MOTIF_IN_HF) || ((texflag & IS_ORNATE) && !(texflag & ISMANY_HFLDS))) {
+        if((exit_status = set_hfmotifs
+            (hs,phrase,phrnotecnt,phraseamp,phrange,phrlastnote,endhsindex,hfphrase,hsnotecnt,fithead,&notestor,dz))<0)
+            return(exit_status);
+    } else if(texflag & IS_MOTIFS) {
+        if((exit_status = set_motifs
+            (dz->tex->phrasecnt,phrase,phrnotecnt,phraseamp,phrange,phrlastnote))<0)
+            return(exit_status);
+    }
+    while(tsetnote!=(noteptr)0) {
+        if(!(texflag & IS_ORNATE)) {
+            /*repeated =*/ (void) chekrepeat(tsetnote,lastpitch);
+            lastpitch = tsetnote->pitch;
+        }
+        tsettime = thistime = (double)tsetnote->ntime;
+        if((exit_status = read_values_from_all_existing_brktables(thistime,dz))<0)
+            return(exit_status);
+        if(texflag & ISMANY_HFLDS) {
+            if((exit_status = get_next_hfield(&hf,&hs,thistime,&hf_cnt,&hs_cnt,
+                                              &hfnotecnt,&thishfnote,&thishftime,&nexthftime,hfdatacnt,
+                                              &hsnotecnt,&thishsnote,&thishstime,&nexthstime,hft,texflag))<0)
+                return(exit_status);
+            hfchanged = exit_status;
+            if(((texflag & MOTIF_IN_HF) || (texflag & IS_ORNATE)) && hfchanged) {
+                if((exit_status = set_hfmotifs
+                    (hs,phrase,phrnotecnt,phraseamp,phrange,phrlastnote,endhsindex,hfphrase,hsnotecnt,fithead,&notestor,dz))<0)
+                    return(exit_status);
+            }
+        }
+        if(texflag & IS_ORN_OR_MTF) {
+            if((exit_status = setup_motif_or_ornament(thistime,&multiplier,&phrno,&phrasenote,phrase,dz))<0)
+                return(exit_status);
+        }
+        if((exit_status = do_amp_instr_dur(&thisamp,&thisinstr,&thisdur,tsetnote,thistime,dz))<0)
+            return(exit_status);
+        if(texflag & IS_DECOR)
+            thispitch = tsetnote->pitch;
+        if(texflag & IS_MTF_OR_GRP) {
+            if(texflag & IS_GROUPS)
+                exit_status = setup_group_note
+                    (thisamp,thisinstr,thisdur,tsetnote,&thispitch,
+                     thistime,&hsindex,hsnotecnt,hs,&pptop,&ppbot,&shadindex,shadbits,dz);
+            else
+                exit_status = setup_motif_note
+                    (thisamp,thisinstr,thisdur,tsetnote,phrasenote,&thispitch,
+                     thistime,&hsindex,hsnotecnt,hs,&pptop,&ppbot,&shadindex,shadbits,multiplier,dz);
+            if(exit_status==CONTINUE)
+                continue;
+        }
+        if(texflag & IS_ORN_OR_MTF)
+            gpsize = phrnotecnt[phrno];
+        else {
+            if((exit_status = get_hfgpparams
+                (thistime,thispitch,hs,hsnotecnt,&gpsize,&hfrange,&hfgpranglo,&hfgpranghi,
+                 &gprange,&gpdense,mingrpsize,&gprlow,dectypecnt,dectypestor,dz))<0)
+                return(exit_status);
+        }
+        if(texflag & IS_DECOR) {
+            if((exit_status = position_and_size_decoration(&thistime,tsettime,gpdense,&gpsize,dz))<0)
+                return(exit_status);
+        } else
+            gpsize--;
+        if(texflag & IS_MOTIFS)
+            phrfirstnote = phrasenote->pitch;
+        else if(texflag & IS_ORNATE) {
+            if((hsi = convert_pitch_to_nearest_hset_pitch((double)tsetnote->pitch,hs,hsnotecnt))<0)
+                gpsize = 0;                     /* note out of bounds, ornament omitted  */
+            if((exit_status = setup_ornament
+                (&timeadjust,&thistime,&gpsize,phrlastnote,multiplier,&phrasenote,phrno,dz))<0)
+                return(exit_status);
+        }
+        if(!(texflag & IS_DECOR))
+            nextnote  = tsetnote->next;
+        if(gpsize>0) {
+            if(texflag & IS_ORN_OR_MTF) {
+                if((exit_status = orn_or_mtf_amp_setup
+                    (ampdirected,phrange,phrno,thisamp,gpsize,&rangemult,&ampstep,&amptype,amptypestor,amptypecnt,dz))<0)
+                    return(exit_status);
+            }
+            if(texflag & IS_MOTIFS) {
+                if((exit_status = set_motif_amp
+                    (tsetnote,&thisamp,gpsize,ampstep,phrasenote,rangemult,phraseamp,phrno,amptype))<0)
+                    return(exit_status);
+            } else if(texflag & IS_ORNATE) {
+                if((exit_status = set_ornament_amp
+                    (phraseamp,phrlastnote,&thisamp,phrasenote,phrno,tsetnote,ampstep,rangemult,gpsize,dz))<0)
+                    return(exit_status);
+            } else if (texflag & IS_GROUPS) {
+                if((exit_status = set_group_amp
+                    (tsetnote,&thisamp,&amptype,&ampstep,gpsize,amptypecnt,amptypestor,dz))<0)
+                    return(exit_status);
+            } else if (texflag & IS_DECOR) {
+                if((exit_status = set_decor_amp
+                    (ampdirected,&thisamp,&ampstep,gpsize,&amptype,amptypecnt,amptypestor,dz))<0)
+                    return(exit_status);
+            }
+            if(dz->iparam[TEX_GPSPACE]!=IS_STILL) {
+                if((exit_status = init_group_spatialisation(tsetnote,shadindex,shadow,shadowsize,dz))<0)
+                    return(exit_status);
+            }
+            thisnote  = tsetnote;
+            if(texflag & MOTIF_IN_HF)
+                starthsindex =  *(hfphrase[phrno]);
+            else if(texflag & IS_ORNATE) {
+                if((exit_status = setup_ornamentation
+                    (&starthsi,&endhsi,&nextevent,tsetnote,&phrasenote,&shadindex,endhsindex,hfphrase[phrno],phrno,dz))<0)
+                    return(exit_status);
+            } else if(texflag & IS_DECOR) {
+                nextnote = tsetnote->next;
+                nextevent = getnextevent_to_decorate(tsetnote,&shadindex,dz);
+            }
+            for(n=0;n<gpsize;n++) {
+                if((exit_status = make_new_note(&thisnote))<0)
+                    return(exit_status);
+                if(texflag & IS_ORN_OR_MTF) {
+                    if((exit_status = check_next_phrasenote_exists(&phrasenote,texflag,dz))<0)
+                        return(exit_status);
+                    notetime = getnotetime(phrasenote,thistime,multiplier,timeadjust,dz);
+                    thisamp += ampstep;
+                    ampdif   = (phraseamp[phrno]-phrasenote->amp)*rangemult;
+                    if((exit_status = setmtfparams
+                        (thisnote,thisamp,phrasenote,tsetnote,ampdif,notetime,gpsize,multiplier,dz))<0)
+                        return(exit_status);
+                } else  {
+                    if((exit_status = set_group_params
+                        (tsetnote,thisnote,gpdense,ampstep,&thisamp,&thistime,thisdur,dz))<0)
+                        return(exit_status);
+                }
+                if(texflag & MOTIF_IN_HF) {
+                    if((exit_status = generate_motifin_note_pitch
+                        (n,hsindex,starthsindex,hsnotecnt,thispitch,hfphrase[phrno],&thisnote,hs,texflag))<0)
+                        return(exit_status);
+                } else if(texflag & IS_MOTIFS) {
+                    if((exit_status = generate_motif_note_pitch(tsetnote,phrasenote,phrfirstnote,thisnote))<0)
+                        return(exit_status);
+                } else if (texflag & IS_ORNATE) {
+                    if((exit_status = generate_ornament_note_pitch
+                        (n,hs,hsi,endhsi,starthsi,&thisnote,&phrasenote,hfphrase[phrno],hfnotecnt,hsnotecnt,dz))<0)
+                        return(exit_status);
+                } else if(texflag & IS_GROUPS) {
+                    if((exit_status = generate_group_note
+                        (thisnote,tsetnote,thistime,hfrange,hfgpranglo,hs,&hsindex,gpsize,dz))<0)
+                        return(exit_status);
+                } else if(texflag & IS_DECOR) {
+                    if((exit_status = generate_decor_note
+                        (thisnote,tsetnote,thispitch,thistime,hfrange,hfgpranghi,hfgpranglo,
+                         hs,&hsindex,hsnotecnt,gprlow,gprange,gpsize,dz))<0)
+                        return(exit_status);
+                }
+                if(exit_status==CONTINUE)
+                    continue;
+            }
+            thisnote->next = nextnote;
+            if(nextnote!=(noteptr)0)
+                nextnote->last = thisnote;
+            if(texflag & IS_ORN_OR_DEC)
+                tsetnote = nextevent;
+        } else if(texflag & IS_ORN_OR_DEC)
+            tsetnote = getnextevent_to_decorate(tsetnote,&shadindex,dz);
+
+        if(texflag & IS_MTF_OR_GRP) {
+            tsetnote = nextnote;
+            shadindex++;
+        }
+    }
+    if(texflag & IS_MTF_OR_GRP)
+        del_ghosts(shshsize,shadbits,shadow,shadowsize,tset);           /* 5 */
+
+    if(texflag & IS_DECOR) {
+        if(dz->vflag[DISCARD_ORIGLINE] && (exit_status = erase_shadow(shadowsize,shadow,tset))<0)
+            return(exit_status);
+    } else
+        free(shadbits);
+    if((texflag & MOTIF_IN_HF) || (texflag & IS_ORNATE))
+        free(fithead);
+    return arrange_notes_in_timeorder(tset);
+}
+
+/**************************** SET_HFMOTIFS *******************************
+ *
+ * initialise all parameters of input motifs to be used for MOTIFS or
+ * ORNAMENTS, including their HS indexing!!!
+ *
+ * (1)For each input motif (called a 'phrase').
+ *    phrnotecnt[n] = 0;
+ * (2)  Initialise count of number of notes to 0, maximum amplitude
+ *      of phrase to 0.0, and lowest pitch-index to hsnotecnt.
+ * (3)  Go through each note of the motif.
+ * (4)  Add up the number of notes in it.
+ * (5)  Find it's lowest pitch.
+ * (6)  Find it's loudest note (and set as phraseamp).
+ * (7)  Establish dynamic range of phrase.
+ * (9)  Ensure motif starts at zero time.
+ * (10) Generate the corresponding HS indices, in their lowest configuration.
+ * (11) Store hfindex of last note of phrase.
+ */
+
+int set_hfmotifs
+(double *hs,motifptr *phrase,int *phrnotecnt,double *phraseamp,double *phrange,noteptr *phrlastnote,
+ int *endhsindex,int **hfphrase,int hsnotecnt,fitptr fithead,double **notestor,dataptr dz)
+{
+    int exit_status;
+    int n;
+    double mintime, minamp, minpitch, maxpitch;
+    noteptr thisnote, lastnote = (noteptr)0;
+    for(n=0;n<dz->tex->phrasecnt;n++) {                                             /* 1 */
+        if((exit_status = arrange_notes_in_timeorder(phrase[n]))<0)
+            return(exit_status);
+        phrnotecnt[n] = 0;
+        phraseamp[n] = 0.0;                                                     /* 2 */
+        minamp   = DBL_MAX;
+        minpitch = DBL_MAX;
+        maxpitch = -2.0f;
+        mintime  = DBL_MAX;
+        thisnote = phrase[n]->firstnote;                        /* 3 */
+        while(thisnote!=(noteptr)0) {
+            phrnotecnt[n]++;                                                        /* 4 */
+            if((double)thisnote->pitch<minpitch)
+                minpitch = thisnote->pitch;                     /* 5 */
+            if((double)thisnote->pitch>maxpitch)
+                maxpitch = thisnote->pitch;                     /* 5 */
+            if(thisnote->ntime<mintime)
+                mintime  = thisnote->ntime;                     /* 5 */
+            if((double)thisnote->amp>phraseamp[n])
+                phraseamp[n] = (double)thisnote->amp;/* 6 */
+            if(thisnote->amp<minamp)
+                minamp = thisnote->amp;                         /* 6 */
+            thisnote = thisnote->next;
+        }
+        if(minamp   == DBL_MAX
+           || minpitch == DBL_MAX
+           || maxpitch == -2.0f
+           || mintime  == DBL_MAX) {
+            sprintf(errstr,"Error parsing notelist: set_hfmotifs()\n");
+            return(PROGRAM_ERROR);
+        }
+        thisnote = phrase[n]->firstnote;
+        phrange[n] = phraseamp[n] - (double)minamp;     /* 7 */
+        while(thisnote!=(noteptr)0) {
+            thisnote->ntime = (float)(thisnote->ntime - mintime);                           /* 9 */
+            lastnote = thisnote;
+            thisnote = thisnote->next;
+        }
+        if((phrlastnote[n] = lastnote)==(noteptr)0) {
+            sprintf(errstr,"Encountered an empty motif: set_hfmotifs()\n");
+            return(PROGRAM_ERROR);
+        }
+        if((exit_status = gethfphrase(hs,notestor,n,minpitch,maxpitch,hfphrase,hsnotecnt,phrnotecnt,phrase,fithead))<0) /* 10 */
+            return(exit_status);
+        endhsindex[n]  = *(hfphrase[n]+phrnotecnt[n]-1);                        /* 11 */
+    }
+    return(FINISHED);
+}
+
+/*********************** GETHFPHRASE *********************************
+ *
+ * Get the hfphrase best corresponding to the input motif.
+ *
+ * (0)  Create storage space to store HS-indices of phrase.
+ * (1)  HIpitch of phrase higher than top of HS
+ *      AND LOpitch of phrase lower than bottom of HS.
+ *      ..Shrink the motif to size of HS, and establish hfphrase.
+ * (2)  HIpitch of phrase higher than top of HS
+ *      BUT LOpitch within HS range.
+ *      .. transpose phraselimits down onto bottom pitch of HS.
+ * (a)  If HIpitch of phrase STILL higher than top of HS
+ *      ..Shrink the motif to size of HS, and establish hfphrase.
+ * (3)  LOpitch of phrase lower than bottom of HS
+ *      BUT HIpitch within HS range.
+ *      .. transpose phraselimits up onto bottom pitch of HS.
+ * (a)  If HIpitch of phrase is NOW higher than top of HS
+ *      ..Shrink the motif to size of HS, and establish hfphrase.
+ * (4)  Phrase lies with the limits of HS.
+ *      .. transpose phraselimits down onto bottom pitch of HS.
+ * (5)  Find appropriate hfphrase.
+ */
+
+int gethfphrase
+(double *hs,double **notestor,int z,double lopitch,double hipitch,
+ int **hfphrase,int hsnotecnt,int *phrnotecnt,motifptr *phrase,fitptr fithead)
+{
+    double origlo = lopitch, hstop = hs[hsnotecnt-1], hsbot = hs[0];
+    double stepdown, stepup;
+    if((hfphrase[z] = (int *)malloc(phrnotecnt[z] * sizeof(int)))==NULL) {  /* 0 */
+        sprintf(errstr,"INSUFFICIENT MEMORY for harmonic field phrase array.\n");
+        return(MEMORY_ERROR);
+    }
+    if(hipitch>=hstop) {
+        if(lopitch<=hsbot)                              /* 1 */
+            return shrink_to_hs(z,hsnotecnt,hipitch,lopitch,hstop,hsbot,hs,hfphrase[z],phrase,phrnotecnt);
+        else  {
+            stepdown = lopitch - hsbot;                     /* 2 */
+            hipitch -= stepdown;
+            lopitch -= stepdown;
+            if(hipitch>hstop)                               /* a */
+                return shrink_to_hs(z,hsnotecnt,hipitch,lopitch,hstop,hsbot,hs,hfphrase[z],phrase,phrnotecnt);
+        }
+    } else {
+        if(lopitch<=hsbot) {                            /* 3 */
+            stepup  = hsbot - lopitch;
+            hipitch += stepup;
+            lopitch += stepup;
+            if(hipitch>hstop)                               /*a */
+                return shrink_to_hs(z,hsnotecnt,hipitch,lopitch,hstop,hsbot,hs,hfphrase[z],phrase,phrnotecnt);
+        } else {                                        /* 4 */
+            stepdown = lopitch - hsbot;
+            hipitch -= stepdown;
+            lopitch -= stepdown;
+        }
+    }
+    return findhfphrase(z,hs,hstop,hsnotecnt,lopitch,origlo,phrase,hfphrase,phrnotecnt,fithead,notestor);
+}                                                                                       /* 5 */
+
+
+/************************* SHRINK_TO_HS **************************
+ *
+ * Shrink motif so it fits with HS, then find best HS fit.
+ *
+ * (1)  Establish pitch-shrinking ratio.
+ * (2)  For every note...
+ * (3)  Shrink intervals and thus move pitch to appropriate position inside
+ *      range of HS.
+ * (4)  Find index of the next lowest HS notes.
+ * (4a) If note falls outside field, set distance to note to maximum poss.
+ * (4b) Else find pitch distances of this note from original pitch.
+ * (5)  Find index of the next highest HS notes.
+ * (5a) If note falls outside field, set distance to note to maximum poss.
+ * (5b) Else find pitch distances of this note from original pitch.
+ * (6)  Select HSindex of nearest pitch and store in hfphrase.
+ * (7)  Save the lowest such index.
+ * (8)  Transpose all indices down to lowest possible values.
+ */
+
+int shrink_to_hs(int z,int hsnotecnt,double hipitch,double lopitch,double hstop,
+                 double hsbot,double *hs, int *hfphrase, motifptr *phrase,int *phrnotecnt)
+{
+    noteptr thisnote = phrase[z]->firstnote;
+    double shrink ,thispitch, x, y;
+    int minindex = MAXINT, xx, yy, q, n = 0;
+    shrink = (hstop - hsbot)/(hipitch-lopitch);                     /* 1 */
+    for(;;) {                                                       /* 2 */
+        thispitch = thisnote->pitch;
+        thispitch = ((thispitch - lopitch) * shrink) + hsbot;   /* 3 */
+        if((xx = geths_lobnd(thispitch,hs,hsnotecnt))<0)                        /* 4 */
+            x = DBL_MAX;                                            /* 4a */
+        else
+            x = fabs(hs[xx] - thispitch);                   /* 4b */
+        if((yy = geths_hibnd(thispitch,hsnotecnt,hs))>=hsnotecnt)               /* 5 */
+            y = DBL_MAX;                                            /* 5a */
+        else
+            y = fabs(hs[yy] - thispitch);                   /* 5b */
+        if(x<y)
+            q = xx;                                         /* 6 */
+        else
+            q = yy;
+        *(hfphrase+n) = q;
+        if(q<minindex)
+            minindex = q;                                   /* 7 */
+        if((thisnote = thisnote->next)==(noteptr)0)
+            break;
+        if(++n >= phrnotecnt[z]) {
+            sprintf(errstr,"accounting problem in shrink_to_hs()\n");
+            return(PROGRAM_ERROR);
+        }
+    }
+    for(n=0;n<phrnotecnt[z];n++)                                    /* 8 */
+        *(hfphrase+n) -= minindex;
+    return(FINISHED);
+}
+
+/*********************** FINDHFPHRASE *********************************
+ *
+ * Extract the best fit onto the HS, and transpose it down to bottom
+ * of indices.
+ *
+ * (1)  Set the FIT-pointer to head of fits-list.
+ * (2)  Set up a store for the note values to be tested.
+ * (3)  Get interval of transposition to take motif to bottom of HS range.
+ * (4)  Store original note values of phrase transposed down to bottom of HS range.
+ * (5)  Find the fit-value for motif in its start position.
+ * (6)  Outer loop will transpose the phrase through a range...
+ *              (7)     Set amount to transpose phrase (shift) to max.
+                        Then for every note of the phrase.....
+                        *              (8) Find the HSindex of the nearest note above the current note.
+                        *              (If there isn't one break out completely).
+                        *              (9)  If the difference in pitch between this and the current note
+                        *              is smaller than the minimum shift, reset minimum shift.
+                        *              (10)Then, for every note of the phrase...
+                        *              (11)transpose it up by this minimum transposition.
+                        *                      If this takes any note of the phrase outside the range of HS
+                        *                      break out completely.
+                        *      (12)Back in outer loop, find the fitting-value for this transposition
+                        *                      of the motif, which is a measure of how far its notes are from
+                        *                      the closest HS values.
+                        * (13) Outside the outer loop, unlink the last unwanted member iof fitlist.
+                        * (14) Find the best fitvalue, and return the amount by which orig motif
+                        *              should be transposed to get onto this best fit.
+                        * (15) Free the fit-list (retains fithead).
+                        * (16) Get the appropriate HS indices.
+                        */
+
+int findhfphrase
+(int z,double *hs,double hstop,int hsnotecnt,double lopitch,double origlo,
+ motifptr *phrase,int **hfphrase,int *phrnotecnt,fitptr fithead,double **notestor)
+{
+    int exit_status;
+    int hsindex, OK = 1, n, got_transpose = 0;
+    noteptr thisnote = phrase[z]->firstnote;
+    fitptr thisfit = fithead;                                                                       /* 1 */
+    double shift, thisshift, transpose = 0.0, stepdown, *noteval;
+    if(*notestor!=NULL)
+        free(*notestor);                                                                                /* 2 */
+    if((noteval = *notestor = (double *)malloc(phrnotecnt[z] * sizeof(double)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY for note value array.\n");
+        return(MEMORY_ERROR);
+    }
+    stepdown = origlo - lopitch;                                                            /* 3 */
+    while(thisnote!=(noteptr)0) {
+        *noteval = (double)thisnote->pitch - stepdown;                  /* 4 */
+        noteval++;
+        thisnote = thisnote->next;
+    }
+    if((exit_status = get_fit(*notestor,thisfit,lopitch,origlo,z,hsnotecnt,phrnotecnt,hs,&thisfit))<0)
+        return(exit_status);                                                                    /* 5 */
+    if(exit_status == CONTINUE) {
+        transpose = thisfit->last->transpose;
+        got_transpose = 1;
+        OK  = 0;
+    }
+    while(OK) {                                                                                                     /* 6 */
+        shift = DBL_MAX;                                                                                /* 7 */
+        noteval = *notestor;
+        for(n=0;n<phrnotecnt[z];n++) {
+            if((hsindex = geths_above(*noteval,hs,hsnotecnt))>=hsnotecnt) { /* 8 */
+                OK = 0;
+                break;
+            }
+            if((thisshift  = hs[hsindex] - *noteval)<shift)
+                shift = thisshift;                                                              /* 9 */
+            noteval++;
+        }
+        if(shift==DBL_MAX) {
+            sprintf(errstr,"Error parsing phrase: findhfphrase()\n");
+            return(PROGRAM_ERROR);
+        }
+        if(!OK)
+            break;
+        noteval = *notestor;
+        for(n=0;n<phrnotecnt[z];n++) {                                                  /* 10 */
+            if((*noteval++  += (float)shift)>hstop) {
+                OK = 0;                                                                                 /* 11 */
+                break;
+            }
+        }
+        lopitch += shift;
+        if((exit_status = get_fit(*notestor,thisfit,lopitch,origlo,z,hsnotecnt,phrnotecnt,hs,&thisfit))<0)
+            return(exit_status);                                                            /* 12 */
+        if(exit_status == CONTINUE) {
+            transpose = thisfit->last->transpose;
+            got_transpose = 1;
+            break;
+        }
+    }
+    if((exit_status = fit_unlink(thisfit))<0)                                       /* 13 */
+        return(exit_status);
+    if (!got_transpose) {
+        if((exit_status = best_fit(fithead,&transpose))<0)              /* 14 */
+            return(exit_status);
+    }
+    free_fitlist(fithead);                                                                          /* 15 */
+    return getmtfindeces(transpose,z,hsnotecnt,hs,phrase,phrnotecnt,hfphrase);
+}                                                                                                                               /* 16 */
+
+/*************************** GETMTFINDECES *****************************
+ *
+ * Get the HS indices of the phrase, transposed to lowest position in HS.
+ *
+ * (0)  Point to start of storage space for the HS-indices of the phrase.
+ * (1)  Mark end of this storage space (for accounting purposes).
+ * (2)  For every note of the phrase...
+ *   (3)  Get the pitch..
+ *   (4)  Transpose the pitch by the input transposition.
+ *   (5)  Find the nearest HS set members above and below the note.
+ *   (6)  Decide which is nearest.
+ *   (7)  Assign index of nearest value to the HS-index store.
+ *   (8)  Keep a note of the smallest index.
+ *   (9)  Increment the index-store pointer.
+ * (10) Decrement all the indeces to tranpose them all to lowest values
+ *      in the hfphrase store.
+ */
+
+int getmtfindeces(double transpose,int z,int hsnotecnt,double *hs,motifptr *phrase,int *phrnotecnt,int **hfphrase)
+{
+    noteptr thisnote = phrase[z]->firstnote;
+    int *thisindex, xx, yy, minindex = MAXINT, *indexend;
+    double x, y, thispitch;
+    thisindex = hfphrase[z];                                                /* 0 */
+    indexend  = hfphrase[z] + phrnotecnt[z];                /* 1 */
+    for(;;) {                                                                               /* 2 */
+        thispitch  = thisnote->pitch;                           /* 3 */
+        thispitch += transpose;                                         /* 4 */
+        xx = geths_lobnd(thispitch,hs,hsnotecnt);       /* 5 */
+        yy = geths_hibnd(thispitch,hsnotecnt,hs);
+        x = fabs(hs[xx] - thispitch);                           /* 6 */
+        y = fabs(hs[yy] - thispitch);
+        if(x<y)
+            *thisindex = xx;                                                /* 7 */
+        else
+            *thisindex = yy;
+        if(*thisindex<minindex)
+            minindex = *thisindex;                                  /* 8 */
+        if((thisnote = thisnote->next)==(noteptr)0)
+            break;
+        if(++thisindex>=indexend) {                                     /* 9 */
+            sprintf(errstr,"TEXTURE: Problem in getmtfindices()\n");
+            return(PROGRAM_ERROR);
+        }
+    }
+    for(thisindex = hfphrase[z];thisindex<indexend;thisindex++)
+        *thisindex -= minindex;                                         /* 10 */
+    return(FINISHED);
+}
+
+/****************************** GET_FIT ************************************
+ *
+ * Create list of fit_values for motif over HS.
+ *
+ * (1)  For every note of the phrase.
+ * (3)  Find the index of the next lowest HS note. If there is not one
+ *      something is wrong!
+ * (4)  Find the index of the next highest HS note. If there is not one
+ *      something is wrong!
+ * (5)  Find the pitch distance between these notes on the original pitch.
+ * (6)  Add the minimum of these two, to a running sum of such differences.
+ * (7)  Store the fit-value and the associated ttansposition, creating a
+ *      new storage space in the fit list, in the process.
+ */
+
+int get_fit(double *notestor,fitptr thisfit,double lopitch,double origlo,int z,
+            int hsnotecnt,int *phrnotecnt,double *hs,fitptr *newfit)
+{
+    int exit_status;
+    double x, y, sum = 0.0, *noteval = notestor;
+    int xx, yy, n;
+    for(n=0;n<phrnotecnt[z];n++) {                                                          /* 1 */
+        if((xx = geths_lobnd(*noteval,hs,hsnotecnt))<0) {               /* 3 */
+            sprintf(errstr,"Problem 1 in get_fit()\n");
+            return(PROGRAM_ERROR);
+        }
+        if((yy=geths_hibnd(*noteval,hsnotecnt,hs))>=hsnotecnt) {/* 4 */
+            sprintf(errstr,"Problem 2 in get_fit()\n");
+            return(PROGRAM_ERROR);
+        }
+        x = fabs(hs[xx] - *noteval);                                                    /* 5 */
+        y = fabs(hs[yy] - *noteval);
+        sum += min(x,y);                                                                                /* 6 */
+        noteval++;
+    }
+    if((exit_status = put_fit(thisfit,lopitch - origlo,sum,newfit))<0)
+        return(exit_status);
+    if(flteq(sum,0.0))
+        return(CONTINUE);
+    return(FINISHED);                                                                                       /* 7 */
+}
+
+/************************* PUT_FIT *****************************
+ *
+ * Put fit value in motif-fits list.
+ */
+
+int put_fit(fitptr thisfit,double transval,double fitval,fitptr *newfit)
+{
+    int exit_status;
+    thisfit->transpose = (float)transval;
+    thisfit->fit       = (float)fitval;
+    if((exit_status = new_fit(thisfit,newfit))<0)
+        return(exit_status);
+    return(FINISHED);
+}
+
+/************************* BEST_FIT *****************************
+ *
+ * Find the appropriate transposition to move the current motif
+ * to a pitch where it has the best fit with the HS.
+ *
+ * (1)  From all available transpositions, find best (lowest) fit value.
+ * (2)  From all available transpositions, find all those which have
+ *      this bestfit value, and select the one which involves the
+ *      least transposition.
+ * (3)  Once the transpositions begin to increase, we are moving away from
+ *      the smallest transposition, so quit.
+ * (4)  Return the best transposition.
+ */
+
+int best_fit(fitptr fithead,double *transpose)
+{
+    fitptr thisfit = fithead;
+    double bestfit = DBL_MAX, besttranspose = DBL_MAX;
+    double abstranspose = DBL_MAX, thistranspose;
+    while(thisfit!=(fitptr)0) {                             /* 1 */
+        if(thisfit->fit<(float)bestfit)
+            bestfit = (double)thisfit->fit;
+        thisfit = thisfit->next;
+    }
+    thisfit = fithead;
+    while(thisfit!=(fitptr)0) {                             /* 2 */
+        thistranspose = fabs((double)thisfit->transpose);
+        if(flteq((double)thisfit->fit,bestfit)) {
+            if(thistranspose<abstranspose) {
+                besttranspose = (double)thisfit->transpose;
+                abstranspose = fabs(besttranspose);
+            }
+        }
+        if(thistranspose>abstranspose+FLTERR)
+            break;                                  /* 3 */
+        thisfit = thisfit->next;
+    }
+    if(besttranspose==DBL_MAX) {
+        sprintf(errstr,"Problem in best_fit()\n");
+        return(PROGRAM_ERROR);
+    }
+    *transpose = besttranspose;
+    return(FINISHED);                               /* 4 */
+}
+
+/************************* INIT_FITS() *****************************
+ *
+ * Set up head item of a list of motif-fits.
+ */
+
+int init_fits(fitptr *thisfit)
+{
+    if((*thisfit = (fitptr)malloc(sizeof (struct ffit)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY for fitting array.\n");
+        return(MEMORY_ERROR);
+    }
+    (*thisfit)->next  = (fitptr)0;
+    (*thisfit)->last  = (fitptr)0;
+    return(FINISHED);
+}
+
+/************************* NEW_FIT() *****************************
+ *
+ * Set up next fit in a list of motif-fits.
+ */
+
+int new_fit(fitptr thisfit,fitptr *newfit)
+{
+    if((*newfit = (fitptr)malloc(sizeof (struct ffit)))==NULL) {
+        sprintf(errstr,"new_fit()\n");
+        return(PROGRAM_ERROR);
+    }
+    thisfit->next   = *newfit;
+    (*newfit)->last = thisfit;
+    (*newfit)->next = (fitptr)0;
+    return(FINISHED);
+}
+
+/********************** FIT_UNLINK() ******************************
+ *
+ * Deletes empty address space at end of fitlist.
+ */
+
+int fit_unlink(fitptr thisfit)
+{
+    if(thisfit->last==(fitptr)0) {
+        sprintf(errstr,"Problem in fit_unlink()\n");
+        return(PROGRAM_ERROR);
+    }
+    thisfit = thisfit->last;
+    free(thisfit->next);
+    thisfit->next = (fitptr)0;
+    return(FINISHED);
+}
+
+/********************** FREE_FITLIST() ******************************
+ *
+ * Deletes fitlist, retaining head.
+ */
+
+void free_fitlist(fitptr fithead)
+{
+    fitptr thisfit;
+    if((thisfit = fithead->next)==(fitptr)0)
+        return;
+    while(thisfit->next!=(fitptr)0) {
+        thisfit = thisfit->next;
+        free(thisfit->last);
+    }
+    free(thisfit);
+}
+
+/**************************** HFADJUST *********************************
+ *
+ * Pitch outside HS range. Adjust it.
+ *
+ * (1)  If this is a HS, there's nothing we can do about it. Return -1.0
+ *      which will cause note to be deleted in calling environment.
+ * (2)  If it's an HF however....
+ *      Set newpitch at appropriate interval from original pitch.
+ * (3)  If it's now above the HS
+ * (4)  transpose it down by octaves until it is in the HS.
+ * (5)  If still not in HS, mark for deletion.
+ * (6)  If it's BELOW the HS.
+ * (7)  transpose it up by octaves until it is in the HS.
+ * (8)  If still not in HS, mark for deletion.
+ * (9)  Return new pitch.
+ */
+
+double hfadjust(double thispitch,double *hs,int x1,int x2,int texflag,int hsnotecnt)
+{
+    double newpitch;
+    if(texflag & IS_HS)
+        return(-1.0);                                                           /* 1 */
+    else {
+        newpitch = thispitch+hs[x1]-hs[x2];                     /* 2 */
+        if(newpitch > hs[hsnotecnt-1]) {                        /* 3 */
+            while(newpitch>hs[hsnotecnt-1])
+                newpitch -= SEMITONES_PER_OCTAVE;       /* 4 */
+            if(newpitch<hs[0])                                              /* 5 */
+                return(-1.0);
+        } else {
+            if(newpitch<hs[0]) {                                    /* 6 */
+                while(newpitch <hs[0])
+                    newpitch += SEMITONES_PER_OCTAVE;/* 7 */
+                if(newpitch>hs[hsnotecnt-1])
+                    return(-1.0);                                   /* 8 */
+            }
+        }
+    }
+    return(newpitch);                                                               /* 9 */
+}
+
+/**************************** CONVERT_PITCH_TO_NEAREST_HSET_PITCH *********************************
+ *
+ * Convert pitch value to nearest HS value.
+ *
+ * ignores the problem of note repetitions in the tset.
+ * Note repetitions were only important where the tset notes were being
+ * forced onto an HS. Here the HS values are being extracted so the notes
+ * can be ornamented. The pitch values of the tset are NOT themselves altered.
+ */
+
+int convert_pitch_to_nearest_hset_pitch(double thispitch,double *hs,int hsnotecnt)
+{
+    int n, m;
+    if(thispitch<hs[0]) {
+        if(hs[0] - thispitch > hs[1] - hs[0])
+            return(-1);
+        else
+            return(0);
+    }
+    n = 1;
+    m = n-1;
+    while(n<hsnotecnt) {
+        if(flteq(hs[n],thispitch))
+            return(n);
+        if(hs[n]>thispitch) {
+            if(hs[n] - thispitch > thispitch - hs[m])
+                return(m);
+            else
+                return(n);
+        }
+        n++;
+        m++;
+    }
+    if(hsnotecnt>1 && (thispitch - hs[hsnotecnt-1] > hs[hsnotecnt-1] - hs[hsnotecnt-2]))
+        return(-1);
+    return(hsnotecnt-1);
+}
+
+/**************************** HFADJ2 *********************************
+ *
+ * HFindex outside HS range. Adjust it.
+ * Applies only to HF (i.e. an HS containing octave transpositions)
+ * not to HS.
+ */
+
+int hfadj2(int hsi,int hfnotecnt,int hsnotecnt)
+{
+    if(hsi<0) {
+        while(hsi<0)
+            hsi += hfnotecnt;
+    } else {
+        while(hsi>=hsnotecnt)
+            hsi -= hfnotecnt;
+    }
+    if(hsi<0 || hsi>=hsnotecnt)
+        return(-1);
+    return(hsi);
+}
+
+/**************************** SETUP_HFIELD *********************************/
+
+int setup_hfield(noteptr thisnote,double **hs,int *hsnotecnt,double **hf,int *hfnotecnt,int texflag)
+{
+    int exit_status;
+    if(texflag & IS_HS) {
+        if((exit_status = geths(thisnote,hs,hsnotecnt))<0)
+            return(exit_status);
+    } else {
+        if((exit_status = gethf(thisnote,hf,hfnotecnt))<0)                                      /* 2 */
+            return(exit_status);
+        if((exit_status = gen_hs(hf,hs,hsnotecnt,*hfnotecnt))<0)
+            return(exit_status);
+    }
+    return(FINISHED);
+}
+
+/**************************** SETUP_FIRST_HFIELD *********************************/
+
+int setup_first_hfield(noteptr thisnote,double **hs,int *hsnotecnt,double **hf,int *hfnotecnt,int texflag)
+{
+    int exit_status;
+    if(texflag & IS_HS) {
+        if((exit_status = get_first_hs(thisnote,hs,hsnotecnt))<0)
+            return(exit_status);
+    } else {
+        if((exit_status = get_first_hf(thisnote,hf,hfnotecnt))<0)                                       /* 2 */
+            return(exit_status);
+        if((exit_status = gen_hs(hf,hs,hsnotecnt,*hfnotecnt))<0)
+            return(exit_status);
+    }
+    return(FINISHED);
+}
+
+/**************************** GET_NEXT_HFIELD *********************************/
+
+int get_next_hfield(double **hf,double **hs,double inputtime,
+                    int *hf_cnt,int *hs_cnt,int *hfnotecnt,noteptr *thishfnote,double *thishftime,double *nexthftime,int hfdatacnt,
+                    int *hsnotecnt,noteptr *thishsnote,double *thishstime,double *nexthstime,double *hft,int texflag)
+{
+    if(texflag & IS_HS)
+        return getnexths(hs,inputtime,hs_cnt,hsnotecnt,thishsnote,thishstime,nexthstime,hfdatacnt,hft);
+    else
+        return getnexthf(hf,hs,hsnotecnt,inputtime,hf_cnt,hfnotecnt,thishfnote,thishftime,nexthftime,hfdatacnt,hft);
+}
+
+/**************************** SETUP_MOTIF_NOTE *********************************
+ *
+ * (1)  If the program is given a pitchrange OUTSIDE the bounds of the
+ *              specified HF or HS, do_ev_hfpch() returns a -ve value. In this
+ *              case, the associated tset note is marked for DELETION by setting
+ *              the bitflag associated with the shadow (address) of the tset note.
+ *              It will be deleted at the very end, by del_ghosts().
+ */
+
+int setup_motif_note
+(double thisamp,int thisinstr,double thisdur,noteptr tsetnote,noteptr phrasenote,
+ double *thispitch,double thistime,int *hsindex,int hsnotecnt,double *hs,
+ double *pptop,double *ppbot,int *shadindex,char *shadbits,double multiplier,dataptr dz)
+{
+    int exit_status;
+    tsetnote->amp = (float)thisamp;
+    tsetnote->instr = (unsigned char)thisinstr;
+    if(dz->vflag[DONT_KEEP_MTFDUR])
+        tsetnote->dur = (float)thisdur;
+    else
+        tsetnote->dur = (float)(phrasenote->dur * multiplier);
+    if(flteq((double)tsetnote->dur,0.0)) {
+        sprintf(errstr,"setup_motif_note(): Zero duration\n");
+        return(PROGRAM_ERROR);
+    }
+    if((exit_status = do_ev_hfpch(thistime,hsindex,thispitch,hsnotecnt,hs,pptop,ppbot,dz))<0)
+        return(exit_status);
+    if(exit_status==CONTINUE) {
+        set_shadbit(*shadindex,shadbits);    /* 1 */
+        tsetnote = tsetnote->next;
+        (*shadindex)++;
+        return(CONTINUE);
+    }
+    tsetnote->pitch = (float)(*thispitch);
+    return(FINISHED);
+}
+
+/**************************** SETUP_GROUP_NOTE *********************************/
+
+int setup_group_note
+(double thisamp,int thisinstr,double thisdur,noteptr tsetnote,
+ double *thispitch,double thistime,int *hsindex,int hsnotecnt,double *hs,
+ double *pptop,double *ppbot,int *shadindex,char *shadbits,dataptr dz)
+{
+    int exit_status;
+    tsetnote->amp = (float)thisamp;
+    tsetnote->instr = (unsigned char)thisinstr;
+    tsetnote->dur = (float)thisdur;
+    if((exit_status = do_ev_hfpch(thistime,hsindex,thispitch,hsnotecnt,hs,pptop,ppbot,dz))<0)   /* 1 */
+        return(exit_status);
+    if(exit_status==CONTINUE) {
+        set_shadbit(*shadindex,shadbits);
+        tsetnote = tsetnote->next;
+        (*shadindex)++;
+        return(CONTINUE);
+    }
+    tsetnote->pitch = (float)(*thispitch);
+    return(FINISHED);
+}
+
+/**************************** SETUP_ORNAMENTATION *********************************/
+
+int setup_ornamentation
+(int *starthsi,int *endhsi,noteptr *nextevent,noteptr tsetnote,
+ noteptr *phrasenote,int *shadindex,int *endhsindex,int *hfphrase,int phrno,dataptr dz)
+{
+    *starthsi  =  *hfphrase;
+    *endhsi    =  endhsindex[phrno];
+    *nextevent = getnextevent_to_decorate(tsetnote,shadindex,dz);
+    if(!dz->vflag[IS_PRE])
+        *phrasenote = (*phrasenote)->next;
+    return(FINISHED);
+}
+
+/**************************** GENERATE_MOTIF_NOTE_PITCH *********************************/
+
+int generate_motifin_note_pitch(int n,int hsindex,int starthsindex,int hsnotecnt,double thispitch,
+                                int *hfphrase,noteptr *thisnote,double *hs,int texflag)
+{
+    int notehsindex, thishsindex;
+    double newpitch;
+    notehsindex = *(hfphrase+n+1);
+    thishsindex = hsindex + notehsindex - starthsindex;
+    if(thishsindex<0 || thishsindex>=hsnotecnt) {
+        if((newpitch = hfadjust(thispitch,hs,notehsindex,starthsindex,texflag,hsnotecnt))<0.0) {
+            *thisnote = (*thisnote)->last;
+            free((*thisnote)->next);
+            return(CONTINUE);
+        } else
+            (*thisnote)->pitch = (float)newpitch;
+    } else
+        (*thisnote)->pitch=(float)hs[thishsindex];
+    return(FINISHED);
+}
+
+/**************************** GENERATE_MOTIF_NOTE_PITCH *********************************/
+
+int generate_motif_note_pitch(noteptr tsetnote,noteptr phrasenote,double phrfirstnote,noteptr thisnote)
+{
+    thisnote->pitch=(float)(tsetnote->pitch + phrasenote->pitch - phrfirstnote);
+    thisnote->pitch=(float)octadjust((double)thisnote->pitch);
+    return(FINISHED);
+}
+
+/**************************** GENERATE_ORNAMENT_NOTE_PITCH *********************************
+ *
+ * hsi = harmonic-set index.
+ */
+
+int generate_ornament_note_pitch
+(int n,double *hs,int hsi, int endhsi,int starthsi,noteptr *thisnote,
+ noteptr *phrasenote,int *hfphrase,int hfnotecnt,int hsnotecnt,dataptr dz)
+{
+    unsigned int texflag = dz->tex->txflag;
+    int thishsi, refhsi, notehsi;
+
+    if(dz->vflag[IS_PRE]) {
+        refhsi = endhsi;
+        notehsi = *(hfphrase+n);
+    } else {
+        refhsi = starthsi;
+        notehsi = *(hfphrase+n+1);
+    }
+    thishsi = hsi + notehsi - refhsi;
+    *phrasenote = (*phrasenote)->next;
+    if(thishsi<0 || thishsi>=hsnotecnt) {
+        if((texflag & IS_HS) || (thishsi=hfadj2(thishsi,hfnotecnt,hsnotecnt))<0) {
+            *thisnote = (*thisnote)->last;
+            free((*thisnote)->next);
+            return(CONTINUE);
+        }
+    }
+    (*thisnote)->pitch=(float)hs[thishsi];
+    return(FINISHED);
+}
+
+/********************** DO_EV_HFPCH *******************************
+ *
+ * Generate pitch of event (note group etc.) within HS.
+ *
+ * (2)  If getp_as_index() returns -1 , this means
+ *      that the pitch range specified is outside the HS, so a value of
+ *      -1.0 is returned to calling environment and tset note is DELETED!!
+ */
+
+int do_ev_hfpch(double thistime,int *hsindex,double *val,int hsnotecnt,double *hs,double *pptop,double *ppbot,dataptr dz)
+{
+    int exit_status;
+    if((exit_status = getp_as_index(thistime,hsindex,hsnotecnt,hs,pptop,ppbot,dz))<0)
+        return(exit_status);
+    if(*hsindex==-1)                                /* a */
+        return(CONTINUE);                       /* 2 */
+    *val = hs[*hsindex];
+    return(FINISHED);
+}
+
+/****************************** GETP_AS_INDEX *********************************
+ *
+ * Get integer value of a hf-pitch index, using pitch either from table,
+ * or fixed value.
+ *
+ * (1)  Read values of pitch-range limits from tables (or fixed vals).
+ * (2)  If either of pitch values is negative, if it's from a table,
+ *      reject it....
+ * (3)  But otherwise it can be regarded as a flag. Return -1 causing
+ *      the INPUT pitch to be converted to a HS pitch and returned.
+ * (4)  Check that range is not inverted.
+ * (5)  Get the note in HS which is >  upper pitch boundary. If all HS notes
+ *      are above this (function returns 0) return -1.
+ *      If all HS notes are BELOW this pitch, function returns hsnotecnt,
+ *      wehich forces upper limit of HSindex generated by doperm() to be
+ *      hsnotecnt-1, the highest pitch in the HS.
+ * (6)  Get the note in HS which is >= lower pitch boundary. If there
+ *      is no such note (function returns hsnotecnt) return -1.
+ * (7)  Return a weighted scattered value of hf-index, within the
+ *      defined range.
+ */
+
+int getp_as_index(double thistime,int *val,int hsnotecnt,double *hs,double *pptop,double *ppbot,dataptr dz)
+{
+    int exit_status;
+    int  a, b;
+    double range;
+    if(dz->brk[TEXTURE_MAXPICH]) {                                          /* 1 */
+        if((exit_status = read_value_from_brktable(thistime,TEXTURE_MAXPICH,dz))<0)
+            return(exit_status);
+    }
+    if(dz->brk[TEXTURE_MINPICH]) {
+        if((exit_status = read_value_from_brktable(thistime,TEXTURE_MINPICH,dz))<0)
+            return(exit_status);
+    }
+    *pptop = dz->param[TEXTURE_MAXPICH];
+    *ppbot = dz->param[TEXTURE_MINPICH];
+    if((range = dz->param[TEXTURE_MAXPICH] - dz->param[TEXTURE_MINPICH])<0.0)               /* 4 */
+        swap (&dz->param[TEXTURE_MAXPICH],&dz->param[TEXTURE_MINPICH]);
+    if((a = geths_above(dz->param[TEXTURE_MAXPICH],hs,hsnotecnt))==0) {                             /* 5 */
+        *val = -1;
+        return(FINISHED);
+    }
+    if((b = geths_hibnd(dz->param[TEXTURE_MINPICH],hsnotecnt,hs))>=hsnotecnt) {             /* 6 */
+        *val = -1;
+        return(FINISHED);
+    }
+    if((exit_status = hfscat(a-b,b,PM_PITCH,&a,dz))<0)      /* 7 */
+        return(exit_status);
+    if( a < 0 || a >= hsnotecnt) {                  /* 7 */
+        sprintf(errstr,"TEXTURE: getp_as_index(): TW's logic of index generation wrong\n");
+        return(DATA_ERROR);
+    }
+    *val = a;
+    return(FINISHED);
+}
+
+/**************************** INIT_SHADBITS ****************************
+ *
+ * Set up, and initialise to zero, a bitflag with one bit for each shadow
+ * (tset address).
+ */
+
+int init_shadbits(int shadowsize,int *shshsize,char **shadbits)
+{
+    int n = shadowsize;
+    *shshsize = 1;
+    while((n -= CHARBITSIZE)>0)
+        (*shshsize)++;
+    if((*shadbits = (char *)malloc((size_t)(*shshsize)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY for shadwoing array.\n");
+        return(MEMORY_ERROR);
+    }
+    for(n=0; n<(*shshsize); n++)
+        (*shadbits)[n] = 0;
+    return(FINISHED);
+}
+
+/****************************** GETHS ***********************************
+ *
+ * Extract HS from input data.
+ */
+
+int geths(noteptr thisnote,double **hs,int *hsnotecnt)
+{
+    int exit_status;
+    int size = BIGARRAY;
+    if((*hs = (double *)malloc(BIGARRAY * sizeof(double)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY for harmonic set array.\n");
+        return(MEMORY_ERROR);
+    }
+    while(thisnote!=(noteptr)0) {
+        if((exit_status = gethsnote(thisnote->pitch,*hs,hsnotecnt))<0)
+            return(exit_status);
+        if(*hsnotecnt >= BIGARRAY) {
+            size += BIGARRAY;
+            if((*hs=(double *)realloc((char *)(*hs),size * sizeof(double)))==NULL){
+                sprintf(errstr,"INSUFFICIENT MEMORY to reallocate harmonic set array.\n");
+                return(MEMORY_ERROR);
+            }
+        }
+        thisnote = thisnote->next;
+    }
+    if((*hs=(double *)realloc((char *)(*hs),*hsnotecnt*sizeof(double)))==NULL){
+        sprintf(errstr,"INSUFFICIENT MEMORY to reallocate harmonic set array.\n");
+        return(MEMORY_ERROR);
+    }
+    upsort(*hs,*hsnotecnt);
+    return(FINISHED);
+}
+
+/****************************** GETHF ***********************************
+ *
+ * Extract HF from input data.
+ */
+
+int gethf(noteptr thisnote,double **hf,int *hfnotecnt)
+{
+    int exit_status;
+    int size = BIGARRAY;
+    if((*hf = (double *)malloc(size * sizeof(double)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY for harmonic field array.\n");
+        return(MEMORY_ERROR);
+    }
+    while(thisnote!=(noteptr)0) {
+        if((exit_status = gethfnote(thisnote->pitch,*hf,hfnotecnt))<0)
+            return(exit_status);
+        if(*hfnotecnt >= size) {
+            size += BIGARRAY;
+            if((*hf = (double *)realloc((char *)(*hf),size * sizeof(double)))==NULL){
+                sprintf(errstr,"INSUFFICIENT MEMORY to reallocate harmonic field array.\n");
+                return(MEMORY_ERROR);
+            }
+        }
+        thisnote = thisnote->next;
+    }
+    if((*hf=(double *)realloc((char *)(*hf),*hfnotecnt * sizeof(double)))==NULL){
+        sprintf(errstr,"INSUFFICIENT MEMORY to reallocate harmonic field array.\n");
+        return(MEMORY_ERROR);
+    }
+    upsort(*hf,*hfnotecnt);
+    return(FINISHED);
+}
+
+/****************************** GEN_HS ***********************************
+ *
+ * Generate HS from a HF.
+ *
+ * NB This function assumes thas HF is ordered in ascending pitch order.
+ *
+ * (1)  Eliminate octave dupliates in hf.
+ * (2)  Initialise the HS count to zero.
+ * (3)  Start in the lowest octave.
+ * (4)  Go round loop generating HS, until we're out of (MIDI) range.
+ * (5)  Each time round loop, point to start of HF.
+ * (6)  And for all HF members, put them in HS + a (loop) number of 8ves,
+ *      counting the HS as we go.
+ * (7)  Once the pitch of any note exceeds MIDI upper limit (MIDITOP), break
+ *      from inner and (OK=0) outer loops.
+ * (8)  Each time round outer loop, increment octave.
+ * (9)  Reallocate the HS to the store 'hs'
+ */
+
+int gen_hs(double **hf,double **hs, int *hsnotecnt, int hfnotecnt)
+{
+    int n, m, k, thisoct, OK = 1;
+    int size = BIGARRAY;
+    double nextpitch;
+    double *thishf;
+    if((*hs)!=(double *)0)
+        free(*hs);
+    if((*hs = (double *)malloc(size * sizeof(double)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY for harmonic set array.\n");
+        return(MEMORY_ERROR);
+    }
+    for(n=0;n<hfnotecnt-1;n++) {            /* 1 */
+        for(m=n+1;m<hfnotecnt;m++) {
+            if(octeq((*hf)[n],(*hf)[m])) {
+                k = m + 1;
+                while(k < hfnotecnt) {
+                    (*hf)[k-1] = (*hf)[k];
+                    k++;
+                }
+                hfnotecnt--;
+                m--;
+            }
+        }
+    }
+    *hsnotecnt = 0;                                                 /* 2 */
+    thisoct = 0;                                            /* 3 */
+    while(OK) {                                                     /* 4 */
+        thishf = *hf;                                           /* 5 */
+        for(n=0;n<hfnotecnt;n++) {                                      /* 6 */
+            if((nextpitch = (*thishf++)+((double)thisoct*SEMITONES_PER_OCTAVE))<=MIDITOP) {
+                (*hs)[(*hsnotecnt)++] = nextpitch;
+                if(*hsnotecnt>=size) {
+                    size += BIGARRAY;
+                    if((*hs =(double *)realloc((char *)(*hs),size * sizeof(double)))==NULL) {
+                        sprintf(errstr,"INSUFFICIENT MEMORY to reallocate harmonic set array.\n");
+                        return(MEMORY_ERROR);
+                    }
+                }
+            } else {
+                OK = 0;                                         /* 7 */
+                break;
+            }
+        }
+        thisoct++;                                              /* 8 */
+    }
+    if((*hs=(double *)realloc((char *)(*hs),*hsnotecnt * sizeof(double)))==NULL){
+        sprintf(errstr,"INSUFFICIENT MEMORY to reallocate harmonic set array.\n");
+        return(MEMORY_ERROR);
+    }
+    return(FINISHED);
+}
+
+/**************************** CHEKREPEAT *********************************
+ *
+ * Flag if there is a repeated note in the source data.
+ */
+
+int chekrepeat(noteptr thisnote,double lastpitch)
+{
+    if(flteq((double)thisnote->pitch,lastpitch))
+        return(TRUE);
+    return(FALSE);
+}
+
+/****************************** GETNEXTHF ***********************************
+ *
+ * Get the harmonic field pertaining to this time, + 'hfnotecnt'.
+ *
+ * NB 2: THIS FUNCTION ASSUMES IN WILL BE ACCESSED IN TIME-INCREASING ORDER.
+ *
+ * (1)  Current time preset to zero.
+ * (2)  Nexttime to time of next hf in hf_data_motif.
+ * (3)  Static pointer points into current place in hf_data_motif.
+ * (3a) If noteptr points to zero w'ere
+        EITHER  we're at end of notelist: therefore no more HF data,
+                hence retain existing data.
+        OR      we have not initialised the noteptr, which should happen
+                on first call to this function, BUT in this case the
+                hfnotecnt will be zero as we have not yet created an HF.
+                In this case, error, exit.
+                * (4)  If time of function access still less than time of entry of next
+                *      harmonic field, do nothing (i.e. stay with current hf returning
+                *      current hfnotecnt).
+                * (5)  If time of function access is after time of next harmonic field
+                *      advance down hfs, until TOFA is before next hf (NB last time in
+                *      the hft[] is AFTER end of texture duration).
+                * (6)  Establish temporary storage space to read a new hf, and set the
+                *      hf pointer 'thishf' to point to it.
+                * (7)  Walk through the input notes until we get to notes corresponding
+                *      to time of the hf we want.
+                * (8)  Store the harmonic field in the temporary array.
+                * (9)  Free any existing hf.
+                * (10) Reallocate the new hf to the array hf[], and set the hf pointer
+                *      'thishf' to point at it.
+                * (11) Generate the associated HS !!!
+                */
+
+int getnexthf
+(double **hf,double **hs, int *hsnotecnt,double inputtime,int *hf_cnt,int *hfnotecnt,
+ noteptr *thishfnote,double *thishftime,double *nexthftime,int hfdatacnt,double *hft)
+{
+    int exit_status;
+    int size = BIGARRAY;
+    if(*thishfnote==(noteptr)0) {                                   /* 3a */
+        if(*hfnotecnt==0) {
+            sprintf(errstr,"INSUFFICIENT MEMORY for hfield notecount array.\n");
+            return(PROGRAM_ERROR);
+        }
+        return(TRUE);
+    }
+    if(inputtime<*nexthftime)                                       /* 4 */
+        return(FALSE);
+    while(*nexthftime<=inputtime) {                         /* 5 */
+        if(*hf_cnt>=hfdatacnt) {
+            sprintf(errstr,"INSUFFICIENT MEMORY for hfield count array.\n");
+            return(PROGRAM_ERROR);
+        }
+        *thishftime = *nexthftime;
+        *nexthftime = hft[*hf_cnt];
+        (*hf_cnt)++;
+    }
+    if(*hf!=(double *)0)                                            /* 9 */
+        free(*hf);
+    if((*hf = (double *)malloc(size * sizeof(double)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY for hfield array.\n");
+        return(MEMORY_ERROR);
+    }
+    while(!flteq((double)(*thishfnote)->ntime,*thishftime)) {               /* 7 */
+        if((*thishfnote = (*thishfnote)->next)==(noteptr)0) {
+            sprintf(errstr,"TEXTURE: Search problem in getnexthf()\n");
+            return(PROGRAM_ERROR);
+        }
+    }
+    *hfnotecnt = 0;
+    while(flteq((double)(*thishfnote)->ntime,*thishftime)) {                /* 8 */
+        if((exit_status = gethfnote((*thishfnote)->pitch,*hf,hfnotecnt))<0)
+            return(exit_status);
+        if(*hfnotecnt >= size) {
+            size += BIGARRAY;
+            if((*hf = (double *)realloc((char *)(*hf),size * sizeof(double)))==NULL) {
+                sprintf(errstr,"TEXTURE: realloc failed in getnexthf()\n");
+                return(PROGRAM_ERROR);
+            }
+        }
+        if((*thishfnote = (*thishfnote)->next)==(noteptr)0)
+            break;
+    }
+    if((*hf=(double *)realloc((char *)(*hf),*hfnotecnt * sizeof(double)))==NULL){
+        sprintf(errstr,"TEXTURE: getnexthf(): realloc() failed\n");     /* 10 */
+        return(PROGRAM_ERROR);
+    }
+    upsort(*hf,*hfnotecnt);
+    if((exit_status = gen_hs(hf,hs,hsnotecnt,*hfnotecnt))<0)  /* 11 */
+        return(exit_status);
+    return(TRUE);
+}
+
+/****************************** GETNEXTHS ***********************************
+ *
+ * Get the harmonic set pertaining to this time.
+ *
+ * NB 2: THIS FUNCTION ASSUMES IT WILL BE ACCESSED IN TIME-INCREASING ORDER.
+ *
+ * (3)  Static pointer points into current place in hf_data_motif.
+ * (3a) If noteptr points to zero w'ere
+        EITHER  we're at end of notelist: therefore no more HF data,
+                hence retain existing data.
+        OR      we have not initialised the noteptr, which should happen
+                on first call to this function, BUT in this case the
+                hsnotecnt will be zero as we have not yet created an HS.
+                In this case, error, exit.
+                * (4)  If time of function access still less than time of entry of next
+                *      harmonic set, do nothing (i.e. stay with current hs returning
+                *      current harmonic set cnt hsnotecnt).
+                * (5)  If time of function access is after time of next harmonic set
+                *      advance down HSs, until TOFA is before next hs (NB last time in
+                *      the hft[] is AFTER end of texture duration).
+                * (6)  Establish temporary storage space to read a new hs, and set the
+                *      hs pointer 'thishs' to point to it.
+                * (7)  Walk through the input notes until we get to notes corresponding
+                *      to time of the hs we want.
+                * (8)  Store the harmonic set in the temporary array.
+                * (9)  Free any existing hs.
+                * (10) Reallocate the new hs to the array hs[], and set the hs pointer
+                *      'thishs' to point at it.
+                */
+
+int getnexths
+(double **hs,double inputtime,int *hs_cnt,int *hsnotecnt,noteptr *thishsnote,
+ double *thishstime,double *nexthstime,int hfdatacnt,double *hft)
+{
+    int exit_status;
+    int size = BIGARRAY;
+    if(*thishsnote==(noteptr)0) {                           /* 3a */
+        if(*hsnotecnt==0) {
+            sprintf(errstr,"getnexths() not initialised\n");
+            return(PROGRAM_ERROR);
+        }
+        return(TRUE);
+    }
+    if(inputtime<*nexthstime)                                       /* 4 */
+        return(FALSE);
+    while(*nexthstime<=inputtime) {                         /* 5 */
+        if(*hs_cnt>=hfdatacnt) {
+            sprintf(errstr,"Timing problem in getnexths()\n");
+            return(PROGRAM_ERROR);
+        }
+        *thishstime = *nexthstime;
+        *nexthstime = hft[*hs_cnt];
+        (*hs_cnt)++;
+    }
+    if(*hs!=(double *)0)                                            /* 9 */
+        free(*hs);
+    if((*hs = (double *)malloc(size * sizeof(double)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY for harmonic set array.\n");
+        return(MEMORY_ERROR);
+    }
+
+    while(!flteq((double)(*thishsnote)->ntime,*thishstime)) {                       /* 7 */
+        if((*thishsnote = (*thishsnote)->next)==(noteptr)0) {
+            sprintf(errstr,"TEXTURE: Search problem in getnexths()\n");
+            return(PROGRAM_ERROR);
+        }
+    }
+    *hsnotecnt = 0;
+    while(flteq((double)(*thishsnote)->ntime,*thishstime)) {                        /* 8 */
+        if((exit_status = gethsnote((*thishsnote)->pitch,*hs,hsnotecnt))<0)
+            return(exit_status);
+        if(*hsnotecnt >= size) {
+            size += BIGARRAY;
+            if((*hs =(double *)realloc((char *)(*hs),size * sizeof(double)))==NULL) {
+                sprintf(errstr,"TEXTURE: realloc failed in getnexths()\n");
+                return(PROGRAM_ERROR);
+            }
+        }
+        if((*thishsnote = (*thishsnote)->next)==(noteptr)0)
+            break;
+    }
+    if((*hs=(double *)realloc((char *)(*hs),*hsnotecnt * sizeof(double)))==NULL){
+        sprintf(errstr,"TEXTURE: getnexths(): realloc() failed\n");/* 10 */
+        return(PROGRAM_ERROR);
+    }
+    upsort(*hs,*hsnotecnt);
+    return(TRUE);
+}
+
+/***************************** GETHSNOTE ************************************
+ *
+ * Read a note and store in harmonic SET,  IF not already there.
+ */
+
+int gethsnote(double thispitch,double *thishs,int *hsnotecnt)
+{
+    int n, OK = 0;
+    for(n=0;n<*hsnotecnt;n++) {
+        if(flteq(thispitch,thishs[n])) {
+            OK = 1;
+            break;
+        }
+    }
+    if(!OK)
+        thishs[*hsnotecnt] = (double)thispitch;
+    (*hsnotecnt)++;
+    return(FINISHED);
+}
+
+/***************************** READHFTIMES ************************************
+ *
+ * Read times at which successive harmonic fields(sets) enter, and store as list.
+ */
+
+int readhftimes(noteptr firstnote, int *hfdatacnt,double **hft)
+{
+    double lasttime, firsttime;
+    int arraysize = BIGARRAY;
+    noteptr thisnote = firstnote;
+    *hfdatacnt = 0;
+    if((*hft = (double *)malloc(arraysize * sizeof(double)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY for harmonic field times array.\n");
+        return(MEMORY_ERROR);
+    }
+    lasttime = thisnote->ntime;
+    (*hft)[0] = lasttime;
+    while(thisnote!=(noteptr)0) {
+        if(!flteq((double)thisnote->ntime,lasttime)) {
+            if(++(*hfdatacnt)>=arraysize-1) {
+                arraysize += BIGARRAY;
+                if((*hft = (double *)realloc((char *)(*hft),arraysize * sizeof(double)))==NULL) {
+                    sprintf(errstr,"INSUFFICIENT MEMORY to reallocate harmonic field times array.\n");
+                    return(PROGRAM_ERROR);
+                }
+            }
+            (*hft)[*hfdatacnt] = thisnote->ntime;
+            lasttime = thisnote->ntime;
+        }
+        thisnote = thisnote->next;
+    }
+    (*hft)[++(*hfdatacnt)] = DBL_MAX;                                       /* 1 */
+    (*hfdatacnt)++;
+    if((*hft = (double *)realloc((char *)(*hft),(*hfdatacnt) * sizeof(double)))==NULL){
+        sprintf(errstr,"INSUFFICIENT MEMORY to reallocate harmonic field times array.\n");
+        return(PROGRAM_ERROR);
+    }
+    if(!flteq(**hft,0.0)) {
+        fprintf(stdout,"WARNING: Harmonic Field Data: No field at ZERO time.\n"
+                "ADJUSTING FIRST FIELD TO ZERO TIME\n");
+        fflush(stdout);
+        thisnote  = firstnote;
+        firsttime = thisnote->ntime;
+        while(flteq(firsttime,**hft)) {
+            thisnote->ntime = 0.0f;
+            if((thisnote = thisnote->next)==(noteptr)0)
+                break;
+        }
+        **hft = 0.0;
+    }
+    return(FINISHED);
+}
+
+/***************************** DEL_GHOSTS ******************************
+ *
+ * Delete all tset notes MARKED for deletion in shadbits bitflag.
+ *
+ * (1)  For each byte in the bitflag...
+ * (2)  Set the bitmask to the first bit.
+ *   (3)  For every bit in this byte....
+ *   (4)  If this bit is set, delete the associated shadow (tset) note.
+ *   (5)  Advance the bitflag internal to the byte leftwards.
+ *   (6)  Advance the count of shadows, and if it reaches the total number
+ *        of shadows, exit, because remaining bits in this byte (if any)
+ *        have no meaning.
+ */
+
+void del_ghosts(int shshsize,char *shadbits,noteptr *shadow,int shadowsize,motifptr tset)
+{
+    int n,m,mask,k = 0;
+    for(n=0;n<shshsize;n++) {                               /* 1 */
+        mask = 1;                                                       /* 2 */
+        for(m=0;m<CHARBITSIZE;m++) {            /* 3 */
+            if(shadbits[n] & mask)                  /* 4 */
+                del_note(shadow[k],tset);
+            mask <<= 1;                                             /* 5 */
+            if(++k >= shadowsize)                   /* 6 */
+                return;
+        }
+    }
+}
+
+/************************** GET_HFGPPARAMS **************************
+ *
+ * Get the parameters for a group of notes.
+ *
+ * (0)  If pitch to decorate lies outside the HF range, return with gpsize
+ *      set to zero.
+ * (1)  If group range is expressed in HS-note units..
+ *   (a) Read the gprange as an integer number of (HS) notes.
+ *   (b) If HS-range exceeds HS limits, squeeze it.
+ *   (c) If HS-range is to be oriented about note, orient it appropriately.
+ * (2)  Otherwise...
+ *   (a) Read group range in normal way.
+ *   (b) If range exceeds HS limits, squeeze it.
+ *   (c) If range is to be oriented about note, orient it appropriately.
+ *   (d) If the range lies outside range of the HS,
+ *       set the groupsize to ZERO and return.
+ *   (e) Otherwise set the HS-range.
+ * (3)  Read group size.
+ * (4)  Read group density.
+ * (5)  number of midicliks in a gpdense time-interval.
+ * (6)  number of quantisation units, rounded.
+ * (7)  readjust gpdense to be number of units * length of units,
+ *      and reconvert to seconds.
+ */
+
+int get_hfgpparams(double thistime,double thispitch,double *hs,int hsnotecnt,
+                   int *gpsize,int *hfrange,int *hfgpranglo,int *hfgpranghi,double *gprange,double *gpdense,int mingrpsize,
+                   double *gprlow, int dectypecnt,unsigned char dectypestor,dataptr dz)
+{
+    int exit_status;
+    if(thispitch<hs[0] || thispitch>hs[hsnotecnt-1]) {
+        *gpsize = 0;                                            /* 0 */
+        return(FINISHED);
+    }
+    if((exit_status = igetvalue(TEX_GPRANGHI,TEX_GPRANGLO,thistime,PM_GPRANG,hfrange,dz))<0)
+        return(exit_status);
+
+    if(!dectypecnt) {
+        hfsqueezrange(thispitch,hfrange,hfgpranghi,hfgpranglo,hsnotecnt,hs);                                    /* b */
+        dz->vflag[DECCENTRE] = FALSE;
+    } else {
+        if((exit_status = hforientrange
+            (thispitch,hfrange,hfgpranghi,hfgpranglo,hsnotecnt,hs,dectypecnt,dectypestor,dz))<0) /* c */
+            return(exit_status);
+    }
+    /* OCT 17 : hfgpranghi,lo are max & min INDECES within the harmonic field */
+
+    *hfrange = *hfgpranghi - *hfgpranglo;                   /* e */
+
+    /* OCT 17 : FROM hfgpranghi,lo the actual PITCH values can be deduced */
+    *gprlow  = hs[*hfgpranglo];
+    *gprange = hs[*hfgpranghi] - hs[*hfgpranglo];
+
+    if((exit_status  = igetvalue(TEX_GPSIZEHI,TEX_GPSIZELO,thistime,PM_GPSIZE,gpsize,dz))<0)
+        return(exit_status);
+
+    if(*gpsize  < mingrpsize) {
+        sprintf(errstr,"TEXTURE: Impossible GROUP SIZE value [%d]: get_hfgpparams()\n",*gpsize);
+        return(PROGRAM_ERROR);
+    }
+
+    if((exit_status = getvalue(TEX_GPPACKHI,TEX_GPPACKLO,thistime,PM_GPDENS,gpdense,dz))<0)
+        return(exit_status);
+    /* NEW MAR 2000 */
+    *gpdense *= MS_TO_SECS;
+
+    if(dz->param[TEX_PHGRID]>0.0)
+        *gpdense = quantise(*gpdense,dz->param[TEX_PHGRID]);
+    return(FINISHED);
+}
+
+/***************************  HFSQUEEZRANGE ******************************
+ *
+ * Adjust range to lie within HF limits.
+ *
+ * (2)  Top of range is at current pitch's HF index (approx). If this is
+ *      above current top-of-HF range (hsnotecnt) move top down.
+ * (3)  Bottom of range is igprange below top. If this is below
+ *      bottom-of-HF (0), move igprlow up.
+ * (4)  Recalculate the true igprange within true limits.
+ */
+
+void hfsqueezrange(double thispitch,int *hfrange,int *hfgpranghi,int *hfgpranglo,int hsnotecnt,double *hs)
+{
+    int halfrange = *hfrange/2;
+    if(halfrange * 2 != *hfrange)
+        halfrange++;
+    *hfgpranghi = min((geths_hibnd(thispitch,hsnotecnt,hs)+halfrange),hsnotecnt);   /* 2 */
+    *hfgpranglo = max((*hfgpranghi - *hfrange),0);                                                  /* 3 */
+    *hfrange = *hfgpranghi - *hfgpranglo;                                                                   /* 4 */
+}
+
+/****************************** GETHS_HIBND **********************************
+ *
+ *      hibnd >= pitch
+ *
+ * Find the index of the harmonic-set note that is immediately above or
+ * equal to the input pitch.
+ *
+ * NB CALL WITH geths_hibnd((double)thisnote->pitch);
+ *
+ * If the pitch is beyond the HS, n returns the value 'hsnotecnt'.
+ */
+
+int geths_hibnd(double thispitch,int hsnotecnt,double *hs)
+{
+    int n;
+    for(n=0;n<hsnotecnt;n++) {
+        if(hs[n]>thispitch || flteq(hs[n],thispitch))
+            break;
+    }
+    return(n);                              /* 1 */
+}
+
+/***************************  HFORIENTRANGE ******************************
+ *
+ * As orientrange() but applied to HF/HS case.
+ */
+
+int hforientrange
+(double thispitch,int *hfrange,
+ int *hfgpranghi,int *hfgpranglo,int hsnotecnt,double *hs,int dectypecnt,unsigned char dectypestor,dataptr dz)
+{
+    int exit_status;
+    unsigned char dectype;
+    int k;
+    if((exit_status=doperm((int)dectypecnt,PM_ORIENT,&k,dz))<0)
+        return(exit_status);
+    if((exit_status=gettritype(k,dectypestor,&dectype))<0)
+        return(exit_status);
+    switch(dectype) {
+    case(0):                        /* centred range */
+        hfsqueezrange(thispitch,hfrange,hfgpranghi,hfgpranglo,hsnotecnt,hs);
+        dz->vflag[DECCENTRE] = TRUE;
+        break;
+    case(1):                        /* range above note */
+        *hfgpranghi = min((geths_hibnd(thispitch,hsnotecnt,hs) + *hfrange),hsnotecnt);
+        *hfgpranglo = max((*hfgpranghi - *hfrange),0);
+        *hfrange    = *hfgpranghi - *hfgpranglo;
+        dz->vflag[DECCENTRE] = FALSE;
+        break;
+    case(2):                        /* range below note */
+        *hfgpranghi = geths_hibnd(thispitch,hsnotecnt,hs);
+        *hfgpranglo = max((*hfgpranghi - *hfrange),0);
+        *hfrange    = *hfgpranghi - *hfgpranglo;
+        dz->vflag[DECCENTRE] = FALSE;
+        break;
+    default:
+        sprintf(errstr,"TEXTURE: Problem in hforientrange()\n");
+        return(PROGRAM_ERROR);
+    }
+    return(FINISHED);
+}
+
+/****************************** GETHS_ABOVE **********************************
+ *
+ *      above > pitch
+ *
+ * Find the index of the harmonic-set note that is immediately above
+ * the input pitch.
+ *
+ * NB CALL WITH geths_above((double)thisnote->pitch);
+ *
+ * If the pitch is beyond the HS, n gets the value 'hsnotecnt', which becomes
+ * the upper limit of the search range for doperm() ensuring that highest
+ * possible HSindex val is hsnotecnt-1, the highest pitch in the HS.
+ */
+
+int geths_above(double thispitch,double *hs,int hsnotecnt)
+{
+    int n;
+    for(n=0;n<hsnotecnt;n++) {
+        if(hs[n]>thispitch)
+            break;
+    }
+    return(n);                                      /* 1 */
+}
+
+/****************************** GENERATE_GROUP_NOTE **********************************/
+
+int generate_group_note
+(noteptr thisnote,noteptr tsetnote,double thistime,int hfrange,int hfgpranglo,
+ double *hs,int *hsindex,int gpsize,dataptr dz)
+{
+    int exit_status;
+    unsigned char thisinstr;
+    if((exit_status = do_grp_ins(tsetnote->instr,&thisinstr,dz))<0)
+        return(exit_status);
+    thisnote->instr = thisinstr;
+    thisnote->motioncentre = tsetnote->motioncentre;
+    if((exit_status = hfscat(hfrange,hfgpranglo,PM_GPPICH,hsindex,dz))<0)
+        return(exit_status);
+    thisnote->pitch  = (float)hs[*hsindex];         /* 7 */
+    thisnote->ntime  = (float)thistime;
+    return setspace(tsetnote,thisnote,gpsize,dz);
+}
+
+/******************************* HFSCAT ***********************************
+ *
+ * A weighted version of hfscatx().
+ */
+
+int hfscat(int prange,int pbottom,int permindex,int *val,dataptr dz)
+{
+    int exit_status;
+    double bandbottom,  bandtop,  bandwidth;
+    int   ibandbottom, ibandtop, ibandwidth, k;
+    if(prange<=LAYERCNT) {
+        if((exit_status = doperm((int)prange,permindex,&k,dz))<0)
+            return(exit_status);
+        *val = k + pbottom;
+        return(FINISHED);
+
+    }
+    if((exit_status = doperm((int)BANDCNT,permindex,&k,dz))<0)
+        return(exit_status);
+    bandwidth = (double)prange/(double)LAYERCNT;
+    switch(k) {
+    case(0):
+        bandbottom = 0;
+        break;
+    case(BANDCNT-1):
+        bandbottom = (double)(LAYERCNT-1) * bandwidth;
+        break;
+    default:
+        bandbottom = bandwidth + ((double)((k-1) * 2) * bandwidth);
+        bandwidth *= 2.0;
+        break;
+    }
+    bandtop     = bandbottom + bandwidth;
+    ibandtop    = round(bandtop);
+    ibandbottom = round(bandbottom);
+    ibandwidth  = ibandtop - ibandbottom;
+    k  = (int)(drand48() * (double)ibandwidth);
+    k += ibandbottom;
+    k += pbottom;
+    *val = k;
+    return(FINISHED);
+}
+
+/****************************** GENERATE_DECOR_NOTE **********************************/
+
+int generate_decor_note(noteptr thisnote,noteptr tsetnote,
+                        double thispitch,double thistime,int hfrange,int hfgpranghi,int hfgpranglo,double *hs,int *hsindex,
+                        int hsnotecnt,double gprlow,double gprange,int gpsize,dataptr dz)
+{
+    int exit_status;
+    double val;
+    if((exit_status = do_grp_ins(tsetnote->instr,&thisnote->instr,dz))<0)
+        return(exit_status);
+    thisnote->motioncentre = tsetnote->motioncentre;
+    if(dz->vflag[DECCENTRE]) {
+        if((exit_status = dec_hfcentre
+            (thispitch,hs,hsnotecnt,hfrange,hfgpranghi,hfgpranglo,gprlow,gprange,gpsize,&val,dz))<0)
+            return(exit_status);
+        thisnote->pitch = (float)val;
+    } else {
+        if((exit_status = hfscat(hfrange,hfgpranglo,PM_GPPICH,hsindex,dz))<0)
+            return(exit_status);
+        thisnote->pitch  = (float)hs[*hsindex];
+    }
+    thisnote->ntime  = (float)(thistime);
+    return setspace(tsetnote,thisnote,gpsize,dz);
+}
+
+/************************* DEC_HFCENTRE *******************************/
+
+int dec_hfcentre(double tsetpitch,double *hs,int hsnotecnt,int hfrange,int hfgpranghi,int hfgpranglo,
+                 double gprlow,double gprange,int gpsize,double *val,dataptr dz)
+{
+    int exit_status;
+    double a, gprhi = gprlow + gprange;
+    int s, save, k, hfcentre, n_above, n_below, hsindex;
+    if(tsetpitch-gprlow<=FLTERR || flteq(tsetpitch,gprhi)) {
+        if((exit_status = hfscatx(hfrange,hfgpranglo,PM_GPPICH,&hsindex,dz))<0)
+            return(exit_status);
+        *val = hs[hsindex];
+        return(FINISHED);                                       /* 1 */
+    }
+    n_below = hfrange/2;                                    /* 2 */
+    if(((n_above=n_below)+n_below)!=hfrange)
+        n_above++;
+    if(((hfcentre =geths_hibnd(tsetpitch,hsnotecnt,hs)) + n_above) > hsnotecnt)
+        n_above = hsnotecnt - hfcentre;                         /* 3 */
+    if(hfcentre - n_below < 0)
+        n_below = hfcentre;                                     /* 4 */
+    if(n_above<=0 || n_below<=0) {
+        if((exit_status = hfscatx(hfrange,hfgpranglo,PM_GPPICH,&hsindex,dz))<0)
+            return(exit_status);
+        else {
+            *val = hs[hsindex];
+            return(FINISHED);                                       /* 5 */
+        }
+    }
+    save = dz->iparray[TXREPETCNT][PM_DECABV];                                              /* 6 */
+    k = (gpsize+1)/2;
+    if(dz->iparray[TXREPETCNT][PM_DECABV]>k)
+        dz->iparray[TXREPETCNT][PM_DECABV] = k;
+    if((exit_status = doperm((int)2,PM_DECABV,&s,dz))<0)
+        return(exit_status);
+    if(s) {
+        if((exit_status = hfscatx(n_above,hfgpranghi - n_above,PM_GPPICH,&hsindex,dz))<0)
+            return(exit_status);
+    } else {
+        if((exit_status = hfscatx(n_below,hfgpranglo,PM_GPPICH2,&hsindex,dz))<0)
+            return(exit_status);
+    }
+    dz->iparray[TXREPETCNT][PM_DECABV] = save;
+    a = hs[hsindex];
+    if(a<MIDIBOT || a>MIDITOP) {
+        sprintf(errstr,"TEXTURE: Problem in dec_hfcentre()\n");
+        return(PROGRAM_ERROR);
+    }
+    *val = a;
+    return(FINISHED);
+}
+
+/******************************* HFSCATX ***********************************
+ *
+ * As pscat, but working with ranges of integers, especially the indeces
+ * of an HS.
+ */
+
+int hfscatx(int prange,int pbottom,int permindex,int *val,dataptr dz)
+{
+    int exit_status;
+    double bandbottom,  bandtop,  bandwidth;
+    int   ibandbottom, ibandtop, ibandwidth, k;
+    if(prange<=BANDCNT) {
+        if((exit_status = doperm((int)prange,permindex,val,dz))<0)
+            return(exit_status);
+        *val += pbottom;
+        return(FINISHED);
+    }
+    if((exit_status = doperm((int)BANDCNT,permindex,val,dz))<0)
+        return(exit_status);
+    k = *val;
+    bandwidth   = (double)prange/(double)BANDCNT;
+    bandbottom  = (double)k     * bandwidth;
+    bandtop     = (double)(k+1) * bandwidth;
+    ibandbottom = round(bandbottom);
+    ibandtop    = round(bandtop);
+    ibandwidth  = ibandtop - ibandbottom;
+    k  = (int)(drand48() * (double)ibandwidth);
+    k += ibandbottom;
+    *val = k + pbottom;
+    return(FINISHED);
+}
+
+/******************************** SET_SHADBIT ****************************
+ *
+ * Set a bit in the shadow's bitfag.
+ */
+
+void set_shadbit(int k,char *shadbits)
+{
+    int bitunit  = k/CHARBITSIZE;
+    int bitshift = k % 8;
+    int mask = 1;
+    mask <<= bitshift;
+    shadbits[bitunit] |= mask;
+}
+
+/****************************** GETHS_LOBND **********************************
+ *
+ *      lobnd =< pitch
+ *
+ * Find the index of the harmonic-set note that is immediately below, or
+ * equal to the input pitch.
+ *
+ * NB CALL WITH geths_lobnd((double)thisnote->pitch);
+ *
+ * NB: If the entered pitch is lower than the entire HS, function returns -1.
+ */
+
+int geths_lobnd(double thispitch,double *hs,int hsnotecnt)
+{
+    int n;
+    for(n=0;n<hsnotecnt;n++) {
+        if(hs[n]>thispitch)
+            break;
+    }
+    return(--n);                                    /* 1 */
+}
+
+/***************************** GETHFNOTE ************************************
+ *
+ * Read a note and store in harmonic field IF not already there.
+ */
+
+int gethfnote(double thispitch,double *hf,int *hfnotecnt)
+{
+    int n, OK  = 0;
+    float notetransp = (float)fmod(thispitch,SEMITONES_PER_OCTAVE);
+    if(flteq((double)notetransp,0.0))
+        notetransp = (float)(notetransp + SEMITONES_PER_OCTAVE);
+    for(n=0;n<*hfnotecnt;n++) {
+        if(flteq((double)notetransp,hf[n])) {
+            OK = 1;
+            break;
+        }
+    }
+    if(!OK)
+        hf[*hfnotecnt] = (double)notetransp;
+    (*hfnotecnt)++;
+    return(FINISHED);
+}
+
+/**************************** SETMTFPARAMS *******************************
+ *
+ * Establish easy parameters of motif or ornament.
+ */
+
+int setmtfparams
+(noteptr thisnote,double thisamp,noteptr phrasenote,noteptr tsetnote,double ampdif,double notetime,
+ int gpsize,double multiplier,dataptr dz)
+{
+    int exit_status;
+    if((exit_status = do_mtf_params(thisnote,thisamp,phrasenote,tsetnote,ampdif,notetime,multiplier,dz))<0)
+        return(exit_status);
+    return setspace(tsetnote,thisnote,gpsize,dz);
+}
+
+/**************************** INITIALISE_HFPHRASES *******************************/
+
+int initialise_hfphrases
+(int ***hfphrase,int **endhsindex,int **phrnotecnt,double **phraseamp,double **phrange,
+ noteptr **phrlastnote,dataptr dz)
+{
+    if((*hfphrase = (int **)malloc(dz->tex->phrasecnt * sizeof(int *)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY for harmonic field phrases.\n");
+        return(MEMORY_ERROR);
+    }
+    if((*endhsindex = (int *)malloc(dz->tex->phrasecnt * sizeof(int)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY for harmonic set indices.\n");
+        return(MEMORY_ERROR);
+    }
+    if((*phrnotecnt = (int *)malloc(dz->tex->phrasecnt * sizeof(int)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY for harmonic field phrase notecnt.\n");
+        return(MEMORY_ERROR);
+    }
+    if((*phraseamp = (double *)malloc(dz->tex->phrasecnt * sizeof(double)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY for phrase amplitude array.\n");
+        return(MEMORY_ERROR);
+    }
+    if((*phrange  = (double *)malloc(dz->tex->phrasecnt * sizeof(double)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY for phrase range array.\n");
+        return(MEMORY_ERROR);
+    }
+    if((*phrlastnote = (noteptr *)malloc(dz->tex->phrasecnt * sizeof(noteptr)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY for phrase lastnote array.\n");
+        return(MEMORY_ERROR);
+    }
+    return(FINISHED);
+}
+
+/****************************** GET_FIRST_HS ***********************************
+ *
+ * Extract HS from input data.
+ */
+
+int get_first_hs(noteptr thisnote,double **hs,int *hsnotecnt)
+{
+    int exit_status;
+    int size = BIGARRAY;
+    noteptr startnote = thisnote;
+    double thistime = 0.0;
+    if((*hs = (double *)malloc(BIGARRAY * sizeof(double)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY for harmonic set array.\n");
+        return(MEMORY_ERROR);
+    }
+    while(thisnote!=(noteptr)0) {
+        if((exit_status = gethsnote(thisnote->pitch,*hs,hsnotecnt))<0)
+            return(exit_status);
+        if(thisnote==startnote)
+            thistime = thisnote->ntime;
+        else {
+            if(!flteq((double)thisnote->ntime,thistime)) {
+                (*hsnotecnt)--;
+                break;
+            }
+        }
+        if(*hsnotecnt >= BIGARRAY) {
+            size += BIGARRAY;
+            if((*hs=(double *)realloc((char *)(*hs),size * sizeof(double)))==NULL){
+                sprintf(errstr,"INSUFFICIENT MEMORY to reallocate harmonic set array.\n");
+                return(MEMORY_ERROR);
+            }
+        }
+        thisnote = thisnote->next;
+    }
+    if((*hs=(double *)realloc((char *)(*hs),*hsnotecnt*sizeof(double)))==NULL){
+        sprintf(errstr,"INSUFFICIENT MEMORY to reallocate harmonic set array.\n");
+        return(MEMORY_ERROR);
+    }
+    upsort(*hs,*hsnotecnt);
+    return(FINISHED);
+}
+
+/****************************** GET_FIRST_HF ***********************************
+ *
+ * Extract first HF from input data.
+ */
+
+int get_first_hf(noteptr thisnote,double **hf,int *hfnotecnt)
+{
+    int exit_status;
+    int size = BIGARRAY;
+    noteptr startnote = thisnote;
+    double thistime = 0.0;
+
+    if((*hf = (double *)malloc(size * sizeof(double)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY for harmonic field array.\n");
+        return(MEMORY_ERROR);
+    }
+    while(thisnote!=(noteptr)0) {
+        if((exit_status = gethfnote(thisnote->pitch,*hf,hfnotecnt))<0)
+            return(exit_status);
+        if(thisnote==startnote)
+            thistime = thisnote->ntime;
+        else {
+            if(!flteq((double)thisnote->ntime,thistime)) {
+                (*hfnotecnt)--;
+                break;
+            }
+        }
+        if(*hfnotecnt >= size) {
+            size += BIGARRAY;
+            if((*hf = (double *)realloc((char *)(*hf),size * sizeof(double)))==NULL){
+                sprintf(errstr,"INSUFFICIENT MEMORY to reallocate harmonic field array.\n");
+                return(MEMORY_ERROR);
+            }
+        }
+        thisnote = thisnote->next;
+    }
+    if((*hf=(double *)realloc((char *)(*hf),*hfnotecnt * sizeof(double)))==NULL){
+        sprintf(errstr,"INSUFFICIENT MEMORY to reallocate harmonic field array.\n");
+        return(MEMORY_ERROR);
+    }
+    upsort(*hf,*hfnotecnt);
+    return(FINISHED);
+}
+
+/******************************** OCTEQ *************************************/
+
+int octeq(double a,double b)
+{
+    a = fmod(a,12.0);
+    b = fmod(b,12.0);
+    if(flteq(a,b)) {
+        return(1);
+    }
+    return(0);
+}

+ 1477 - 0
dev/texture/prevsrc/prev-src/texture4.c

@@ -0,0 +1,1477 @@
+/*
+ * Copyright (c) 1983-2013 Trevor Wishart and Composers Desktop Project Ltd
+ * http://www.trevorwishart.co.uk
+ * http://www.composersdesktop.com
+ *
+ This file is part of the CDP System.
+
+ The CDP System is free software; you can redistribute it
+ and/or modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The CDP System is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the CDP System; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA
+ *
+ */
+
+
+
+/* floatsam version : no changes */
+#include <stdio.h>
+#include <stdlib.h>
+#include <float.h>
+#include <structures.h>
+#include <tkglobals.h>
+#include <globcon.h>
+#include <processno.h>
+#include <modeno.h>
+#include <arrays.h>
+#include <texture.h>
+#include <cdpmain.h>
+
+#include <sfsys.h>
+#include <osbind.h>
+
+#if defined unix || defined __GNUC__
+#define round(x) lround((x))
+#endif
+
+/**** ALL FUNCTIONS WHICH ARE GLOBAL TO ALL PROCESS FUNCTIONS TYPES ***/
+
+/* Functions which are global to all texture applications.
+ */
+static void orn_subzero(double *thistime,noteptr phrlastnote,noteptr *phrasenote,
+                        double *timeadjust,double multiplier,int *gpsize);
+static int  getmtfampstep
+(double amp,double framp,double *ampstep,unsigned char *amptype,
+ unsigned char amptypestor,unsigned char amptypecnt,int gpsize,dataptr dz);
+static int  space_gpnote(noteptr thisnote,int gpsize,dataptr dz);
+static int  sp_scatter(noteptr mnote,dataptr dz);
+static int  pre_place(noteptr thisnote,int gpsize,dataptr dz);
+static int  post_place(noteptr thisnote,int gpsize,dataptr dz);
+static int  read_direction(int shi,noteptr *shadow,int shadowsize);
+
+static int  do_ev_ins(unsigned char *thisinstr,double thistime,dataptr dz);
+static int  do_ev_amp(double *thisamp,double thistime,dataptr dz);
+static int  do_ev_dur(double *thisdur,double thistime,dataptr dz);
+static int  getdirampstep
+(double amp,unsigned char amptypecnt,double *ampstep,int gpsize,dataptr dz);
+static int  getampstep
+(double *ampstep,double amp,unsigned char *amptype,int gpsize,unsigned char amptypecnt,
+ unsigned char amptypestor,dataptr dz);
+static int  get_dec_or_orn_pos(dataptr dz);
+
+static int  subzero(double *thistime,double gpdense,int *gpsize);
+
+static noteptr reverse_search_for_time(noteptr start,double reftime);
+static void    move_notelist_item(noteptr a,noteptr b);
+static double  setup_first_notelist_time(noteptr *base);
+static int     reset_mtfhead(motifptr mtf);
+static int         post_place(noteptr thisnote,int gpsize,dataptr dz);
+static int     getmtfdirampstep
+(double amp,double framp,unsigned char amptypecnt,double *ampstep,int gpsize,dataptr dz);
+static void cyclicperm(dataptr dz);
+static void hinsert(int m,int t,int *perm,int permlen);
+static void hprefix(int m,int *perm,int permlen);
+static void hshuflup(int k,int *perm,int permlen);
+
+/***************************** OCTADJUST *****************************
+ *
+ * Check for range overflow of pitch.
+ */
+
+double octadjust(double thispitch)
+{
+    if(thispitch>MIDITOP)
+        thispitch -= SEMITONES_PER_OCTAVE;
+    if(thispitch<MIDIBOT)
+        thispitch += SEMITONES_PER_OCTAVE;
+    return(thispitch);
+}
+
+/***************************** DO_AMP_INSTR_DUR ************************************/
+
+int do_amp_instr_dur
+(double *thisamp,unsigned char *thisinstr,double *thisdur,noteptr tsetnote,double thistime,dataptr dz)
+{
+    int exit_status;
+    if((exit_status = do_ev_amp(thisamp,thistime,dz))<0)
+        return(exit_status);
+    tsetnote->amp = (float)(*thisamp);
+    if((exit_status = do_ev_ins(thisinstr,thistime,dz))<0)
+        return(exit_status);
+    tsetnote->instr = *thisinstr;
+    if((exit_status = do_ev_dur(thisdur,thistime,dz))<0)
+        return(exit_status);
+    tsetnote->dur = (float)(*thisdur);
+    return(FINISHED);
+}
+
+/********************** DO_EV_INS *******************************
+ *
+ * Set instrument of event (not group etc.).
+ *
+ * (0)  If instruments in ornament or decoration are to be relative to
+ *      input instr, return this input instrument.
+ * (1)  If there is a pre-existing timed set (pretimed = 1).
+ * (2)  Negative value causes original value to be replaced
+ *      by orig + abs(neg value).
+ *      Zero value, by default, causes orig value to be retained.
+ */
+
+int do_ev_ins(unsigned char *thisinstr,double thistime,dataptr dz)
+{
+    int exit_status;
+    int instrval;
+    if(dz->process == SIMPLE_TEX && dz->vflag[CYCLIC_TEXFLAG]) {
+        if(dz->itemcnt == dz->infilecnt)
+            dz->itemcnt = 0;
+        if(dz->vflag[PERM_TEXFLAG]) {
+            if(dz->itemcnt == 0)
+                cyclicperm(dz);
+            *thisinstr = (unsigned char)dz->peakno[dz->itemcnt];
+        } else {
+            *thisinstr = (unsigned char)dz->itemcnt;
+        }
+        dz->itemcnt++;
+    } else {
+        if((exit_status = igetvalue(TEXTURE_INSHI,TEXTURE_INSLO,thistime,PM_INSNO,&instrval,dz))<0)
+            return(exit_status);
+        *thisinstr = (unsigned char)instrval;
+    }
+    return(FINISHED);
+}
+
+/********************** DO_EV_AMP ********************************/
+
+int do_ev_amp(double *thisamp,double thistime,dataptr dz)
+{
+    int exit_status;
+    if((exit_status = getvalue(TEXTURE_MAXAMP,TEXTURE_MINAMP,thistime,PM_AMP,thisamp,dz))<0)
+        return(exit_status);
+
+    *thisamp *= dz->param[TEXTURE_ATTEN];
+
+    if(*thisamp>MIDITOP + 0.5) {
+        sprintf(errstr,"TEXTURE: amplitude [%.1f] out of midirange at time %.2f\n",*thisamp,thistime);
+        return(DATA_ERROR);
+    }
+    return(FINISHED);
+}
+
+/********************** DO_EV_DUR ********************************/
+
+int do_ev_dur(double *thisdur,double thistime,dataptr dz)
+{
+    int exit_status;
+    if((exit_status = getvalue(TEXTURE_MAXDUR,TEXTURE_MINDUR,thistime,PM_DUR,thisdur,dz))<0)
+        return(exit_status);
+    return(FINISHED);                                       /* 4 */
+}
+
+/************************ MAKE_SHADOW ****************************
+ *
+ * Store addresses of original tset notes.
+ */
+
+int make_shadow(motifptr tset,int *shadowsize,noteptr **shadow)
+{
+    noteptr *sh, thisnote = tset->firstnote;
+    int n;
+    *shadowsize     = 0;
+    while(thisnote!=(noteptr)0) {
+        (*shadowsize)++;
+        thisnote = thisnote->next;
+    }
+    if((sh = *shadow = (noteptr *)malloc((*shadowsize) * sizeof(noteptr)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY for shadow.\n");
+        return(MEMORY_ERROR);
+    }
+    thisnote = tset->firstnote;
+    n = 0;
+    while(thisnote!=(noteptr)0) {
+        sh[n++]  = thisnote;
+        thisnote = thisnote->next;
+    }
+    return(FINISHED);
+}
+
+/************************ ERASE_SHADOW ****************************
+ *
+ * Erase original tset from resultant list.
+ *
+ * (0)  Assuming shadow starts at start of tset, if first note of
+ *      shadow is deleted, del_note automatically resets motifptr (tset)
+ *      to next note (and so on).
+ * (1)  In case shadow started AFTER start of tset (should be impossible!!)
+ *      reset pointer to start of remaining motif !
+ */
+
+int erase_shadow(int shadowsize,noteptr *shadow,motifptr tset)
+{
+    int n;
+    noteptr thisnote;
+    for(n=0;n<shadowsize;n++)                                       /* 0 */
+        del_note(shadow[n],tset);
+    if((thisnote = tset->firstnote->last)!=(noteptr)0) {    /* 1 */
+        sprintf(errstr,"TEXTURE: erase_shadow(): First note of shadow NOT first note of tset.\n"
+                "This should never happen\n");
+        return(PROGRAM_ERROR);
+        /**** REMOVED FOLLOWING AUTO-CORRECTION CODE : OCT 1997 *****
+              while(thisnote->last!=(noteptr)0)
+              thisnote = thisnote->last;
+              tset->firstnote = thisnote;
+        ****/
+    }
+    return(FINISHED);
+}
+
+/************************ SETUP_DECOR ****************************/
+
+void setup_decor(double *pptop,double *ppbot,int *shadindex,noteptr *tsetnote,dataptr dz)
+{
+    *pptop = MIDITOP;
+    *ppbot = MIDIBOT;
+    if(dz->vflag[WHICH_CHORDNOTE]==DECOR_HIGHEST)
+        *tsetnote = gethipitch(*tsetnote,shadindex);
+}
+
+/**************************** SETUP_ORNAMENT *********************************/
+
+int setup_ornament
+(double *timeadjust,double *thistime,int *gpsize,noteptr *phrlastnote,
+ double multiplier,noteptr *phrasenote,int phrno,dataptr dz)
+{
+    int exit_status;
+    double origtime;
+    if((exit_status = get_dec_or_orn_pos(dz))<0)
+        return(exit_status);
+    *timeadjust = 0.0;
+    if(dz->vflag[IS_PRE]) {
+        origtime = *thistime;
+        if((*thistime -= (phrlastnote[phrno])->ntime * multiplier)<0.0) {
+            *thistime = origtime;
+            orn_subzero(thistime,phrlastnote[phrno],phrasenote,timeadjust,multiplier,gpsize);
+        }
+    }
+    return(FINISHED);
+}
+
+/**************************** SET_MOTIF_AMP *********************************/
+
+int set_motif_amp
+(noteptr tsetnote,double *thisamp,int gpsize,double ampstep,noteptr phrasenote,double rangemult,
+ double *phraseamp,int phrno,unsigned char amptype)
+{
+    double ampdif;
+    if(amptype==CRESC) {
+        *thisamp -= (double)(gpsize) * ampstep;
+        ampdif    = (phraseamp[phrno] - phrasenote->amp) * rangemult;
+        tsetnote->amp = (float)(*thisamp - ampdif);
+    }
+    return(FINISHED);
+}
+
+/**************************** SET_ORNAMENT_AMP *********************************/
+
+int set_ornament_amp
+(double *phraseamp,noteptr *phrlastnote,double *thisamp,
+ noteptr phrasenote,int phrno,noteptr tsetnote,
+ double ampstep,double rangemult,int gpsize,dataptr dz)
+{
+    double ampdif;
+    if(dz->vflag[IS_PRE])
+        ampdif=(phraseamp[phrno]-phrlastnote[phrno]->amp) * rangemult;
+    else
+        ampdif=(phraseamp[phrno]-phrasenote->amp) * rangemult;
+    tsetnote->amp -= (float)ampdif;
+    if(ampstep>0.0) /* CRESCENDO */
+        *thisamp -= (double)(gpsize+1) * ampstep;
+    return(FINISHED);
+}
+
+/**************************** CHECK_NEXT_PHRASENOTE_EXISTS *********************************/
+
+int check_next_phrasenote_exists(noteptr *phrasenote,int texflag,dataptr dz)
+{
+    if(texflag & IS_MOTIFS) {
+        if((*phrasenote = (*phrasenote)->next)==(noteptr)0) {
+            sprintf(errstr,"TEXTURE: Accounting Problem in check_next_phrasenote_exists()\n");
+            return(PROGRAM_ERROR);
+        }
+    } else if (texflag & IS_ORNATE){
+        if(*phrasenote==(noteptr)0) {
+            sprintf(errstr,"TEXTURE: 1st Accounting Problem in check_next_phrasenote_exists()\n");
+            return(PROGRAM_ERROR);
+        }
+        if(dz->vflag[IS_PRE] && ((*phrasenote)->next==(noteptr)0)) {
+            sprintf(errstr,"TEXTURE: 2nd Accounting Problem in check_next_phrasenote_exists()\n");
+            return(PROGRAM_ERROR);
+        }
+    }
+    return(CONTINUE);
+}
+
+/************************* GETNEXTEVENT_TO_DECORATE ***************************
+ *
+ * Get the next event in list, i.e. skip over simultaneous events
+ * (e.g. chords).
+ *
+ * (0)  If flagged as 2, ornaments/decorations are attached to EVERY note
+ *      so the next event is just the next note in the tset.
+ *      OTHERWISE we search for the next event AT A NEW TIME.
+ * (1)  If flagged, force a search for the highest note of a simultaneous
+ *      group (chord). Hence ornament/dec attaches to highest note.
+ *      Otherwise, ornament attached to first listed note of chord in input
+ *      data.
+ */
+
+noteptr getnextevent_to_decorate(noteptr tsetnote,int *shaddoindex,dataptr dz)
+{
+    if(dz->vflag[WHICH_CHORDNOTE]==DECOR_EVERY)                                             /* 0 */
+        return(tsetnote->next);
+    while(tsetnote->next!=(noteptr)0) {
+        tsetnote = tsetnote->next;
+        (*shaddoindex)++;
+        if(!flteq((double)tsetnote->ntime,(double)tsetnote->last->ntime)) {
+            if(dz->vflag[WHICH_CHORDNOTE]==DECOR_HIGHEST)
+                tsetnote = gethipitch(tsetnote,shaddoindex);    /* 1 */
+            return(tsetnote);
+        }
+    }
+    return((noteptr)0);
+}
+
+/************************** GETNOTETIME ********************************
+ *
+ * Get actual time of note, from time of tset note, and time of motif
+ * or ornament note.
+ * (a)  Time is set by an offset from the tset-note, THROUGHOUT each
+ *      motif-placement. The offset for each note is its position in the
+ *      original note (which have been set relative to zero by set_mtfs())
+ *      times the multiplier, with an adjustment if we're actually using
+ *      less than the whole motif for some reason.
+ * (b)  Time may need to be quantised.
+ * (c)  Time of note is this tset-note + offset.
+ */
+
+double getnotetime(noteptr phrasenote,double thistime,double multiplier,double timeadjust,dataptr dz)
+{
+    int qunits;
+    double timestep = ((double)phrasenote->ntime - timeadjust) * (double)multiplier; /* a */
+    double thisgrid;
+
+    if(dz->param[TEX_PHGRID]>0.0) {
+        /* NEW  2000 */
+        thisgrid = dz->param[TEX_PHGRID] * MS_TO_SECS;
+
+        qunits    = round(timestep/thisgrid);           /* b */
+        timestep  = (double)(qunits*thisgrid);
+    }
+    return(thistime + timestep);                            /* c */
+}
+
+/************************ GETMTFDUR **********************************/
+
+int getmtfdur(noteptr tsetnote,noteptr phrasenote,double *dur,double multiplier,dataptr dz)
+{
+    if(dz->vflag[DONT_KEEP_MTFDUR])
+        *dur = tsetnote->dur;
+    else
+        *dur = phrasenote->dur * multiplier;
+    if(flteq(*dur,0.0)) {
+        sprintf(errstr,"TEXTURE: Problem 3 in getmtfdur(): Zero duration\n");
+        return(PROGRAM_ERROR);
+    }
+    return(FINISHED);
+}
+
+/***************************** ORN_OR_MTF_AMP_SETUP ************************************/
+
+int orn_or_mtf_amp_setup
+(int ampdirected,double *phrange,int phrno,double thisamp,int gpsize,double *rangemult,double *ampstep,
+ unsigned char *amptype,unsigned char amptypestor,unsigned char amptypecnt,dataptr dz)
+{
+    int exit_status;
+    double kk;
+    if(phrange[phrno]>=thisamp) {
+        kk = (double)phrange[phrno]*((double)(gpsize+1)/(double)gpsize);
+        *rangemult = (double)thisamp / kk;
+        *ampstep   = 0.0;
+    } else {
+        if(ampdirected) {
+            if((exit_status = getmtfdirampstep(thisamp,phrange[phrno],amptypecnt,ampstep,gpsize,dz))<0)
+                return(exit_status);
+        } else {
+            if((exit_status = getmtfampstep(thisamp,phrange[phrno],ampstep,amptype,amptypestor,amptypecnt,gpsize,dz))<0)
+                return(exit_status);
+        }
+        *rangemult = 1.0;
+    }
+    return(FINISHED);
+}
+
+/**************************** DO_MTF_PARAMS *******************************/
+
+int do_mtf_params
+(noteptr thisnote,double thisamp,noteptr phrasenote,noteptr tsetnote,
+ double ampdif,double notetime,double multiplier,dataptr dz)
+{
+    int exit_status;
+    double duration;
+    thisnote->amp   = (float)(thisamp - ampdif);
+    if((exit_status = getmtfdur(tsetnote,phrasenote,&duration,multiplier,dz))<0)
+        return(exit_status);
+    thisnote->dur = (float)duration;
+    if((exit_status = do_grp_ins(tsetnote->instr,&(thisnote->instr),dz))<0)
+        return(exit_status);
+    thisnote->motioncentre = tsetnote->motioncentre;
+    thisnote->ntime  = (float)notetime;
+    return(FINISHED);
+}
+
+/***************************** SETUP_MOTIF_OR_ORNAMENT ************************************/
+
+int setup_motif_or_ornament
+(double thistime,double *multiplier,int *phrno,noteptr *phrasenote,motifptr *phrase,dataptr dz)
+{
+    int exit_status;
+    if((exit_status = getvalue(TEX_MULTHI,TEX_MULTLO,thistime,PM_MULT,multiplier,dz))<0)
+        return(exit_status);
+    if((exit_status = doperm((int)dz->tex->phrasecnt,PM_WHICH,phrno,dz))<0)
+        return(exit_status);
+    *phrasenote    = phrase[*phrno]->firstnote;
+    return(FINISHED);
+}
+
+/****************************** POSITION_AND_SIZE_DECORATION **********************************/
+
+int position_and_size_decoration
+(double *thistime,double tsettime,double gpdense,int *gpsize,dataptr dz)
+{
+    int exit_status;
+    if((exit_status = get_dec_or_orn_pos(dz))<0)
+        return(exit_status);
+    if(dz->vflag[IS_PRE]) {
+        if((*thistime -= gpdense * (double)((*gpsize) + 1))< -gpdense) {
+            *thistime = tsettime;
+            if((exit_status = subzero(thistime,gpdense,gpsize))<0)
+                return(exit_status);
+        }
+    }
+    return(FINISHED);
+}
+
+/****************************** SET_DECOR_AMP **********************************/
+
+int set_decor_amp
+(int ampdirected,double *thisamp,double *ampstep,int gpsize,
+ unsigned char *amptype,unsigned char amptypecnt,unsigned char amptypestor,dataptr dz)
+{
+    int exit_status;
+    if(ampdirected) {
+        if((exit_status = getdirampstep(*thisamp,amptypecnt,ampstep,gpsize,dz))<0)
+            return(exit_status);
+    } else  {
+        if((exit_status = getampstep(ampstep,*thisamp,amptype,gpsize,amptypecnt,amptypestor,dz))<0)
+            return(exit_status);
+    }
+    if(*ampstep>0.0)
+        *thisamp -= (double)(gpsize+1) * (*ampstep);
+    return(FINISHED);
+}
+
+/****************************** SET_GROUP_AMP **********************************/
+
+int set_group_amp
+(noteptr tsetnote,double *thisamp,unsigned char *amptype, double *ampstep,int gpsize,
+ unsigned char amptypecnt,unsigned char amptypestor,dataptr dz)
+{
+    int exit_status;
+    if((exit_status = getampstep(ampstep,*thisamp,amptype,gpsize,amptypecnt,amptypestor,dz))<0)
+        return(exit_status);
+    if(*amptype==CRESC) {
+        *thisamp -= (double)(gpsize) * (*ampstep);
+        tsetnote->amp = (float)(*thisamp);
+    }
+    return(FINISHED);
+}
+
+/* LOCAL TO THESE GLOBALS */
+
+/****************************** ORN_SUBZERO *******************************
+ *
+ * Readjust the groupsize and the pointer to first note of phrase, where
+ * otherwise phrase would start before zero.
+ *
+ * (1)  Note the endtime of the phrase.
+ * (2)  For each note in the phrase.
+ * (3)  Find the duration of the phrase FROM THIS NOTE, by subtracting time of
+ *      current note from end (total) time, and adjusting by multiplier.
+ * (4)  If the duration of phrase from here, would put it's start after
+ *      zero-time, break from loop.
+ * (5)  Count number of notes rejected, and go to next phrase note.
+ * (6)  If we're at end of phrase, none of it's notes fall after zero time,
+ *      so return a gpsize of 0.
+ * (7)  Otherwise reset the event time (mifitime) to start of the group or
+ *      part-group which 'thisnote' points to.
+ * (8)  Resert the phrase pointer to point at this note of the phrase.
+ * (9)  When note times are finally calculated, timeadjust will reset all
+ *      the note times WITHIN the ornament to run from the note from
+ *      which we're starting, rather than the true start, by subtracting
+ *      'timeadjust'.
+ * (10) Return a size for the group reduced by the number of rejected notes.
+ */
+
+void orn_subzero
+(double *thistime,noteptr phrlastnote,noteptr *phrasenote,double *timeadjust,double multiplier,int *gpsize)
+{
+    double endtime = phrlastnote->ntime;            /* 1 */
+    double phrdur = 0.0;
+    int cnt = 0;
+    noteptr thisnote = *phrasenote;
+    while(thisnote!=(noteptr)0) {                           /* 2 */
+        phrdur = (endtime - thisnote->ntime) * multiplier;      /* 3 */
+        if(*thistime - phrdur >= 0.0)                   /* 4 */
+            break;
+        cnt++;                                                                  /* 5 */
+        thisnote = thisnote->next;
+    }
+    if(thisnote==(noteptr)0) {
+        *gpsize = 0;                                                    /* 6 */
+        return;
+    } else {
+        *thistime -= phrdur;                                    /* 7 */
+        *phrasenote = thisnote;                                 /* 8 */
+        *timeadjust = thisnote->ntime;                  /* 9 */
+    }
+    *gpsize -= cnt;
+    return;                                                                         /* 10 */
+}
+
+/*************************** GETMTFAMPSTEP ******************************
+ *
+ * Select flat, cresc or decresc, from available types, for motifs.
+ *
+ * (0)  If the amplitude is bigger than the size of amprise and the
+ *      range of the phrase, taken together, amprise is OK as it is.
+ * (00) Otherwise, amprise (set as ampstep at this point) is the amount
+ *      of the total amplitude left when the amplitude range of the phrase
+ *      has been subtracted. This ensures that no note of the phrase
+ *      can possibly end up below zero.
+ * (1)  IF the cresc will be from zero, clrzamp is 1, and this makes
+ *      the amplitude steps a little smaller, so that 1 of the notes
+ *      in sequence cannot be at amplitude zero.
+ *      OTHERWISE, clrzamp = 0,  and ampstep is as normal.
+ */
+
+int getmtfampstep(double amp,double framp,double *ampstep,unsigned char *amptype,
+                  unsigned char amptypestor,unsigned char amptypecnt,int gpsize,dataptr dz)
+{
+    int exit_status;
+    int clrzamp = 0;
+    int k;
+    if((exit_status = doperm((int)amptypecnt,PM_GPCNTR,&k,dz))<0)
+        return(exit_status);
+    if((exit_status=gettritype(k,amptypestor,amptype))<0)
+        return(exit_status);
+    if(*amptype==FLAT) {            /**** FLAT *****/
+        *ampstep =0.0;
+    } else {
+        if(amp>(dz->param[TEX_AMPRISE] + framp)) /* 0 */
+            *ampstep = dz->param[TEX_AMPRISE];
+        else {
+            *ampstep = amp - framp;                 /* 00 */
+            clrzamp = 1;
+        }
+        *ampstep /= (double)(gpsize+clrzamp);           /* 1 */
+        if(*amptype==DECRESC)           /** DECRESCENDO **/
+            *ampstep = -(*ampstep);
+    }
+    return(FINISHED);
+}
+
+/************************************************************************
+ *
+ * Calculating spatial orientation of motifs,groups,ornaments,decorations.
+ */
+
+/**************************** SETSPACE *******************************/
+
+int setspace(noteptr tsetnote,noteptr thisnote,int gpsize,dataptr dz)
+{
+    int exit_status;
+    if(dz->iparam[TEX_GPSPACE]!=IS_STILL) {
+        if((exit_status = space_gpnote(thisnote,gpsize,dz))<0)
+            return(exit_status);
+    } else
+        thisnote->spacepos = tsetnote->spacepos;
+    return(FINISHED);
+}
+
+/***************************** SPACE_GPNOTE *******************************
+ *
+ * (1)  OUTSIDE THE GROUP- OR PHRASE-MAKING LOOP
+ *      (a) Need to know gpsize, dectype(is_post?), gpsprange
+ *          (which MUST be +ve!).
+ *      (b) Need to run 'init_group_spatialisation()' to establish spinit, & hence
+ *          range modifications etc.
+ *
+ *  Then this will work INSIDE the loop.
+ *
+ * (1)  NB !!!!! is_pre is defaulted to ZERO. This means that groups
+ *      or motifs which CANNOT BE pre- or post- are defaulted to
+ *      post (which means the groups start on the tset notes, rather
+ *      leading up to them).
+ */
+
+int space_gpnote(noteptr thisnote,int gpsize,dataptr dz)
+{
+    int exit_status;
+    if(dz->iparam[TEX_GPSPACE]==IS_SCATTER) {
+        if((exit_status = sp_scatter(thisnote,dz))<0)
+            return(exit_status);
+    } else {
+        if(dz->vflag[IS_PRE]) {                         /* 1 */
+            if((exit_status = pre_place(thisnote,gpsize,dz))<0)
+                return(exit_status);
+        } else {
+            if((exit_status = post_place(thisnote,gpsize,dz))<0)
+                return(exit_status);
+        }
+    }
+    dz->iparam[SPINIT] = 0;         /* disable initialisation after first call to group */
+    return(FINISHED);
+}
+
+/**************************** SP_SCATTER *************************
+ *
+ * scatter group note around position of main event.
+ */
+
+int sp_scatter(noteptr mnote,dataptr dz)
+{
+    int exit_status;
+    double sptop = 1.0, spbot= 0.0, hfthissprange,val;
+    if(dz->param[THISSPRANGE]<=0.0) {
+        mnote->spacepos = (float)dz->param[TPOSITION];
+        return(FINISHED);
+    }
+    if(dz->iparam[SPINIT]) {
+        hfthissprange = dz->param[THISSPRANGE]/(double)2.0;
+        spbot = max((dz->param[TPOSITION] - hfthissprange),0.0);
+        sptop = min((dz->param[TPOSITION] + hfthissprange),1.0);
+        dz->param[THISSPRANGE] = sptop - spbot;
+    }
+    if((exit_status = pscatx(dz->param[THISSPRANGE],spbot,PM_GPSPAC,&val,dz))<0)
+        return(exit_status);
+    mnote->spacepos      = (float)val;
+    return(FINISHED);
+}
+
+/************** MACROS FOR RANGE REORIENTATIONS AND TRUNCATIONS **************
+ *
+ *      r = group spatial range         p = position of event
+ *      c = centre of motion            d = direction of motion
+ *
+ * (1)  If position to left  of centre, reverse range.
+ * (2)  If position to right of centre, reverse range.
+ * (3)  If no motion, zero the range.
+ * (4)  If motion is right to left reverse range.
+ * (5)  If motion is left to right reverse range.
+ * (6)  avoid centre crossing
+ * (7)  avoid right-edge crossing
+ * (8)  avoid left-edge crossing
+ * (9)  avoid edge crossing
+ */
+
+#define TURNOUTWARD(r,p,c) if((p)-(c)<0.0)  (r) = -(r);                                         /* 1 */
+#define TURNINWARD(r,p,c)  if((p)-(c)>0.0)  (r) = -(r);                                         /* 2 */
+#define CHECKSTIL(r,d)     if((d)==0) (r) = 0.0;                                                        /* 3 */
+#define FOLLOW(r,d)                CHECKSTIL(r,d) else { if((d)<0) (r) = -(r); }        /* 4 */
+#define CONTRARY(r,d)      CHECKSTIL(r,d) else { if((d)>0) (r) = -(r); }        /* 5 */
+#define SET_PRE_INRANGE(r,p,c) if(p<c) r = min(p,r); else r = max(p-1.0,r);
+
+
+#define FREECENTRE(r,p,c)  if((r)>fabs((p)-(c))) (r)=fabs((p)-(c));                     /* 6 */
+#define FREEREDGE(r,p)     if((p)+(r)>1.0) (r) = 1.0 - (p);                                     /* 7 */
+#define FREELEDGE(r,p)     if((p)+(r)<0.0) (r) = -(p);                                          /* 8 */
+#define FREEEDGES(r,p)     if((r)>=0.0) { FREEREDGE((r),(p)) } else { FREELEDGE((r),(p)) }
+/* 9 */
+
+#define FREEREDGE_PRE(r,p) if((p)-(r)>1.0) (r) = (p) - 1.0;                                     /* 7 */
+#define FREELEDGE_PRE(r,p) if((p)-(r)<0.0) (r) = (p);                                           /* 8 */
+#define FREEEDGES_PRE(r,p) if((r)>=0.0) { FREELEDGE_PRE((r),(p)) } else { FREEREDGE_PRE((r),(p)) }
+/* 9 */
+/************************* PRE_PLACE *****************************
+ *
+ * place-in-space ornaments or decorations BEFORE notes, or motifs or groups
+ * at texture points.
+ *
+ * is_pre = 1.
+ */
+
+int pre_place(noteptr thisnote,int gpsize,dataptr dz)
+{
+    if(dz->iparam[SPINIT])
+        dz->iparam[SPCNT] = 0;
+
+    switch(dz->iparam[TEX_GPSPACE]) {
+    case(IS_STILL):
+        dz->param[THISSPRANGE] = 0.0;
+        break;
+    case(IS_INWARD):
+        if(dz->iparam[SPINIT]) {
+            TURNINWARD(dz->param[THISSPRANGE],dz->param[TPOSITION],dz->param[CPOS])
+                SET_PRE_INRANGE(dz->param[THISSPRANGE],dz->param[TPOSITION],dz->param[CPOS])
+
+                }
+        break;
+    case(IS_OUTWARD):
+        if(dz->iparam[SPINIT]) {
+            FREECENTRE(dz->param[THISSPRANGE],dz->param[TPOSITION],dz->param[CPOS])
+                TURNOUTWARD(dz->param[THISSPRANGE],dz->param[TPOSITION],dz->param[CPOS])
+                }
+        break;
+    case(IS_FOLLOWING):
+        if(dz->iparam[SPINIT]) {
+            FOLLOW(dz->param[THISSPRANGE],dz->iparam[DIRECTION])
+                FREEEDGES_PRE(dz->param[THISSPRANGE],dz->param[TPOSITION])
+                }
+        break;
+    case(IS_CONTRARY):
+        if(dz->iparam[SPINIT]) {
+            CONTRARY(dz->param[THISSPRANGE],dz->iparam[DIRECTION])
+                FREEEDGES_PRE(dz->param[THISSPRANGE],dz->param[TPOSITION])
+                }
+        break;
+    default:
+        sprintf(errstr,"TEXTURE: Invalid space-type %d in pre_place()\n",dz->iparam[TEX_GPSPACE]);
+        return(PROGRAM_ERROR);
+    }
+    thisnote->spacepos = (float)(dz->param[TPOSITION] - dz->param[THISSPRANGE]
+                                 + ((dz->param[THISSPRANGE]/(double)gpsize)*(double)(dz->iparam[SPCNT])));
+    dz->iparam[SPCNT]++;
+    return(FINISHED);
+}
+
+/************************* POST_PLACE *****************************
+ *
+ * place-in-space ornaments or decorations AFTER notes, or motifs or groups
+ * at texture points.
+ *
+ * is_pre = 0, (or no ornament).
+ */
+
+int post_place(noteptr thisnote,int gpsize,dataptr dz)
+{
+    if(dz->iparam[SPINIT])
+        dz->iparam[SPCNT] = 1;
+    switch(dz->iparam[TEX_GPSPACE]) {
+    case(IS_STILL):
+        dz->param[THISSPRANGE] = 0.0;
+        break;
+    case(IS_INWARD):
+        if(dz->iparam[SPINIT]) {
+            FREECENTRE(dz->param[THISSPRANGE],dz->param[TPOSITION],dz->param[CPOS])
+                TURNINWARD(dz->param[THISSPRANGE],dz->param[TPOSITION],dz->param[CPOS])
+                }
+        break;
+    case(IS_OUTWARD):
+        if(dz->iparam[SPINIT]) {
+            TURNOUTWARD(dz->param[THISSPRANGE],dz->param[TPOSITION],dz->param[CPOS])
+                FREEEDGES(dz->param[THISSPRANGE],dz->param[TPOSITION])
+                }
+        break;
+    case(IS_FOLLOWING):
+        if(dz->iparam[SPINIT]) {
+            FOLLOW(dz->param[THISSPRANGE],dz->iparam[DIRECTION])
+                FREEEDGES(dz->param[THISSPRANGE],dz->param[TPOSITION])
+                }
+        break;
+    case(IS_CONTRARY):
+        if(dz->iparam[SPINIT]) {
+            CONTRARY(dz->param[THISSPRANGE],dz->iparam[DIRECTION])
+                FREEEDGES(dz->param[THISSPRANGE],dz->param[TPOSITION])
+                }
+        break;
+    default:
+        sprintf(errstr,"TEXTURE: Invalid space-type %d in post_place()\n",dz->iparam[TEX_GPSPACE]);
+        return(PROGRAM_ERROR);
+    }
+    thisnote->spacepos = (float)(dz->param[TPOSITION] +
+                                 ((dz->param[THISSPRANGE]/(double)gpsize)*(double)(dz->iparam[SPCNT])));
+    dz->iparam[SPCNT]++;
+
+    return(FINISHED);
+}
+
+/************************** GPSP_INIT ***********************************
+ *
+ * Initialise the space-param for each group, before calling the spatialise
+ * routines. 'spinit' causes initialisation of range etc elsewhere (in
+ * pre_place() or post_place() ).
+ */
+
+int init_group_spatialisation(noteptr tsetnote,int shaddoindex,noteptr *shadow,int shadowsize,dataptr dz)
+{
+    int exit_status;
+    dz->iparam[SPINIT] = 1;
+    dz->param[TPOSITION] = tsetnote->spacepos;
+    dz->param[CPOS]      = tsetnote->motioncentre;
+    if(dz->brksize[TEX_GRPSPRANGE]) { /* TABLE VALUES MUST BE 0 - 1 */
+        if((exit_status = read_value_from_brktable((double)tsetnote->ntime,TEX_GRPSPRANGE,dz))<0)
+            return(exit_status);
+    }
+    if(IS_DIRECTED(dz->iparam[TEX_GPSPACE]))
+        dz->iparam[DIRECTION] = read_direction(shaddoindex,shadow,shadowsize);
+    dz->param[THISSPRANGE] = dz->param[TEX_GRPSPRANGE];
+    return(FINISHED);
+}
+
+/**************************** READ_DIRECTION ****************************
+ *
+ * Read direction of motion from spatial position stored in note.
+ *
+ * NB: as the tset is in the process of being modified, we cannot
+ * refer directly to the tset linked list. We can only access the original
+ * tset through it's 'shadow'.
+ *
+ * (0)  Save the time of the current note as 'now'.
+ * (1)  Save position of current note as 'here'.
+ * (2)  Whilever we're not at the end of the tset (shadow).
+ * (a)  Note time of next note, store as 'then'.
+ * (b)  If 'then' is later than 'now'.
+ *              Note position of new note as 'there'.
+ *              Set as OK and break out of loop.
+ * (3)  If it's not OK (i.e. we were at, or came to the end of the tset
+ *              (shadow))....
+ * (a)  Go back to where we started.
+ * (b)  Call this position 'there'.
+ * (4)  While ever we're not at beginning of tset...
+ * (a)  Note time of previous note, store as 'then'.
+ * (b)  If 'then' is 'earlier' than 'now'...
+ *              Note position of new note as 'here'.
+ *              Set as OK and break out of loop.
+ * (5)  If still not OK, then there is no more than 1 (non-simultaneous)
+ *              event in the tset, so therefore no motion, so return 0.
+ * (6)  If there>here, left-to-right motion, return 1.
+ * (7)  If here>there, right-to-left motion, return -1.
+ * (8)  Otherwise, no motion, return 0.
+ */
+
+int read_direction(int shi,noteptr *shadow,int shadowsize)
+{
+    unsigned char OK;
+    float here, there = 0.0;
+    double now, then;
+    int startshi = shi;
+    now  = (shadow[shi])->ntime;                    /* 0 */
+    here = (shadow[shi])->motioncentre;             /* 1 */
+    OK = 0;
+    while(++shi<shadowsize) {                       /* 2 */
+        then = (shadow[shi])->ntime;            /* a */
+        if(then>(now+FLTERR)) {                 /* b */
+            there = (shadow[shi])->motioncentre;
+            OK = 1;
+            break;
+        }
+    }
+    if(!OK) {                                       /* 3 */
+        shi = startshi;                         /* a */
+        there = here;                           /* b */
+        while(--shi>=0) {                       /* 4 */
+            then = (shadow[shi])->ntime;            /* a */
+            if(then<(now-FLTERR)) {         /* b */
+                here = (shadow[shi])->motioncentre;
+                OK = 1;
+                break;
+            }
+        }
+    }
+    if(!OK)
+        return(0);                              /* 5 */
+    if(there>here)                          /* 6 */
+        return(1);
+    if(there<here)                          /* 7 */
+        return(-1);
+    return(0);                                      /* 8 */
+}
+
+/*************************** GETAMPSTEP ******************************
+ *
+ * Select flat, cresc or decresc, from available types.
+ *
+ * (1)  IF the cresc will be from zero, clrzamp is 1, and this makes
+ *      the amplitude steps a little smaller, so that 1st note in sequence
+ *      will not be at amplitude zero.
+ *      OTHERWISE, clrzamp = 0,  and ampstep is as normal.
+ */
+
+int getampstep
+(double *ampstep,double amp,unsigned char *amptype,int gpsize,unsigned char amptypecnt,
+ unsigned char amptypestor,dataptr dz)
+{
+    int exit_status;
+    int clrzamp = 0, k;
+    /*int texflag = dz->tex->txflag;*/
+    if((exit_status = doperm((int)amptypecnt,PM_GPCNTR,&k,dz))<0)
+        return(exit_status);
+    if((exit_status = gettritype(k,amptypestor,amptype))<0)
+        return(exit_status);
+
+    if(*amptype==FLAT)              /**** FLAT *****/
+        *ampstep =0.0;
+    else {
+        *ampstep = dz->param[TEX_AMPRISE]; /* param with <|> option */
+
+        if(*ampstep>=amp) {
+            clrzamp  = 1;
+            *ampstep = amp;
+        }
+        *ampstep /= (double)(gpsize + clrzamp);         /* 1 */
+        if(*amptype==DECRESC)           /** DECRESCENDO **/
+            *ampstep = -(*ampstep);
+    }
+    return(FINISHED);
+}
+
+/*************************** GETDIRAMPSTEP ******************************
+ *
+ * (1)  If there are two amplitude types, in THIS CASE, these can only
+ *              be DIRECTED or FLAT. So...
+ *   (2)  Choose flat or directed via perm.
+ *   (3)  and if it's flat, return an ampstep of zero.
+ *        Otherwise, we proceed as in the normal case of a directed amp.
+ * (4)  Set initial ampstep to amprise.
+ * (5)  IF the cresc will be from zero, or decresc to zero,  clrzamp is 1,
+ *              and this makes the amplitude steps a little smaller, so that 1st note
+ *              of cresc (or last note of decresc) will not be at amplitude zero.
+ *              OTHERWISE, clrzamp = 0,  and ampstep is as normal.
+ * (6)  Divide ampstep by number of members in group.
+ * (7)  If it's a post-ornament, ampstep is negative.
+ */
+
+int getdirampstep
+(double amp,unsigned char amptypecnt,double *ampstep,int gpsize,dataptr dz)
+{
+    int exit_status;
+    int k, clrzamp = 0;
+    if(amptypecnt==2) {                                                                     /* 1 */
+        if((exit_status= doperm((int)2,PM_GPCNTR,&k,dz))<0)     /* 2 */
+            return(exit_status);
+        if(k==0) {
+            *ampstep = 0.0;
+            return(FINISHED);                                                       /* 3 */
+        }
+    }
+    *ampstep = dz->param[TEX_AMPRISE];      /* param with <|> option */                             /* 4 */
+    if(*ampstep>=amp) {                                                                     /* 5 */
+        clrzamp = 1;
+        *ampstep = amp;
+    }
+    *ampstep /= (double)(gpsize + clrzamp);                         /* 6 */
+    if(!dz->vflag[IS_PRE])                                                          /* 7 */
+        *ampstep = -(*ampstep);
+
+    return(FINISHED);
+}
+
+/*************************** GETMTFDIRAMPSTEP *******************************
+ *
+ *      Intelligent guesswork!! Nov 4: 1997
+ */
+
+int getmtfdirampstep(double amp,double framp,unsigned char amptypecnt,double *ampstep,int gpsize,dataptr dz)
+{
+    int exit_status;
+    int k, clrzamp = 0;
+    if(amptypecnt==2) {                                                                     /* 1 */
+        if((exit_status= doperm((int)2,PM_GPCNTR,&k,dz))<0)     /* 2 */
+            return(exit_status);
+        if(k==0) {
+            *ampstep = 0.0;
+            return(FINISHED);                                                       /* 3 */
+        }
+    }
+    if(amp>(dz->param[TEX_AMPRISE] + framp))
+        *ampstep = dz->param[TEX_AMPRISE];
+    else {
+        *ampstep = amp - framp;
+        clrzamp = 1;
+    }
+    *ampstep /= (double)(gpsize + clrzamp);                         /* 6 */
+    if(!dz->vflag[IS_PRE])                                                          /* 7 */
+        *ampstep = -(*ampstep);
+
+    return(FINISHED);
+}
+
+/*************************  GET_DEC_OR_ORN_POS ***************************
+ *
+ * Decuptype flags are selected and shifted down into the range 0-3
+ * If its 01 (1), it's a post-ornament, so set 'is_pre' = FALSE.
+ * If its 10 (2), it's a pre_ornament,  so set 'is_pre' = TRUE
+ * If its 00 (0), it's not set, so we select 'is_pre' at random using doperm on 2 (output 0S or 1).
+ *
+ * NB: If we are using a group or motif, rather than a decoration
+ *      or ornament, is_pre is BY DEFAULT set to 0.
+ */
+
+int get_dec_or_orn_pos(dataptr dz)
+{
+    int exit_status;
+    int k;
+    unsigned int dectype = dz->tex->txflag & GET_DECORNPOS;
+    switch(dectype) {
+    case(1): dz->vflag[IS_PRE] = TRUE;      break;
+    case(2): dz->vflag[IS_PRE] = FALSE;     break;
+    default:
+        if((exit_status = doperm((int)2,PM_ORNPOS,&k,dz))<0)
+            return(exit_status);
+        dz->vflag[IS_PRE] = (char)k;
+        break;
+    }
+    if(dz->vflag[IS_PRE] > 1) {
+        sprintf(errstr,"Error from perm in  get_dec_or_orn_pos()\n");
+        return(PROGRAM_ERROR);
+    }
+    return(FINISHED);
+}
+
+/**************************** SUBZERO ***********************************
+ *
+ * If start of a decoration falls before time zero, adjust its size
+ * and hence starttime(-minus-gpdense) appropriately.
+ */
+
+int subzero(double *thistime,double gpdense,int *gpsize)
+{
+    int n = -1;
+    while(*thistime>=0.0) {
+        *thistime -= gpdense;
+        n++;
+    }
+    if(n<0) {
+        sprintf(errstr,"TEXTURE: Problem in subzero()\n");
+        return(PROGRAM_ERROR);
+    }
+    *gpsize = n;
+    return(FINISHED);
+}
+
+/*************************** GETHIPITCH *********************************#
+ *
+ * Find highest pitch at current time.
+ */
+
+noteptr gethipitch(noteptr tsetnote,int *shaddoindex)
+{
+    noteptr hinote, thisnote;
+    double hipitch;
+    int zz = *shaddoindex;
+    hinote = thisnote = tsetnote;
+    hipitch = (double)hinote->pitch;
+    while(thisnote->next!=(noteptr)0) {
+        if(thisnote->next->ntime > thisnote->ntime + FLTERR)
+            return(hinote);
+        thisnote = thisnote->next;
+        zz++;
+        if((double)thisnote->pitch > hipitch) {
+            hipitch = (double)thisnote->pitch;
+            hinote  = thisnote;
+            (*shaddoindex) = zz;
+        }
+    }
+    return(hinote);
+}
+
+/****************************** DO_GRP_INS **********************************
+ *
+ * Choose instr-no within group/decoration/motif or ornament.
+ * Values of instr-no range are preset when instr is chosen for the
+ * tset, in do_ev_ins().
+ */
+
+int do_grp_ins(unsigned char thisinstr,unsigned char *val,dataptr dz)
+{
+    int exit_status;
+    int irange, ival;
+    if(dz->vflag[INS_TO_SCATTER]) {
+        if((irange = (int)(dz->iparam[TEXTURE_INSHI] - dz->iparam[TEXTURE_INSLO])) < 0) {
+            iswap((int *)&(dz->iparam[TEXTURE_INSHI]),(int *)&(dz->iparam[TEXTURE_INSLO]));
+            irange = -irange;
+        }
+        if(irange==0)
+            *val = (unsigned char)dz->iparam[TEXTURE_INSLO];
+        else {
+            if((exit_status = doperm(irange+1,PM_INSNO,&ival,dz))<0)        /* range INCLUSIVE for ints */
+                return(exit_status);
+            *val = (unsigned char)(ival     + dz->iparam[TEXTURE_INSLO]);
+        }
+    } else
+        *val = thisinstr;
+    return(FINISHED);
+}
+
+/***************************** PSCATX ************************************
+ *
+ * Select a random value within 'range', by permuting one of BANDCNT equal
+ * ranges, and selecting a random value within the chosen range.
+ */
+
+int pscatx(double range,double bottom,int pindex,double *val,dataptr dz)
+{
+    int k, exit_status;
+    double bandwidth, bandbottom, x;
+    if((exit_status = doperm((int)BANDCNT,pindex,&k,dz))<0)
+        return(exit_status);
+    bandwidth       = range/(double)BANDCNT;
+    bandbottom      = (double)k * bandwidth;
+    x  = (drand48() * bandwidth);
+    x += bandbottom;
+    *val = x + bottom;
+    return(FINISHED);
+}
+
+/*************************** DEL_NOTE ************************************/
+
+void del_note(noteptr thisnote,motifptr thismotif)
+{
+    if(thisnote->next!=(noteptr)0)
+        thisnote->next->last = thisnote->last;          /* 1 */
+    if(thisnote->last!=(noteptr)0)
+        thisnote->last->next = thisnote->next;          /* 2 */
+    else
+        thismotif->firstnote = thisnote->next;          /* 3 */
+    free(thisnote);                                 /* 4 */
+}
+
+/************************** TIMESORT ****************************
+ *
+ * Timesorts notes in a list
+ *
+ * (1)  Move the item with earliest time to start of list, and set this
+ *      (minimum) time as maximum time also.
+ *      For each item in the list....
+ *   (2)   If this item is earlier than current latest item (maxtime)..
+ *     (3)    Find where it should be in the list.
+ *     (4)    move it to that location.
+ *   (5)   Otherwise, set this item's time as latest time(maxtime).
+ * (6)  Reset motifhead to start of notelist!!
+ */
+
+int arrange_notes_in_timeorder(motifptr mtf)
+{
+    noteptr base, here, there, mark;
+    double thistime, maxtime;
+    if((base = mtf->firstnote)==(noteptr)0)
+        return(FINISHED);
+    maxtime = setup_first_notelist_time(&base);                     /* 1 */
+    here = base;
+    while(here!=(noteptr)0) {
+        if((thistime = here->ntime) < maxtime) {                /* 2 */
+            if((mark = here->last)==(noteptr)0) {
+                sprintf(errstr,"Problem (1) in arrange_notes_in_timeorder()\n");
+                return(PROGRAM_ERROR);
+            }
+            if((there = reverse_search_for_time(here,thistime))==(noteptr)0) {
+                sprintf(errstr,"Timing problem in arrange_notes_in_timeorder()\n");
+                return(PROGRAM_ERROR);
+            }                                               /* 3 */
+            move_notelist_item(here,there);                 /* 4 */
+            here = mark;
+        } else
+            maxtime = here->ntime;                  /* 5 */
+        here = here->next;
+    }
+    return reset_mtfhead(mtf);                                      /* 6 */
+}
+
+/************************* RESET_MTFHEAD ***************************
+ *
+ * Reset pointer to start of notelist.
+ */
+
+int reset_mtfhead(motifptr mtf)
+{
+    noteptr here = mtf->firstnote;
+    if(mtf->firstnote==NULL) {
+        sprintf(errstr,"Problem in reset_mrfhead()\n");
+        return(PROGRAM_ERROR);
+    }
+    while(here->last!=(noteptr)0)
+        here = here->last;
+    mtf->firstnote = here;
+
+    return(FINISHED);
+}
+
+/************************** SETUP_FIRST_NOTELIST_TIME ***************************
+ *
+ * Put the earliest timed item in a list of notes into start of list.
+ */
+
+double setup_first_notelist_time(noteptr *base)
+{
+    noteptr firstnote, here;
+    double  mintime, thistime;
+    firstnote = here = *base;
+    mintime   = (*base)->ntime;
+    while(here!=(noteptr)0) {
+        if((thistime = here->ntime)<mintime) {
+            firstnote = here;
+            mintime = thistime;
+        }
+        here = here->next;
+    }
+    if(firstnote!=(*base)) {
+        move_notelist_item(firstnote,(*base));
+        *base = firstnote;
+    }
+    return(mintime);
+}
+
+/************************* MOVE_NOTELIST_ITEM ***************************
+ *
+ * Move an item in a notelist from location a to BEFORE location b.
+ */
+
+void move_notelist_item(noteptr a,noteptr b)
+{
+    if(a->last!=(noteptr)0)
+        a->last->next = a->next;
+    if(a->next!=(noteptr)0)
+        a->next->last = a->last;
+    a->next = b;
+    a->last = b->last;
+    if(b->last!=(noteptr)0)
+        b->last->next = a;
+    b->last = a;
+}
+
+/************************** REVERSE_SEARCH_FOR_TIME *****************************
+ *
+ * Reverse search note-list using a time as index, and return address
+ * of note whose time is AFTER the input time.
+ * WILL RETURN (noteptr)0 IF REFTIME IS OFF END OF LIST.
+ */
+
+noteptr reverse_search_for_time(noteptr start,double reftime)
+{
+    noteptr here = start;
+    while(here->ntime >= reftime) {
+        if(here->last == (noteptr)0)
+            return(here);
+        here = here->last;
+    }
+    return(here->next);
+}
+
+/************************** ISWAP *****************************/
+
+void iswap(int *a,int *b)
+{
+    int temp;
+    temp = *a;
+    *a = *b;
+    *b = temp;
+}
+
+/****************************** SET_GROUP_PARAMS **********************************/
+
+int set_group_params
+(noteptr tsetnote,noteptr thisnote,double gpdense,double ampstep,double *thisamp,double *thistime,double thisdur,dataptr dz)
+{
+    int exit_status;
+    double thisgpdense, time_left;
+    *thisamp += ampstep;
+    thisnote->amp   = (float)*thisamp;
+    thisnote->dur   = (float)thisdur;
+    if(dz->vflag[FIXED_STEP])
+        *thistime += gpdense;
+    else {
+        if((exit_status = get_density_val(*thistime,&thisgpdense,dz))<0)
+            return(exit_status);
+        if((dz->tex->txflag & IS_DECOR) && dz->vflag[IS_PRE]) {
+            if((time_left = tsetnote->ntime - *thistime)<0.0) {
+                sprintf(errstr,"Error in assumptions: set_group_params()\n");
+                return(PROGRAM_ERROR);
+            }
+            time_left *= 0.66;
+            thisgpdense = min(time_left,thisgpdense);
+        }
+        *thistime += thisgpdense;
+    }
+    return(FINISHED);
+}
+
+/***************************** GETTRITYPE *****************************
+ *
+ * Choose a type, from up to three available types in bit-flag.
+ * e.g.
+ * Choose an amplitude type (flat,cresc,decresc) from 3 available types.
+ * Choose a decoration-orientation type (above,below,mid) from 3 types.
+ *
+ * (1)  For each type in the bitflag.
+ * (2)  If this option is flagged, count it.
+ * (3)  IF this option is chosen, return its bit-number.
+ * (4)  Advance the bitflag mask.
+ */
+
+int gettritype(int k,unsigned stor,unsigned char *val)
+{
+    int v = 0, mask = 1, n;
+    k++;
+    for(n=0;n<3;n++) {                              /* 1 */
+        if(mask & stor)                         /* 2 */
+            v++;
+        if(k==v) {                              /* 3 */
+            *val = (unsigned char)n;
+            return(FINISHED);
+        }
+        mask <<= 1;                             /* 4 */
+    }
+    sprintf(errstr,"TEXTURE: Problem in gettritype()\n");
+    return(PROGRAM_ERROR);
+}
+
+/***************************  GET_DENSITY_VAL ******************************/
+
+int get_density_val(double thistime,double *gpdense,dataptr dz)
+{
+    int exit_status;
+    if((exit_status = getvalue(TEX_GPPACKHI,TEX_GPPACKLO,thistime,PM_GPDENS,gpdense,dz))<0)
+        return(PROGRAM_ERROR);
+
+    /* NEW MAR 2000 */
+    *gpdense *= MS_TO_SECS;
+
+    if(dz->param[TEX_PHGRID]>0.0)
+        *gpdense = quantise(*gpdense,dz->param[TEX_PHGRID]);
+
+    return FINISHED;
+}
+
+/**************************** SET_MOTIFS *******************************
+ *
+ * initialise all parameters of input motifs to be used for MOTIFS or
+ * ORNAMENTS.
+ *
+ * (1)For each input motif (called a 'phrase').
+ *    phrnotecnt[n] = 0;
+ * (2)  Initialise count of number of notes to 0, maximum amplitude
+ *      of phrase to 0.0, and lowest pitch to MIDITOP.
+ * (3)  Go through each note of the motif.
+ * (4)  Add up the number of notes in it.
+ * (5)  Find it's lowest pitch.
+ * (6)  Find it's loudest note (and set as phraseamp).
+ * (7)  Establish dynamic range of phrase.
+ * (8)  Transpose the motif into it's lowest possible register.
+ * (9)  Ensure motif starts at zero time.
+ * (10) Store addresses of last notes in phrases.
+ */
+
+int set_motifs
+(int phrcount,motifptr *phrase,int *phrnotecnt,double *phraseamp,double *phrange,noteptr *phrlastnote)
+{
+    int exit_status;
+    int n;
+    double minpitch, mintime, minamp;
+    noteptr thisnote, lastnote = (noteptr)0;
+    for(n=0;n<phrcount;n++) {                                               /* 1 */
+        if((exit_status = arrange_notes_in_timeorder(phrase[n]))<0)
+            return(exit_status);
+        phrnotecnt[n] = 0;
+        phraseamp[n] = 0.0;                                                     /* 2 */
+        minamp   = DBL_MAX;
+        minpitch = MIDITOP;
+        mintime  = DBL_MAX;
+        thisnote = phrase[n]->firstnote;                        /* 3 */
+        while(thisnote!=(noteptr)0) {
+            phrnotecnt[n]++;                                                        /* 4 */
+            if(thisnote->pitch<minpitch)
+                minpitch = thisnote->pitch;                     /* 5 */
+            if(thisnote->ntime<mintime)
+                mintime  = thisnote->ntime;                     /* 5 */
+            if((double)thisnote->amp>phraseamp[n])
+                phraseamp[n] = (double)thisnote->amp;/* 6 */
+            if(thisnote->amp<minamp)
+                minamp = thisnote->amp;                         /* 6 */
+            thisnote = thisnote->next;
+        }
+        if(minamp  == DBL_MAX || mintime == DBL_MAX) {
+            sprintf(errstr,"Error parsing motif: set_motifs()\n");
+            return(PROGRAM_ERROR);
+        }
+        thisnote = phrase[n]->firstnote;
+        phrange[n] = phraseamp[n] - minamp;                     /* 7 */
+        while(thisnote!=(noteptr)0) {
+            thisnote->pitch = (float)(thisnote->pitch - (minpitch + MIDIBOT));      /* 8 */
+            thisnote->ntime = (float)(thisnote->ntime - mintime);                           /* 9 */
+            lastnote = thisnote;                                                                                            /* 10 */
+            thisnote = thisnote->next;
+        }
+        if((phrlastnote[n] = lastnote) == (noteptr)0) {
+            sprintf(errstr,"Zero length phrase encountered: set_motifs()\n");
+            return(PROGRAM_ERROR);
+        }
+    }
+    return(FINISHED);
+}
+
+void cyclicperm(dataptr dz)
+{
+    int n, t;
+    do {
+        for(n=0;n<dz->infilecnt;n++) {
+            t = (int)floor(drand48() * (n+1));
+            if(t==n) {
+                hprefix(n,dz->peakno,dz->infilecnt);
+            } else {
+                hinsert(n,t,dz->peakno,dz->infilecnt);
+            }
+        }
+    } while(dz->peakno[0] == dz->lastpeakno[dz->infilecnt - 1]);    // Avoid repetitions at perm boundaries.
+    for(n=0;n<dz->infilecnt;n++)
+        dz->lastpeakno[n] = dz->peakno[n];
+}
+
+void hinsert(int m,int t,int *perm,int permlen)
+{
+    hshuflup(t+1,perm,permlen);
+    perm[t+1] = m;
+}
+
+void hprefix(int m,int *perm,int permlen)
+{
+    hshuflup(0,perm,permlen);
+    perm[0] = m;
+}
+
+void hshuflup(int k,int *perm,int permlen)
+{
+    int n, *i;
+    int z = permlen - 1;
+    i = perm+z;
+    for(n = z;n > k;n--) {
+        *i = *(i-1);
+        i--;
+    }
+}
+
+#ifndef round
+
+int round(double a)
+{
+    return (int)floor(a + 0.5);
+}
+#endif

+ 623 - 0
dev/texture/prevsrc/prev-src/texture5.c

@@ -0,0 +1,623 @@
+/*
+ * Copyright (c) 1983-2013 Trevor Wishart and Composers Desktop Project Ltd
+ * http://www.trevorwishart.co.uk
+ * http://www.composersdesktop.com
+ *
+ This file is part of the CDP System.
+
+ The CDP System is free software; you can redistribute it
+ and/or modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The CDP System is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the CDP System; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA
+ *
+ */
+
+
+
+/* floatsam version */
+#include <stdio.h>
+#include <stdlib.h>
+#include <memory.h>                     /*RWD*/
+#include <structures.h>
+#include <tkglobals.h>
+#include <globcon.h>
+#include <processno.h>
+#include <modeno.h>
+#include <arrays.h>
+#include <texture.h>
+#include <cdpmain.h>
+
+#include <sfsys.h>
+#ifdef _DEBUG
+#include <assert.h>
+#endif
+
+#if defined unix || defined __GNUC__
+#define round(x) lround((x))
+#endif
+
+static int setup_splice(int st_splicecnt,double **splicebuf);
+static int generate_origdur_and_frq(double **origdur,double **origfrq,dataptr dz);
+static int init_soundout_set(sndoutptr *sndout);
+static int replace_tset_by_soundout_set(noteptr thisnote,sndoutptr *sndout,
+                                        double *origdur,double *origfrq,double  mindur,int st_splicecnt,dataptr dz);
+static int convert_tsetnote_to_sndout_item(noteptr thisnote,sndoutptr sndout,
+                                           double *origdur,double *origfrq,double mindur,int st_splicecnt,int *warning_set,dataptr dz);
+static int generate_previous_sndout(sndoutptr *sndout);
+static int get_thisdur(double *thisdur,noteptr thisnote,int thisins,
+                       double *origdur,double inv_trnsp,double mindur,dataptr dz);
+static int get_stereospace_compensation(double position,double *compensate);
+
+static int do_mix(sndoutptr sndout,double *splicebuf,dataptr dz);
+static int check_sequencing(sndoutptr sndout);
+static int add_samples_to_outbuf_from_inbuf(int *out_of_insamples,int * max_samp_written,
+                                            sndoutptr sndout,double *splicebuf,int splicelen,/*int*/float *lbuf,dataptr dz);
+static void unlink_sndoutptr_at_start_of_list(sndoutptr sndout);
+static void unlink_sndoutptr(sndoutptr sndout);
+static double get_interpd_value(unsigned int here,double ibufpos,sndoutptr sndout);
+static int  free_first_sndout(sndoutptr *sndout);
+
+//TW UPDATE 2002: to make texture from stereo sources (updated to flotsams)
+static int add_stereo_samples_to_outbuf_from_inbuf
+(int *out_of_insamples,int *max_samp_written,sndoutptr sndout,double *splicebuf,int splicelen,float *lbuffer,dataptr dz);
+static double get_interpd_value_stereo(unsigned int here,double ibufpos,double *chanval2,sndoutptr sndout);
+
+/**************************** PRODUCE_TEXTURE_SOUND *****************************/
+
+int produce_texture_sound(dataptr dz)
+{
+    int exit_status;
+    /*insamptr  *insound = dz->tex->insnd;*/
+    motifptr  tset     = dz->tex->timeset;
+    sndoutptr sndout;
+    noteptr   thisnote = tset->firstnote;
+    double *origdur, *origfrq, *splicebuf;
+    double mindur = (dz->frametime + TEXTURE_SAFETY) * MS_TO_SECS;
+    int st_splicecnt = round((dz->frametime * MS_TO_SECS) * dz->infile->srate);
+    if((exit_status = setup_splice(st_splicecnt,&splicebuf))<0)
+        return(exit_status);
+    if((exit_status = generate_origdur_and_frq(&origdur,&origfrq,dz))<0)
+        return(exit_status);
+    if((exit_status = init_soundout_set(&sndout))<0)
+        return(exit_status);
+    if((exit_status = replace_tset_by_soundout_set(thisnote,&sndout,origdur,origfrq,mindur,st_splicecnt,dz))<0)
+        return(exit_status);
+    free(origdur);
+    free(origfrq);
+    return do_mix(sndout,splicebuf,dz);
+}
+
+/************************** SETUP_SPLICE ************************/
+
+int setup_splice(int st_splicecnt,double **splicebuf)
+{
+    int n, m;
+    if((*splicebuf = (double *)malloc(st_splicecnt * sizeof(double)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY for splice buffer.\n");
+        return(MEMORY_ERROR);
+    }
+    for(m=0,n=st_splicecnt-1; n>=0; n--,m++)
+        (*splicebuf)[m] = (double)n/(double)st_splicecnt;
+    return(FINISHED);
+}
+
+/************************** GENERATE_ORIGDUR_AND_FRQ ************************/
+
+int generate_origdur_and_frq(double **origdur,double **origfrq,dataptr dz)
+{
+    int n;
+    if((*origdur = (double *)malloc(dz->infilecnt * sizeof(double)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY to store original durations.\n");
+        return(MEMORY_ERROR);
+    }
+    if((*origfrq = (double *)malloc(dz->infilecnt * sizeof(double)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY to store original frqs.\n");
+        return(MEMORY_ERROR);
+    }
+    for(n=0;n <dz->infilecnt;n++) {
+        //TW UPDATE: Now allowing stereo sources to be used to make texture
+        (*origdur)[n] = (double)dz->insams[n]/(double)dz->infile->channels/(double)dz->infile->srate;
+        (*origfrq)[n] = miditohz(((dz->tex->insnd)[n])->pitch);
+    }
+    return(FINISHED);
+}
+
+/************************** INIT_SOUNDOUT_SET ************************/
+
+int init_soundout_set(sndoutptr *sndout)
+{
+    if((*sndout = (sndoutptr)malloc(sizeof(struct soundout)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY for soundout pointers.\n");
+        return(MEMORY_ERROR);
+    }
+    (*sndout)->last = (sndoutptr)0;
+    (*sndout)->next = (sndoutptr)0;
+    return(FINISHED);
+}
+
+/************************** REPLACE_TSET_BY_SOUNDOUT_SET ************************/
+
+int replace_tset_by_soundout_set
+(noteptr thisnote,sndoutptr *sndout,double *origdur,double *origfrq,double  mindur,int st_splicecnt,dataptr dz)
+{
+    int exit_status;
+    int warning_set = FALSE;
+    while((thisnote->next)!=(noteptr)0)     /* go to end of tset */
+        thisnote = thisnote->next;
+    while(thisnote!=(noteptr)0) {
+        if((exit_status = convert_tsetnote_to_sndout_item
+            (thisnote,*sndout,origdur,origfrq,mindur,st_splicecnt,&warning_set,dz))<0)
+            return(exit_status);
+        if((exit_status = generate_previous_sndout(sndout))<0)
+            return(exit_status);
+        if(thisnote->last!=NULL) {
+            thisnote = thisnote->last;              /* free tset from end backwards */
+            free(thisnote->next);
+        } else {
+            free(thisnote);
+            if((exit_status = free_first_sndout(sndout))<0)
+                return(exit_status);
+            thisnote = NULL;
+        }
+    }
+    return(FINISHED);
+}
+
+/************************** CONVERT_TSETNOTE_TO_SNDOUT_ITEM ************************/
+
+//TW "STEREO" defined in globcon.h
+#define MAXGAIN (1.0)
+
+int convert_tsetnote_to_sndout_item
+(noteptr thisnote,sndoutptr sndout,double *origdur,double *origfrq,double mindur,int st_splicecnt,int *warning_set,dataptr dz)
+{
+    int exit_status;
+    int thisins;
+    unsigned int insampcnt, st_osampcnt;
+    double indur;
+    double thisfrq,thisdur,trnspstep,inv_trnsp,thisamp,thispos,compensate;
+
+    thisins   = thisnote->instr;
+    thisfrq   = miditohz((double)thisnote->pitch);
+    trnspstep = thisfrq/origfrq[thisins];
+    inv_trnsp = 1.0/trnspstep;
+    if((exit_status = get_thisdur(&thisdur,thisnote,thisins,origdur,inv_trnsp,mindur,dz))<0)
+        return(exit_status);
+    indur       = thisdur * trnspstep;
+    //TW UPDATE now counting either mono samples or pairs-of-stereo-sample pairs (as with st_osampcnt) as possibly using stereo input
+    insampcnt   = min(dz->insams[thisins]/dz->infile->channels,round(indur * (double)dz->infile->srate));
+    st_osampcnt = round((double)insampcnt * inv_trnsp);
+    if(st_osampcnt <= (unsigned int)st_splicecnt) {
+        sprintf(errstr,"Error in samplecount calculations: convert_tsetnote_to_sndout_item()\n");
+        return(PROGRAM_ERROR);
+    }
+    thisamp   = thisnote->amp/(double)MIDITOP;
+    thispos   = thisnote->spacepos;
+    if((exit_status = get_stereospace_compensation(thispos,&compensate))<0)
+        return(exit_status);
+    if(thisamp > MAXGAIN) {
+#ifdef _DEBUG
+        assert(thisamp <= MAXGAIN);
+#endif
+        if(!(*warning_set)) {
+            fprintf(stdout,"WARNING: one or more events exceed max level. Adjusted.\n");
+            fflush(stdout);
+            *warning_set = TRUE;
+        }
+        thisamp = MAXGAIN;
+    }
+    sndout->inbuf       = ((dz->tex->insnd)[thisins])->buffer;
+    sndout->ibufcnt     = insampcnt;
+    sndout->st_sstttime = round(thisnote->ntime * dz->infile->srate);
+    sndout->st_sendtime = sndout->st_sstttime + st_osampcnt; /* Redundant variable: might need if func revised */
+    sndout->st_splicpos = sndout->st_sendtime - st_splicecnt;
+    sndout->ibufpos         = 0.0;
+    sndout->step            = trnspstep;
+    //TW UPDATE: in stereo-input case, only 1 gain value used, as no spatialisation takes place
+    if(dz->infile->channels==STEREO) {
+        sndout->lgain           = thisamp;
+    } else {
+        sndout->lgain           = thisamp * (1.0 - thispos) * compensate;
+        sndout->rgain           = thisamp * thispos * compensate;
+    }
+    return(FINISHED);
+}
+
+/************************** GENERATE_PREVIOUS_SNDOUT ************************/
+
+int generate_previous_sndout(sndoutptr *sndout)
+{
+    sndoutptr new;
+    if((new = (sndoutptr)malloc(sizeof(struct soundout)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY for new soundout pointers.\n");
+        return(MEMORY_ERROR);
+    }
+    new->last     = (sndoutptr)0;
+    new->next     = *sndout;
+    (*sndout)->last = new;
+    *sndout = new;
+    return(FINISHED);
+}
+
+/************************** FREE_FIRST_SNDOUT ************************/
+
+int free_first_sndout(sndoutptr *sndout)
+{
+    if((*sndout = (*sndout)->next)==NULL) {
+        sprintf(errstr,"Problem in free_first_sndout()\n");
+        return(PROGRAM_ERROR);
+    }
+    free((*sndout)->last);
+    (*sndout)->last = NULL;
+    return(FINISHED);
+}
+
+/************************** GET_THISDUR ************************/
+
+int get_thisdur
+(double *thisdur,noteptr thisnote,int thisins,double *origdur,double inv_trnsp,double mindur,dataptr dz)
+{
+    double transposed_dur = origdur[thisins] * inv_trnsp;
+    *thisdur   = thisnote->dur;
+    if(*thisdur>transposed_dur)
+        *thisdur = transposed_dur;
+    else if(dz->vflag[TEX_IGNORE_DUR])
+        *thisdur = transposed_dur;
+    if(*thisdur<mindur) {
+        sprintf(errstr,
+                "too short dur generated (%lf : mindur = %lf): get_thisdur()\n",*thisdur,mindur);
+        return(PROGRAM_ERROR);
+    }
+    return(FINISHED);
+}
+
+/************************** GET_STEREOSPACE_COMPENSATION ************************
+ *
+ * 1)   comp(ensation) is a factor which compensates for the apparent
+ *              loss of perceived amplitude as a sound moves out of the absolute
+ *              left or absolute right position (sound from a single loudspeaker)
+ *              by simple linear interpolation.
+ *              At first we define comp to vary LINERALY from 0.0 at L or R,
+ *              to 1.0 in centre.
+ * 2)   NONLIN makes this varation nonlinear, but smooth at the centre, and
+ *              still between 0.0 and 1.0
+ * 3)   As a signal of fixed perceived level moves from left to right (or v.v.)
+ *              we wish to boost the amplitude from each loudspeaker somewhat,
+ *              using a curve of the shape now defined.
+ *              The maximum possible amplitude is 1.0. To define how much we should
+ *              boost amplitude at any point on the L-R axis, we need to define
+ *              a ratio (MAXBOOST) with which to multiply the signal.
+ *              Multiplying comp-curve by this, defines a curve of amplitude-boosting values.
+ * 4)   1.0 is now added to this curve, to give a multiplier of amplitude at
+ *              each point along the left-right axis.
+ *              And MAXBOOST is subtracted, so that the level
+ *              from each loudspeaker when at maximum boost cannot exceed
+ *              MAXGAIN (1.0).
+ */
+
+#define NONLIN   (0.5)
+#define MAXBOOST (0.25)
+
+int get_stereospace_compensation(double position,double *compensate)
+{
+    double comp = 1.0 - (fabs((position * (double)2.0) - (double)1.0));     /* 9a */
+    comp = pow(comp,NONLIN);                    /* 9b */
+    comp *= MAXBOOST;                                   /* 9c */
+    comp += (1.0 - MAXBOOST);                   /* 9d */
+    *compensate = comp;
+    return(FINISHED);
+}
+
+/************************** DO_MIX ************************
+ *
+ * 1)   Position, in stereo-samples, of start-of-splice in this-sndout-struct =
+ *                      sndout->st_splicpos
+ *              Position in actual-samples of ditto =
+ *                       sndout->st_splicpos * STEREO
+ *              Position relative to start of current buffer =
+ *                      (sndout->st_splicpos * STEREO) - (obufcnt * dz->buflen);
+ *              Same position expressed relative to start-of-splice (so that value 0 = start_of_splice) =
+ *                      -((sndout->st_splicpos * STEREO) - (obufcnt * dz->buflen));
+ */
+
+int do_mix(sndoutptr sndout,double *splicebuf,dataptr dz)
+{
+    int exit_status;
+    int out_of_insamples;
+    /*unsigned int totaltime = 0;*/
+    int max_samp_written, n;
+    unsigned int this_sampend, obufcnt = 0;
+    int splicelen = round((dz->frametime * MS_TO_SECS) * dz->infile->srate) * STEREO;
+    sndoutptr startsnd = sndout, endsnd = sndout;
+    /*int*/float *lbuf;
+    //TW UPDATE handles stereo input files
+    int is_stereo = 0;
+    if(dz->infile->channels == STEREO)
+        is_stereo = 1;
+    //TW MOVED from texprepro
+    dz->infile->channels = STEREO;  /* for output time calculations */
+    if((exit_status = create_sized_outfile(dz->outfilename,dz))<0)
+        return(exit_status);
+
+    if((lbuf = (float *)malloc(dz->buflen * sizeof(float)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY for mixing buffers.\n");
+        return(MEMORY_ERROR);
+    }
+    dz->sbufptr[0] = dz->sampbuf[0];
+    /* <--SAFETY CHECK */
+    if((exit_status = check_sequencing(sndout))<0)
+        return(exit_status);
+    /* SAFETY CHECK--> */
+    while(startsnd != NULL) {                                                                               /* until we reach end of event list */
+        this_sampend = (obufcnt+1) * dz->buflen;                /* get absolute samplecnt of end of current buf */
+        /* look for NEW events starting during this outbuf */
+        if(sndout!=NULL) {
+            while(sndout->st_sstttime * STEREO < this_sampend) {
+                sndout->obufpos  = (sndout->st_sstttime * STEREO) % dz->buflen;/* obufptr for new event */
+                sndout->st_splicpos = (sndout->st_splicpos * STEREO)-(obufcnt * dz->buflen);/* NOTE1 abv*/
+                sndout->st_splicpos = -(sndout->st_splicpos);                                                   /* NOTE 1 above */
+                sndout = sndout->next;
+                endsnd = sndout;                                          /* update the endmarker of the active events list */
+                if(endsnd == NULL)                                                                              /* if all events finished,break */
+                    break;
+            }
+        }
+        sndout = startsnd;                                                                               /* set start to 1st event still active */
+
+        memset((char *)lbuf,0,dz->buflen * sizeof(float));                                           /* empty output buffer */
+        if(sndout == endsnd) {                                      /* If there are NO active events during this buffer */
+            if(endsnd != NULL)                                                                       /* and we are not at end of event list */
+                max_samp_written = dz->buflen;                                            /* setup to write an empty buffer */
+            else {
+                sprintf(errstr,"Error in loop logic: do_mix()\n");
+                return(PROGRAM_ERROR);
+            }
+        } else
+            max_samp_written = 0;
+        while(sndout!= endsnd) {                                                                              /* look in all active buffers */
+            out_of_insamples = FALSE;
+
+            //TW UPDATE: handles stereo input
+            if(is_stereo) {
+                if((exit_status = add_stereo_samples_to_outbuf_from_inbuf
+                    (&out_of_insamples,&max_samp_written,sndout,splicebuf,splicelen,lbuf,dz))<0)
+                    return(exit_status);
+            } else {
+                if((exit_status = add_samples_to_outbuf_from_inbuf
+                    (&out_of_insamples,&max_samp_written,sndout,splicebuf,splicelen,lbuf,dz))<0)
+                    return(exit_status);
+            }
+            if(out_of_insamples) {                                                             /* if inbuf exhausted for THIS event */
+
+                if(sndout->next==NULL) {                                                                                   /* if at end of list */
+                    if(sndout->last==NULL) {                   /* if this is definitively the last active event */
+                        free(sndout);                                                                                                           /* free it */
+                        startsnd = NULL;                        /* and set ptr to NULL, so we dropout of outerloop */
+                        break;
+                    } else {                                                                 /* BUT if some previous event still active */
+                        sndout = sndout->last;                                                  /* unlink final event from list */
+                        free(sndout->next);
+                        sndout->next = NULL;
+                        sndout = sndout->next;                                                    /* move sndout to end of list */
+                    }
+                } else if(sndout==startsnd) {                                    /* if this is 1st active event in list */
+                    sndout   = sndout->next;                                                           /* proceed to next event */
+                    startsnd = sndout;                              /* move start of active list to this next event */
+                    unlink_sndoutptr_at_start_of_list(sndout->last);
+                } else {                                                                /* else if this is NOT 1st active event in list */
+                    sndout   = sndout->next;                                                           /* proceed to next event */
+                    unlink_sndoutptr(sndout->last);/* unlink the exhausted event from (active) list */
+                }
+            } else {                                                        /* else there is data remaining in inbuf for THIS event */
+                sndout->obufpos = 0;                                          /* so reset obufpos to start of next obuf */
+                sndout->st_splicpos += dz->buflen;/* reset relativeposition splice-start & nextbufstart */
+                sndout = sndout->next;                                                                     /* and proceed to next event */
+            }
+        }
+        if(startsnd!=NULL)                                /* If we're not at the end of ALL events, write a full buffer */
+            max_samp_written = dz->buflen;
+
+        for(n=0;n<max_samp_written;n++)
+            dz->sampbuf[0][n] = lbuf[n];
+        if(max_samp_written > 0) {
+            if((exit_status = write_samps(dz->sampbuf[0],max_samp_written,dz))<0)
+                return(exit_status);
+        }
+        obufcnt++;
+    }
+    /*if(dz->iparam[TEX_MAXOUT] > MAXSAMP) {*/
+    if(dz->param[TEX_MAXOUT] > F_MAXSAMP) {
+        fprintf(stdout,"WARNING: OVERLOAD: suggest attenuation by < %lf\n",
+                //TW UPDATE (need to factor in the attenation already being used to give correct new attenuation)
+                (((double)F_MAXSAMP/(double)dz->param[TEX_MAXOUT])) * dz->param[TEXTURE_ATTEN]);
+        fflush(stdout);
+    }
+    return(FINISHED);
+}
+
+/************************** CHECK_SEQUENCING ************************/
+
+int check_sequencing(sndoutptr sndout)
+{
+    unsigned int lasttime = sndout->st_sstttime;
+    unsigned int thistime;
+    while(sndout->next != (sndoutptr)0) {
+        sndout = sndout->next;
+        if((thistime = sndout->st_sstttime) < lasttime) {
+            sprintf(errstr,"Sequencing anomaly in sndout list: check_sequencing()\n");
+            return(PROGRAM_ERROR);
+        }
+        lasttime = thistime;
+    }
+    return(FINISHED);
+}
+
+/************************** ADD_SAMPLES_TO_OUTBUF_FROM_INBUF ************************/
+
+int add_samples_to_outbuf_from_inbuf
+(int *out_of_insamples,int *max_samp_written,sndoutptr sndout,double *splicebuf,int splicelen,float *lbuffer,dataptr dz)
+{
+    unsigned int thisopos = sndout->obufpos;
+    unsigned int here;
+    double hereval = 0.0;
+    float *lbuf    = lbuffer + thisopos;
+    float *lbufend = lbuffer + dz->buflen;
+    int splicpos  = sndout->st_splicpos + thisopos;
+    float outval, thismaxoutval;
+    int max_set = FALSE;
+    while(lbuf < lbufend) {
+        if((here = (unsigned int) sndout->ibufpos) >= sndout->ibufcnt) {        /* TRUNCATE : get current pos in inbuf */
+            *out_of_insamples = TRUE;
+            *max_samp_written = max(*max_samp_written,lbuf - lbuffer);
+            /* SAFETY CHECK--> */
+            if(splicpos < splicelen) {
+                sprintf(errstr,"BUM endsplice: add_samples_to_outbuf_from_inbuf()\n");
+                return(PROGRAM_ERROR);
+            }
+            /* <--SAFETY CHECK */
+
+            max_set = TRUE;
+            break;
+        }
+        hereval = get_interpd_value(here,sndout->ibufpos,sndout);
+        /* SAFETY FOR ARITHMETIC ROUNDING ERROS CALCULATING START OF SPLICE --> */
+        if(splicpos >= splicelen)
+            hereval = 0.0;
+        /* <--SAFETY */
+
+        if(splicpos >= 0)
+            hereval *= splicebuf[splicpos >> 1];
+        splicpos += STEREO;
+        outval =(float)( *lbuf + (hereval * sndout->lgain ));
+        if((thismaxoutval = (float) fabs(outval)) > dz->param[TEX_MAXOUT])
+            dz->param[TEX_MAXOUT] = thismaxoutval;
+        *lbuf  = outval;
+        lbuf++;
+        outval = (float)(*lbuf + (hereval * sndout->rgain));
+        if((thismaxoutval = (float) fabs(outval)) > dz->param[TEX_MAXOUT])
+            dz->param[TEX_MAXOUT] =  thismaxoutval;
+        *lbuf = outval;
+        lbuf++;
+        sndout->ibufpos += sndout->step;
+    }
+    if(!max_set)
+        *max_samp_written = dz->buflen;
+    return(FINISHED);
+}
+
+//TW UPDATE: NEW FUNCTIONfor stereo input (updated for flotsams)
+/************************** ADD_STEREO_SAMPLES_TO_OUTBUF_FROM_INBUF ************************/
+
+int add_stereo_samples_to_outbuf_from_inbuf
+(int *out_of_insamples,int *max_samp_written,sndoutptr sndout,double *splicebuf,int splicelen,float *lbuffer,dataptr dz)
+{
+    unsigned int thisopos = sndout->obufpos;
+    unsigned int here;
+    double chanval1, chanval2;
+    float *lbuf    = lbuffer + thisopos;
+    float *lbufend = lbuffer + dz->buflen;
+    int splicpos  = sndout->st_splicpos + thisopos;
+    float outval, thismaxoutval;
+    int max_set = FALSE;
+    while(lbuf < lbufend) {
+        if((here = (unsigned int)sndout->ibufpos)>=sndout->ibufcnt) {   /* TRUNCATE : get current pos in inbuf */
+            *out_of_insamples = TRUE;
+            *max_samp_written = max(*max_samp_written,lbuf - lbuffer);
+            if(splicpos < splicelen) {
+                sprintf(errstr,"BUM endsplice: add_samples_to_outbuf_from_inbuf()\n");
+                return(PROGRAM_ERROR);
+            }
+            max_set = TRUE;
+            break;
+        }
+        chanval1 = get_interpd_value_stereo(here,sndout->ibufpos,&chanval2,sndout);
+        /* SAFETY FOR ARITHMETIC ROUNDING ERROS CALCULATING START OF SPLICE --> */
+        if(splicpos >= splicelen) {
+            chanval1 = 0.0;
+            chanval2 = 0.0;
+        }
+        /* <--SAFETY */
+        if(splicpos >= 0) {
+            chanval1 *= splicebuf[splicpos >> 1];
+            chanval2 *= splicebuf[splicpos >> 1];
+        }
+        splicpos += STEREO;
+        outval = (float)(*lbuf + (chanval1 * sndout->lgain));
+        if((thismaxoutval = (float)fabs(outval))>dz->param[TEX_MAXOUT])
+            dz->param[TEX_MAXOUT] = thismaxoutval;
+        *lbuf  = outval;
+        lbuf++;
+        outval = (float)(*lbuf + (chanval2 * sndout->lgain));   /* only one gain val for stereo inputs: kept in lgain */
+        if((thismaxoutval = (float)fabs(outval))>dz->param[TEX_MAXOUT])
+            dz->param[TEX_MAXOUT] = thismaxoutval;
+        *lbuf = outval;
+        lbuf++;
+        sndout->ibufpos += sndout->step;
+    }
+    if(!max_set)
+        *max_samp_written = dz->buflen;
+    return(FINISHED);
+}
+
+/************************** GET_INTERPD_VALUE ************************/
+
+double get_interpd_value(unsigned int here,double ibufpos,sndoutptr sndout)
+{
+    unsigned int next = here+1;             /* NB  all inbufs have a wraparound (0val) point at end */
+    double frac     = ibufpos - (double)here;
+    double hereval  = (double)(sndout->inbuf[here]);
+    double nextval  = (double)(sndout->inbuf[next]);
+    double diff     = nextval - hereval;
+    diff    *= frac;
+    return(hereval+diff);
+}
+
+//TW UPDATE NEW FUNCTION for stereo input
+/************************** GET_INTERPD_VALUE_STEREO ************************/
+
+double get_interpd_value_stereo(unsigned int here,double ibufpos,double *chanval2,sndoutptr sndout)
+{
+    unsigned int next = here+1;             /* NB  all inbufs have a wraparound (0val) point at end */
+    double frac     = ibufpos - (double)here;
+    double hereval, nextval, diff;
+    double chanval1;
+    unsigned int sthere = here * 2, stnext = next * 2;
+    hereval  = (double)(sndout->inbuf[sthere]);
+    nextval  = (double)(sndout->inbuf[stnext]);
+    diff     = (nextval - hereval) * frac;
+    chanval1 = hereval+diff;
+    sthere++;
+    stnext++;
+    hereval  = (double)(sndout->inbuf[sthere]);
+    nextval  = (double)(sndout->inbuf[stnext]);
+    diff     = (nextval - hereval) * frac;
+    *chanval2 = hereval+diff;
+    return(chanval1);
+}
+
+/************************** UNLINK_SNDOUTPTR_AT_START_OF_LIST ************************/
+
+void unlink_sndoutptr_at_start_of_list(sndoutptr sndout)
+{
+    sndout->next->last = (sndoutptr)0;
+    free(sndout);
+}
+
+/************************** UNLINK_SNDOUTPTR ************************/
+
+void unlink_sndoutptr(sndoutptr sndout)
+{
+    sndout->next->last = sndout->last;
+    sndout->last->next = sndout->next;
+    free(sndout);
+}

+ 191 - 0
dev/texture/texperm.c

@@ -0,0 +1,191 @@
+/*
+ * Copyright (c) 1983-2013 Trevor Wishart and Composers Desktop Project Ltd
+ * http://www.trevorwishart.co.uk
+ * http://www.composersdesktop.com
+ *
+ This file is part of the CDP System.
+ 
+ The CDP System is free software; you can redistribute it
+ and/or modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+ 
+ The CDP System is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU Lesser General Public License for more details.
+ 
+ You should have received a copy of the GNU Lesser General Public
+ License along with the CDP System; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA
+ *
+ */
+/* floatsam version: no changes */
+#include <stdio.h>
+#include <stdlib.h>
+#include <structures.h>
+#include <tkglobals.h>
+#include <texture.h>
+#include <globcon.h>
+#include <arrays.h>
+
+#include <osbind.h>
+
+static void rndpermm(int k,int pindex,int **permm,dataptr dz);
+static void insert(int m,int t,int pindex,int **permm,dataptr dz);
+static void prefix(int m,int pindex,int **permm,dataptr dz);
+static void shuflup(int k,int pindex, int **permm,dataptr dz);
+
+/******************************** DOPERM *********************************
+ *
+ * Either deliver next item in a permuted set, or (if set exhausted)
+ * generate a randon permutation of the set and deliver its first
+ * element.
+ *
+ * (1)  If this permset does not have the same length as the last...
+ * (2)    Set a new permset length.
+ * (3)    If a permset already exists (i.e. this is not first)
+ *    Free the permset space, and malloc a new space of correct size,
+ * (4)    Create a random permutation of elements into the permset.
+ * (5)    Set the pointer-to-the-set to 0.
+ * (6)    Set the size of the previous perm (which will be this one,
+ *    next time!) to this permset size.
+ * (6a) Whether or not a new perm set has been set up...
+ * (7)    Get the value of the next item in the current permset,
+ *    incrementing the set pointer in the process.
+ * (8)    If this has the same value as the previous-one-output-from-doperm
+ *    increment the repetition counter.
+ * (9)    Otherwise set the repetition counter to 1.
+ * (10)   If the set pointer has run beyond the permset.
+ * (11)     reset the pointer to 0.
+ * (12)     generate a new random perm (of same length).
+ * (13) Continue this process if the number of permissible repetitions
+ *  is exceeded.
+ * (14) Set the value for lastpermval, for next call.
+ * (15) Return the value.
+ */
+
+int doperm(int k,int pindex,int *val,dataptr dz)
+{
+    int i, OK;
+    int **permm = dz->tex->perm;
+    if(pindex >= PERMCNT) {
+        sprintf(errstr,"doperm(): Perm index %d too big (max = %d)\n",pindex,PERMCNT);
+        return(PROGRAM_ERROR);
+    }
+    if(k <= 1) {
+        if(k>=0) {
+            *val = 0;
+            return(FINISHED);
+        } else {
+            sprintf(errstr,"doperm(): Invalid perm count %d\n",k);
+            return(PROGRAM_ERROR);
+        }
+    }
+    if((k*dz->iparray[TXRPT][pindex])!=dz->iparray[TXLASTPERMLEN][pindex]) {    /* 1 */
+        dz->iparray[TXPERMLEN][pindex] = (int)(k * dz->iparray[TXRPT][pindex]); /* 2 */
+        if(permm[pindex]   != (int *)0)                                         /* 3 */
+            free(permm[pindex]);
+        if((permm[pindex] = (int *)malloc(dz->iparray[TXPERMLEN][pindex] * sizeof(int)))==NULL) {
+            sprintf(errstr,"INSUFFICIENT MEMORY for permutation %d\n",pindex+1);
+            return(MEMORY_ERROR);
+        }
+        rndpermm(k,pindex,permm,dz);                                            /* 4 */
+        dz->iparray[TXPERMINDEX][pindex]   = 0;                                 /* 5 */
+        dz->iparray[TXLASTPERMLEN][pindex] = dz->iparray[TXPERMLEN][pindex];    /* 6 */
+    }
+    do {                        /* 6a */
+        OK = 1;
+        i = *(permm[pindex] + (dz->iparray[TXPERMINDEX][pindex]++));            /* 7 */
+        if(i==dz->iparray[TXLASTPERMVAL][pindex]) {                             /* 8 */
+            dz->iparray[TXREPETCNT][pindex]++;
+            if(dz->iparray[TXREPETCNT][pindex]>dz->iparray[TXRPT][pindex]) {
+                dz->iparray[TXREPETCNT][pindex] = dz->iparray[TXRPT][pindex];
+                OK = 0;
+            }
+        } else {
+            dz->iparray[TXREPETCNT][pindex]=1;
+        }
+        if(dz->iparray[TXPERMINDEX][pindex]>=dz->iparray[TXPERMLEN][pindex]) {  /* 10 */
+            dz->iparray[TXPERMINDEX][pindex] = 0;                               /* 11 */
+            rndpermm(k,pindex,permm,dz);                                        /* 12 */
+        }
+    }while(!OK);                                                                /* 13 */
+    dz->iparray[TXLASTPERMVAL][pindex] = i;                                     /* 14 */
+    *val = i;
+    return(FINISHED);                                                           /* 15 */
+}
+
+/*************************** RNDPERMM *******************************
+ *
+ * Produce a permutation of k objects and store it in permutation-store
+ * number 'pindex'.
+ *
+ * (1)  permlen is the number of objects (k) times the number of repetitions
+ *      permitted (rpt[pindex]) = N.
+ * (2)  This is the efficient algorithm for distributing N objects into
+ *      a random perm.
+ * (3)  As we really only have k objects, we take the value%rpt in each
+ *      permutation location.
+ *      e.g. 3 objects repeated 3 times would give us a random perm of
+ *      nine objects such as
+ *      5 6 2 8 3 0 1 7 4
+ *      applying %3 to this we get
+ *      2 0 2 2 0 0 1 1 1
+ *      i.e. a perm of 3 objects with no more than 3 consecutive repets
+ *      of any one object!!
+ */
+
+void rndpermm(int k,int pindex,int **permm,dataptr dz)
+{
+    int n, t;
+    for(n=0;n<dz->iparray[TXPERMLEN][pindex];n++) {     /* 1 */
+        t = (int)(drand48() * (double)(n+1));       /* 2 */
+        if(t==n) {
+            prefix(n,pindex,permm,dz);
+        } else {
+            insert(n,t,pindex,permm,dz);
+        }
+    }
+    for(n=0;n<dz->iparray[TXPERMLEN][pindex];n++)       /* 3 */
+        *(permm[pindex]+n) = (int)(*(permm[pindex]+n) % k);
+}
+
+/***************************** INSERT **********************************
+ *
+ * Insert the value m AFTER the T-th element in permm[pindex].
+ */
+
+void insert(int m,int t,int pindex,int **permm,dataptr dz)
+{   
+    shuflup(t+1,pindex,permm,dz);
+    *(permm[pindex]+t+1) = m;
+}
+
+/***************************** PREFIX ************************************
+ *
+ * Insert the value m at start of the permutation permm[pindex].
+ */
+
+void prefix(int m,int pindex,int **permm,dataptr dz)
+{
+    shuflup(0,pindex,permm,dz);
+    *permm[pindex] = m;
+}
+
+/****************************** SHUFLUP ***********************************
+ *
+ * move set members in permm[pindex] upwards, starting from element k.
+ */
+
+void shuflup(int k,int pindex, int **permm,dataptr dz)
+{
+    int n, *i;
+    int z = dz->iparray[TXPERMLEN][pindex] - 1;
+    i = permm[pindex] + z;
+    for(n = z;n > k;n--) {
+        *i = *(i-1);
+        i--;
+    }
+}

+ 1661 - 0
dev/texture/texprepro.c

@@ -0,0 +1,1661 @@
+/*
+ * Copyright (c) 1983-2013 Trevor Wishart and Composers Desktop Project Ltd
+ * http://www.trevorwishart.co.uk
+ * http://www.composersdesktop.com
+ *
+ This file is part of the CDP System.
+
+    The CDP System is free software; you can redistribute it
+    and/or modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    The CDP System is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with the CDP System; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+    02111-1307 USA
+ *
+ */
+/* floatsam version */
+#include <stdio.h>
+#include <stdlib.h>
+#include <memory.h>
+#include <structures.h>
+#include <tkglobals.h>
+#include <globcon.h>
+#include <processno.h>
+#include <modeno.h>
+#include <arrays.h>
+#include <texture.h>
+#include <ctype.h>
+#include <sfsys.h>
+#include <osbind.h>
+#include <cdpmain.h>
+
+#if defined unix || defined __GNUC__
+#define round(x) lround((x))
+#endif
+
+#define omit_count  is_rectified
+#define omit_item   is_mapping
+#define one_in      rampbrksize
+#define negscat     fzeroset
+
+#define SQUASH    (2.0) /* non-linearity factor */
+#define MAXPOSCNT (512) /* max no. of spatial positions between lspkrs */
+
+static int  initialise_texture_structure(dataptr dz);
+static int  set_up_and_fill_insample_buffers(insamptr **insound,dataptr dz);
+static int  setup_texflag(texptr tex,dataptr dz);
+static int  adjust_some_input_params(dataptr dz);
+static int  preset_some_internal_texture_params(dataptr dz);
+static int  install_unused_texture_flags(int *total_flags,int unused_flags,dataptr dz);
+static int  install_the_internal_flags(int total_flags,int internal_flags,dataptr dz);
+static int  get_the_notedata(texptr tex,dataptr dz);
+static int  extend_timeset(dataptr dz);
+static int  generate_timeset(dataptr dz);
+static int  do_prespace(motifptr tset,dataptr dz);
+static int  get_sample_pitches(FILE *fp,dataptr dz);
+static int  get_motifs(FILE *fp,int *motifcnt,dataptr dz);
+static int  motifchek(motifptr thismotif);
+static void convert_cmdline_instrnos_to_internal_representation(dataptr dz);
+static int  check_max_transpos_compatible_with_splicelen(dataptr dz);
+static int  set_amptype_params(dataptr dz);
+static int  set_decor_pitchposition_params(dataptr dz);
+static void copy_note(noteptr thisnote,noteptr orignote);
+static int  add_motif_to_end_of_motiflist(motifptr *new,dataptr dz);
+static int  scatter_and_quantise_tset_times(double *lasttime,noteptr *thisnote,dataptr dz);
+static int  pre_space(noteptr thisnote,dataptr dz);
+static int  getpos(double thistime,double *position,dataptr dz);
+static int  spread_and_set_cpos(double *position,double given_position,double spread,dataptr dz);
+static int  chekrang(double *val);
+static int  read_a_note_from_notedata_file
+                (noteptr thisnote,int noteno,int motifno,double *lasttime,dataptr dz);
+static int  generate_tset_times(double *thistime,noteptr *thisnote,dataptr dz);
+static int  un_link_note(noteptr thisnote);
+static int  new_motif(motifptr *thismotif);
+static int  unlink_last_motif(motifptr thismotif);
+static void subtract_one_from_brkvals(int paramno,dataptr dz);
+static int  bigscatter(noteptr *thisnote,double thistime,double timestep,double scatter,double *lasttime,dataptr dz);
+static int  get_data_item(char *q,char **p,double *val);
+static int  init_note(noteptr *thisnote);
+static void put_znote(noteptr thisnote);
+static int  assign_timeset_hfset_motifsets(dataptr dz);
+static int  massage_params(dataptr dz);
+static int  init_motifs(dataptr dz);
+
+/************************* TEXTURE_PREPROCESS ****************************
+ *
+ * (1)  Establish the bitflag which characterises the texture process.
+ * (2)  For consistency across all texture processes, all unused flags are mallocd.
+ *      This ensures that the numbering of the INTERNAL flags is consistent across all applics.
+ * (3)  Convert some input parameters to form used internally, and check some against insnd lengths.
+ */
+
+int texture_preprocess(dataptr dz)
+{
+    int exit_status;
+    int total_flags, unused_flags, n;
+    unsigned int texflag;
+
+    initialise_random_sequence(0,TEXTURE_SEED,dz);
+    if((exit_status = initialise_texture_structure(dz))<0)
+        return(exit_status);
+
+    if((exit_status = set_up_and_fill_insample_buffers(&(dz->tex->insnd),dz))<0)
+        return(exit_status);
+    
+   if((exit_status = initperm(&(dz->tex->perm),dz))<0)
+        return(exit_status);
+
+    if((exit_status = setup_texflag(dz->tex,dz))<0)                     /* 1 */
+        return(exit_status);
+
+    texflag = dz->tex->txflag;
+
+    if((exit_status = adjust_some_input_params(dz))<0)
+        return(exit_status);
+                                                                        
+    if((exit_status = preset_some_internal_texture_params(dz))<0)
+        return(exit_status);
+                                                                        /* 2 */
+    unused_flags = TOTAL_POSSIBLE_USER_FLAGS - dz->application->vflag_cnt;
+
+    if((exit_status = install_unused_texture_flags(&total_flags,unused_flags,dz))<0)
+        return(exit_status);
+
+    if((exit_status = install_the_internal_flags(total_flags,INTERNAL_FLAGS_CNT,dz))<0)
+        return(exit_status);
+
+    if((exit_status = get_the_notedata(dz->tex,dz))<0)
+        return(exit_status);
+
+    if((exit_status = assign_timeset_hfset_motifsets(dz))<0)
+        return(exit_status);
+
+    if((exit_status = massage_params(dz))<0)                            /* 3 */
+        return(exit_status);
+   if(texflag & ORN_DEC_OR_TIMED) {
+        if((exit_status = extend_timeset(dz))<0)                        /* 7 */
+            return(exit_status);
+    } else {
+        if((exit_status = generate_timeset(dz))<0)                      /* 8 */
+            return(exit_status);
+    }
+    if((exit_status = do_prespace(dz->tex->timeset,dz))<0)
+        return(exit_status);
+
+    if(dz->process == SIMPLE_TEX && dz->vflag[CYCLIC_TEXFLAG]) {
+        if(dz->infilecnt < 2)
+            dz->vflag[CYCLIC_TEXFLAG] = 0;
+        else if (dz->vflag[PERM_TEXFLAG]) {
+            if((dz->peakno = (int *)malloc(dz->infilecnt * sizeof(int))) == NULL) {
+                sprintf(errstr,"Insufficient memory for cyclic permutations of input files.\n");
+                return(MEMORY_ERROR);
+            }
+            if((dz->lastpeakno = (int *)malloc(dz->infilecnt * sizeof(int))) == NULL) {
+                sprintf(errstr,"Insufficient memory for cyclic permutations of input files.\n");
+                return(MEMORY_ERROR);
+            }
+            for(n=0;n<dz->infilecnt;n++) {
+                dz->peakno[n] = n;
+                dz->lastpeakno[n] = n;
+            }
+        }
+    }
+    /* create stereo outfile here! */
+    /* RWD 4:2002  now we can open outfile with corect params! */
+//TW UPDATE to use stereo input means that dz->infile->channels must be retained for now
+//TW Open outfile later (texture5.c)
+    return(FINISHED);
+}
+
+/*********************** INITIALISE_TEXTURE_STRUCTURE ******************************/
+
+int initialise_texture_structure(dataptr dz)
+{
+    int n;
+    if((dz->tex = (texptr)malloc(sizeof(struct textural)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY for texture structure.\n");
+        return(MEMORY_ERROR);
+    }
+
+    dz->tex->txflag     = 0;
+    dz->tex->motifhead  = (motifptr)0;
+    dz->tex->insnd      = (insamptr *)0;
+    dz->tex->timeset    = (motifptr)0;
+    dz->tex->hfldmotif  = (motifptr)0;
+    dz->tex->phrase     = (motifptr *)0;
+    dz->tex->perm       = (int **)0;
+    dz->tex->dectypstor = 0;
+    dz->tex->dectypcnt  = 0;
+    dz->tex->amptypstor = 0;
+    dz->tex->amptypcnt  = 0;
+    dz->tex->phrasecnt  = 0;
+    dz->tex->ampdirectd = FALSE;
+
+    if((dz->tex->insnd  = (insamptr *)malloc(dz->infilecnt * sizeof(insamptr)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY for texture insound structure.\n");
+        return(MEMORY_ERROR);
+    }
+    for(n=0;n<dz->infilecnt;n++) {
+        dz->tex->insnd[n] = (insamptr)0;
+        if((dz->tex->insnd[n]= (insamptr)malloc(sizeof(struct insample)))==NULL) {
+            sprintf(errstr,"INSUFFICIENT MEMORY for texture insound[%d] structure.\n",n+1);
+            return(MEMORY_ERROR);
+        }
+    }
+    return(FINISHED);
+}
+ 
+/************************** SET_UP_AND_FILL_INSAMPLE_BUFFERS ****************************
+ *
+ * 1) Set buffer pointer to zero, until it has been malloced.
+ *    This make freeing of tex structure possible.
+ */
+
+int set_up_and_fill_insample_buffers(insamptr **insound,dataptr dz)
+{
+    int n;
+    int samps_read;
+    int thisbufsize;
+    int wrap_around_samps = 1;
+    for(n=0;n<dz->infilecnt;n++) {
+        ((*insound)[n])->buffer = /*(float *)0*/NULL;                   /* 1 */
+        thisbufsize = dz->insams[n];
+        thisbufsize += wrap_around_samps; 
+        if((((*insound)[n])->buffer  = (float *)malloc(thisbufsize * sizeof(float)))==NULL) {
+            sprintf(errstr,"INSUFFICIENT MEMORY for texture insound buffer pointer %d.\n",n+1);
+            return(MEMORY_ERROR);
+        }
+        memset((char *)((*insound)[n])->buffer,0,thisbufsize * sizeof(float));
+        if((samps_read = fgetfbufEx(((*insound)[n])->buffer,thisbufsize,dz->ifd[n],0)) < 0) {
+            sprintf(errstr,"Can't read sndfile %d to buffer: set_up_and_fill_insample_buffers()\n",n+1);
+            return(SYSTEM_ERROR);
+        }
+        if(samps_read != dz->insams[n]) {
+            sprintf(errstr,"Error reading sndfile %d to buf: set_up_and_fill_insample_buffers()\n",n+1);
+            return(PROGRAM_ERROR);
+        }
+    }
+    return(FINISHED);
+}
+
+/***************************** SETUP_TEXFLAG ****************************/
+
+int setup_texflag(texptr tex,dataptr dz)
+{
+    tex->txflag = 0;
+    switch(dz->process) {
+    case(SIMPLE_TEX): break;
+    case(GROUPS):     tex->txflag |= IS_GROUPS;                                                     break;
+    case(DECORATED):  tex->txflag |= IS_DECOR;                                                      break;
+    case(PREDECOR):   tex->txflag |= IS_DECOR;  tex->txflag |= ISPRE_DECORORN;                      break;
+    case(POSTDECOR):  tex->txflag |= IS_DECOR;  tex->txflag |= ISPOST_DECORORN;                     break;
+    case(ORNATE):     tex->txflag |= IS_ORNATE;                                                     break;
+    case(PREORNATE):  tex->txflag |= IS_ORNATE; tex->txflag |= ISPRE_DECORORN;                      break;
+    case(POSTORNATE): tex->txflag |= IS_ORNATE; tex->txflag |= ISPOST_DECORORN;                     break;
+    case(MOTIFS):     tex->txflag |= IS_MOTIFS;                                                     break;
+    case(MOTIFSIN):   tex->txflag |= IS_MOTIFS; tex->txflag |= MOTIF_IN_HF;                         break;
+    case(TIMED):                                                            tex->txflag |= ISTIMED; break;
+    case(TGROUPS):    tex->txflag |= IS_GROUPS;                             tex->txflag |= ISTIMED; break;
+    case(TMOTIFS):    tex->txflag |= IS_MOTIFS;                             tex->txflag |= ISTIMED; break;
+    case(TMOTIFSIN):  tex->txflag |= IS_MOTIFS; tex->txflag |= MOTIF_IN_HF; tex->txflag |= ISTIMED; break;
+    default:
+        sprintf(errstr,"Unknown process in setup_texflag()\n");
+        return(PROGRAM_ERROR);
+    }
+    switch(dz->mode) {
+    case(TEX_NEUTRAL):  break;
+    case(TEX_HFIELD):   tex->txflag |= ISHARM;                                                          break;
+    case(TEX_HFIELDS):  tex->txflag |= ISHARM;                          tex->txflag |= ISMANY_HFLDS;    break;
+    case(TEX_HSET):     tex->txflag |= ISHARM;  tex->txflag |= IS_HS;                                   break;
+    case(TEX_HSETS):    tex->txflag |= ISHARM;  tex->txflag |= IS_HS;   tex->txflag |= ISMANY_HFLDS;    break;
+    default:
+        sprintf(errstr,"Unknown mode in setup_texflag()\n");
+        return(PROGRAM_ERROR);
+    }
+    return(FINISHED);
+}
+
+/************************** ADJUST_SOME_INPUT_PARAMS ****************************
+ *
+ * (1)  dz->vflag[WHICH_CHORDNOTE] internally carries all 3 vals (first,highest,every).
+ *
+ * (2)  Gprange, in cases with Hfields, is an integer count of HF-field notes to use.
+ */
+
+int adjust_some_input_params(dataptr dz)
+{
+    int texflag = dz->tex->txflag;
+    if((texflag & IS_ORN_OR_DEC) && dz->vflag[FORCE_EVERY]==TRUE)
+        dz->vflag[WHICH_CHORDNOTE] = DECOR_EVERY;                       /* 1 */
+
+    if((texflag & IS_DEC_OR_GRP) && (texflag & ISHARM)) {               /* 2 */
+        dz->is_int[TEX_GPRANGLO] = TRUE;
+        dz->is_int[TEX_GPRANGHI] = TRUE;
+        dz->iparam[TEX_GPRANGLO] = round(dz->param[TEX_GPRANGLO]);
+        dz->iparam[TEX_GPRANGHI] = round(dz->param[TEX_GPRANGHI]);
+    }
+    return(FINISHED);
+}
+
+/***************************** PRESET_SOME_INTERNAL_TEXTURE_PARAMS ****************************/
+
+int preset_some_internal_texture_params(dataptr dz)
+{   
+    int cnt = 0;
+    dz->iparam[SPINIT]    = 0;   cnt++; /* ALL CLUMPS */
+    dz->iparam[SPCNT]     = 0;   cnt++; 
+    dz->iparam[DIRECTION] = 0;   cnt++; 
+    dz->param[CPOS]       = 0.5; cnt++; /* for safety only */   /* SPATIALISATION */
+    dz->param[TPOSITION]  = 0.5; cnt++; /* for safety only */
+    dz->param[THISSPRANGE]= 1.0; cnt++; /* full range */
+    /*dz->iparam[TEX_MAXOUT]= 0.0;   cnt++; *//* min value */
+    dz->param[TEX_MAXOUT] = 0.0;   cnt++;         /*RWD*/
+    if(cnt != dz->application->internal_param_cnt) {
+        sprintf(errstr,"preset_some_internal_texture_params() has false count\n");
+        return(PROGRAM_ERROR);
+    }
+    dz->itemcnt = 0;
+    return(FINISHED);
+}
+
+/***************************** INSTALL_UNUSED_TEXTURE_FLAGS ****************************/
+
+int install_unused_texture_flags(int *total_flags,int unused_flags,dataptr dz)
+{
+    int n;
+    *total_flags = dz->application->vflag_cnt + unused_flags;
+    if(unused_flags > 0) {
+        if((dz->vflag  = 
+            (char *)realloc(dz->vflag,(*total_flags) * sizeof(char)))==NULL) {
+            sprintf(errstr,"INSUFFICIENT MEMORY for internal flags.\n");
+            return(MEMORY_ERROR);
+        }
+        for(n=0;n<unused_flags;n++) {
+            switch(n) {
+            case(4):    dz->vflag[2] = FALSE;   break;
+            case(3):    dz->vflag[3] = FALSE;   break;
+            case(2):    dz->vflag[4] = FALSE;   break;
+            case(1):    dz->vflag[5] = FALSE;   break;
+            case(0):    dz->vflag[6] = FALSE;   break;
+            }
+        }
+    }
+    return(FINISHED);
+}
+
+/***************************** INSTALL_THE_INTERNAL_FLAGS ****************************/
+
+int install_the_internal_flags(int total_flags,int internal_flags,dataptr dz)
+{
+        /* THESE FLAGS ARE NOT AVAILABLE TO USER : but they are used in the code */
+    total_flags += internal_flags;
+    if((dz->vflag  = 
+        (char *)realloc(dz->vflag,total_flags * sizeof(char)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY to reallocate internal flags.\n");
+        return(MEMORY_ERROR);
+    }
+    dz->iparam[DECCENTRE] = FALSE;
+    return(FINISHED);
+}
+
+/***************************** GET_THE_NOTEDATA ****************************/
+
+int get_the_notedata(texptr tex,dataptr dz)
+{
+    int exit_status;
+    unsigned int texflag = tex->txflag;
+    int motifcnt, expected_motifcnt = 0;
+
+    if(dz->fp==NULL) {
+        sprintf(errstr,"notedata fileptr not initialised: get_the_notedata()\n");
+        return(PROGRAM_ERROR);
+    }
+    if((exit_status = get_sample_pitches(dz->fp,dz))<0) {
+        sprintf(errstr,"Insufficient pitch values in notedata file.\n");
+        return(DATA_ERROR);
+    }
+    if((exit_status = get_motifs(dz->fp,&motifcnt,dz))<0)
+        return(exit_status);
+    if(texflag & ORN_DEC_OR_TIMED)  expected_motifcnt++;    /* Line to work on */
+    if(texflag & ISHARM)            expected_motifcnt++;    /* HF data         */
+    if(texflag & IS_ORN_OR_MTF)     expected_motifcnt++;    /* Ornmnts or mtfs */
+
+    if(texflag & IS_ORN_OR_MTF) {
+        if(motifcnt < expected_motifcnt) {
+            sprintf(errstr,"Insufficient motifs in notedata file.\n");
+            return(DATA_ERROR);
+        }
+    } else {
+        if(motifcnt!=expected_motifcnt) {
+            sprintf(errstr,"Incorrect number [%d] of motifs in notedata file (expected %d).\n",
+            motifcnt,expected_motifcnt);
+            return(DATA_ERROR);
+        }
+    }
+    return(FINISHED);
+}
+
+/**************************** EXTEND_TIMESET *******************************/
+
+int extend_timeset(dataptr dz)
+{
+    int exit_status;
+    int origcnt = 0, n;
+    noteptr startnote = dz->tex->motifhead->firstnote;
+    noteptr orignote, thisnote  = startnote;
+    double *timediff;
+    
+    if(startnote==(noteptr)0) {
+        sprintf(errstr,"Problem in note timings: extend_timeset()\n");
+        return(PROGRAM_ERROR);
+    }
+    while(thisnote!=(noteptr)0) {
+        if(thisnote->ntime > dz->param[TEXTURE_DUR]) {
+            delete_notes_here_and_beyond(thisnote);
+            return(FINISHED);
+        }
+        thisnote = thisnote->next;
+        origcnt++;
+    }
+
+    if((timediff = (double *)malloc(origcnt * sizeof(double)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY for timegaps array.\n");
+        return(MEMORY_ERROR);
+    }
+    n = 1;
+    thisnote = startnote;
+    while(thisnote->next !=(noteptr)0) {
+        thisnote = thisnote->next;
+        timediff[n++] = thisnote->ntime - thisnote->last->ntime;
+    }
+    if(dz->brksize[TEXTURE_SKIP]) {
+        if((exit_status = read_value_from_brktable(thisnote->ntime,TEXTURE_SKIP,dz))<0) {
+            free(timediff);
+            return(exit_status);
+        }
+    }
+    timediff[0] = dz->param[TEXTURE_SKIP];
+    n = 0;
+    orignote = startnote;
+
+    for(;;) {
+        if(thisnote->ntime > dz->param[TEXTURE_DUR] && timediff[n] > 0.0)
+            break;
+        if((exit_status = make_new_note(&thisnote))<0) {
+            free(timediff);
+            return(exit_status);
+        }
+        copy_note(thisnote,orignote);
+        thisnote->ntime = (float)(thisnote->last->ntime + timediff[n]);
+        if(++n>=origcnt) {
+            if(dz->brksize[TEXTURE_SKIP]) {
+                if((exit_status = read_value_from_brktable(thisnote->ntime,TEXTURE_SKIP,dz))<0) {
+                    free(timediff);
+                    return(exit_status);
+                }
+                timediff[0] = dz->param[TEXTURE_SKIP];
+            }
+            n = 0;
+            orignote = startnote;
+        } else
+            orignote = orignote->next;
+    }
+    dz->brksize[TEXTURE_SKIP] = 0;  /* prevent future reads */
+    free(timediff);
+    return(FINISHED);
+}
+
+
+/*********************************************************************
+ *
+ * (1)  Generating the tset (set of timed values on or around which the
+ *      texture is to be generated).
+*/
+/************************** GENERATE_TIMESET ******************************
+ *
+ * (A)  Zero all other parameters besides time.
+ */     
+
+int generate_timeset(dataptr dz)
+{
+    int exit_status;
+    double lasttime, thistime = 0.0;
+    noteptr thisnote;
+    motifptr tset;
+    if((exit_status = add_motif_to_end_of_motiflist(&(dz->tex->timeset),dz))<0)
+        return(exit_status);
+    tset =  dz->tex->timeset;
+    if((thisnote = tset->firstnote)==(noteptr)0) {
+        sprintf(errstr,"Failure to find 1st note in motif: generate_timeset()\n");
+        return(PROGRAM_ERROR);
+    }
+    put_znote(thisnote);            /* A */
+    thisnote->ntime = (float)thistime;
+    if(dz->brksize[TEXTURE_PACK]) {
+        if((exit_status = read_value_from_brktable(thistime,TEXTURE_PACK,dz))<0)
+            return(exit_status);
+    }       
+    thistime += dz->param[TEXTURE_PACK];
+    while(thistime<dz->param[TEXTURE_DUR]) {
+        if((exit_status = generate_tset_times(&thistime,&thisnote,dz))<0)
+            return(exit_status);
+        put_znote(thisnote);                /* A */
+    }
+    thisnote = tset->firstnote;
+    lasttime = thisnote->ntime;
+    thisnote = thisnote->next;
+    dz->omit_count = 0;
+    dz->omit_item  = 0;
+    dz->negscat    = -1;    // Initialisation
+    while(thisnote!=(noteptr)0) {
+        if((exit_status = scatter_and_quantise_tset_times(&lasttime,&thisnote,dz))<0)
+            return(exit_status);
+    }
+    dz->brksize[TEXTURE_PACK]  = 0; /* set these brktables to appear empty, so no read attempts later */
+    dz->brksize[TEXTURE_SCAT]  = 0;
+    dz->brksize[TEXTURE_TGRID] = 0;
+    if(dz->process == SIMPLE_TEX)
+        dz->brksize[TEX_PHGRID] = 0;
+    return(FINISHED);
+}
+
+/***************************** DO_PRESPACE ******************************
+ *
+ * Spatialise the time set, prior to output phase&/or ornamentation.
+ */
+
+int do_prespace(motifptr tset,dataptr dz)
+{
+    int exit_status;
+    noteptr thisnote = tset->firstnote;
+    while(thisnote!=(noteptr)0) {
+        if((exit_status = pre_space(thisnote,dz))<0)
+            return(exit_status);
+        thisnote = thisnote->next;
+    }
+    return(FINISHED);
+}
+
+/**************************** GET_SAMPLE_PITCHES *****************************/
+
+int get_sample_pitches(FILE *fp,dataptr dz)
+{
+    int exit_status;
+/* TW AUGUST 2006: 200--> 2000 */
+    char temp[200000], *q;
+    int pitchcnt = 0;
+    double *p;
+    int got_all_pitches = FALSE;
+/* TW AUGUST 2006: 200--> 2000 */
+    while(!got_all_pitches && (fgets(temp,200000,fp)!=NULL)) {
+        q = temp;
+        if(*q == ';')   //  Allow comments in file
+            continue;
+        p = &(((dz->tex->insnd)[pitchcnt])->pitch);
+        while((exit_status = get_float_from_within_string(&q,p))==TRUE) {
+            if(++pitchcnt >= dz->infilecnt) {
+                got_all_pitches = TRUE;
+                break;
+            }
+            p = &(((dz->tex->insnd)[pitchcnt])->pitch);
+        }
+        if(exit_status==FALSE)
+            return(DATA_ERROR);
+    }
+    if(!got_all_pitches)
+        return(DATA_ERROR);
+    return(FINISHED);
+}
+
+/**************************** GET_MOTIFS *****************************
+ * 
+ * Read data from an ascii file to notelist.
+ */
+
+int get_motifs(FILE *fp,int *motifcnt,dataptr dz)
+{
+    int exit_status;
+    motifptr thismotif;
+    noteptr thisnote;
+    char *p, temp[200];
+    double lasttime = 0.0;
+    int datalen, noteno, motifno = 0;
+    if((exit_status = init_motifs(dz))<0)       /* 8 */
+        return(exit_status);
+    thismotif = dz->tex->motifhead;
+    while(fgets(temp,200,fp)!=NULL) {
+        p = temp;
+        while(isspace(*p))
+            p++;
+        if(*p==ENDOFSTR)
+            continue;
+        if(*p!=TEXTURE_SEPARATOR) {
+//TW UPDATE
+            sprintf(errstr,"'%c' missing before datacount in notedata file: motif %d (or more notes listed than indicated by %cN)\n"
+            "check datalen is correct\n",TEXTURE_SEPARATOR,motifno+1,TEXTURE_SEPARATOR);
+            return(DATA_ERROR);
+        }
+        p++;
+        if(!isdigit(*p) || sscanf(p,"%d",&datalen)!=1) {
+            sprintf(errstr,"No datalength given: motif %d\n",motifno+1);
+            return(DATA_ERROR);
+        }
+        if(datalen <= 0) {
+            sprintf(errstr,"Invalid data length %d in notedata: motif %d\n",datalen,motifno+1);
+            return(DATA_ERROR);
+        }
+        motifno++;
+        thisnote = thismotif->firstnote;
+        for(noteno=1;noteno<=datalen;noteno++) {
+            if((exit_status = read_a_note_from_notedata_file(thisnote,noteno,motifno,&lasttime,dz))<0)
+                return(exit_status);
+            if(exit_status==CONTINUE) {
+                noteno--;
+                continue;
+            }               
+            if((exit_status = make_new_note(&thisnote))<0)
+                return(exit_status);
+        }
+        if((exit_status = un_link_note(thisnote))<0)
+            return(exit_status);
+        if((exit_status = new_motif(&thismotif))<0)
+            return(exit_status);
+    }
+    *motifcnt = motifno;
+    if(motifno > 0)
+        return unlink_last_motif(thismotif);
+    return(FINISHED);
+}
+
+/************************** MOTIFCHEK ********************************
+ *
+ * Check we've not run out of motifs.
+ */
+
+int motifchek(motifptr thismotif)
+{
+    if(thismotif == (motifptr)0) {
+        sprintf(errstr,"motifchek(): Insufficient motifs: even though correctly counted.\n");
+        return(PROGRAM_ERROR);
+    }
+    return(FINISHED);
+}
+
+/***************************** CONVERT_CMDLINE_INSTRNOS_TO_INTERNAL_REPRESENTATION ****************************/
+
+void convert_cmdline_instrnos_to_internal_representation(dataptr dz)
+{
+    if(dz->brksize[TEXTURE_INSLO])
+        subtract_one_from_brkvals(TEXTURE_INSLO,dz);
+    else
+        dz->iparam[TEXTURE_INSLO]--;
+
+    if(dz->brksize[TEXTURE_INSHI])
+        subtract_one_from_brkvals(TEXTURE_INSHI,dz);
+    else
+        dz->iparam[TEXTURE_INSHI]--;
+}
+
+/***************************** CHECK_MAX_TRANSPOS_COMPATIBLE_WITH_SPLICELEN ****************************/
+
+int check_max_transpos_compatible_with_splicelen(dataptr dz)
+{
+    int n, exit_status;
+    double max_maxpitch, max_minpitch, max_transpospitch, maxupshift, upratio, minlen;
+    double min_sndlength = (TEXTURE_SPLICELEN + TEXTURE_SAFETY) * MS_TO_SECS * (double)dz->infile->srate;
+    dz->frametime = TEXTURE_SPLICELEN;
+
+    if(dz->brksize[TEXTURE_MAXPICH]) {
+        if((exit_status = get_maxvalue_in_brktable(&max_maxpitch,TEXTURE_MAXPICH,dz))<0)
+            return(exit_status);
+    } else
+        max_maxpitch = dz->param[TEXTURE_MAXPICH];
+
+    if(dz->brksize[TEXTURE_MINPICH]) {
+        if((exit_status = get_maxvalue_in_brktable(&max_minpitch,TEXTURE_MINPICH,dz))<0)
+            return(exit_status);
+    } else
+        max_minpitch = dz->param[TEXTURE_MINPICH];
+
+    max_transpospitch = max(max_minpitch,max_maxpitch);
+
+    dz->zeroset = 0;    /* use as flag re splicelen change */
+    for(n=0;n<dz->infilecnt;n++) {
+        maxupshift = max_transpospitch - ((dz->tex->insnd)[n])->pitch;
+        upratio    = pow(2.0,(maxupshift/SEMITONES_PER_OCTAVE));
+        minlen     = (double)dz->insams[n]/upratio;
+        if(minlen < min_sndlength) {
+            dz->frametime = 2.0;    
+            min_sndlength = (dz->frametime + TEXTURE_SAFETY) * MS_TO_SECS * (double)dz->infile->srate;
+#ifdef MINDUR_OVERRIDE
+            min_sndlength = 0.0;
+#endif
+            if(minlen < min_sndlength) {
+                dz->frametime = 1.0;    
+                min_sndlength = (dz->frametime + TEXTURE_SAFETY) * MS_TO_SECS * (double)dz->infile->srate;
+                if(minlen < min_sndlength) {
+                    sprintf(errstr,"sndfile %d [%.3lf secs] too short for max upward transposition [ratio %.2lf].\n",
+                    n+1,(double)dz->insams[n]/(double)dz->infile->srate,upratio);
+                    return(DATA_ERROR);
+                }
+            }
+        }
+    }
+    return(FINISHED);
+}
+
+/************************* SET_AMPTYPE_PARAMS *******************************/
+
+int set_amptype_params(dataptr dz)
+{   int mask = 1, n;
+    dz->tex->amptypcnt  = 0;
+    dz->tex->amptypstor = 0;
+    switch(dz->iparam[TEX_AMPCONT]) {
+    case(IS_MIXED):              dz->tex->amptypstor |= 1;  dz->tex->amptypstor |= 2;                           break;
+    case(IS_CRESC):                                         dz->tex->amptypstor |= 2;                           break;
+    case(IS_FLAT):               dz->tex->amptypstor |= 1;                                                      break;
+    case(IS_DECRESC):                                                                 dz->tex->amptypstor |= 4; break;
+    case(IS_FLAT_AND_CRESC):     dz->tex->amptypstor |= 1;  dz->tex->amptypstor |= 2;                           break;
+    case(IS_CRESC_AND_DECRESC):                             dz->tex->amptypstor |= 2; dz->tex->amptypstor |= 4; break;
+    case(IS_FLAT_AND_DECRESC):   dz->tex->amptypstor |= 1;                            dz->tex->amptypstor |= 4; break;
+
+    case(IS_DIRECTIONAL):        dz->tex->ampdirectd = TRUE;    dz->tex->amptypcnt = 1;                         break;
+    case(IS_DIREC_OR_FLAT):      dz->tex->ampdirectd = TRUE;    dz->tex->amptypcnt = 2;                         break;
+    default:
+        sprintf(errstr,"Unknown case in set_amptype_params()\n");
+        return(PROGRAM_ERROR);
+    }
+    if(dz->tex->amptypstor > 0) {
+        for(n=0;n<3;n++) {
+            if(mask & dz->tex->amptypstor)
+                dz->tex->amptypcnt++;
+            mask <<= 1;
+        }
+    }
+    return(FINISHED);
+}
+
+/************************* SET_DECOR_PITCHPOSITION_PARAMS ******************************/
+
+int set_decor_pitchposition_params(dataptr dz)
+{
+    int n, mask = 1;
+    dz->tex->dectypstor = 0;
+    dz->tex->dectypcnt  = 0;
+    switch(dz->iparam[TEX_DECPCENTRE]) {
+    case(DEC_CENTRED): dz->tex->dectypstor |= 1;                                                        break;
+    case(DEC_ABOVE):                             dz->tex->dectypstor |= 2;                              break;
+    case(DEC_BELOW):                                                        dz->tex->dectypstor |= 4;   break;
+    case(DEC_C_A):     dz->tex->dectypstor |= 1; dz->tex->dectypstor |= 2;                              break;
+    case(DEC_C_B):     dz->tex->dectypstor |= 1;                            dz->tex->dectypstor |= 4;   break;
+    case(DEC_A_B):                               dz->tex->dectypstor |= 2;  dz->tex->dectypstor |= 4;   break;
+    case(DEC_C_A_B):   dz->tex->dectypstor |= 1; dz->tex->dectypstor |= 2;  dz->tex->dectypstor |= 4;   break;
+    default:
+        sprintf(errstr,"Unknown case in set_decor_pitchposition_params()\n");
+        return(PROGRAM_ERROR);
+    }
+    if(dz->tex->dectypstor > 0) {
+        for(n=0;n<3;n++) {
+            if(mask & dz->tex->dectypstor)
+                dz->tex->dectypcnt++;
+            mask <<= 1;
+        }
+    }
+    return(FINISHED);
+}
+
+/********************** DELETE_NOTES_HERE_AND_BEYOND *******************************
+
+void delete_notes_here_and_beyond(noteptr startnote)
+{
+    noteptr here = startnote;
+    if(here==(noteptr)0)
+        return;
+    while(here->next!=(noteptr)0)
+        here=here->next;
+    while(here!=startnote) {
+        here=here->last;
+        free(here->next);
+    }
+    if(startnote->last!=(noteptr)0)
+        startnote->last->next = (noteptr)0;
+    free(startnote);
+}
+****/
+
+/********************** MAKE_NEW_NOTE ****************************
+ *
+ * Create new link in note list.
+ */
+
+int make_new_note(noteptr *thisnote)
+{
+    if(((*thisnote)->next = (noteptr)malloc(sizeof(struct nnote)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY for a further note store.\n");
+        return(MEMORY_ERROR);
+    }
+    (*thisnote)->next->last = *thisnote;
+    *thisnote = (*thisnote)->next;
+    (*thisnote)->next = (noteptr)0;
+    return(FINISHED);
+}
+
+/**************************** COPY_NOTE *******************************/
+
+void copy_note(noteptr thisnote,noteptr orignote)
+{
+    thisnote->ntime = orignote->ntime;
+    thisnote->amp   = orignote->amp;
+    thisnote->pitch = orignote->pitch;
+    thisnote->dur   = orignote->dur;
+    thisnote->instr = orignote->instr;
+    thisnote->spacepos = orignote->spacepos;
+    thisnote->motioncentre = orignote->motioncentre;
+}
+
+/************************** ADD_MOTIF_TO_END_OF_MOTIFLIST ******************************
+ *
+ * Create new motif at end of list.
+ */
+
+int add_motif_to_end_of_motiflist(motifptr *new,dataptr dz)
+{
+    int exit_status;
+    motifptr here = dz->tex->motifhead;
+    while(here->next!=(motifptr)0)
+        here = here->next;
+    if((exit_status =  new_motif(&here))<0)
+        return(exit_status);
+    *new = here;
+    return(FINISHED);
+}
+    
+/************************* SCATTER_AND_QUANTISE_TSET_TIMES ******************************/
+//
+//int scatter_and_quantise_tset_times(double *lasttime,noteptr *thisnote,dataptr dz)
+//{
+//  int exit_status;
+//  double thistime = (*thisnote)->ntime;           /* 1 */
+//  double timestep = thistime - *lasttime;         /* 2 */
+//  *lasttime = thistime;                           /* 2a */
+//  if(dz->brksize[TEXTURE_SCAT]) {
+//      if((exit_status = read_value_from_brktable(thistime,TEXTURE_SCAT,dz))<0)
+//          return(exit_status);
+//  }       
+//  if(dz->param[TEXTURE_SCAT]>1.0) {               /* 3a */
+//      if((exit_status = bigscatter(thisnote,thistime,timestep,dz->param[TEXTURE_SCAT],lasttime,dz))<0)
+//          return(exit_status);
+//  } else {
+//      if(!flteq(dz->param[TEXTURE_SCAT],0.0))             /* 4 */
+//          thistime -= (float)(drand48() * dz->param[TEXTURE_SCAT] * timestep);
+//  
+//      if(dz->param[TEXTURE_TGRID]>0.0)
+//          thistime  = quantise(thistime,dz->param[TEXTURE_TGRID]);    /* 6 */
+//      (*thisnote)->ntime = (float)thistime;
+//  }
+//  *thisnote = (*thisnote)->next;
+//  return(FINISHED);               /* 8a */
+//}
+//
+/************************* SCATTER_AND_QUANTISE_TSET_TIMES ******************************/
+
+int scatter_and_quantise_tset_times(double *lasttime,noteptr *thisnote,dataptr dz)
+{
+    int exit_status;
+    double thistime = (*thisnote)->ntime;           /* 1 */
+    double timestep = thistime - *lasttime;         /* 2 */
+    noteptr lastnote, priornote;
+    *lasttime = thistime;                           /* 2a */
+    if(dz->brksize[TEXTURE_SCAT]) {
+        if((exit_status = read_value_from_brktable(thistime,TEXTURE_SCAT,dz))<0)
+            return(exit_status);
+    }       
+    if(dz->param[TEXTURE_SCAT]>1.0) {               /* 3a */
+        if((exit_status = bigscatter(thisnote,thistime,timestep,dz->param[TEXTURE_SCAT],lasttime,dz))<0)
+            return(exit_status);
+    } else {
+        if(!flteq(dz->param[TEXTURE_SCAT],0.0))             /* 4 */
+            thistime -= (float)(drand48() * dz->param[TEXTURE_SCAT] * timestep);
+    
+        if(dz->param[TEXTURE_TGRID]>0.0)
+            thistime  = quantise(thistime,dz->param[TEXTURE_TGRID]);    /* 6 */
+        (*thisnote)->ntime = (float)thistime;
+    }
+    if(dz->brksize[TEX_PHGRID]) {
+        if((exit_status = read_value_from_brktable(thistime,TEX_PHGRID,dz))<0)
+            return(exit_status);
+        dz->one_in = (int)ceil(dz->param[TEX_PHGRID]);
+    } else
+        dz->one_in = dz->iparam[TEX_PHGRID];
+    dz->one_in %= 64;                                   //  Omit 1 in 63, goes to omit none (at value 64)
+    if(dz->one_in == 0) {                               //  No omissions: go to next note
+        dz->omit_count = 0;
+        *thisnote = (*thisnote)->next;
+    } else {
+        dz->one_in = max(dz->one_in,2);                 //  dz->one_in cannot be less than 2
+        if(dz->omit_count == dz->omit_item) {           //  If this is item to omit
+            lastnote = *thisnote; 
+            *thisnote = (*thisnote)->next;              //  Go to next note
+            priornote = lastnote->last;                 //  Unlink last note
+            priornote->next = *thisnote;
+            if(*thisnote != NULL)
+                (*thisnote)->last = priornote;
+            free(lastnote);
+        } else                                          //  Else don't omit this note
+            *thisnote = (*thisnote)->next;              //  Just go to next note
+
+        dz->omit_count++;                               //  Advance counter in omit-size group.
+        if(dz->omit_count >= dz->one_in) {              //  Once the group has been used up
+            dz->omit_count = 0;                         //  Reset noteset-group counter, and determine (by random selection)
+            if(dz->param[TEXTURE_SEED] < 32)
+                dz->omit_item = (int)floor(drand48() * dz->one_in); //  event to drop in next dz->one_in events.
+        }
+        return FINISHED;
+    }
+    return(FINISHED);               /* 8a */
+}
+
+/************************* SCATTER_AND_QUANTISE_TSET_TIMES ******************************/
+//
+//int scatter_and_quantise_tset_times(double *lasttime,noteptr *thisnote,dataptr dz)
+//{
+//  int exit_status;
+//  double thistime = (*thisnote)->ntime;           /* 1 */
+//  double timestep = thistime - *lasttime;         /* 2 */
+//  noteptr lastnote, priornote;
+//  double thisscat;
+//  *lasttime = thistime;                           /* 2a */
+//  if(dz->brksize[TEXTURE_SCAT]) {
+//      dz->negscat = 0;
+//      if((exit_status = read_value_from_brktable(thistime,TEXTURE_SCAT,dz))<0)
+//          return(exit_status);
+//      if(dz->param[TEXTURE_SCAT] < 0.0)
+//          dz->negscat = 1;
+//  } else if(dz->negscat < 0) {                            // Initialise negative-scattering, where not a trime-variable pscatter param
+//      dz->negscat = 0;
+//      if(dz->param[TEXTURE_SCAT] < 0.0)
+//          dz->negscat = 1;
+//  }
+//  if (dz->negscat) {                                      //  -3.1 becomes scatter = 0.1 ,events-to-drop = 1-in-3
+//      thisscat   = -dz->param[TEXTURE_SCAT];
+//      dz->one_in = (int)floor(thisscat);                  //  Proportion of events to be dropped = 1 in dz->one_in        
+//      thisscat  -= dz->one_in;                            //  Scatter to be used
+//      dz->one_in = max(dz->one_in,2);                     //  dz->one_in cannot be less than 2
+//
+//      if(dz->omit_count == dz->omit_item) {               //  If this is item to omit
+//          lastnote = *thisnote; 
+//          *thisnote = (*thisnote)->next;                  //  Go to next note
+//          priornote = lastnote->last;                     //  Unlink last note
+//          priornote->next = *thisnote;
+//          (*thisnote)->last = priornote;
+//          free(lastnote);
+//      } else {                                        //  Otherwise, scatter event time       
+//          if(!flteq(thisscat,0.0))
+//              thistime -= (float)(drand48() * thisscat * timestep);
+//          if(dz->param[TEXTURE_TGRID]>0.0)                //  (and quantise if ness)
+//              thistime  = quantise(thistime,dz->param[TEXTURE_TGRID]);
+//          (*thisnote)->ntime = (float)thistime;
+//          *thisnote = (*thisnote)->next;                  //  and go to next note
+//      }
+//      dz->omit_count++;                                   //  Advance counter in omit-size group.
+//      if(dz->omit_count >= dz->one_in) {                  //  Once the group has been used up
+//          dz->omit_count = 0;                             //  Reset noteset-group counter, and determine (by random selection)
+//          if(dz->param[TEXTURE_SEED] < 32)
+//              dz->omit_item = (int)floor(drand48() * dz->one_in); //  event to drop in next dz->one_in events.
+//      }
+//      return FINISHED;
+//  } else if(dz->param[TEXTURE_SCAT]>1.0)  {               /* 3a */
+////TW UPDATE (original code error)
+//      if((exit_status = bigscatter(thisnote,thistime,timestep,dz->param[TEXTURE_SCAT],lasttime,dz))<0)
+//          return(exit_status);
+//  } else {
+//      if(!flteq(dz->param[TEXTURE_SCAT],0.0))             /* 4 */
+//          thistime -= (float)(drand48() * dz->param[TEXTURE_SCAT] * timestep);
+//  
+//      if(dz->param[TEXTURE_TGRID]>0.0)
+//          thistime  = quantise(thistime,dz->param[TEXTURE_TGRID]);    /* 6 */
+//      (*thisnote)->ntime = (float)thistime;
+//  }
+//  *thisnote = (*thisnote)->next;
+//  return(FINISHED);               /* 8a */
+//}
+
+/************************** PRE_SPACE ********************************
+ *
+ * Store spatial data in the tsetnote spacepos and motioncentre.
+ */
+
+int pre_space(noteptr thisnote,dataptr dz)
+{
+    int exit_status;
+    double position;
+    if((exit_status = getpos((double)thisnote->ntime,&position,dz))<0)
+        return(exit_status);
+    thisnote->spacepos     = (float)position;
+    thisnote->motioncentre = (float)dz->param[CPOS];
+    return(FINISHED);
+}
+
+/************************** GETPOS ****************************
+ *
+ * Calculate spatial position of event from it's time.
+ */
+
+int getpos(double thistime,double *position,dataptr dz)
+{
+    int exit_status;
+    if(dz->brksize[TEXTURE_POS] && (exit_status = read_value_from_brktable(thistime,TEXTURE_POS,dz))<0)
+        return(exit_status);
+    if(dz->brksize[TEXTURE_SPRD] && (exit_status = read_value_from_brktable(thistime,TEXTURE_SPRD,dz))<0)
+        return(exit_status);
+    if(dz->param[TEXTURE_SPRD] > 0.0) {
+        if((exit_status = spread_and_set_cpos(position,dz->param[TEXTURE_POS],dz->param[TEXTURE_SPRD],dz))<0)
+            return(exit_status);
+    } else {
+/* NOV 1997--> */
+        dz->param[CPOS] = dz->param[TEXTURE_POS];
+/* <--NOV 1997 */
+        *position       = dz->param[TEXTURE_POS];
+    }
+    return(FINISHED);
+}
+
+/***************************** SPREAD_AND_SET_CPOS *****************************/
+
+int spread_and_set_cpos(double *position,double given_position,double spread,dataptr dz)
+{
+    int exit_status;
+    int    posno, spswitch;
+    int    poscnt,hposcnt;
+    double hspread,spacing, closeness, squash;
+
+    /* total stereospace has MAXPOSCNT positions: calc no. & spacing of positions available at given spread */
+    poscnt  = round(spread * (double)MAXPOSCNT);
+    hposcnt = poscnt/2;
+    hspread = spread/(double)2.0;
+    if(hposcnt != 0)
+        spacing = hspread/(double)hposcnt;
+    else {
+    /* bandwidth effectively zero: return given position */ 
+        dz->param[CPOS] = given_position;
+        *position       = given_position;
+        return(FINISHED);
+    }
+    /* randomly select leftwards/rightwards of the given position */
+    if((exit_status = doperm(2,PM_SPACE,&spswitch,dz))<0)
+        return(exit_status);                    
+    if(!spswitch)
+        spswitch = -1;                              
+
+    /* randomly chose a pos (to left or right) around centre pos */
+    posno  = round(drand48() * hposcnt);                
+    posno *= spswitch;                              
+
+    /* calculate warping coefficient to avoid position-spread leaking over edges of stereo-space */
+    if(spread>(double)1.0/SQUASH)
+        squash = (double)1.0/spread;
+    else
+        squash = SQUASH;
+
+    /* If (position+spread) leaks to right of stereo-space : squeeze position */
+    if(given_position>=0.5 && (given_position + spread) > 1.0) {
+        closeness = (given_position - 0.5)/(double)0.5;
+        dz->param[CPOS] = given_position - (hspread*pow(closeness,squash));
+    /* If (position+spread) leaks to left of stereo-space : squeeze position */
+    } else if(given_position<0.5 && given_position < spread) {  
+        closeness = (0.5 - given_position)/(double)0.5;
+        dz->param[CPOS] = given_position + (hspread*pow(closeness,squash));
+    } else
+        dz->param[CPOS] = given_position;
+
+    /* generate true position, around central position */
+    *position = dz->param[CPOS] + ((double)posno * spacing);
+    return chekrang(position);
+}
+
+/*************************** CHEKRANG **************************
+ * 
+ * Check variable lies within range 0.0 to 1.0.
+ */
+
+int chekrang(double *val)
+{
+    if(flteq(*val,1.0))
+        *val = 1.0;
+    if(flteq(*val,0.0))
+        *val = 0.0;
+    if(*val<0.0 || *val>1.0) {                       
+        sprintf(errstr,"value [%f] outside range 0-1: chekrang()\n",*val);
+        return(PROGRAM_ERROR);
+    }
+    return(FINISHED);
+}
+
+/************************** READ_A_NOTE_FROM_NOTEDATA_FILE ********************************/
+
+int read_a_note_from_notedata_file(noteptr thisnote,int noteno,int motifno,double *lasttime,dataptr dz)
+{
+    int exit_status;
+    unsigned int texflag = dz->tex->txflag;
+    char temp[200], *p, *q;
+    double val;
+    int instr_no, start;
+    if(dz->fp==NULL) {
+        sprintf(errstr,"Note datafile descriptor not initialised: read_a_note_from_notedata_file()\n");
+        return(PROGRAM_ERROR);
+    }
+    if(fgets(temp,200,dz->fp)==NULL){
+        sprintf(errstr,"Note data line for note %d, motif %d missing in notedatafile\n",noteno,motifno);
+        return(DATA_ERROR);
+    }
+    p =temp;
+    while(isspace(*p))
+        p++;
+    q = p;
+    if(*q==ENDOFSTR)
+        return(CONTINUE);
+    if((exit_status = get_data_item(q,&p,&val))<0) {
+        sprintf(errstr,"No time data for note %d, motif %d in notedatafile\n",noteno,motifno); 
+        return(DATA_ERROR);
+    }
+    if(exit_status==FINISHED) {
+        sprintf(errstr,"No data after time for note %d, motif %d in notedatafile\n",noteno,motifno); 
+        return(DATA_ERROR);
+    }
+    thisnote->ntime = (float)val;
+    if((noteno > 1) && (*lasttime > thisnote->ntime)) {
+        sprintf(errstr,"Notes in reverse time order: notedata file : motif %d: notes %d & %d\n",
+        motifno,noteno,noteno-1);
+        return(DATA_ERROR);
+    }
+    *lasttime = thisnote->ntime;
+    p++;
+    q = p;
+    if((exit_status = get_data_item(q,&p,&val))<0) {
+        sprintf(errstr,"No instr_no for note %d, motif %d in notedatafile\n",noteno,motifno); 
+        return(DATA_ERROR);
+    }
+    if(exit_status==FINISHED) {
+        sprintf(errstr,"No data after instr_no for note %d, motif %d in notedatafile\n",noteno,motifno); 
+        return(DATA_ERROR);
+    }
+    instr_no = round(val);
+
+    p++;
+    q = p;
+    if((exit_status = get_data_item(q,&p,&val))<0) {
+        sprintf(errstr,"No pitch data for note %d, motif %d in notedatafile\n",noteno,motifno); 
+        return(DATA_ERROR);
+    }
+    if(exit_status==FINISHED) {
+        sprintf(errstr,"No data after pitch for note %d, motif %d in notedatafile\n",noteno,motifno); 
+        return(DATA_ERROR);
+    }
+    thisnote->pitch = (float)val;
+
+/* NEEDS TESTING FOR MIDIRANGE: EXCEPT IN TIMING SET CASE */
+    if(!(texflag & ISTIMED) || motifno!=1) {
+        if(val < MIDIMIN || val > MIDIMAX) {
+            sprintf(errstr,"pitch value [%lf] out of range (%d to %d): motif %d: note %d\n",
+            val,MIDIMIN,MIDIMAX,motifno,noteno);
+            return(DATA_ERROR);
+        }
+    }
+    p++;
+    q = p;
+    if((exit_status = get_data_item(q,&p,&val))<0) {
+        sprintf(errstr,"No amplitude data for note %d, motif %d in notedatafile\n",noteno,motifno); 
+        return(DATA_ERROR);
+    }
+    if(exit_status==FINISHED) {
+        sprintf(errstr,"No data after amp for note %d, motif %d in notedatafile\n",noteno,motifno); 
+        return(DATA_ERROR);
+    }
+    thisnote->amp = (float)val;
+/* 1999 THIS NEEDS TESTING FOR MIDIRANGE EXCEPT IN TIMING SET CASE */
+    if(!(texflag & ISTIMED) || motifno!=1) {
+        if(val < MIDIMIN || val > MIDIMAX) {
+            sprintf(errstr,"amplitude value [%lf] out of range (%d to %d): motif %d: note %d\n",
+            val,MIDIMIN,MIDIMAX,motifno,noteno);
+            return(DATA_ERROR);
+        }
+    }
+    p++;
+    q = p;
+    if((exit_status = get_data_item(q,&p,&val))<0) {
+        sprintf(errstr,"No duration data for note %d, motif %d in notedatafile\n",noteno,motifno); 
+        return(DATA_ERROR);
+    }
+    thisnote->dur = (float)val;
+    if(texflag & IS_ORN_OR_MTF) {
+        if(texflag & IS_ORNATE) {
+            start = 2;
+        } else {
+            start = 1;
+            if(texflag & ISTIMED)
+                start++;
+        }
+        if(texflag & ISHARM)
+            start++;
+        if(motifno >= start) {
+            if(val <= FLTERR) {
+                sprintf(errstr,"Duration value [%lf] is too small: motif %d: note %d\n",val,motifno,noteno);
+                return(DATA_ERROR);
+            }
+        }
+    } else {
+        thisnote->dur = 1.0f;   /* default ; redundant */
+    }
+    return(FINISHED);
+}
+
+/***************************** GENERATE_TSET_TIMES **********************************
+ *
+ * Store time initially as SECONDS.
+ *
+ * (1)  Create location for a new note.
+ * (2)  Go to that new note.
+ * (3)  Store the current time at this note.
+ * (4)  Find note-density at this time, and generate time of next event.
+ * (5)  Return nextnote.
+ */
+
+int generate_tset_times(double *thistime,noteptr *thisnote,dataptr dz)
+{
+    int exit_status;
+    if((exit_status = make_new_note(thisnote))<0)
+        return(exit_status);                        /* 1 */
+    (*thisnote)->ntime = (float)(*thistime);            /* 3 */
+    if(dz->brksize[TEXTURE_PACK]) {
+        if((exit_status = read_value_from_brktable(*thistime,TEXTURE_PACK,dz))<0)
+            return(exit_status);
+    }       
+    *thistime  += dz->param[TEXTURE_PACK];          /* 4 */
+    return(FINISHED);                               /* 5 */
+}
+
+/********************** UN_LINK_NOTE ******************************
+ *
+ * Deletes empty address space at end of notelist.
+ */
+
+int un_link_note(noteptr thisnote)
+{
+    if(thisnote->last==(noteptr)0) {
+        sprintf(errstr,"Problem in un_link_note()\n");
+        return(PROGRAM_ERROR);
+    }
+    thisnote = thisnote->last;
+    free(thisnote->next);
+    thisnote->next = (noteptr)0;
+    return(FINISHED);
+}
+
+/************************ NEW_MOTIF *****************************
+ *
+ * Set up next motif in a list of musical-motifs.
+ * Set up location of first note of this motif.
+ */
+
+int new_motif(motifptr *thismotif)
+{
+    int exit_status;
+    motifptr newmotif;
+    noteptr  thisnote;
+    
+    if((newmotif = (motifptr)malloc(sizeof (struct motif)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY to store next motif.\n");
+        return(MEMORY_ERROR);
+    }
+    (*thismotif)->next = newmotif;
+    newmotif->last = *thismotif;
+    newmotif->next = (motifptr)0;
+    if((exit_status = init_note(&thisnote))<0)
+        return(exit_status);
+    thisnote->next = (noteptr)0;   
+    thisnote->last = (noteptr)0;   
+    newmotif->firstnote = thisnote;
+    *thismotif = newmotif;
+    return(FINISHED);
+}
+
+/********************** UNLINK_LAST_MOTIF ******************************
+ *
+ * Deletes empty address space at end of motiflist.
+ */
+
+int unlink_last_motif(motifptr thismotif)
+{
+    if(thismotif->last==(motifptr)0) {
+        sprintf(errstr,"Problem in unlink_last_motif()\n");
+        return(PROGRAM_ERROR);
+    }
+    thismotif = thismotif->last;
+    free(thismotif->next);
+    thismotif->next = (motifptr)0;
+    return(FINISHED);
+}
+
+/**************************** SUBTRACT_ONE_FROM_BRKVALS ****************************/
+
+void subtract_one_from_brkvals(int paramno,dataptr dz)
+{
+    double *p = dz->brk[paramno] + 1;
+    double *pend = dz->brk[paramno] + (dz->brksize[paramno] * 2);
+    while(p < pend) {
+        *p -= 1.0;
+        p += 2;
+    }
+}
+
+/************************ BIGSCATTER *************************************
+ *
+ * (1)  The number of time-points to be randomly scattered as a group is
+ *  scatcnt.
+ * (1a) Base time is the time from which these new scattered times are offset.
+ * (2)  Save the current position in note list as 'here'.
+ * (3)  Go forward in note list until there are scatcnt notes inclusive
+ *  between here and there, or until list runs out.
+ * (3a) If the list runs out, modify scatcnt accordingly.
+ * (4)  Note the (original) time of the last of these events. This will
+ *  be returned as the new 'lasttime' for the next cycle of the
+ *  program.
+ * (5)  Make the time-step include the total duration of all these
+ *  events.
+ * (5a) Generate a set of times AT RANDOM within this large timestep,
+    sort them and store them.
+ * (6)  Replace existing times by scattered times, relative to basetime.
+ * (6a) Convert to MIDitime.
+ * (6b) Quantise if necessary.
+ * (7)  Replace the last time.
+ * (9)  Return the last note we worked on.
+ */
+
+int bigscatter(noteptr *thisnote,double thistime,double timestep,double scatter,double *lasttime,dataptr dz)
+{
+    int n, scatcnt = round(scatter);        /* 1 */
+    double *sct, *scti;
+    double basetime = thistime - timestep;  /* 1a */
+    noteptr here  = *thisnote;              /* 2 */
+    noteptr there = *thisnote;              /* 2 */
+    if((scti = (double *)malloc(scatcnt * sizeof(double)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY for scattering structure.\n");
+        return(MEMORY_ERROR);
+    }
+    sct = scti;
+    for(n=0;n < scatcnt-1; n++) {           /* 3 */
+        if(there->next==(noteptr)0) {
+            scatcnt = n+1;                  /* 3a */
+            break;
+        }
+        there = there->next;
+    }
+    *lasttime = there->ntime;               /* 4 */
+    timestep += *lasttime - thistime;       /* 5 */
+    for(n= 0;n<scatcnt;n++)                 /* 5a */
+        *sct++ = drand48() * timestep;
+    upsort(scti,scatcnt);                   
+    sct = scti;
+    while(here!=there) {                    /* 6 */
+        thistime = basetime + (*sct++);
+        if(dz->param[TEXTURE_TGRID]>0.0)
+            thistime  = quantise(thistime,dz->param[TEXTURE_TGRID]);    /* 6b */
+        here->ntime = (float)thistime;
+        here = here->next;
+    }
+    thistime = basetime + *sct;             /* 7 */
+    if(dz->param[TEXTURE_TGRID]>0.0)
+        thistime  = quantise(thistime,dz->param[TEXTURE_TGRID]);
+    there->ntime = (float)thistime;
+    free(scti);
+    *thisnote = there;
+    return(FINISHED);                   /* 9 */
+}
+
+/************************** QUANTISE *************************************
+ *
+ * Quantise time point onto a grid.
+ */
+
+double quantise(double thistime,double timegrid)
+{
+    int gridpoint;
+    timegrid *= MS_TO_SECS;
+    gridpoint = round(thistime/timegrid);
+    return((double)gridpoint * timegrid);
+}
+
+/************************* GET_DATA_ITEM ****************************/
+
+int get_data_item(char *q,char **p,double *val)
+{
+    int exit_status = CONTINUE;
+    if(*q==ENDOFSTR)
+        return(DATA_ERROR);
+    while(isspace(**p)) {
+        (*p)++;
+        if(**p == ENDOFSTR)
+            return(DATA_ERROR);
+    }
+    if(**p==TEXTURE_SEPARATOR)
+        return(DATA_ERROR);
+    while(!isspace(**p) && **p!=ENDOFSTR) {
+        (*p)++;
+    }
+    if(**p==ENDOFSTR)
+        exit_status = FINISHED;
+    **p = ENDOFSTR;
+    if(sscanf(q,"%lf",val)!=1)
+        return(DATA_ERROR);
+    return(exit_status);
+}
+
+/************************* INIT_NOTE ****************************
+ *
+ * Initialise notelist.
+ */
+
+int init_note(noteptr *thisnote)
+{
+    if((*thisnote = (noteptr)malloc(sizeof(struct nnote)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY for another note.\n");
+        return(MEMORY_ERROR);
+    }
+    (*thisnote)->next = (noteptr)0;
+    (*thisnote)->last = (noteptr)0;
+    return(FINISHED);
+}
+
+/********************** UPSORT *******************************
+ * 
+ * Sort set of doubles into ascending order.
+ */
+
+void upsort(double *scti,int scatcnt)
+{
+    double sct;
+    int n, m;
+    for(n=0;n<(scatcnt-1);n++) {
+        for(m=n+1;m<scatcnt;m++) {
+            if(*(scti+m)<*(scti+n)) {
+                sct       = *(scti+m);
+                *(scti+m) = *(scti+n);
+                *(scti+n) = sct;
+            }
+        }
+    }
+}
+
+/*********************** PUT_ZNOTE ********************************
+ *
+ * Put zero values in all parameters except time.
+ */
+
+void put_znote(noteptr thisnote)
+{
+    thisnote->amp   = 0.0f;
+    thisnote->pitch  = 0.0f;
+    thisnote->dur   = 0.0f;
+    thisnote->instr = 0;
+    thisnote->spacepos = 0.0f;
+    thisnote->motioncentre = 0.0f;
+}
+
+/************************* ASSIGN_TIMESET_HFSET_MOTIFSETS ******************************
+ *
+ * Assign appropriate pointers to input motifs.
+ *
+ * (1)  If it's a timed texture, indicate first motif in list as that
+ *      which defines the set of times (tset).
+ *      Similarly, if texture is ornamented or decorated, point to first
+ *      motif as that to BE ornamented or decorated (tset).
+ * (2)  If the texture restricted to HF(s) or HS(s), indicate next motif
+ *      as the HF-set (hfldmotif). It may be read in different ways (as HF, as
+ *      HS, or as time-varying of either type) at a later time.
+ * (3)  If texture consists of motifs, or is to use specific ornaments...
+ * (4)  count the number of motifs remaining.
+ * (5)  Set up the array of phrases to point to the appropriate motifs.
+ */
+
+int assign_timeset_hfset_motifsets(dataptr dz)
+{
+    int exit_status;
+    unsigned int texflag = dz->tex->txflag;
+    motifptr here, thismotif = dz->tex->motifhead;
+    int n;
+    dz->tex->phrasecnt = 0;    
+    if(texflag & ORN_DEC_OR_TIMED) {
+        if((exit_status = motifchek(thismotif))<0)
+            return(exit_status);
+        dz->tex->timeset = thismotif;                   /* 1 */
+        thismotif = thismotif->next;
+    }
+    if(texflag & ISHARM) {                              /* 2 */
+        if((exit_status = motifchek(thismotif))<0)
+            return(exit_status);
+        dz->tex->hfldmotif = thismotif;
+        thismotif = thismotif->next;
+    }
+    if((texflag & IS_ORNATE) || (texflag & IS_MOTIFS)) {    /* 3 */
+        if((exit_status = motifchek(thismotif))<0)
+            return(exit_status);
+        here = thismotif;
+        while(thismotif!=(motifptr)0) {                 /* 4 */
+            dz->tex->phrasecnt++;
+            thismotif = thismotif->next;
+        }                                               /* 5 */
+        if((dz->tex->phrase = (motifptr *)malloc(dz->tex->phrasecnt * sizeof(motifptr)))==NULL) {
+            sprintf(errstr,"INSUFFICIENT MEMORY for phrase array.\n");
+            return(MEMORY_ERROR);
+        }
+        thismotif = here;
+        n = -1;
+        while(thismotif!=(motifptr)0) {
+            dz->tex->phrase[++n] = thismotif;
+            thismotif = thismotif->next;
+        }
+    }
+    return(FINISHED);
+}
+
+/***************************** MASSAGE_PARAMS ****************************/
+
+int massage_params(dataptr dz)
+{
+    int exit_status;
+    unsigned int texflag = dz->tex->txflag;
+    convert_cmdline_instrnos_to_internal_representation(dz);
+    if((exit_status = check_max_transpos_compatible_with_splicelen(dz))<0)
+        return(exit_status);
+    if(texflag & IS_CLUMPED) {
+        if((exit_status = set_amptype_params(dz))<0)
+            return(exit_status);
+    }
+    if(texflag & IS_DECOR) {
+        if((exit_status = set_decor_pitchposition_params(dz))<0)
+            return(exit_status);
+    }
+    return(FINISHED);
+}
+
+/************************* INIT_MOTIFS *****************************
+ *
+ * Set up head item of a list of musical-motifs.
+ * Set up location of first note of first motif.
+ */
+
+int init_motifs(dataptr dz)
+{
+    int exit_status;
+    noteptr thisnote;
+    if((dz->tex->motifhead = (motifptr)malloc(sizeof (struct motif)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY to store any motifs.\n");
+        return(MEMORY_ERROR);
+    }
+    dz->tex->motifhead->next  = (motifptr)0;
+    dz->tex->motifhead->last  = (motifptr)0;
+    if((exit_status = init_note(&thisnote))<0)
+        return(exit_status);
+    dz->tex->motifhead->firstnote = thisnote;
+    thisnote->next = (noteptr)0;   
+    thisnote->last = (noteptr)0;   
+    return(FINISHED);
+}
+
+/******************************** INITPERM *********************************
+ *
+ * Establish storage space for permutation parameters.
+ *
+ * (1)  create pointers to the items within the permuted sets.      Initialise to zero.
+ * (2)  Create storage for current length of each perm.             Initialise to zero.
+ * (3)  Create storage for previous length of each perm.            Initialise to -1 (impossible).
+ *      If new perm different length to old, space for permuted elements will need to be re-malloced.
+ * (4)  Create pointers to storage areas for each permuted set.     Initialise to point nowhere. 
+ *      These will be malloced when the size of each set-to-permute is known.
+ * (5)  Create storage for previous outputed val in each perm.      Initialise to -1 (impossible). 
+ *      This is useful at permutation boundaries, when a particular element may be repeated more
+ *      than permitted no. of times if there's no check. These constants allow no. of repets to be counted.
+ * (6)  Create counter of current no. of consecutive repets of an element in each of the (output) perms.
+ *      Initialise to 0, though this is arbitrary, as repetcnt should always be set on any call of do_perm.
+ * (7)  Create storage for max no. of allowed consecutive repets of an element in each perm-set.
+ *      Initialise to 1, which is the default if no info is given to the contrary.
+ */
+
+int initperm(int ***permm,dataptr dz)
+{
+    int n;
+    if((dz->iparray[TXPERMINDEX] = (int *)malloc(PERMCNT * sizeof(int)))==NULL) {   /* 1 */
+        sprintf(errstr,"INSUFFICIENT MEMORY for permutation indeces.\n");
+        return(MEMORY_ERROR);
+    }
+    for(n=0;n<PERMCNT;n++)
+        dz->iparray[TXPERMINDEX][n] = 0;
+
+    if((dz->iparray[TXPERMLEN] = (int *)malloc(PERMCNT * sizeof(int)))==NULL) {   /* 2 */
+        sprintf(errstr,"INSUFFICIENT MEMORY for permutation lengths.\n");
+        return(MEMORY_ERROR);
+    }
+    for(n=0;n<PERMCNT;n++)
+        dz->iparray[TXPERMLEN][n] = 0;
+
+    if((dz->iparray[TXLASTPERMLEN] = (int *)malloc(PERMCNT * sizeof(int)))==NULL) {   /* 3 */
+        sprintf(errstr,"INSUFFICIENT MEMORY for last permutation lengths.\n");
+        return(MEMORY_ERROR);
+    }
+    for(n=0;n<PERMCNT;n++)
+        dz->iparray[TXLASTPERMLEN][n] = -1;
+
+    if((*permm = (int **)malloc(PERMCNT * sizeof(int *)))==NULL) {   /* 4 */
+        sprintf(errstr,"INSUFFICIENT MEMORY for permutations.\n");
+        return(MEMORY_ERROR);
+    }
+
+    for(n=0;n<PERMCNT;n++)
+        (*permm)[n] = (int *)0;
+
+    if((dz->iparray[TXLASTPERMVAL] = (int *)malloc(PERMCNT * sizeof(int)))==NULL) {   /* 5 */
+        sprintf(errstr,"INSUFFICIENT MEMORY for last permutation values.\n");
+        return(MEMORY_ERROR);
+    }
+    for(n=0;n<PERMCNT;n++)
+        dz->iparray[TXLASTPERMVAL][n] = -1;
+
+    if((dz->iparray[TXREPETCNT] = (int *)malloc(PERMCNT * sizeof(int)))==NULL) {   /* 6 */
+        sprintf(errstr,"INSUFFICIENT MEMORY for permutation repetition counts.\n");
+        return(MEMORY_ERROR);
+    }
+    for(n=0;n<PERMCNT;n++)
+        dz->iparray[TXREPETCNT][n] = 1;
+
+    if((dz->iparray[TXRPT] = (int *)malloc(PERMCNT * sizeof(int)))==NULL) {   /* 7 */
+        sprintf(errstr,"INSUFFICIENT MEMORY for permutation repetitions.\n");
+        return(MEMORY_ERROR);
+    }
+    /* THESE ARE THE DEFAULT NUMBER OF REPETITIONS-OF-AN-ENTITY ALLOWED IN A PERM */
+    dz->iparray[TXRPT][PM_SPACE]  = SPACE_REPETS;
+    dz->iparray[TXRPT][PM_PITCH]  = PITCH_REPETS;
+    dz->iparray[TXRPT][PM_AMP]    = AMP_REPETS;
+    dz->iparray[TXRPT][PM_DUR]    = DUR_REPETS;
+    dz->iparray[TXRPT][PM_INSNO]  = INSNO_REPETS;
+    dz->iparray[TXRPT][PM_GPRANG] = GPRANG_REPETS;
+    dz->iparray[TXRPT][PM_GPSIZE] = GPSIZE_REPETS;
+    dz->iparray[TXRPT][PM_GPDENS] = GPDENS_REPETS;
+    dz->iparray[TXRPT][PM_GPCNTR] = GPCNTR_REPETS;
+    dz->iparray[TXRPT][PM_GPPICH] = GPPICH_REPETS;
+    dz->iparray[TXRPT][PM_ORNPOS] = ORNPOS_REPETS;
+    dz->iparray[TXRPT][PM_GPSPAC] = GPSPAC_REPETS;
+    dz->iparray[TXRPT][PM_ORIENT] = ORIENT_REPETS;
+    dz->iparray[TXRPT][PM_DECABV] = DECABV_REPETS;
+    dz->iparray[TXRPT][PM_MULT]   = MULT_REPETS;
+    dz->iparray[TXRPT][PM_WHICH]  = WHICH_REPETS;
+    dz->iparray[TXRPT][PM_GPPICH2]= GPPICH2_REPETS;
+    return(FINISHED);
+}

+ 220 - 0
dev/texture/texture1.c

@@ -0,0 +1,220 @@
+/*
+ * Copyright (c) 1983-2013 Trevor Wishart and Composers Desktop Project Ltd
+ * http://www.trevorwishart.co.uk
+ * http://www.composersdesktop.com
+ *
+ This file is part of the CDP System.
+ 
+ The CDP System is free software; you can redistribute it
+ and/or modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+ 
+ The CDP System is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU Lesser General Public License for more details.
+ 
+ You should have received a copy of the GNU Lesser General Public
+ License along with the CDP System; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA
+ *
+ */
+/* floatsam version: no changes */
+#include <stdio.h>
+#include <stdlib.h>
+#include <structures.h>
+#include <tkglobals.h>
+#include <globcon.h>
+#include <processno.h>
+#include <modeno.h>
+#include <arrays.h>
+#include <texture.h>
+#include <cdpmain.h>
+
+#include <sfsys.h>
+
+/********************* GETTING DATA VALUES VIA RAND PERMUTATIONS *************/
+
+
+
+static int  delete_all_other_motifs(motifptr thismotif,dataptr dz);
+static int  delete_motifs_before(motifptr thismotif,dataptr dz);
+static int  delete_motifs_beyond(motifptr thismotif);
+
+/***************************** TEXTURE 1 ********************************
+ * (1)  Generating random permutations of sets of values, and delivering
+ *      the next value from one of these.
+ * (2)  Scattering values within a range.
+ */
+
+/*************************** MAKE_TEXTURE *********************************/
+
+int make_texture(dataptr dz)
+{
+    int exit_status;
+    unsigned int texflag = dz->tex->txflag;
+    display_virtual_time(0,dz);
+    if(texflag & ISHARM) {
+        if(texflag & IS_CLUMPED) {
+            if((exit_status = do_clumped_hftexture(dz))<0)
+                return(exit_status);
+        } else {
+            if((exit_status = do_simple_hftexture(dz))<0)
+                return(exit_status);
+        }
+    } else {
+        if((exit_status = do_texture(dz))<0)
+            return(exit_status);
+    }
+    if((exit_status = delete_all_other_motifs(dz->tex->timeset,dz))<0)
+        return(exit_status);
+    return(FINISHED);
+}
+
+/****************************** GETVALUE **********************************
+ *
+ * Get value of a parameter, either from table, or fixed value.
+ */
+
+int getvalue(int paramhi,int paramlo,double thistime,int z,double *val,dataptr dz)
+{   
+    int exit_status;
+    double range;
+    int is_swap = 0;
+    if(dz->is_int[paramhi] || dz->is_int[paramlo]) {
+        sprintf(errstr,"getvalue() called on integer parameter %d or %d\n",paramhi,paramlo);
+        return(PROGRAM_ERROR);
+    }
+    if(dz->brk[paramhi]) {
+        if((exit_status = read_value_from_brktable(thistime,paramhi,dz))<0)
+            return(exit_status);
+    }
+    if(dz->brk[paramlo]) {
+        if((exit_status = read_value_from_brktable(thistime,paramlo,dz))<0)
+            return(exit_status);
+    }
+    if((range = dz->param[paramhi] - dz->param[paramlo])<0.0) {
+        swap(&dz->param[paramhi],&dz->param[paramlo]);
+        range = -range;
+        is_swap = 1;
+    }
+    if(flteq(range,0.0)) {
+        *val = dz->param[paramhi];
+        if(is_swap)
+            swap(&dz->param[paramhi],&dz->param[paramlo]);
+        return(FINISHED);
+    }
+    if((exit_status = pscatx(range,dz->param[paramlo],z,val,dz))<0)
+        return(exit_status);
+    if(is_swap)
+        swap(&dz->param[paramhi],&dz->param[paramlo]);
+    return(FINISHED);
+}
+
+/****************************** IGETVALUE **********************************
+ *
+ * Get integer value of a parameter, either from table, or fixed value.
+ */
+
+int igetvalue(int paramhi,int paramlo,double thistime,int z,int *ival,dataptr dz)
+{
+    int   exit_status;
+    int  irange;
+    int   a, is_swap = 0;
+
+    if(!dz->is_int[paramhi] || !dz->is_int[paramlo]) {
+        sprintf(errstr,"igetvalue() called on non-integer parameter %d or %d\n",paramhi,paramlo);
+        return(PROGRAM_ERROR);
+    }
+    if(dz->brk[paramhi]) {
+        if((exit_status = read_value_from_brktable(thistime,paramhi,dz))<0)
+            return(exit_status);
+    }
+    if(dz->brk[paramlo]) {
+        if((exit_status = read_value_from_brktable(thistime,paramlo,dz))<0)
+            return(exit_status);
+    }
+
+    if((irange = dz->iparam[paramhi] - dz->iparam[paramlo])<0) {
+        iiswap(&dz->iparam[paramhi],&dz->iparam[paramlo]);
+        irange = -irange;
+        is_swap = 1;
+    }
+    if(irange==0) {
+        *ival = (int)dz->iparam[paramlo]; 
+        if(is_swap)
+            iiswap(&dz->iparam[paramhi],&dz->iparam[paramlo]);
+        return(FINISHED);
+/* OCT 1997 replace ****
+    } else if((exit_status = doperm(irange,z,&a,dz))<0)
+*/
+/* BY */
+    } else if((exit_status = doperm(irange+1,z,&a,dz))<0)
+/* because the range of an integer variable between(say) 3 & 7 is INCLUSIVELY 5, not 7-3) */
+        return(exit_status);
+    a = (int)(a + dz->iparam[paramlo]);
+    *ival = a;
+    if(is_swap)
+        iiswap(&dz->iparam[paramhi],&dz->iparam[paramlo]);
+    return(FINISHED);
+}
+
+/*************************** DELETE_ALL_OTHER_MOTIFS **********************************
+ *
+ * Deletes all other motifs in motif list.
+ */
+
+int delete_all_other_motifs(motifptr thismotif,dataptr dz)
+{
+    int exit_status;
+    motifptr here = thismotif->next;
+    if((exit_status = delete_motifs_before(thismotif,dz))<0)
+        return(exit_status);
+    if(here!=(motifptr)0) {
+        if((exit_status = delete_motifs_beyond(here))<0)
+            return(exit_status);
+    }
+    dz->tex->motifhead = thismotif;
+    return(exit_status);
+}
+
+/********************** DELETE_MOTIFS_BEYOND ******************************
+ *
+ * Deletes motif-space from this space onwards.
+ */
+
+int delete_motifs_beyond(motifptr thismotif)
+{
+    motifptr start = thismotif;
+    while(thismotif->next!=(motifptr)0)
+        thismotif = thismotif->next;
+    while(thismotif!=start) {
+        thismotif = thismotif->last;
+        free(thismotif->next);
+    }
+    thismotif->next = (motifptr)0;
+    return(FINISHED);
+}
+
+/*********************** DELETE_MOTIFS_BEFORE ***************************
+ *
+ * Kill all motifs BEFORE this one in the motif list.
+ */
+
+int delete_motifs_before(motifptr thismotif,dataptr dz)
+{
+    motifptr here = dz->tex->motifhead;
+    while(here!=thismotif) {
+        if((here = here->next)==(motifptr)0) {
+            sprintf(errstr,"Problem in delete_motifs_before()\n");
+            return(PROGRAM_ERROR);
+        }
+        delete_notes_here_and_beyond(here->last->firstnote);
+        free(here->last);
+        here->last = (motifptr)0;
+    }
+    dz->tex->motifhead = thismotif;
+    return(FINISHED);
+}

+ 517 - 0
dev/texture/texture2.c

@@ -0,0 +1,517 @@
+/*
+ * Copyright (c) 1983-2013 Trevor Wishart and Composers Desktop Project Ltd
+ * http://www.trevorwishart.co.uk
+ * http://www.composersdesktop.com
+ *
+ This file is part of the CDP System.
+ 
+ The CDP System is free software; you can redistribute it
+ and/or modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+ 
+ The CDP System is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU Lesser General Public License for more details.
+ 
+ You should have received a copy of the GNU Lesser General Public
+ License along with the CDP System; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA
+ *
+ */
+/* floatsam version: no changes */
+#include <stdio.h>
+#include <stdlib.h>
+#include <structures.h>
+#include <tkglobals.h>
+#include <globcon.h>
+#include <processno.h>
+#include <modeno.h>
+#include <arrays.h>
+#include <texture.h>
+#include <cdpmain.h>
+#include <sfsys.h>
+#include <osbind.h>
+
+/***************************** GENERATING TEXTURES WITH NO HFIELD(S) ******************************/
+
+static int  setup_motif_params
+            (noteptr phrasenote,double tsettime,double *thisamp,double ampstep,double *phraseamp,
+            int phrno,double rangemult,noteptr thisnote,noteptr tsetnote,
+            double multiplier,double timeadjust,dataptr dz);
+static void gen_orn_pitch(noteptr thisnote,noteptr tsetnote,noteptr phrasenote,
+            float phrlpitch,float phrfirstpitch,dataptr dz);
+static void gen_mtf_pitch(noteptr thisnote,noteptr tsetnote,noteptr phrasenote,float phrfirstpitch);
+static int  dec_centre(double tsetpitch,float *val,int gpsize,double gprlow,double gprange,dataptr dz);
+static int  pscat(double range,double bottom,int pindex,double *val,dataptr dz);
+static int  initialise_phrases
+            (int **phrnotecnt,double **phraseamp,double **phrange,noteptr **phrlastnote,dataptr dz);
+static int  do_ev_pch
+            (double *thispitch,double thistime,double *pptop,double *ppbot,dataptr dz);
+static int  get_gpparams
+            (double thistime,double thispitch,unsigned char dectypecnt,double *gprange,double *gprlow,int *gpsize,
+            double *gpdense,double pptop,double ppbot,unsigned char dectypestor,int mingrpsize,dataptr dz);
+static int orientrange
+            (double thispitch,double pptop, double ppbot,double *gprange, double *gprlow,
+            unsigned char dectypestor,unsigned char dectypecnt,dataptr dz);
+static void squeezrange(double thispitch,double *gprange,double *gprlow, double pptop, double ppbot);
+
+/**************************** DO_TEXTURE *****************************/
+
+int do_texture(dataptr dz)
+{
+    int exit_status;
+    noteptr tsetnote = dz->tex->timeset->firstnote;
+    unsigned int texflag     = dz->tex->txflag;
+    unsigned char dectypestor = dz->tex->dectypstor;
+    unsigned char dectypecnt  = dz->tex->dectypcnt;
+    unsigned char amptypestor = dz->tex->amptypstor;
+    unsigned char amptypecnt  = dz->tex->amptypcnt;
+    int ampdirected           = dz->tex->ampdirectd;
+    motifptr tset             = dz->tex->timeset;
+    motifptr *phrase          = dz->tex->phrase;
+    int phrcount              = dz->tex->phrasecnt;
+    int *phrnotecnt=NULL;
+    double *phraseamp=NULL, *phrange=NULL;  
+    noteptr thisnote=NULL, nextnote=NULL, phrasenote=NULL, nextevent=NULL, *phrlastnote=NULL, *shadow=NULL;
+    float phrlpitch=0.0, phrfirstpitch=0.0;
+    unsigned char thisinstr, amptype=0;
+    double  tsettime=0.0, thistime=0.0, thispitch=0.0, ampstep=0.0, thepitch=0.0, thisamp=0.0, thisdur=0.0;
+    double  rangemult=0.0, gpdense=0.0, gprange=0.0, gprlow=0.0, multiplier=0.0;
+    double timeadjust = 0.0; /* default */
+    int phrno=0, n=0, shadowsize=0, gpsize=0, mingrpsize = 0;
+    double pptop=0.0, ppbot=0.0;
+    int shadindex = 0;
+
+    dz->iparam[SPINIT] = 0;
+    if(texflag & IS_CLUMPED) {
+        if((dz->tex->phrasecnt > 0) 
+        && (exit_status = initialise_phrases(&phrnotecnt,&phraseamp,&phrange,&phrlastnote,dz))<0)
+            return(exit_status);
+
+        if(texflag & IS_GROUPS)
+            mingrpsize = 1;         
+
+        if((exit_status= make_shadow(tset,&shadowsize,&shadow))<0)
+            return(exit_status);
+
+        if(texflag & IS_DECOR) {
+            setup_decor(&pptop,&ppbot,&shadindex,&tsetnote,dz);
+        } else if(texflag & IS_MOTIFS)  {
+            if((exit_status = set_motifs(phrcount,phrase,phrnotecnt,phraseamp,phrange,phrlastnote))<0)
+                return(exit_status);
+        } else if(texflag & IS_ORNATE) {
+            if((exit_status = set_motifs(phrcount,phrase,phrnotecnt,phraseamp,phrange,phrlastnote))<0)
+                return(exit_status);
+            if(dz->vflag[WHICH_CHORDNOTE]==DECOR_HIGHEST)
+                tsetnote = gethipitch(tsetnote,&shadindex);
+        }
+    }
+
+    while(tsetnote!=(noteptr)0) {
+        tsettime  = (double)tsetnote->ntime;
+        thistime  = tsettime;
+        if((exit_status = read_values_from_all_existing_brktables(thistime,dz))<0)
+            return(exit_status);
+        if(texflag & IS_DECOR)
+            thispitch = tsetnote->pitch;
+        if(texflag & IS_ORN_OR_MTF) {
+            if((exit_status = 
+            setup_motif_or_ornament(thistime,&multiplier,&phrno,&phrasenote,phrase,dz))<0)
+                return(exit_status);
+        }
+        if(!(texflag & IS_ORN_OR_DEC)) {
+            if((exit_status = do_ev_pch(&thispitch,thistime,&pptop,&ppbot,dz))<0)
+                return(exit_status);
+            tsetnote->pitch = (float)thispitch;
+        }
+        if((exit_status = do_amp_instr_dur(&thisamp,&thisinstr,&thisdur,tsetnote,thistime,dz))<0)
+            return(exit_status);
+        if(texflag & IS_CLUMPED) {
+            if(texflag & IS_MOTIFS) {
+                if((exit_status = getmtfdur(tsetnote,phrasenote,&thisdur,multiplier,dz))<0)
+                    return(exit_status);
+                tsetnote->dur = (float)thisdur;
+            }
+            if(texflag & IS_ORN_OR_MTF) {
+                gpsize = phrnotecnt[phrno];
+                phrfirstpitch = phrasenote->pitch;
+            } else {
+                if((exit_status = get_gpparams(thistime,thispitch,dectypecnt,
+                &gprange,&gprlow,&gpsize,&gpdense,pptop,ppbot,dectypestor,mingrpsize,dz))<0)
+                    return(exit_status);
+            }
+            if(texflag & IS_DECOR) {
+                if((exit_status = position_and_size_decoration(&thistime,tsettime,gpdense,&gpsize,dz))<0)
+                    return(exit_status);
+            } else
+                gpsize--;
+            if(texflag & IS_ORNATE) {
+                phrlpitch = (phrlastnote[phrno])->pitch;
+                if((exit_status = setup_ornament
+                (&timeadjust,&thistime,&gpsize,phrlastnote,multiplier,&phrasenote,phrno,dz))<0)
+                    return(exit_status);
+            }
+            if(!(texflag & IS_DECOR))
+                nextnote = tsetnote->next;
+            if(gpsize>0) {                      /* 3b */
+                if(texflag & IS_ORN_OR_MTF) {
+                    if((exit_status = orn_or_mtf_amp_setup
+                    (ampdirected,phrange,phrno,thisamp,gpsize,&rangemult,&ampstep,&amptype,amptypestor,amptypecnt,dz))<0)
+                        return(exit_status);
+                }
+                if(texflag & IS_MOTIFS) {
+                    if((exit_status = set_motif_amp
+                    (tsetnote,&thisamp,gpsize,ampstep,phrasenote,rangemult,phraseamp,phrno,amptype))<0)
+                        return(exit_status);
+                } else if(texflag & IS_ORNATE) {
+                    if((exit_status = set_ornament_amp
+                    (phraseamp,phrlastnote,&thisamp,phrasenote,phrno,tsetnote,ampstep,rangemult,gpsize,dz))<0)
+                        return(exit_status);
+                } else if(texflag & IS_GROUPS) {
+                    if((exit_status = set_group_amp
+                    (tsetnote,&thisamp,&amptype,&ampstep,gpsize,amptypecnt,amptypestor,dz))<0)
+                        return(exit_status);
+                } else if(texflag & IS_DECOR) {
+                    if((exit_status = set_decor_amp
+                    (ampdirected,&thisamp,&ampstep,gpsize,&amptype,amptypecnt,amptypestor,dz))<0)
+                        return(exit_status);
+                }
+                if(dz->iparam[TEX_GPSPACE]!=IS_STILL) {
+                    if((exit_status = init_group_spatialisation(tsetnote,shadindex,shadow,shadowsize,dz))<0)
+                        return(exit_status);
+                }
+                thisnote  = tsetnote;
+                if(texflag & IS_DECOR)
+                    nextnote = tsetnote->next;
+                else if(texflag & IS_ORNATE) {
+                    if(!dz->vflag[IS_PRE])
+                        phrasenote = phrasenote->next;
+                }
+                if(texflag & IS_ORN_OR_DEC)
+                    nextevent = getnextevent_to_decorate(tsetnote,&shadindex,dz);
+                for(n=0;n<gpsize;n++) {
+                    if((exit_status = make_new_note(&thisnote))<0)
+                        return(exit_status);
+                    if(texflag & IS_DEC_OR_GRP) {
+                        if((exit_status = set_group_params
+                        (tsetnote,thisnote,gpdense,ampstep,&thisamp,&thistime,thisdur,dz))<0)
+                            return(exit_status);
+                        if((exit_status = do_grp_ins(tsetnote->instr,&(thisnote->instr),dz))<0)
+                            return(exit_status);
+                        thisnote->motioncentre = tsetnote->motioncentre;
+                        if(texflag & IS_DECOR) {
+                            if((exit_status = dec_centre
+                            (thispitch,&(thisnote->pitch),gpsize,gprlow,gprange,dz))<0) 
+                                return(exit_status);
+                        } else {
+                            if((exit_status = pscat(gprange,gprlow,PM_GPPICH,&thepitch,dz))<0)
+                                return(exit_status);
+                            thisnote->pitch = (float)thepitch;
+                        }
+                        thisnote->ntime  = (float)thistime; 
+                    } else {
+                        if((exit_status = check_next_phrasenote_exists(&phrasenote,texflag,dz))<0)
+                            return(exit_status);
+                        if((exit_status = setup_motif_params(phrasenote,thistime,&thisamp,ampstep,phraseamp,phrno,
+                        rangemult,thisnote,tsetnote,multiplier,timeadjust,dz))<0)
+                            return(exit_status);
+                        if(texflag & IS_MOTIFS) {
+                            gen_mtf_pitch(thisnote,tsetnote,phrasenote,phrfirstpitch);
+                        } else {
+                            gen_orn_pitch(thisnote,tsetnote,phrasenote,phrlpitch,phrfirstpitch,dz);
+                            phrasenote = phrasenote->next;
+                        }
+                    }
+                    if((exit_status = setspace(tsetnote,thisnote,gpsize,dz))<0)
+                        return(exit_status);
+                }
+                thisnote->next = nextnote;
+                if(nextnote!=(noteptr)0)
+                    nextnote->last = thisnote;
+                if(texflag & IS_ORN_OR_DEC)
+                    tsetnote = nextevent;
+
+            } else if(texflag & IS_ORN_OR_DEC)
+                tsetnote = getnextevent_to_decorate(tsetnote,&shadindex,dz);
+
+        } else 
+            tsetnote = tsetnote->next;
+
+        if(texflag & IS_MTF_OR_GRP) {
+            tsetnote = nextnote;
+            shadindex++;
+        }
+    }
+    if((texflag & IS_DECOR) && dz->vflag[DISCARD_ORIGLINE]) {
+        if((exit_status = erase_shadow(shadowsize,shadow,tset))<0)
+            return(exit_status);
+    }
+    if(texflag & IS_CLUMPED)
+        return arrange_notes_in_timeorder(tset);
+    return(FINISHED);
+}
+
+/**************************** SETUP_MOTIF_PARAMS ****************************/
+
+int setup_motif_params
+(noteptr phrasenote,double tsettime,double *thisamp,double ampstep,double *phraseamp, int phrno,
+double rangemult,noteptr thisnote,noteptr tsetnote,double multiplier,double timeadjust,dataptr dz)
+{
+    double notetime, ampdif;
+    notetime = getnotetime(phrasenote,tsettime,multiplier,timeadjust,dz);
+    *thisamp  += ampstep;
+    ampdif    =(phraseamp[phrno] - phrasenote->amp)*rangemult;/* e */
+    return do_mtf_params(thisnote,*thisamp,phrasenote,tsetnote,ampdif,notetime,multiplier,dz);
+}
+
+/**************************** GEN_ORN_PITCH ****************************/
+
+void gen_orn_pitch
+(noteptr thisnote,noteptr tsetnote,noteptr phrasenote,float phrlpitch,float phrfirstpitch,dataptr dz)
+{
+    if(dz->vflag[IS_PRE])   
+        thisnote->pitch = (float)(tsetnote->pitch + phrasenote->pitch - phrlpitch);
+    else 
+        thisnote->pitch = (float)(tsetnote->pitch + phrasenote->pitch - phrfirstpitch);
+}
+
+/**************************** GEN_MTF_PITCH ****************************/
+
+void gen_mtf_pitch(noteptr thisnote,noteptr tsetnote,noteptr phrasenote,float phrfirstpitch)
+{
+    thisnote->pitch = (float)(tsetnote->pitch + phrasenote->pitch - phrfirstpitch);
+    thisnote->pitch = (float)octadjust((double)thisnote->pitch);
+}
+
+/************************* DEC_CENTRE ******************************
+ *
+ * Centre a decoration on the decorated pitch.
+ *
+ * (1)  For groupsize 1 or 2, k=1
+ *      For groupsize 3 or 4, k=2
+ *      For groupsize 5 or 6, k=3 etc
+ * (2)  Scatter pitches as normally.
+ * (3)  If range is NOT one-sided, proceed..otherwise return in normal way.
+ * (4)  Find ratio of upper half of range to lower. 
+ * (5)  Find distance from decorated note.
+ * (6)  Save the current value of allowed repetitions.
+ *      THese are number of times a note occurs above the decorated pitch,
+ *      before it can do so again (same for below).
+ * (7)  If the allowed repetitions are bigger than k, replace it by k.
+ *      This means that if we allow 3 repetitions but there are only
+ *      1,2,3 or 4 notes, we force, 1 repetition for 2 notes, 2 repetitions
+ *      for 3 or 4 notes etc. but allow 3 repetitions for 5,6 etc notes.
+ * (8)  Select above or below decorated pitch.
+ * (9)  If meant to be above note, but is below it, put note in other
+ *      half of range, with appropriate adjustment for relative sizes
+ *      of half-ranges.
+ * (10) If meant to be below note, but is above it, put note in other
+ *      half of range, with appropriate adjustment for relative sizes
+ *      of half-ranges.
+ * (11) Restore the repetcnt value!!
+ */
+ 
+int dec_centre(double tsetpitch,float *val,int gpsize,double gprlow,double gprange,dataptr dz)
+{
+    int exit_status;
+    double a, q, w, gprhi = gprlow + gprange, ulratio;
+    int s, save, k = (gpsize+1)/2;                              /* 1 */
+    if((exit_status = pscat(gprange,gprlow,PM_GPPICH,&a,dz))<0) /* 2 */
+        return(exit_status);
+    if((w=tsetpitch-gprlow)>FLTERR && !flteq(tsetpitch,gprhi)) {/* 3 */
+        ulratio = (gprhi-tsetpitch)/w;                          /* 4 */
+        q       = a-tsetpitch;                                  /* 5 */
+        save    = dz->iparray[TXREPETCNT][PM_DECABV];           /* 6 */
+        if(dz->iparray[TXREPETCNT][PM_DECABV]>k)                /* 7 */
+            dz->iparray[TXREPETCNT][PM_DECABV] = k;         
+        if((exit_status = doperm((int)2,PM_DECABV,&s,dz))<0)            /* 8 */
+            return(exit_status);
+        if(s && q<0.0)                                          /* 9 */
+            a = tsetpitch - (q*ulratio);
+        if(!s && q>0.0)                                         /* 10 */
+            a = tsetpitch - (q/ulratio);
+        dz->iparray[TXREPETCNT][PM_DECABV] = save;              /* 11 */
+        if(a<MIDIBOT || a>MIDITOP) {
+            sprintf(errstr,"TEXTURE: Problem in dec_centre()\n");
+            return(PROGRAM_ERROR);
+        }
+    }
+    *val = (float)a;
+    return(FINISHED);
+}
+
+/***************************** PSCAT ************************************
+ *
+ * A weighted version of pscatx().
+ *
+ * Select a random value within 'range', by permuting one of BANDCNT UNequal
+ * ranges, and selecting a random value within the chosen range. The upper
+ * and lower band are half as wide as the inner 3 bands, ensuring that
+ * values within these outer bands are squeezed into a narrow-range-of-values
+ * near the boundaries of the total range.
+ */
+
+int pscat(double range,double bottom,int pindex,double *val,dataptr dz)
+{
+    int exit_status;
+    double bandbottom, bandwidth, x;
+    int k;
+    if((exit_status = doperm((int)BANDCNT,pindex,&k,dz))<0)
+        return(exit_status);
+    bandwidth = range/(double)LAYERCNT;
+    switch(k) {
+    case(0):
+        bandbottom = 0.0;
+        break;
+    case(BANDCNT-1):
+        bandbottom = (LAYERCNT-1) * bandwidth;
+        break;
+    default:
+        bandbottom = bandwidth + ((double)((k-1) * 2) * bandwidth);
+        bandwidth *= 2.0;
+        break;
+    }
+    x  = (drand48() * bandwidth);
+    x += bandbottom;
+    *val = x + bottom;
+    return(FINISHED);
+}
+
+/**************************** INITIALISE_PHRASES *******************************/
+
+int initialise_phrases(int **phrnotecnt,double **phraseamp,double **phrange,noteptr **phrlastnote,dataptr dz)
+{
+    if((*phrnotecnt = (int *)malloc(dz->tex->phrasecnt * sizeof(int)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY for phrase notecnt array.\n");
+        return(MEMORY_ERROR);
+    }
+    if((*phraseamp = (double *)malloc(dz->tex->phrasecnt * sizeof(double)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY for phrase amplitude array.\n");
+        return(MEMORY_ERROR);
+    }
+    if((*phrange = (double *)malloc(dz->tex->phrasecnt * sizeof(double)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY for phrase range array.\n");
+        return(MEMORY_ERROR);
+    }
+    if((*phrlastnote = (noteptr *)malloc(dz->tex->phrasecnt * sizeof(noteptr)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY for phrase lastnote array.\n");
+        return(MEMORY_ERROR);
+    }
+    return(FINISHED);
+}
+
+/********************** DO_EV_PCH *******************************
+ *
+ * Set pitch of event (not group etc.).
+ */
+
+int do_ev_pch
+(double *thispitch,double thistime,double *pptop,double *ppbot,dataptr dz)
+{
+    int exit_status;
+    if((exit_status = getvalue(TEXTURE_MAXPICH,TEXTURE_MINPICH,thistime,PM_PITCH,thispitch,dz))<0)
+        return(exit_status);
+    if(*thispitch > MIDITOP || *thispitch < MIDIBOT) {
+        sprintf(errstr,"TEXTURE: pitch [%.1f] out of midirange at time %.2f\n",*thispitch,thistime); 
+        return(DATA_ERROR);
+    }
+    *pptop = dz->param[TEXTURE_MAXPICH];
+    *ppbot = dz->param[TEXTURE_MINPICH];
+    return(FINISHED);
+}
+
+/************************** GET_GPPARMAS **************************
+ *
+ * Get the parameters for a group of notes.
+ *
+ * (1)  Get gprange in normal way.
+ * (2)  Don't adjust range.
+ * (3)  For decorations, the range may be oriented, above, below
+ *      or centred on the initial note. So range is adjusted here.
+ */
+                                                                                           
+int get_gpparams(double thistime,double thispitch,unsigned char dectypecnt,
+double *gprange,double *gprlow,int *gpsize,double *gpdense,double pptop,double ppbot,
+unsigned char dectypestor,int mingrpsize,dataptr dz)
+{
+    int exit_status;
+    if((exit_status = getvalue(TEX_GPRANGHI,TEX_GPRANGLO,thistime,PM_GPRANG,gprange,dz))<0)
+        return(exit_status);                                                /* 1 */
+    if(!dectypecnt)
+        squeezrange(thispitch,gprange,gprlow,pptop,ppbot);
+    else {
+        if((exit_status = orientrange
+        (thispitch,pptop,ppbot,gprange,gprlow,dectypestor,dectypecnt,dz))<0)/* 3 */
+            return(exit_status);
+    }
+    if((exit_status = igetvalue(TEX_GPSIZEHI,TEX_GPSIZELO,thistime,PM_GPSIZE,gpsize,dz))<0)
+        return(PROGRAM_ERROR);
+
+    if(*gpsize < mingrpsize) {
+        sprintf(errstr,"Impossible GROUP SIZE value [%d]\n",*gpsize);
+        return(PROGRAM_ERROR);
+    }
+    return get_density_val(thistime,gpdense,dz);
+}
+
+/***************************  ORIENTRANGE ******************************
+ *
+ */
+
+int orientrange
+(double thispitch,double pptop, double ppbot,double *gprange, double *gprlow,
+unsigned char dectypestor,unsigned char dectypecnt,dataptr dz)
+{
+    int exit_status;
+    unsigned char dectype;
+    double top;
+    int k;
+    if((exit_status = doperm((int)dectypecnt,PM_ORIENT,&k,dz))<0)
+        return(exit_status);
+    if((exit_status = gettritype(k,dectypestor,&dectype))<0)
+        return(exit_status);
+    switch(dectype) {
+    case(0):            /* centred range */
+        squeezrange(thispitch,gprange,gprlow,pptop,ppbot);
+        dz->vflag[DECCENTRE] = TRUE;
+        break;
+    case(1):            /* range above note */
+        top      = min((thispitch + *gprange),pptop);
+        *gprlow  = max((top - *gprange),ppbot);
+        *gprange = top - *gprlow;
+        dz->vflag[DECCENTRE] = FALSE;
+        break;              
+    case(2):            /* range below note */
+        top      = thispitch;
+        *gprlow  = max((top - *gprange),ppbot);
+        *gprange = top - *gprlow;
+        dz->vflag[DECCENTRE] = FALSE;
+        break;              
+    default:
+        sprintf(errstr,"TEXTURE: Problem in orientrange()\n");
+        return(PROGRAM_ERROR);
+    }
+    return(FINISHED);
+}
+
+/***************************  SQUEEZRANGE ******************************
+ *
+ * Adjust range to lie within texture limits.
+ *
+ * (2)  Top of range is at current pitch plus half range. If this is
+ *  above current top-of-texture range (pptop) move top down.
+ * (3)  Bottom of range is gprange below top. If this is below
+ *  bottom-of-texture range (ppbot), move gprangelo up.
+ * (4)  Recalculate the true gprange within true limits.
+ */
+
+void squeezrange(double thispitch,double *gprange,double *gprlow, double pptop, double ppbot)
+{
+    double top;
+    top     = min((thispitch + (*gprange/2.0)),pptop);      /* 2 */
+    *gprlow  = max((top-*gprange),ppbot);                   /* 3 */
+    *gprange = top - *gprlow;                               /* 4 */
+}

+ 2360 - 0
dev/texture/texture3.c

@@ -0,0 +1,2360 @@
+/*
+ * Copyright (c) 1983-2013 Trevor Wishart and Composers Desktop Project Ltd
+ * http://www.trevorwishart.co.uk
+ * http://www.composersdesktop.com
+ *
+ This file is part of the CDP System.
+ 
+ The CDP System is free software; you can redistribute it
+ and/or modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+ 
+ The CDP System is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU Lesser General Public License for more details.
+ 
+ You should have received a copy of the GNU Lesser General Public
+ License along with the CDP System; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA
+ *
+ */
+/* floatsam version: no changes */
+#include <stdio.h>
+#include <stdlib.h>
+#include <float.h>
+#include <structures.h>
+#include <tkglobals.h>
+#include <globcon.h>
+#include <processno.h>
+#include <modeno.h>
+#include <arrays.h>
+#include <texture.h>
+#include <cdpmain.h>
+
+#include <sfsys.h>
+#include <osbind.h>
+
+#if defined unix || defined __GNUC__
+#define round(x) lround((x))
+#endif
+
+#define CHARBITSIZE (8)     /* number of bits in a char          */
+
+struct ffit {               /* Structure for FIT of motif to HS  */
+    float transpose;
+    float fit;
+    struct ffit *next;
+    struct ffit *last;
+};
+
+typedef struct ffit *fitptr;
+
+/* RWD Feb 2014: now in sfsys,h, differently! */
+#ifdef MAXINT
+# undef MAXINT
+#endif
+#define MAXINT (2147483647)
+/***************************** GENERATING TEXTURES WITH HFIELD(S) ******************************/
+
+
+static int set_hfmotifs(double *hs,motifptr *phrase,int *phrnotecnt,double *phraseamp,
+            double *phrange, noteptr *phrlastnote,int *endhsindex,int **hfphrase,
+            int hsnotecnt,fitptr fithead,double **notestor,dataptr dz);
+static int gethfphrase
+            (double *hs,double **notestor,int z,double lopitch,double hipitch,int **hfphrase,
+            int hsnotecnt,int *phrnotecnt,motifptr *phrase,fitptr fithead);
+static int shrink_to_hs
+            (int z,int hsnotecnt,double hipitch,double lopitch,double hstop,double hsbot,
+            double *hs, int *hfphrase,motifptr *phrase,int *phrnotecnt);
+static int findhfphrase
+            (int z,double *hs,double hstop,int hsnotecnt,double lopitch,
+            double origlo,motifptr *phrase,int **hfphrase,int *phrnotecnt,fitptr fithead,double **notestor);
+static int getmtfindeces
+            (double transpose,int z,int hsnotecnt,double *hs,motifptr *phrase,int *phrnotecnt,int **hfphrase);
+static int get_fit(double *notestor,fitptr thisfit,double lopitch,double origlo,int z,
+            int hsnotecnt,int *phrnotecnt,double *hs,fitptr *newfit);
+static int put_fit(fitptr thisfit,double transval,double fitval,fitptr *newfit);
+static int best_fit(fitptr fithead,double *transpose);
+static void free_fitlist(fitptr fithead);
+static double hfadjust(double thispitch,double *hs,int x1,int x2,int texflag,int hsnotecnt);
+static int convert_pitch_to_nearest_hset_pitch(double thispitch,double *hs,int hsnotecnt);
+static int hfadj2(int hsi,int hfnotecnt,int hsnotecnt);
+static int setup_hfield(noteptr thisnote,double **hs,int *hsnotecnt,double **hf,int *hfnotecnt,int texflag);
+static int get_next_hfield
+            (double **hf,double **hs,double inputtime,int *hf_cnt,int *hs_cnt,int *hfnotecnt,
+            noteptr *thishfnote,double *thishftime,double *nexthftime,int hfdatacnt,int *hsnotecnt,
+            noteptr *thishsnote,double *thishstime,double *nexthstime,double *hft,int texflag);
+static int setup_motif_note
+            (double thisamp,int thisinstr,double thisdur,noteptr tsetnote,noteptr phrasenote,
+            double *thispitch,double thistime,int *hsindex,int hsnotecnt,double *hs,
+            double *pptop,double *ppbot,int *shadindex,char *shadbits,double multiplier,dataptr dz);
+static int setup_group_note
+            (double thisamp,int thisinstr,double thisdur,noteptr tsetnote,
+            double *thispitch,double thistime,int *hsindex,int hsnotecnt,double *hs,
+            double *pptop,double *ppbot,int *shadindex,char *shadbits,dataptr dz);
+static int setup_ornamentation
+            (int *starthsi,int *endhsi,noteptr *nextevent,noteptr tsetnote,noteptr *phrasenote,
+            int *shadindex, int *endhsindex,int *hfphrase,int phrno,dataptr dz);
+static int generate_motifin_note_pitch
+            (int n,int hsindex,int starthsindex,int hsnotecnt,double thispitch,
+            int *hfphrase,noteptr *thisnote,double *hs,int texflag);
+static int generate_motif_note_pitch
+            (noteptr tsetnote,noteptr phrasenote,double phrfirstnote,noteptr thisnote);
+static int generate_ornament_note_pitch
+            (int n,double *hs, int hsi, int endhsi,int starthsi,noteptr *thisnote,noteptr *phrasenote,
+            int *hfphrase,int hfnotecnt,int hsnotecnt,dataptr dz);
+static int do_ev_hfpch
+            (double thistime,int *hsindex,double *val,
+            int hsnotecnt,double *hs,double *pptop,double *ppbot,dataptr dz);
+static int getp_as_index
+            (double thistime,int *val,int hsnotecnt,double *hs,double *pptop,double *ppbot,dataptr dz);
+static int init_shadbits(int shadowsize,int *shshsize,char **shadbits);
+static int geths(noteptr thisnote,double **hs,int *hsnotecnt);
+static int gethf(noteptr thisnote,double **hf,int *hfnotecnt);
+static int gen_hs(double **hf,double **hs, int *hsnotecnt, int hfnotecnt);
+static int chekrepeat(noteptr thisnote,double lastpitch);
+static void set_shadbit(int k,char *shadbits);
+static int  geths_lobnd(double thispitch,double *hs,int hsnotecnt);
+static int  gethfnote(double thispitch,double *hf,int *hfnotecnt);
+static int  setmtfparams
+            (noteptr thisnote,double thisamp,noteptr phrasenote,noteptr tsetnote,double ampdif,
+            double notetime,int gpsize,double multiplier,dataptr dz);
+static int  initialise_hfphrases
+            (int ***hfphrase,int **endhsindex,int **phrnotecnt,double **phraseamp,double **phrange,
+            noteptr **phrlastnote,dataptr dz);
+static int  readhftimes(noteptr firstnote, int *hfdatacnt,double **hft);
+static int  init_fits(fitptr *thisfit);
+static int  get_hfgpparams(double thistime,double thispitch,double *hs,int hsnotecnt,
+        int *gpsize,int *hfrange,int *hfgpranglo,int *hfgpranghi,
+        double *gprange,double *gpdense,int mingrpsize,
+        double *gprlow, int dectypecnt,unsigned char dectypestor,dataptr dz);
+static int  generate_group_note(noteptr thisnote,noteptr testnote,double thistime,
+        int hfrange,int hfgpranglo,double *hs,int *hsindex,int gpsize,dataptr dz);
+static int  generate_decor_note(noteptr thisnote,noteptr tsetnote,
+        double thispitch,double thistime,int hfrange,int hfgpranghi,int hfgpranglo,
+        double *hs,int *hsindex,int hsnotecnt,double gprlow,double gprange,int gpsize,dataptr dz);
+static void del_ghosts(int shshsize,char *shadbits,noteptr *shadow,int shadowsize,motifptr tset);
+static int  geths_hibnd(double thispitch,int hsnotecnt,double *hs);
+static int  geths_above(double thispitch,double *hs,int hsnotecnt);
+static int  fit_unlink(fitptr thisfit);
+static int  new_fit(fitptr thisfit,fitptr *newfit);
+static int  getnexths(double **hs,double inputtime,int *hs_cnt,int *hsnotecnt,noteptr *thishsnote,
+        double *thishstime,double *nexthstime,int hfdatacnt,double *hft);
+static int  getnexthf(double **hf,double **hs, int *hsnotecnt,double inputtime,int *hf_cnt,
+        int *hfnotecnt,noteptr *thishfnote,double *thishftime,double *nexthftime,int hfdatacnt,double *hft);
+static int  hfscat(int prange,int pbottom,int permindex,int *val,dataptr dz);
+static int  gethsnote(double thispitch,double *thishs,int *hsnotecnt);
+static void hfsqueezrange
+        (double thispitch,int *hfrange,int *hfgpranghi,int *hfgpranglo,int hsnotecnt,double *hs);
+static int  hforientrange(double thispitch,int *hfrange,int *hfgpranghi,int *hfgpranglo,
+        int hsnotecnt,double *hs,int dectypecnt,unsigned char dectypestor,dataptr dz);
+static int  dec_hfcentre(double tsetpitch,double *hs,int hsnotecnt,
+        int hfrange,int hfgpranghi,int hfgpranglo,double gprlow,double gprange,int gpsize,
+        double *val,dataptr dz);
+static int  hfscatx(int prange,int pbottom,int permindex,int *val,dataptr dz);
+static int  get_first_hs(noteptr thisnote,double **hs,int *hsnotecnt);
+static int  get_first_hf(noteptr thisnote,double **hf,int *hfnotecnt);
+static int  setup_first_hfield
+        (noteptr thisnote,double **hs,int *hsnotecnt,double **hf,int *hfnotecnt,int texflag);
+static int octeq(double a,double b);
+
+/**************************** DO_SIMPLE_HFTEXTURE ****************************/
+
+int do_simple_hftexture(dataptr dz)
+{
+    int exit_status;
+    unsigned int texflag     = dz->tex->txflag;
+    motifptr tset             = dz->tex->timeset;
+    motifptr hfmotif          = dz->tex->hfldmotif;
+    int hsindex;
+    noteptr tsetnote = tset->firstnote;
+    noteptr nextnote;
+    double thistime, thispitch, lastpitch = -1.0;
+    noteptr thishfnote = hfmotif->firstnote;
+    noteptr thishsnote = hfmotif->firstnote;
+    double thishftime,nexthftime,thishstime,nexthstime,thisamp,thisdur;
+    unsigned char thisinstr;
+    int hf_cnt = 1, hfnotecnt = 0;
+    int hs_cnt = 1, hsnotecnt = 0, repeated = 0;
+    int hfdatacnt = 0;
+    double *hft, pptop, ppbot;
+    double *hs = (double *)0, *hf = (double *)0;
+    dz->iparam[SPINIT] = 0;
+
+    if((exit_status = readhftimes(hfmotif->firstnote,&hfdatacnt,&hft))<0)
+        return(exit_status);
+    thishftime = nexthftime = thishstime = nexthstime = hft[0];
+
+    if(texflag & ISMANY_HFLDS) {
+        if((exit_status = setup_first_hfield(hfmotif->firstnote,&hs,&hsnotecnt,&hf,&hfnotecnt,texflag))<0)
+            return(exit_status);
+    } else {
+        if((exit_status = setup_hfield(hfmotif->firstnote,&hs,&hsnotecnt,&hf,&hfnotecnt,texflag))<0)
+            return(exit_status);
+    }
+    while(tsetnote!=(noteptr)0) {                   /* 3 */
+        repeated  =  chekrepeat(tsetnote,lastpitch);
+        lastpitch = tsetnote->pitch;                                                    
+        thistime  = (double)tsetnote->ntime;        /* 5 */
+        if((exit_status = read_values_from_all_existing_brktables(thistime,dz))<0)
+            return(exit_status);
+        if(texflag & ISMANY_HFLDS) {
+            if((exit_status = get_next_hfield(&hf,&hs,thistime,&hf_cnt,&hs_cnt,
+            &hfnotecnt,&thishfnote,&thishftime,&nexthftime,hfdatacnt,
+            &hsnotecnt,&thishsnote,&thishstime,&nexthstime,hft,texflag))<0)
+                return(exit_status);
+        }
+        if((exit_status = do_amp_instr_dur(&thisamp,&thisinstr,&thisdur,tsetnote,thistime,dz))<0)
+            return(exit_status);
+        if((exit_status = do_ev_hfpch(thistime,&hsindex,&thispitch,hsnotecnt,hs,&pptop,&ppbot,dz))<0)
+            return(exit_status);
+        tsetnote->pitch = (float)thispitch;
+        if(exit_status == CONTINUE) {
+            nextnote = tsetnote->next;
+            del_note(tsetnote,tset);
+            tsetnote = nextnote;
+        } else
+            tsetnote = tsetnote->next;
+    }
+    if(tset->firstnote==(noteptr)0) {
+        sprintf(errstr,"The harmonic set specified does not tally with the range.\n");
+        return(DATA_ERROR);
+    }
+    return(FINISHED);
+}
+
+/**************************** DO_CLUMPED_HFTEXTURE ****************************/
+
+int do_clumped_hftexture(dataptr dz)
+{
+    int exit_status;
+    unsigned int texflag     = dz->tex->txflag;
+    unsigned char dectypestor = dz->tex->dectypstor;
+    unsigned char dectypecnt  = dz->tex->dectypcnt;
+    unsigned char amptypestor = dz->tex->amptypstor;
+    unsigned char amptypecnt  = dz->tex->amptypcnt;
+    int ampdirected           = dz->tex->ampdirectd;
+    motifptr tset             = dz->tex->timeset;
+    motifptr hfmotif          = dz->tex->hfldmotif;
+    motifptr *phrase          = dz->tex->phrase;
+    int **hfphrase = NULL;
+    int *endhsindex=NULL, *phrnotecnt=NULL;
+    double *phraseamp=NULL, *phrange=NULL;
+    unsigned char amptype = 0;
+    fitptr fithead = NULL;
+    noteptr tsetnote = tset->firstnote;
+    noteptr thisnote=NULL, nextnote=NULL, phrasenote=NULL, nextevent=NULL, *shadow=NULL;
+    double thispitch = 0.0, lastpitch = -1.0, ampstep = 0.0, ampdif = 0.0, notetime = 0.0, thisamp = 0.0, thisdur = 0.0;
+    unsigned char thisinstr;
+    double phrfirstnote = 0.0, thistime = 0.0, rangemult = 0.0, gprlow = 0.0;
+    double timeadjust = 0.0; /* default */
+    noteptr thishfnote = hfmotif->firstnote;
+    noteptr thishsnote = hfmotif->firstnote;
+    noteptr *phrlastnote = NULL;
+    double thishftime = 0.0,nexthftime = 0.0,thishstime = 0.0,nexthstime = 0.0,tsettime = 0.0;
+    int hf_cnt = 1, hfnotecnt = 0, mingrpsize = 0, shadindex = 0, shadowsize=0;
+    double gprange = 0.0,gpdense = 0.0,multiplier = 0.0;
+    double *notestor=NULL;
+    int hfgpranglo=0,hfgpranghi=0;
+    int hs_cnt = 1, hsnotecnt = 0, repeated = 0;
+    int hfdatacnt = 0, hfrange = 0, gpsize,shshsize = 0;
+    int phrno = 0, n=0,  hsindex=0, starthsindex=0, hfchanged=0;
+    int hsi=0, starthsi = 0, endhsi=0;
+    char *shadbits = NULL;
+    double *hft=NULL, pptop=0.0, ppbot=0.0;
+    double *hs = (double *)0, *hf = (double *)0;
+
+    if((dz->tex->phrasecnt > 0) && (exit_status = initialise_hfphrases
+    (&hfphrase,&endhsindex,&phrnotecnt,&phraseamp,&phrange,&phrlastnote,dz))<0)
+        return(exit_status);
+    dz->iparam[SPINIT] = 0;
+    if(texflag & IS_GROUPS)
+        mingrpsize = 1;
+
+    if((exit_status = readhftimes(hfmotif->firstnote,&hfdatacnt,&hft))<0)
+        return(exit_status);
+    thishftime = nexthftime = thishstime = nexthstime = hft[0];
+
+    if((exit_status = make_shadow(tset,&shadowsize,&shadow))<0)
+            return(exit_status);
+
+    if((texflag & MOTIF_IN_HF) || (texflag & IS_ORNATE)) {
+        if((exit_status = init_fits(&fithead))<0)
+            return(exit_status);
+    }
+    if(texflag & IS_DECOR)
+        setup_decor(&pptop,&ppbot,&shadindex,&tsetnote,dz);
+    else {
+        if((exit_status = init_shadbits(shadowsize,&shshsize,&shadbits))<0)
+            return(exit_status);
+    }
+    if(texflag & ISMANY_HFLDS) {
+        if((exit_status = setup_first_hfield(hfmotif->firstnote,&hs,&hsnotecnt,&hf,&hfnotecnt,texflag))<0)
+            return(exit_status);
+    } else {
+        if((exit_status = setup_hfield(hfmotif->firstnote,&hs,&hsnotecnt,&hf,&hfnotecnt,texflag))<0)
+            return(exit_status);
+    }
+    if((texflag & MOTIF_IN_HF) || ((texflag & IS_ORNATE) && !(texflag & ISMANY_HFLDS))) {
+        if((exit_status = set_hfmotifs
+        (hs,phrase,phrnotecnt,phraseamp,phrange,phrlastnote,endhsindex,hfphrase,hsnotecnt,fithead,&notestor,dz))<0)
+            return(exit_status);
+    } else if(texflag & IS_MOTIFS) {
+        if((exit_status = set_motifs
+        (dz->tex->phrasecnt,phrase,phrnotecnt,phraseamp,phrange,phrlastnote))<0)
+            return(exit_status);
+    }
+    while(tsetnote!=(noteptr)0) {
+        if(!(texflag & IS_ORNATE)) {
+            repeated =  chekrepeat(tsetnote,lastpitch);
+            lastpitch = tsetnote->pitch;
+        }
+        tsettime = thistime = (double)tsetnote->ntime;
+        if((exit_status = read_values_from_all_existing_brktables(thistime,dz))<0)
+            return(exit_status);
+        if(texflag & ISMANY_HFLDS) {
+            if((exit_status = get_next_hfield(&hf,&hs,thistime,&hf_cnt,&hs_cnt,
+            &hfnotecnt,&thishfnote,&thishftime,&nexthftime,hfdatacnt,
+            &hsnotecnt,&thishsnote,&thishstime,&nexthstime,hft,texflag))<0)
+                return(exit_status);
+            hfchanged = exit_status;
+            if(((texflag & MOTIF_IN_HF) || (texflag & IS_ORNATE)) && hfchanged) {
+                if((exit_status = set_hfmotifs
+                (hs,phrase,phrnotecnt,phraseamp,phrange,phrlastnote,endhsindex,hfphrase,hsnotecnt,fithead,&notestor,dz))<0)
+                    return(exit_status);
+            }                                                      
+        }
+        if(texflag & IS_ORN_OR_MTF) {
+            if((exit_status = setup_motif_or_ornament(thistime,&multiplier,&phrno,&phrasenote,phrase,dz))<0)
+                return(exit_status);
+        }
+        if((exit_status = do_amp_instr_dur(&thisamp,&thisinstr,&thisdur,tsetnote,thistime,dz))<0)
+            return(exit_status);
+        if(texflag & IS_DECOR)        
+            thispitch = tsetnote->pitch;
+        if(texflag & IS_MTF_OR_GRP) {
+            if(texflag & IS_GROUPS)
+                exit_status = setup_group_note
+                (thisamp,thisinstr,thisdur,tsetnote,&thispitch,
+                thistime,&hsindex,hsnotecnt,hs,&pptop,&ppbot,&shadindex,shadbits,dz);
+            else
+                exit_status = setup_motif_note
+                (thisamp,thisinstr,thisdur,tsetnote,phrasenote,&thispitch,
+                thistime,&hsindex,hsnotecnt,hs,&pptop,&ppbot,&shadindex,shadbits,multiplier,dz);
+            if(exit_status==CONTINUE)
+                continue;
+        }
+        if(texflag & IS_ORN_OR_MTF)
+            gpsize = phrnotecnt[phrno];
+        else {
+            if((exit_status = get_hfgpparams
+            (thistime,thispitch,hs,hsnotecnt,&gpsize,&hfrange,&hfgpranglo,&hfgpranghi,
+            &gprange,&gpdense,mingrpsize,&gprlow,dectypecnt,dectypestor,dz))<0)
+                return(exit_status);
+        }
+        if(texflag & IS_DECOR) {
+            if((exit_status = position_and_size_decoration(&thistime,tsettime,gpdense,&gpsize,dz))<0)
+                return(exit_status);
+        } else
+            gpsize--;
+        if(texflag & IS_MOTIFS)
+            phrfirstnote = phrasenote->pitch;
+        else if(texflag & IS_ORNATE) {
+            if((hsi = convert_pitch_to_nearest_hset_pitch((double)tsetnote->pitch,hs,hsnotecnt))<0)
+                gpsize = 0;         /* note out of bounds, ornament omitted  */
+            if((exit_status = setup_ornament
+            (&timeadjust,&thistime,&gpsize,phrlastnote,multiplier,&phrasenote,phrno,dz))<0)
+                return(exit_status);
+        }
+        if(!(texflag & IS_DECOR))
+            nextnote  = tsetnote->next;
+        if(gpsize>0) {
+            if(texflag & IS_ORN_OR_MTF) {
+                if((exit_status = orn_or_mtf_amp_setup
+                (ampdirected,phrange,phrno,thisamp,gpsize,&rangemult,&ampstep,&amptype,amptypestor,amptypecnt,dz))<0)
+                    return(exit_status);
+            }
+            if(texflag & IS_MOTIFS) {
+                if((exit_status = set_motif_amp
+                (tsetnote,&thisamp,gpsize,ampstep,phrasenote,rangemult,phraseamp,phrno,amptype))<0)
+                    return(exit_status);
+            } else if(texflag & IS_ORNATE) {
+                if((exit_status = set_ornament_amp
+                (phraseamp,phrlastnote,&thisamp,phrasenote,phrno,tsetnote,ampstep,rangemult,gpsize,dz))<0)
+                    return(exit_status);
+            } else if (texflag & IS_GROUPS) {
+                if((exit_status = set_group_amp
+                (tsetnote,&thisamp,&amptype,&ampstep,gpsize,amptypecnt,amptypestor,dz))<0)
+                    return(exit_status);
+            } else if (texflag & IS_DECOR) {
+                if((exit_status = set_decor_amp
+                (ampdirected,&thisamp,&ampstep,gpsize,&amptype,amptypecnt,amptypestor,dz))<0)
+                    return(exit_status);
+            }
+            if(dz->iparam[TEX_GPSPACE]!=IS_STILL) {
+                if((exit_status = init_group_spatialisation(tsetnote,shadindex,shadow,shadowsize,dz))<0)
+                    return(exit_status);
+            }
+            thisnote  = tsetnote;
+            if(texflag & MOTIF_IN_HF)
+                starthsindex =  *(hfphrase[phrno]);
+            else if(texflag & IS_ORNATE) {
+                if((exit_status = setup_ornamentation
+                (&starthsi,&endhsi,&nextevent,tsetnote,&phrasenote,&shadindex,endhsindex,hfphrase[phrno],phrno,dz))<0)
+                    return(exit_status);
+            } else if(texflag & IS_DECOR) {
+                nextnote = tsetnote->next;
+                nextevent = getnextevent_to_decorate(tsetnote,&shadindex,dz);
+            }
+            for(n=0;n<gpsize;n++) {
+                if((exit_status = make_new_note(&thisnote))<0)
+                    return(exit_status);
+                if(texflag & IS_ORN_OR_MTF) {
+                    if((exit_status = check_next_phrasenote_exists(&phrasenote,texflag,dz))<0)
+                        return(exit_status);
+                    notetime = getnotetime(phrasenote,thistime,multiplier,timeadjust,dz);
+                    thisamp += ampstep;
+                    ampdif   = (phraseamp[phrno]-phrasenote->amp)*rangemult;
+                    if((exit_status = setmtfparams
+                    (thisnote,thisamp,phrasenote,tsetnote,ampdif,notetime,gpsize,multiplier,dz))<0)
+                        return(exit_status);
+                } else  {
+                    if((exit_status = set_group_params
+                    (tsetnote,thisnote,gpdense,ampstep,&thisamp,&thistime,thisdur,dz))<0)
+                        return(exit_status);
+                }
+                if(texflag & MOTIF_IN_HF) {
+                    if((exit_status = generate_motifin_note_pitch
+                    (n,hsindex,starthsindex,hsnotecnt,thispitch,hfphrase[phrno],&thisnote,hs,texflag))<0)
+                        return(exit_status);
+                } else if(texflag & IS_MOTIFS) {
+                    if((exit_status = generate_motif_note_pitch(tsetnote,phrasenote,phrfirstnote,thisnote))<0)
+                        return(exit_status);
+                } else if (texflag & IS_ORNATE) {
+                    if((exit_status = generate_ornament_note_pitch
+                    (n,hs,hsi,endhsi,starthsi,&thisnote,&phrasenote,hfphrase[phrno],hfnotecnt,hsnotecnt,dz))<0)
+                        return(exit_status);
+                } else if(texflag & IS_GROUPS) {
+                    if((exit_status = generate_group_note
+                    (thisnote,tsetnote,thistime,hfrange,hfgpranglo,hs,&hsindex,gpsize,dz))<0)
+                        return(exit_status);
+                } else if(texflag & IS_DECOR) {
+                    if((exit_status = generate_decor_note
+                    (thisnote,tsetnote,thispitch,thistime,hfrange,hfgpranghi,hfgpranglo,
+                    hs,&hsindex,hsnotecnt,gprlow,gprange,gpsize,dz))<0)
+                        return(exit_status);
+                }
+                if(exit_status==CONTINUE)
+                    continue;
+            }
+            thisnote->next = nextnote;
+            if(nextnote!=(noteptr)0)
+                nextnote->last = thisnote;
+            if(texflag & IS_ORN_OR_DEC)
+                tsetnote = nextevent;
+        } else if(texflag & IS_ORN_OR_DEC)
+            tsetnote = getnextevent_to_decorate(tsetnote,&shadindex,dz);
+
+        if(texflag & IS_MTF_OR_GRP) {
+            tsetnote = nextnote;
+            shadindex++;
+        }
+    }
+    if(texflag & IS_MTF_OR_GRP) 
+        del_ghosts(shshsize,shadbits,shadow,shadowsize,tset);       /* 5 */
+
+    if(texflag & IS_DECOR) {
+        if(dz->vflag[DISCARD_ORIGLINE] && (exit_status = erase_shadow(shadowsize,shadow,tset))<0)
+            return(exit_status);
+    } else
+        free(shadbits);
+    if((texflag & MOTIF_IN_HF) || (texflag & IS_ORNATE))
+        free(fithead);
+    return arrange_notes_in_timeorder(tset);
+}
+
+/**************************** SET_HFMOTIFS *******************************
+ *
+ * initialise all parameters of input motifs to be used for MOTIFS or
+ * ORNAMENTS, including their HS indexing!!!
+ *
+ * (1)For each input motif (called a 'phrase').
+ *    phrnotecnt[n] = 0;
+ * (2)  Initialise count of number of notes to 0, maximum amplitude
+ *  of phrase to 0.0, and lowest pitch-index to hsnotecnt.
+ * (3)  Go through each note of the motif.
+ * (4)  Add up the number of notes in it.
+ * (5)  Find it's lowest pitch.
+ * (6)  Find it's loudest note (and set as phraseamp).
+ * (7)  Establish dynamic range of phrase.
+ * (9)  Ensure motif starts at zero time.
+ * (10) Generate the corresponding HS indices, in their lowest configuration.
+ * (11) Store hfindex of last note of phrase.
+ */
+
+int set_hfmotifs
+(double *hs,motifptr *phrase,int *phrnotecnt,double *phraseamp,double *phrange,noteptr *phrlastnote,
+int *endhsindex,int **hfphrase,int hsnotecnt,fitptr fithead,double **notestor,dataptr dz)
+{
+    int exit_status;
+    int n;
+    double mintime, minamp, minpitch, maxpitch;
+    noteptr thisnote, lastnote = (noteptr)0;
+    for(n=0;n<dz->tex->phrasecnt;n++) {                     /* 1 */
+        if((exit_status = arrange_notes_in_timeorder(phrase[n]))<0)
+            return(exit_status);
+        phrnotecnt[n] = 0;
+        phraseamp[n] = 0.0;                         /* 2 */
+        minamp   = DBL_MAX;
+        minpitch = DBL_MAX;
+        maxpitch = -2.0f;
+        mintime  = DBL_MAX;
+        thisnote = phrase[n]->firstnote;            /* 3 */
+        while(thisnote!=(noteptr)0) {
+            phrnotecnt[n]++;                            /* 4 */
+            if((double)thisnote->pitch<minpitch)
+                minpitch = thisnote->pitch;         /* 5 */
+            if((double)thisnote->pitch>maxpitch)
+                maxpitch = thisnote->pitch;         /* 5 */
+            if(thisnote->ntime<mintime)
+                mintime  = thisnote->ntime;         /* 5 */
+            if((double)thisnote->amp>phraseamp[n])
+                phraseamp[n] = (double)thisnote->amp;/* 6 */
+            if(thisnote->amp<minamp)
+                minamp = thisnote->amp;             /* 6 */
+            thisnote = thisnote->next;
+        }
+        if(minamp   == DBL_MAX
+        || minpitch == DBL_MAX
+        || maxpitch == -2.0f
+        || mintime  == DBL_MAX) {
+            sprintf(errstr,"Error parsing notelist: set_hfmotifs()\n");
+            return(PROGRAM_ERROR);
+        }
+        thisnote = phrase[n]->firstnote;
+        phrange[n] = phraseamp[n] - (double)minamp; /* 7 */
+        while(thisnote!=(noteptr)0) {
+            thisnote->ntime = (float)(thisnote->ntime - mintime);               /* 9 */
+            lastnote = thisnote;
+            thisnote = thisnote->next;
+        }   
+        if((phrlastnote[n] = lastnote)==(noteptr)0) {
+            sprintf(errstr,"Encountered an empty motif: set_hfmotifs()\n");
+            return(PROGRAM_ERROR);
+        }
+        if((exit_status = gethfphrase(hs,notestor,n,minpitch,maxpitch,hfphrase,hsnotecnt,phrnotecnt,phrase,fithead))<0) /* 10 */
+            return(exit_status);
+        endhsindex[n]  = *(hfphrase[n]+phrnotecnt[n]-1);            /* 11 */
+    }
+    return(FINISHED);
+}
+
+/*********************** GETHFPHRASE *********************************
+ *
+ * Get the hfphrase best corresponding to the input motif.
+ *
+ * (0)  Create storage space to store HS-indices of phrase.
+ * (1)  HIpitch of phrase higher than top of HS
+ *  AND LOpitch of phrase lower than bottom of HS.
+ *  ..Shrink the motif to size of HS, and establish hfphrase.
+ * (2)  HIpitch of phrase higher than top of HS
+ *  BUT LOpitch within HS range.
+ *  .. transpose phraselimits down onto bottom pitch of HS.
+ * (a)  If HIpitch of phrase STILL higher than top of HS
+ *  ..Shrink the motif to size of HS, and establish hfphrase.
+ * (3)  LOpitch of phrase lower than bottom of HS
+ *  BUT HIpitch within HS range.
+ *  .. transpose phraselimits up onto bottom pitch of HS.
+ * (a)  If HIpitch of phrase is NOW higher than top of HS
+ *  ..Shrink the motif to size of HS, and establish hfphrase.
+ * (4)  Phrase lies with the limits of HS.
+ *  .. transpose phraselimits down onto bottom pitch of HS.
+ * (5)  Find appropriate hfphrase.
+ */
+
+int gethfphrase
+(double *hs,double **notestor,int z,double lopitch,double hipitch,
+int **hfphrase,int hsnotecnt,int *phrnotecnt,motifptr *phrase,fitptr fithead)
+{
+    double origlo = lopitch, hstop = hs[hsnotecnt-1], hsbot = hs[0];
+    double stepdown, stepup;
+    if((hfphrase[z] = (int *)malloc(phrnotecnt[z] * sizeof(int)))==NULL) {  /* 0 */
+        sprintf(errstr,"INSUFFICIENT MEMORY for harmonic field phrase array.\n");
+        return(MEMORY_ERROR);
+    }
+    if(hipitch>=hstop) {    
+        if(lopitch<=hsbot)              /* 1 */
+            return shrink_to_hs(z,hsnotecnt,hipitch,lopitch,hstop,hsbot,hs,hfphrase[z],phrase,phrnotecnt);
+        else  {
+            stepdown = lopitch - hsbot;         /* 2 */
+            hipitch -= stepdown;
+            lopitch -= stepdown;
+            if(hipitch>hstop)               /* a */
+                return shrink_to_hs(z,hsnotecnt,hipitch,lopitch,hstop,hsbot,hs,hfphrase[z],phrase,phrnotecnt);
+        }
+    } else {
+        if(lopitch<=hsbot) {                /* 3 */
+            stepup  = hsbot - lopitch;
+            hipitch += stepup;
+            lopitch += stepup;
+            if(hipitch>hstop)               /*a */
+                return shrink_to_hs(z,hsnotecnt,hipitch,lopitch,hstop,hsbot,hs,hfphrase[z],phrase,phrnotecnt); 
+        } else {                    /* 4 */
+            stepdown = lopitch - hsbot;
+            hipitch -= stepdown;
+            lopitch -= stepdown;
+        }
+    }
+    return findhfphrase(z,hs,hstop,hsnotecnt,lopitch,origlo,phrase,hfphrase,phrnotecnt,fithead,notestor);   
+}                                           /* 5 */
+
+
+/************************* SHRINK_TO_HS **************************
+ *
+ * Shrink motif so it fits with HS, then find best HS fit.
+ *
+ * (1)  Establish pitch-shrinking ratio.
+ * (2)  For every note...
+ * (3)  Shrink intervals and thus move pitch to appropriate position inside
+ *  range of HS.
+ * (4)  Find index of the next lowest HS notes.
+ * (4a) If note falls outside field, set distance to note to maximum poss.
+ * (4b) Else find pitch distances of this note from original pitch.
+ * (5)  Find index of the next highest HS notes.
+ * (5a) If note falls outside field, set distance to note to maximum poss.
+ * (5b) Else find pitch distances of this note from original pitch.
+ * (6)  Select HSindex of nearest pitch and store in hfphrase.
+ * (7)  Save the lowest such index.
+ * (8)  Transpose all indices down to lowest possible values.
+ */
+
+int shrink_to_hs(int z,int hsnotecnt,double hipitch,double lopitch,double hstop,
+                double hsbot,double *hs, int *hfphrase, motifptr *phrase,int *phrnotecnt)
+{
+    noteptr thisnote = phrase[z]->firstnote;
+    double shrink ,thispitch, x, y;
+    int minindex = MAXINT, xx, yy, q, n = 0;
+    shrink = (hstop - hsbot)/(hipitch-lopitch);         /* 1 */
+    for(;;) {                           /* 2 */
+        thispitch = thisnote->pitch;    
+        thispitch = ((thispitch - lopitch) * shrink) + hsbot;   /* 3 */
+        if((xx = geths_lobnd(thispitch,hs,hsnotecnt))<0)            /* 4 */
+            x = DBL_MAX;                        /* 4a */
+        else
+            x = fabs(hs[xx] - thispitch);           /* 4b */
+        if((yy = geths_hibnd(thispitch,hsnotecnt,hs))>=hsnotecnt)       /* 5 */
+            y = DBL_MAX;                        /* 5a */
+        else
+            y = fabs(hs[yy] - thispitch);           /* 5b */
+        if(x<y)
+            q = xx;                     /* 6 */
+        else
+            q = yy;
+        *(hfphrase+n) = q;
+        if(q<minindex)
+            minindex = q;                   /* 7 */
+        if((thisnote = thisnote->next)==(noteptr)0)
+            break;
+        if(++n >= phrnotecnt[z]) {
+            sprintf(errstr,"accounting problem in shrink_to_hs()\n");
+            return(PROGRAM_ERROR);
+        }
+    }
+    for(n=0;n<phrnotecnt[z];n++)                    /* 8 */
+        *(hfphrase+n) -= minindex;
+    return(FINISHED);
+}
+
+/*********************** FINDHFPHRASE *********************************
+ *
+ * Extract the best fit onto the HS, and transpose it down to bottom
+ * of indices.
+ *
+ * (1)  Set the FIT-pointer to head of fits-list.
+ * (2)  Set up a store for the note values to be tested.
+ * (3)  Get interval of transposition to take motif to bottom of HS range.
+ * (4)  Store original note values of phrase transposed down to bottom of HS range.
+ * (5)  Find the fit-value for motif in its start position.
+ * (6)  Outer loop will transpose the phrase through a range...
+ *      (7) Set amount to transpose phrase (shift) to max.
+            Then for every note of the phrase.....
+ *          (8) Find the HSindex of the nearest note above the current note.
+ *              (If there isn't one break out completely).
+ *          (9)  If the difference in pitch between this and the current note
+ *              is smaller than the minimum shift, reset minimum shift.
+ *          (10)Then, for every note of the phrase...
+ *          (11)transpose it up by this minimum transposition.
+ *              If this takes any note of the phrase outside the range of HS
+ *              break out completely.
+ *      (12)Back in outer loop, find the fitting-value for this transposition
+ *          of the motif, which is a measure of how far its notes are from
+ *          the closest HS values.
+ * (13) Outside the outer loop, unlink the last unwanted member iof fitlist.
+ * (14) Find the best fitvalue, and return the amount by which orig motif
+ *      should be transposed to get onto this best fit.
+ * (15) Free the fit-list (retains fithead).
+ * (16) Get the appropriate HS indices.
+ */
+
+int findhfphrase
+(int z,double *hs,double hstop,int hsnotecnt,double lopitch,double origlo,
+motifptr *phrase,int **hfphrase,int *phrnotecnt,fitptr fithead,double **notestor)
+{
+    int exit_status;
+    int hsindex, OK = 1, n, got_transpose = 0;
+    noteptr thisnote = phrase[z]->firstnote;
+    fitptr thisfit = fithead;                                   /* 1 */
+    double shift, thisshift, transpose = 0.0, stepdown, *noteval;
+    if(*notestor!=NULL)
+        free(*notestor);                                        /* 2 */
+    if((noteval = *notestor = (double *)malloc(phrnotecnt[z] * sizeof(double)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY for note value array.\n");
+        return(MEMORY_ERROR);
+    }
+    stepdown = origlo - lopitch;                                /* 3 */
+    while(thisnote!=(noteptr)0) {                               
+        *noteval = (double)thisnote->pitch - stepdown;          /* 4 */
+        noteval++;
+        thisnote = thisnote->next;
+    }
+    if((exit_status = get_fit(*notestor,thisfit,lopitch,origlo,z,hsnotecnt,phrnotecnt,hs,&thisfit))<0)
+        return(exit_status);                                    /* 5 */
+    if(exit_status == CONTINUE) {
+        transpose = thisfit->last->transpose;
+        got_transpose = 1;
+        OK  = 0;
+    }
+    while(OK) {                                                 /* 6 */
+        shift = DBL_MAX;                                        /* 7 */
+        noteval = *notestor;
+        for(n=0;n<phrnotecnt[z];n++) {
+            if((hsindex = geths_above(*noteval,hs,hsnotecnt))>=hsnotecnt) { /* 8 */
+                OK = 0;
+                break;
+            }
+            if((thisshift  = hs[hsindex] - *noteval)<shift)
+                shift = thisshift;                              /* 9 */
+            noteval++;
+        }
+        if(shift==DBL_MAX) {
+            sprintf(errstr,"Error parsing phrase: findhfphrase()\n");
+            return(PROGRAM_ERROR);
+        }
+        if(!OK)
+            break;
+        noteval = *notestor;
+        for(n=0;n<phrnotecnt[z];n++) {                          /* 10 */
+            if((*noteval++  += (float)shift)>hstop) {
+                OK = 0;                                         /* 11 */
+                break;
+            }
+        }
+        lopitch += shift;
+        if((exit_status = get_fit(*notestor,thisfit,lopitch,origlo,z,hsnotecnt,phrnotecnt,hs,&thisfit))<0)      
+            return(exit_status);                                /* 12 */
+        if(exit_status == CONTINUE) {
+            transpose = thisfit->last->transpose;
+            got_transpose = 1;
+            break;
+        }
+    }
+    if((exit_status = fit_unlink(thisfit))<0)                   /* 13 */
+        return(exit_status);
+    if (!got_transpose) {
+        if((exit_status = best_fit(fithead,&transpose))<0)      /* 14 */
+            return(exit_status);
+    }
+    free_fitlist(fithead);                                      /* 15 */
+    return getmtfindeces(transpose,z,hsnotecnt,hs,phrase,phrnotecnt,hfphrase);  
+}                                                               /* 16 */
+
+/*************************** GETMTFINDECES *****************************
+ *
+ * Get the HS indices of the phrase, transposed to lowest position in HS.
+ *
+ * (0)  Point to start of storage space for the HS-indices of the phrase.
+ * (1)  Mark end of this storage space (for accounting purposes).
+ * (2)  For every note of the phrase...
+ *   (3)  Get the pitch..
+ *   (4)  Transpose the pitch by the input transposition.
+ *   (5)  Find the nearest HS set members above and below the note.
+ *   (6)  Decide which is nearest.
+ *   (7)  Assign index of nearest value to the HS-index store.
+ *   (8)  Keep a note of the smallest index.
+ *   (9)  Increment the index-store pointer.
+ * (10) Decrement all the indeces to tranpose them all to lowest values
+ *  in the hfphrase store.
+ */
+
+int getmtfindeces(double transpose,int z,int hsnotecnt,double *hs,motifptr *phrase,int *phrnotecnt,int **hfphrase)
+{
+    noteptr thisnote = phrase[z]->firstnote;
+    int *thisindex, xx, yy, minindex = MAXINT, *indexend;
+    double x, y, thispitch;
+    thisindex = hfphrase[z];                        /* 0 */
+    indexend  = hfphrase[z] + phrnotecnt[z];        /* 1 */
+    for(;;) {                                       /* 2 */
+        thispitch  = thisnote->pitch;               /* 3 */
+        thispitch += transpose;                     /* 4 */
+        xx = geths_lobnd(thispitch,hs,hsnotecnt);   /* 5 */
+        yy = geths_hibnd(thispitch,hsnotecnt,hs);
+        x = fabs(hs[xx] - thispitch);               /* 6 */
+        y = fabs(hs[yy] - thispitch);
+        if(x<y)
+            *thisindex = xx;                        /* 7 */
+        else
+            *thisindex = yy;
+        if(*thisindex<minindex)
+            minindex = *thisindex;                  /* 8 */
+        if((thisnote = thisnote->next)==(noteptr)0)
+            break;
+        if(++thisindex>=indexend) {                 /* 9 */
+            sprintf(errstr,"TEXTURE: Problem in getmtfindices()\n");
+            return(PROGRAM_ERROR);
+        }
+    }
+    for(thisindex = hfphrase[z];thisindex<indexend;thisindex++)
+        *thisindex -= minindex;                     /* 10 */
+    return(FINISHED);
+}
+
+/****************************** GET_FIT ************************************
+ *
+ * Create list of fit_values for motif over HS.
+ * 
+ * (1)  For every note of the phrase.
+ * (3)  Find the index of the next lowest HS note. If there is not one
+ *  something is wrong!
+ * (4)  Find the index of the next highest HS note. If there is not one
+ *  something is wrong!
+ * (5)  Find the pitch distance between these notes on the original pitch.
+ * (6)  Add the minimum of these two, to a running sum of such differences.
+ * (7)  Store the fit-value and the associated ttansposition, creating a
+ *  new storage space in the fit list, in the process.
+ */
+
+int get_fit(double *notestor,fitptr thisfit,double lopitch,double origlo,int z,
+            int hsnotecnt,int *phrnotecnt,double *hs,fitptr *newfit)
+{
+    int exit_status;
+    double x, y, sum = 0.0, *noteval = notestor;
+    int xx, yy, n;  
+    for(n=0;n<phrnotecnt[z];n++) {                              /* 1 */
+        if((xx = geths_lobnd(*noteval,hs,hsnotecnt))<0) {       /* 3 */
+            sprintf(errstr,"Problem 1 in get_fit()\n");
+            return(PROGRAM_ERROR);
+        }   
+        if((yy=geths_hibnd(*noteval,hsnotecnt,hs))>=hsnotecnt) {/* 4 */
+            sprintf(errstr,"Problem 2 in get_fit()\n");
+            return(PROGRAM_ERROR);
+        }
+        x = fabs(hs[xx] - *noteval);                            /* 5 */
+        y = fabs(hs[yy] - *noteval);
+        sum += min(x,y);                                        /* 6 */
+        noteval++;
+    }
+    if((exit_status = put_fit(thisfit,lopitch - origlo,sum,newfit))<0)
+        return(exit_status);
+    if(flteq(sum,0.0))
+        return(CONTINUE);
+    return(FINISHED);                                           /* 7 */
+}
+
+/************************* PUT_FIT *****************************
+ *
+ * Put fit value in motif-fits list.
+ */
+
+int put_fit(fitptr thisfit,double transval,double fitval,fitptr *newfit)
+{
+    int exit_status;
+    thisfit->transpose = (float)transval;
+    thisfit->fit       = (float)fitval;
+    if((exit_status = new_fit(thisfit,newfit))<0)
+        return(exit_status);
+    return(FINISHED);
+}
+
+/************************* BEST_FIT *****************************
+ *
+ * Find the appropriate transposition to move the current motif
+ * to a pitch where it has the best fit with the HS.
+ *
+ * (1)  From all available transpositions, find best (lowest) fit value.
+ * (2)  From all available transpositions, find all those which have
+ *  this bestfit value, and select the one which involves the
+ *  least transposition.
+ * (3)  Once the transpositions begin to increase, we are moving away from
+ *  the smallest transposition, so quit.
+ * (4)  Return the best transposition. 
+ */
+
+int best_fit(fitptr fithead,double *transpose)
+{
+    fitptr thisfit = fithead;
+    double bestfit = DBL_MAX, besttranspose = DBL_MAX;
+    double abstranspose = DBL_MAX, thistranspose;
+    while(thisfit!=(fitptr)0) {             /* 1 */
+        if(thisfit->fit<(float)bestfit)
+            bestfit = (double)thisfit->fit;
+        thisfit = thisfit->next;
+    }
+    thisfit = fithead;
+    while(thisfit!=(fitptr)0) {             /* 2 */
+        thistranspose = fabs((double)thisfit->transpose);
+        if(flteq((double)thisfit->fit,bestfit)) {
+            if(thistranspose<abstranspose) {
+                besttranspose = (double)thisfit->transpose;
+                abstranspose = fabs(besttranspose);
+            }
+        }
+        if(thistranspose>abstranspose+FLTERR)
+            break;                  /* 3 */
+        thisfit = thisfit->next;
+    }
+    if(besttranspose==DBL_MAX) {
+        sprintf(errstr,"Problem in best_fit()\n");
+        return(PROGRAM_ERROR);
+    }
+    *transpose = besttranspose;
+    return(FINISHED);               /* 4 */
+}
+
+/************************* INIT_FITS() *****************************
+ *
+ * Set up head item of a list of motif-fits.
+ */
+
+int init_fits(fitptr *thisfit)
+{
+    if((*thisfit = (fitptr)malloc(sizeof (struct ffit)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY for fitting array.\n");
+        return(MEMORY_ERROR);
+    }
+    (*thisfit)->next  = (fitptr)0;
+    (*thisfit)->last  = (fitptr)0;
+    return(FINISHED);
+}
+
+/************************* NEW_FIT() *****************************
+ *
+ * Set up next fit in a list of motif-fits.
+ */
+
+int new_fit(fitptr thisfit,fitptr *newfit)
+{
+    if((*newfit = (fitptr)malloc(sizeof (struct ffit)))==NULL) {
+        sprintf(errstr,"new_fit()\n");
+        return(PROGRAM_ERROR);
+    }
+    thisfit->next   = *newfit;
+    (*newfit)->last = thisfit;
+    (*newfit)->next = (fitptr)0;
+    return(FINISHED);
+}
+
+/********************** FIT_UNLINK() ******************************
+ *
+ * Deletes empty address space at end of fitlist.
+ */
+
+int fit_unlink(fitptr thisfit)
+{
+    if(thisfit->last==(fitptr)0) {
+        sprintf(errstr,"Problem in fit_unlink()\n");
+        return(PROGRAM_ERROR);
+    }
+    thisfit = thisfit->last;
+    free(thisfit->next);
+    thisfit->next = (fitptr)0;
+    return(FINISHED);
+}
+
+/********************** FREE_FITLIST() ******************************
+ *
+ * Deletes fitlist, retaining head.
+ */
+
+void free_fitlist(fitptr fithead)
+{
+    fitptr thisfit;
+    if((thisfit = fithead->next)==(fitptr)0)
+        return;
+    while(thisfit->next!=(fitptr)0) {
+        thisfit = thisfit->next;
+        free(thisfit->last);
+    }
+    free(thisfit);
+}
+
+/**************************** HFADJUST *********************************
+ *
+ * Pitch outside HS range. Adjust it.
+ *
+ * (1)  If this is a HS, there's nothing we can do about it. Return -1.0
+ *  which will cause note to be deleted in calling environment.
+ * (2)  If it's an HF however....
+ *  Set newpitch at appropriate interval from original pitch.
+ * (3)  If it's now above the HS
+ * (4)  transpose it down by octaves until it is in the HS.
+ * (5)  If still not in HS, mark for deletion.
+ * (6)  If it's BELOW the HS.
+ * (7)  transpose it up by octaves until it is in the HS.
+ * (8)  If still not in HS, mark for deletion.
+ * (9)  Return new pitch.
+ */
+
+double hfadjust(double thispitch,double *hs,int x1,int x2,int texflag,int hsnotecnt)
+{
+    double newpitch;
+    if(texflag & IS_HS)
+        return(-1.0);                               /* 1 */
+    else {                                      
+        newpitch = thispitch+hs[x1]-hs[x2];         /* 2 */
+        if(newpitch > hs[hsnotecnt-1]) {            /* 3 */
+            while(newpitch>hs[hsnotecnt-1])
+                newpitch -= SEMITONES_PER_OCTAVE;   /* 4 */
+            if(newpitch<hs[0])                      /* 5 */
+                return(-1.0);
+        } else {
+            if(newpitch<hs[0]) {                    /* 6 */
+                while(newpitch <hs[0])
+                    newpitch += SEMITONES_PER_OCTAVE;/* 7 */
+                if(newpitch>hs[hsnotecnt-1])
+                    return(-1.0);                   /* 8 */
+            }
+        }
+    }
+    return(newpitch);                               /* 9 */
+}
+
+/**************************** CONVERT_PITCH_TO_NEAREST_HSET_PITCH *********************************
+ *
+ * Convert pitch value to nearest HS value.
+ *
+ * ignores the problem of note repetitions in the tset.
+ * Note repetitions were only important where the tset notes were being
+ * forced onto an HS. Here the HS values are being extracted so the notes
+ * can be ornamented. The pitch values of the tset are NOT themselves altered.
+ */
+
+int convert_pitch_to_nearest_hset_pitch(double thispitch,double *hs,int hsnotecnt)
+{
+    int n, m;
+    if(thispitch<hs[0]) {
+        if(hs[0] - thispitch > hs[1] - hs[0])
+            return(-1);
+        else
+            return(0);
+    }
+    n = 1;
+    m = n-1;
+    while(n<hsnotecnt) {
+        if(flteq(hs[n],thispitch))
+            return(n);
+        if(hs[n]>thispitch) {
+            if(hs[n] - thispitch > thispitch - hs[m])
+                return(m);
+            else
+                return(n);
+        }
+        n++;
+        m++;
+    }
+    if(hsnotecnt>1 && (thispitch - hs[hsnotecnt-1] > hs[hsnotecnt-1] - hs[hsnotecnt-2]))
+        return(-1);
+    return(hsnotecnt-1);
+}
+
+/**************************** HFADJ2 *********************************
+ *
+ * HFindex outside HS range. Adjust it.
+ * Applies only to HF (i.e. an HS containing octave transpositions)
+ * not to HS.
+ */
+
+int hfadj2(int hsi,int hfnotecnt,int hsnotecnt)
+{
+    if(hsi<0) {
+        while(hsi<0)
+            hsi += hfnotecnt;
+    } else {
+        while(hsi>=hsnotecnt)
+            hsi -= hfnotecnt;
+    }
+    if(hsi<0 || hsi>=hsnotecnt)
+        return(-1);
+    return(hsi);
+}
+
+/**************************** SETUP_HFIELD *********************************/
+
+int setup_hfield(noteptr thisnote,double **hs,int *hsnotecnt,double **hf,int *hfnotecnt,int texflag)
+{
+    int exit_status;
+    if(texflag & IS_HS) {
+        if((exit_status = geths(thisnote,hs,hsnotecnt))<0)
+            return(exit_status);
+    } else {
+        if((exit_status = gethf(thisnote,hf,hfnotecnt))<0)                  /* 2 */
+            return(exit_status);
+        if((exit_status = gen_hs(hf,hs,hsnotecnt,*hfnotecnt))<0)
+            return(exit_status);
+    }
+    return(FINISHED);
+}
+
+/**************************** SETUP_FIRST_HFIELD *********************************/
+
+int setup_first_hfield(noteptr thisnote,double **hs,int *hsnotecnt,double **hf,int *hfnotecnt,int texflag)
+{
+    int exit_status;
+    if(texflag & IS_HS) {
+        if((exit_status = get_first_hs(thisnote,hs,hsnotecnt))<0)
+            return(exit_status);
+    } else {
+        if((exit_status = get_first_hf(thisnote,hf,hfnotecnt))<0)                   /* 2 */
+            return(exit_status);
+        if((exit_status = gen_hs(hf,hs,hsnotecnt,*hfnotecnt))<0)
+            return(exit_status);
+    }
+    return(FINISHED);
+}
+
+/**************************** GET_NEXT_HFIELD *********************************/
+
+int get_next_hfield(double **hf,double **hs,double inputtime,
+int *hf_cnt,int *hs_cnt,int *hfnotecnt,noteptr *thishfnote,double *thishftime,double *nexthftime,int hfdatacnt,
+int *hsnotecnt,noteptr *thishsnote,double *thishstime,double *nexthstime,double *hft,int texflag)
+{
+    if(texflag & IS_HS)
+        return getnexths(hs,inputtime,hs_cnt,hsnotecnt,thishsnote,thishstime,nexthstime,hfdatacnt,hft);
+    else
+        return getnexthf(hf,hs,hsnotecnt,inputtime,hf_cnt,hfnotecnt,thishfnote,thishftime,nexthftime,hfdatacnt,hft);
+}
+
+/**************************** SETUP_MOTIF_NOTE *********************************
+ *
+ * (1)  If the program is given a pitchrange OUTSIDE the bounds of the
+ *      specified HF or HS, do_ev_hfpch() returns a -ve value. In this
+ *      case, the associated tset note is marked for DELETION by setting
+ *      the bitflag associated with the shadow (address) of the tset note.
+ *      It will be deleted at the very end, by del_ghosts().
+ */
+
+int setup_motif_note
+(double thisamp,int thisinstr,double thisdur,noteptr tsetnote,noteptr phrasenote,
+double *thispitch,double thistime,int *hsindex,int hsnotecnt,double *hs,
+double *pptop,double *ppbot,int *shadindex,char *shadbits,double multiplier,dataptr dz)
+{
+    int exit_status;
+    tsetnote->amp = (float)thisamp;
+    tsetnote->instr = (unsigned char)thisinstr;
+    if(dz->vflag[DONT_KEEP_MTFDUR])
+        tsetnote->dur = (float)thisdur;
+    else
+        tsetnote->dur = (float)(phrasenote->dur * multiplier);
+    if(flteq((double)tsetnote->dur,0.0)) {
+        sprintf(errstr,"setup_motif_note(): Zero duration\n");
+        return(PROGRAM_ERROR);
+    }
+    if((exit_status = do_ev_hfpch(thistime,hsindex,thispitch,hsnotecnt,hs,pptop,ppbot,dz))<0) 
+        return(exit_status);
+    if(exit_status==CONTINUE) {
+        set_shadbit(*shadindex,shadbits);    /* 1 */
+        tsetnote = tsetnote->next;              
+        (*shadindex)++;
+        return(CONTINUE);
+    }
+    tsetnote->pitch = (float)(*thispitch);
+    return(FINISHED);
+}
+
+/**************************** SETUP_GROUP_NOTE *********************************/
+
+int setup_group_note
+(double thisamp,int thisinstr,double thisdur,noteptr tsetnote,
+double *thispitch,double thistime,int *hsindex,int hsnotecnt,double *hs,
+double *pptop,double *ppbot,int *shadindex,char *shadbits,dataptr dz)
+{
+    int exit_status;
+    tsetnote->amp = (float)thisamp;
+    tsetnote->instr = (unsigned char)thisinstr;
+    tsetnote->dur = (float)thisdur;
+    if((exit_status = do_ev_hfpch(thistime,hsindex,thispitch,hsnotecnt,hs,pptop,ppbot,dz))<0)   /* 1 */
+        return(exit_status);
+    if(exit_status==CONTINUE) {
+        set_shadbit(*shadindex,shadbits);
+        tsetnote = tsetnote->next;              
+        (*shadindex)++;
+        return(CONTINUE);
+    }
+    tsetnote->pitch = (float)(*thispitch);
+    return(FINISHED);
+}
+
+/**************************** SETUP_ORNAMENTATION *********************************/
+
+int setup_ornamentation
+(int *starthsi,int *endhsi,noteptr *nextevent,noteptr tsetnote,
+noteptr *phrasenote,int *shadindex,int *endhsindex,int *hfphrase,int phrno,dataptr dz)
+{
+    *starthsi  =  *hfphrase;            
+    *endhsi    =  endhsindex[phrno];
+    *nextevent = getnextevent_to_decorate(tsetnote,shadindex,dz);
+    if(!dz->vflag[IS_PRE])
+        *phrasenote = (*phrasenote)->next;
+    return(FINISHED);
+}
+
+/**************************** GENERATE_MOTIF_NOTE_PITCH *********************************/
+
+int generate_motifin_note_pitch(int n,int hsindex,int starthsindex,int hsnotecnt,double thispitch,
+                                int *hfphrase,noteptr *thisnote,double *hs,int texflag)
+{
+    int notehsindex, thishsindex;
+    double newpitch;
+    notehsindex = *(hfphrase+n+1);
+    thishsindex = hsindex + notehsindex - starthsindex;
+    if(thishsindex<0 || thishsindex>=hsnotecnt) {
+        if((newpitch = hfadjust(thispitch,hs,notehsindex,starthsindex,texflag,hsnotecnt))<0.0) {
+            *thisnote = (*thisnote)->last;
+            free((*thisnote)->next);
+            return(CONTINUE);
+        } else
+            (*thisnote)->pitch = (float)newpitch;
+    } else
+        (*thisnote)->pitch=(float)hs[thishsindex];
+    return(FINISHED);
+}
+
+/**************************** GENERATE_MOTIF_NOTE_PITCH *********************************/
+
+int generate_motif_note_pitch(noteptr tsetnote,noteptr phrasenote,double phrfirstnote,noteptr thisnote)
+{
+    thisnote->pitch=(float)(tsetnote->pitch + phrasenote->pitch - phrfirstnote);
+    thisnote->pitch=(float)octadjust((double)thisnote->pitch);
+    return(FINISHED);
+}
+
+/**************************** GENERATE_ORNAMENT_NOTE_PITCH *********************************
+ *
+ * hsi = harmonic-set index.
+ */
+ 
+int generate_ornament_note_pitch
+(int n,double *hs,int hsi, int endhsi,int starthsi,noteptr *thisnote,
+noteptr *phrasenote,int *hfphrase,int hfnotecnt,int hsnotecnt,dataptr dz)
+{
+    unsigned int texflag = dz->tex->txflag;
+    int thishsi, refhsi, notehsi;       
+
+    if(dz->vflag[IS_PRE]) {
+        refhsi = endhsi;
+        notehsi = *(hfphrase+n);
+    } else {
+        refhsi = starthsi;
+        notehsi = *(hfphrase+n+1);
+    }
+    thishsi = hsi + notehsi - refhsi;
+    *phrasenote = (*phrasenote)->next;
+    if(thishsi<0 || thishsi>=hsnotecnt) {
+        if((texflag & IS_HS) || (thishsi=hfadj2(thishsi,hfnotecnt,hsnotecnt))<0) {
+            *thisnote = (*thisnote)->last;      
+            free((*thisnote)->next);
+            return(CONTINUE);
+        }
+    }
+    (*thisnote)->pitch=(float)hs[thishsi];  
+    return(FINISHED);
+}
+
+/********************** DO_EV_HFPCH *******************************
+ *
+ * Generate pitch of event (note group etc.) within HS.
+ *
+ * (2)  If getp_as_index() returns -1 , this means
+ *  that the pitch range specified is outside the HS, so a value of 
+ *  -1.0 is returned to calling environment and tset note is DELETED!!
+ */
+
+int do_ev_hfpch(double thistime,int *hsindex,double *val,int hsnotecnt,double *hs,double *pptop,double *ppbot,dataptr dz)
+{
+    int exit_status;
+    if((exit_status = getp_as_index(thistime,hsindex,hsnotecnt,hs,pptop,ppbot,dz))<0)
+        return(exit_status);
+    if(*hsindex==-1)                /* a */
+        return(CONTINUE);           /* 2 */
+    *val = hs[*hsindex];
+    return(FINISHED);
+}
+
+/****************************** GETP_AS_INDEX *********************************
+ *
+ * Get integer value of a hf-pitch index, using pitch either from table,
+ * or fixed value.
+ *
+ * (1)  Read values of pitch-range limits from tables (or fixed vals).
+ * (2)  If either of pitch values is negative, if it's from a table,
+ *  reject it....
+ * (3)  But otherwise it can be regarded as a flag. Return -1 causing
+ *  the INPUT pitch to be converted to a HS pitch and returned.
+ * (4)  Check that range is not inverted.
+ * (5)  Get the note in HS which is >  upper pitch boundary. If all HS notes
+ *  are above this (function returns 0) return -1.
+ *  If all HS notes are BELOW this pitch, function returns hsnotecnt,
+ *  wehich forces upper limit of HSindex generated by doperm() to be
+ *  hsnotecnt-1, the highest pitch in the HS.
+ * (6)  Get the note in HS which is >= lower pitch boundary. If there
+ *  is no such note (function returns hsnotecnt) return -1.
+ * (7)  Return a weighted scattered value of hf-index, within the
+ *  defined range.
+ */
+
+int getp_as_index(double thistime,int *val,int hsnotecnt,double *hs,double *pptop,double *ppbot,dataptr dz)
+{
+    int exit_status;
+    int  a, b;
+    double range;
+    if(dz->brk[TEXTURE_MAXPICH]) {                      /* 1 */
+        if((exit_status = read_value_from_brktable(thistime,TEXTURE_MAXPICH,dz))<0)
+            return(exit_status);
+    }
+    if(dz->brk[TEXTURE_MINPICH]) {
+        if((exit_status = read_value_from_brktable(thistime,TEXTURE_MINPICH,dz))<0)
+            return(exit_status);
+    }
+    *pptop = dz->param[TEXTURE_MAXPICH];
+    *ppbot = dz->param[TEXTURE_MINPICH];
+    if((range = dz->param[TEXTURE_MAXPICH] - dz->param[TEXTURE_MINPICH])<0.0)       /* 4 */
+        swap (&dz->param[TEXTURE_MAXPICH],&dz->param[TEXTURE_MINPICH]);
+    if((a = geths_above(dz->param[TEXTURE_MAXPICH],hs,hsnotecnt))==0) {             /* 5 */
+        *val = -1;
+        return(FINISHED);
+    }
+    if((b = geths_hibnd(dz->param[TEXTURE_MINPICH],hsnotecnt,hs))>=hsnotecnt) {     /* 6 */
+        *val = -1;
+        return(FINISHED);
+    }
+    if((exit_status = hfscat(a-b,b,PM_PITCH,&a,dz))<0)  /* 7 */
+        return(exit_status);
+    if( a < 0 || a >= hsnotecnt) {          /* 7 */
+        sprintf(errstr,"TEXTURE: getp_as_index(): TW's logic of index generation wrong\n");
+        return(DATA_ERROR);
+    }
+    *val = a;
+    return(FINISHED);
+}
+
+/**************************** INIT_SHADBITS ****************************
+ *
+ * Set up, and initialise to zero, a bitflag with one bit for each shadow
+ * (tset address).
+ */
+
+int init_shadbits(int shadowsize,int *shshsize,char **shadbits)
+{
+    int n = shadowsize;
+    *shshsize = 1;
+    while((n -= CHARBITSIZE)>0)
+        (*shshsize)++;
+    if((*shadbits = (char *)malloc((size_t)(*shshsize)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY for shadwoing array.\n");
+        return(MEMORY_ERROR);
+    }
+    for(n=0; n<(*shshsize); n++)
+        (*shadbits)[n] = 0;
+    return(FINISHED);
+}
+
+/****************************** GETHS ***********************************
+ *
+ * Extract HS from input data.
+ */
+
+int geths(noteptr thisnote,double **hs,int *hsnotecnt)
+{
+    int exit_status;
+    int size = BIGARRAY;
+    if((*hs = (double *)malloc(BIGARRAY * sizeof(double)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY for harmonic set array.\n");
+        return(MEMORY_ERROR);
+    }
+    while(thisnote!=(noteptr)0) {
+        if((exit_status = gethsnote(thisnote->pitch,*hs,hsnotecnt))<0)
+            return(exit_status);
+        if(*hsnotecnt >= BIGARRAY) {
+            size += BIGARRAY;
+            if((*hs=(double *)realloc((char *)(*hs),size * sizeof(double)))==NULL){
+                sprintf(errstr,"INSUFFICIENT MEMORY to reallocate harmonic set array.\n");
+                return(MEMORY_ERROR);
+            }   
+        }
+        thisnote = thisnote->next;
+    }
+    if((*hs=(double *)realloc((char *)(*hs),*hsnotecnt*sizeof(double)))==NULL){
+        sprintf(errstr,"INSUFFICIENT MEMORY to reallocate harmonic set array.\n");
+        return(MEMORY_ERROR);
+    }
+    upsort(*hs,*hsnotecnt);
+    return(FINISHED);
+}
+    
+/****************************** GETHF ***********************************
+ *
+ * Extract HF from input data.
+ */
+
+int gethf(noteptr thisnote,double **hf,int *hfnotecnt)
+{
+    int exit_status;
+    int size = BIGARRAY;
+    if((*hf = (double *)malloc(size * sizeof(double)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY for harmonic field array.\n");
+        return(MEMORY_ERROR);
+    }
+    while(thisnote!=(noteptr)0) {
+        if((exit_status = gethfnote(thisnote->pitch,*hf,hfnotecnt))<0)
+            return(exit_status);
+        if(*hfnotecnt >= size) {
+            size += BIGARRAY;
+            if((*hf = (double *)realloc((char *)(*hf),size * sizeof(double)))==NULL){
+                sprintf(errstr,"INSUFFICIENT MEMORY to reallocate harmonic field array.\n");
+                return(MEMORY_ERROR);
+            }   
+        }
+        thisnote = thisnote->next;
+    }
+    if((*hf=(double *)realloc((char *)(*hf),*hfnotecnt * sizeof(double)))==NULL){
+        sprintf(errstr,"INSUFFICIENT MEMORY to reallocate harmonic field array.\n");
+        return(MEMORY_ERROR);
+    }
+    upsort(*hf,*hfnotecnt);
+    return(FINISHED);
+}
+    
+/****************************** GEN_HS ***********************************
+ *
+ * Generate HS from a HF.
+ *
+ * NB This function assumes thas HF is ordered in ascending pitch order.
+ *
+ * (1)  Eliminate octave dupliates in hf.
+ * (2)  Initialise the HS count to zero.
+ * (3)  Start in the lowest octave.
+ * (4)  Go round loop generating HS, until we're out of (MIDI) range.
+ * (5)  Each time round loop, point to start of HF.
+ * (6)  And for all HF members, put them in HS + a (loop) number of 8ves,
+ *  counting the HS as we go.
+ * (7)  Once the pitch of any note exceeds MIDI upper limit (MIDITOP), break
+ *  from inner and (OK=0) outer loops.
+ * (8)  Each time round outer loop, increment octave.
+ * (9)  Reallocate the HS to the store 'hs'
+ */
+
+int gen_hs(double **hf,double **hs, int *hsnotecnt, int hfnotecnt)
+{
+    int n, m, k, thisoct, OK = 1;
+    int size = BIGARRAY;
+    double nextpitch;
+    double *thishf;
+    if((*hs)!=(double *)0)
+        free(*hs);
+    if((*hs = (double *)malloc(size * sizeof(double)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY for harmonic set array.\n");
+        return(MEMORY_ERROR);
+    }
+    for(n=0;n<hfnotecnt-1;n++) {        /* 1 */
+        for(m=n+1;m<hfnotecnt;m++) {
+            if(octeq((*hf)[n],(*hf)[m])) {
+                k = m + 1;
+                while(k < hfnotecnt) {
+                    (*hf)[k-1] = (*hf)[k];
+                    k++;
+                }
+                hfnotecnt--;
+                m--;
+            }
+        }
+    }
+    *hsnotecnt = 0;                         /* 2 */
+    thisoct = 0;                        /* 3 */
+    while(OK) {                         /* 4 */
+        thishf = *hf;                       /* 5 */
+        for(n=0;n<hfnotecnt;n++) {                  /* 6 */
+            if((nextpitch = (*thishf++)+((double)thisoct*SEMITONES_PER_OCTAVE))<=MIDITOP) {
+                (*hs)[(*hsnotecnt)++] = nextpitch;
+                if(*hsnotecnt>=size) {
+                    size += BIGARRAY;
+                    if((*hs =(double *)realloc((char *)(*hs),size * sizeof(double)))==NULL) {
+                        sprintf(errstr,"INSUFFICIENT MEMORY to reallocate harmonic set array.\n");
+                        return(MEMORY_ERROR);
+                    }   
+                }
+            } else {
+                OK = 0;                     /* 7 */
+                break;
+            }
+        }
+        thisoct++;                      /* 8 */
+    }
+    if((*hs=(double *)realloc((char *)(*hs),*hsnotecnt * sizeof(double)))==NULL){
+        sprintf(errstr,"INSUFFICIENT MEMORY to reallocate harmonic set array.\n");
+        return(MEMORY_ERROR);
+    }
+    return(FINISHED);
+}
+    
+/**************************** CHEKREPEAT *********************************
+ *
+ * Flag if there is a repeated note in the source data.
+ */
+
+int chekrepeat(noteptr thisnote,double lastpitch)
+{ 
+    if(flteq((double)thisnote->pitch,lastpitch))
+        return(TRUE);
+    return(FALSE);
+}
+
+/****************************** GETNEXTHF ***********************************
+ *
+ * Get the harmonic field pertaining to this time, + 'hfnotecnt'.
+ *
+ * NB 2: THIS FUNCTION ASSUMES IN WILL BE ACCESSED IN TIME-INCREASING ORDER.
+ *
+ * (1)  Current time preset to zero.
+ * (2)  Nexttime to time of next hf in hf_data_motif.
+ * (3)  Static pointer points into current place in hf_data_motif.
+ * (3a) If noteptr points to zero w'ere
+    EITHER  we're at end of notelist: therefore no more HF data,
+        hence retain existing data.
+    OR  we have not initialised the noteptr, which should happen
+        on first call to this function, BUT in this case the
+        hfnotecnt will be zero as we have not yet created an HF.
+        In this case, error, exit.
+ * (4)  If time of function access still less than time of entry of next
+ *  harmonic field, do nothing (i.e. stay with current hf returning
+ *  current hfnotecnt).
+ * (5)  If time of function access is after time of next harmonic field
+ *  advance down hfs, until TOFA is before next hf (NB last time in
+ *  the hft[] is AFTER end of texture duration).
+ * (6)  Establish temporary storage space to read a new hf, and set the
+ *  hf pointer 'thishf' to point to it.
+ * (7)  Walk through the input notes until we get to notes corresponding
+ *  to time of the hf we want.
+ * (8)  Store the harmonic field in the temporary array.
+ * (9)  Free any existing hf.
+ * (10) Reallocate the new hf to the array hf[], and set the hf pointer
+ *  'thishf' to point at it.
+ * (11) Generate the associated HS !!!
+ */
+
+int getnexthf
+(double **hf,double **hs, int *hsnotecnt,double inputtime,int *hf_cnt,int *hfnotecnt,
+ noteptr *thishfnote,double *thishftime,double *nexthftime,int hfdatacnt,double *hft)
+{
+    int exit_status;
+    int size = BIGARRAY;
+    if(*thishfnote==(noteptr)0) {                   /* 3a */
+        if(*hfnotecnt==0) {
+            sprintf(errstr,"INSUFFICIENT MEMORY for hfield notecount array.\n");
+            return(PROGRAM_ERROR);
+        }
+        return(TRUE);
+    }
+    if(inputtime<*nexthftime)                   /* 4 */
+        return(FALSE);
+    while(*nexthftime<=inputtime) {             /* 5 */
+        if(*hf_cnt>=hfdatacnt) {
+            sprintf(errstr,"INSUFFICIENT MEMORY for hfield count array.\n");
+            return(PROGRAM_ERROR);
+        }
+        *thishftime = *nexthftime;
+        *nexthftime = hft[*hf_cnt];
+        (*hf_cnt)++;
+    }
+    if(*hf!=(double *)0)                        /* 9 */
+        free(*hf);                      
+    if((*hf = (double *)malloc(size * sizeof(double)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY for hfield array.\n");
+        return(MEMORY_ERROR);
+    }
+    while(!flteq((double)(*thishfnote)->ntime,*thishftime)) {       /* 7 */
+        if((*thishfnote = (*thishfnote)->next)==(noteptr)0) {
+            sprintf(errstr,"TEXTURE: Search problem in getnexthf()\n");
+            return(PROGRAM_ERROR);
+        }
+    }
+    *hfnotecnt = 0;
+    while(flteq((double)(*thishfnote)->ntime,*thishftime)) {        /* 8 */
+        if((exit_status = gethfnote((*thishfnote)->pitch,*hf,hfnotecnt))<0)
+            return(exit_status);
+        if(*hfnotecnt >= size) {
+            size += BIGARRAY;
+            if((*hf = (double *)realloc((char *)(*hf),size * sizeof(double)))==NULL) {
+                sprintf(errstr,"TEXTURE: realloc failed in getnexthf()\n");
+                return(PROGRAM_ERROR);
+            }   
+        }
+        if((*thishfnote = (*thishfnote)->next)==(noteptr)0)
+            break;
+    }
+    if((*hf=(double *)realloc((char *)(*hf),*hfnotecnt * sizeof(double)))==NULL){
+        sprintf(errstr,"TEXTURE: getnexthf(): realloc() failed\n"); /* 10 */
+        return(PROGRAM_ERROR);
+    }
+    upsort(*hf,*hfnotecnt);
+    if((exit_status = gen_hs(hf,hs,hsnotecnt,*hfnotecnt))<0)  /* 11 */
+        return(exit_status);
+    return(TRUE);
+}
+
+/****************************** GETNEXTHS ***********************************
+ *
+ * Get the harmonic set pertaining to this time.
+ *
+ * NB 2: THIS FUNCTION ASSUMES IT WILL BE ACCESSED IN TIME-INCREASING ORDER.
+ *
+ * (3)  Static pointer points into current place in hf_data_motif.
+ * (3a) If noteptr points to zero w'ere
+    EITHER  we're at end of notelist: therefore no more HF data,
+        hence retain existing data.
+    OR  we have not initialised the noteptr, which should happen
+        on first call to this function, BUT in this case the
+        hsnotecnt will be zero as we have not yet created an HS.
+        In this case, error, exit.
+ * (4)  If time of function access still less than time of entry of next
+ *  harmonic set, do nothing (i.e. stay with current hs returning 
+ *  current harmonic set cnt hsnotecnt).
+ * (5)  If time of function access is after time of next harmonic set
+ *  advance down HSs, until TOFA is before next hs (NB last time in
+ *  the hft[] is AFTER end of texture duration).
+ * (6)  Establish temporary storage space to read a new hs, and set the
+ *  hs pointer 'thishs' to point to it.
+ * (7)  Walk through the input notes until we get to notes corresponding
+ *  to time of the hs we want.
+ * (8)  Store the harmonic set in the temporary array.
+ * (9)  Free any existing hs.
+ * (10) Reallocate the new hs to the array hs[], and set the hs pointer
+ *  'thishs' to point at it.
+ */
+
+int getnexths
+(double **hs,double inputtime,int *hs_cnt,int *hsnotecnt,noteptr *thishsnote,
+double *thishstime,double *nexthstime,int hfdatacnt,double *hft)
+{
+    int exit_status;
+    int size = BIGARRAY;
+    if(*thishsnote==(noteptr)0) {               /* 3a */
+        if(*hsnotecnt==0) {
+            sprintf(errstr,"getnexths() not initialised\n");
+            return(PROGRAM_ERROR);
+        }
+        return(TRUE);
+    }
+    if(inputtime<*nexthstime)                   /* 4 */
+        return(FALSE);
+    while(*nexthstime<=inputtime) {             /* 5 */
+        if(*hs_cnt>=hfdatacnt) {
+            sprintf(errstr,"Timing problem in getnexths()\n");
+            return(PROGRAM_ERROR);
+        }
+        *thishstime = *nexthstime;
+        *nexthstime = hft[*hs_cnt];
+        (*hs_cnt)++;
+    }
+    if(*hs!=(double *)0)                        /* 9 */
+        free(*hs);                      
+    if((*hs = (double *)malloc(size * sizeof(double)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY for harmonic set array.\n");
+        return(MEMORY_ERROR);
+    }
+
+    while(!flteq((double)(*thishsnote)->ntime,*thishstime)) {           /* 7 */
+        if((*thishsnote = (*thishsnote)->next)==(noteptr)0) {
+            sprintf(errstr,"TEXTURE: Search problem in getnexths()\n");
+            return(PROGRAM_ERROR);
+        }
+    }
+    *hsnotecnt = 0;
+    while(flteq((double)(*thishsnote)->ntime,*thishstime)) {            /* 8 */
+        if((exit_status = gethsnote((*thishsnote)->pitch,*hs,hsnotecnt))<0)
+            return(exit_status);
+        if(*hsnotecnt >= size) {
+            size += BIGARRAY;
+            if((*hs =(double *)realloc((char *)(*hs),size * sizeof(double)))==NULL) {
+                sprintf(errstr,"TEXTURE: realloc failed in getnexths()\n");
+                return(PROGRAM_ERROR);
+            }   
+        }
+        if((*thishsnote = (*thishsnote)->next)==(noteptr)0)
+            break;
+    }
+    if((*hs=(double *)realloc((char *)(*hs),*hsnotecnt * sizeof(double)))==NULL){
+        sprintf(errstr,"TEXTURE: getnexths(): realloc() failed\n");/* 10 */
+        return(PROGRAM_ERROR);
+    }
+    upsort(*hs,*hsnotecnt);
+    return(TRUE);
+}
+
+/***************************** GETHSNOTE ************************************
+ *
+ * Read a note and store in harmonic SET,  IF not already there.
+ */
+
+int gethsnote(double thispitch,double *thishs,int *hsnotecnt)
+{
+    int n, OK = 0;
+    for(n=0;n<*hsnotecnt;n++) {
+        if(flteq(thispitch,thishs[n])) {
+            OK = 1;
+            break;
+        }
+    }
+    if(!OK)
+        thishs[*hsnotecnt] = (double)thispitch;
+    (*hsnotecnt)++;
+    return(FINISHED);
+}
+
+/***************************** READHFTIMES ************************************
+ *
+ * Read times at which successive harmonic fields(sets) enter, and store as list.
+ */
+
+int readhftimes(noteptr firstnote, int *hfdatacnt,double **hft)
+{
+    double lasttime, firsttime;
+    int arraysize = BIGARRAY;
+    noteptr thisnote = firstnote;
+    *hfdatacnt = 0;
+    if((*hft = (double *)malloc(arraysize * sizeof(double)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY for harmonic field times array.\n");
+        return(MEMORY_ERROR);
+    }
+    lasttime = thisnote->ntime;
+    (*hft)[0] = lasttime;
+    while(thisnote!=(noteptr)0) {
+        if(!flteq((double)thisnote->ntime,lasttime)) {
+            if(++(*hfdatacnt)>=arraysize-1) {
+                arraysize += BIGARRAY;
+                if((*hft = (double *)realloc((char *)(*hft),arraysize * sizeof(double)))==NULL) {
+                    sprintf(errstr,"INSUFFICIENT MEMORY to reallocate harmonic field times array.\n");
+                    return(PROGRAM_ERROR);
+                }   
+            }
+            (*hft)[*hfdatacnt] = thisnote->ntime;
+            lasttime = thisnote->ntime;
+        }
+        thisnote = thisnote->next;
+    }
+    (*hft)[++(*hfdatacnt)] = DBL_MAX;                   /* 1 */
+    (*hfdatacnt)++;
+    if((*hft = (double *)realloc((char *)(*hft),(*hfdatacnt) * sizeof(double)))==NULL){
+        sprintf(errstr,"INSUFFICIENT MEMORY to reallocate harmonic field times array.\n");
+        return(PROGRAM_ERROR);
+    }
+    if(!flteq(**hft,0.0)) {
+        fprintf(stdout,"WARNING: Harmonic Field Data: No field at ZERO time.\n"
+                       "ADJUSTING FIRST FIELD TO ZERO TIME\n");
+        fflush(stdout);
+        thisnote  = firstnote;
+        firsttime = thisnote->ntime;
+        while(flteq(firsttime,**hft)) {
+            thisnote->ntime = 0.0f;
+            if((thisnote = thisnote->next)==(noteptr)0)
+                break;
+        }
+        **hft = 0.0;
+    }
+    return(FINISHED);
+}
+
+/***************************** DEL_GHOSTS ******************************
+ *
+ * Delete all tset notes MARKED for deletion in shadbits bitflag.
+ *
+ * (1)  For each byte in the bitflag...
+ * (2)  Set the bitmask to the first bit.
+ *   (3)  For every bit in this byte....
+ *   (4)  If this bit is set, delete the associated shadow (tset) note.
+ *   (5)  Advance the bitflag internal to the byte leftwards.
+ *   (6)  Advance the count of shadows, and if it reaches the total number
+ *    of shadows, exit, because remaining bits in this byte (if any)
+ *    have no meaning.
+ */
+
+void del_ghosts(int shshsize,char *shadbits,noteptr *shadow,int shadowsize,motifptr tset)
+{
+    int n,m,mask,k = 0;
+    for(n=0;n<shshsize;n++) {               /* 1 */
+        mask = 1;                           /* 2 */
+        for(m=0;m<CHARBITSIZE;m++) {        /* 3 */
+            if(shadbits[n] & mask)          /* 4 */
+                del_note(shadow[k],tset);
+            mask <<= 1;                     /* 5 */
+            if(++k >= shadowsize)           /* 6 */
+                return;
+        }
+    }
+}
+
+/************************** GET_HFGPPARAMS **************************
+ *
+ * Get the parameters for a group of notes.
+ *
+ * (0)  If pitch to decorate lies outside the HF range, return with gpsize
+ *  set to zero.
+ * (1)  If group range is expressed in HS-note units..
+ *   (a) Read the gprange as an integer number of (HS) notes.
+ *   (b) If HS-range exceeds HS limits, squeeze it.
+ *   (c) If HS-range is to be oriented about note, orient it appropriately.
+ * (2)  Otherwise...
+ *   (a) Read group range in normal way.
+ *   (b) If range exceeds HS limits, squeeze it.
+ *   (c) If range is to be oriented about note, orient it appropriately.
+ *   (d) If the range lies outside range of the HS,
+ *   set the groupsize to ZERO and return.
+ *   (e) Otherwise set the HS-range.
+ * (3)  Read group size.
+ * (4)  Read group density.
+ * (5)  number of midicliks in a gpdense time-interval.
+ * (6)  number of quantisation units, rounded.
+ * (7)  readjust gpdense to be number of units * length of units,
+ *  and reconvert to seconds.
+ */
+                                        
+int get_hfgpparams(double thistime,double thispitch,double *hs,int hsnotecnt,
+int *gpsize,int *hfrange,int *hfgpranglo,int *hfgpranghi,double *gprange,double *gpdense,int mingrpsize,
+double *gprlow, int dectypecnt,unsigned char dectypestor,dataptr dz)
+{
+    int exit_status;
+    if(thispitch<hs[0] || thispitch>hs[hsnotecnt-1]) {
+        *gpsize = 0;                        /* 0 */
+        return(FINISHED);
+    }
+    if((exit_status = igetvalue(TEX_GPRANGHI,TEX_GPRANGLO,thistime,PM_GPRANG,hfrange,dz))<0)
+        return(exit_status);
+
+    if(!dectypecnt) {   
+        hfsqueezrange(thispitch,hfrange,hfgpranghi,hfgpranglo,hsnotecnt,hs);                    /* b */
+        dz->vflag[DECCENTRE] = FALSE;
+    } else {
+        if((exit_status = hforientrange
+        (thispitch,hfrange,hfgpranghi,hfgpranglo,hsnotecnt,hs,dectypecnt,dectypestor,dz))<0) /* c */
+            return(exit_status);
+    }
+/* OCT 17 : hfgpranghi,lo are max & min INDECES within the harmonic field */
+
+    *hfrange = *hfgpranghi - *hfgpranglo;           /* e */
+
+/* OCT 17 : FROM hfgpranghi,lo the actual PITCH values can be deduced */
+    *gprlow  = hs[*hfgpranglo];
+    *gprange = hs[*hfgpranghi] - hs[*hfgpranglo];
+
+    if((exit_status  = igetvalue(TEX_GPSIZEHI,TEX_GPSIZELO,thistime,PM_GPSIZE,gpsize,dz))<0)
+        return(exit_status);
+
+    if(*gpsize  < mingrpsize) {
+        sprintf(errstr,"TEXTURE: Impossible GROUP SIZE value [%d]: get_hfgpparams()\n",*gpsize);
+        return(PROGRAM_ERROR);
+    }
+
+    if((exit_status = getvalue(TEX_GPPACKHI,TEX_GPPACKLO,thistime,PM_GPDENS,gpdense,dz))<0)
+        return(exit_status);
+/* NEW MAR 2000 */
+    *gpdense *= MS_TO_SECS;
+
+    if(dz->param[TEX_PHGRID]>0.0)
+        *gpdense = quantise(*gpdense,dz->param[TEX_PHGRID]);
+    return(FINISHED);
+}
+
+/***************************  HFSQUEEZRANGE ******************************
+ *
+ * Adjust range to lie within HF limits.
+ *
+ * (2)  Top of range is at current pitch's HF index (approx). If this is
+ *  above current top-of-HF range (hsnotecnt) move top down.
+ * (3)  Bottom of range is igprange below top. If this is below
+ *  bottom-of-HF (0), move igprlow up.
+ * (4)  Recalculate the true igprange within true limits.
+ */
+
+void hfsqueezrange(double thispitch,int *hfrange,int *hfgpranghi,int *hfgpranglo,int hsnotecnt,double *hs) 
+{
+    int halfrange = *hfrange/2;
+    if(halfrange * 2 != *hfrange)
+        halfrange++;
+    *hfgpranghi = min((geths_hibnd(thispitch,hsnotecnt,hs)+halfrange),hsnotecnt);   /* 2 */
+    *hfgpranglo = max((*hfgpranghi - *hfrange),0);                          /* 3 */
+    *hfrange = *hfgpranghi - *hfgpranglo;                                   /* 4 */
+}
+
+/****************************** GETHS_HIBND **********************************
+ *
+ *  hibnd >= pitch
+ *
+ * Find the index of the harmonic-set note that is immediately above or
+ * equal to the input pitch.
+ *
+ * NB CALL WITH geths_hibnd((double)thisnote->pitch);
+ *
+ * If the pitch is beyond the HS, n returns the value 'hsnotecnt'.
+ */
+
+int geths_hibnd(double thispitch,int hsnotecnt,double *hs)
+{
+    int n;
+    for(n=0;n<hsnotecnt;n++) {
+        if(hs[n]>thispitch || flteq(hs[n],thispitch))
+            break;
+    }
+    return(n);              /* 1 */
+}
+
+/***************************  HFORIENTRANGE ******************************
+ *
+ * As orientrange() but applied to HF/HS case.
+ */
+
+int hforientrange
+(double thispitch,int *hfrange,
+int *hfgpranghi,int *hfgpranglo,int hsnotecnt,double *hs,int dectypecnt,unsigned char dectypestor,dataptr dz)
+{
+    int exit_status;
+    unsigned char dectype;
+    int k;
+    if((exit_status=doperm((int)dectypecnt,PM_ORIENT,&k,dz))<0)
+        return(exit_status);
+    if((exit_status=gettritype(k,dectypestor,&dectype))<0)
+        return(exit_status);
+    switch(dectype) {
+    case(0):            /* centred range */
+        hfsqueezrange(thispitch,hfrange,hfgpranghi,hfgpranglo,hsnotecnt,hs);
+        dz->vflag[DECCENTRE] = TRUE;
+        break;
+    case(1):            /* range above note */
+        *hfgpranghi = min((geths_hibnd(thispitch,hsnotecnt,hs) + *hfrange),hsnotecnt);
+        *hfgpranglo = max((*hfgpranghi - *hfrange),0);
+        *hfrange    = *hfgpranghi - *hfgpranglo;
+        dz->vflag[DECCENTRE] = FALSE;
+        break;              
+    case(2):            /* range below note */
+        *hfgpranghi = geths_hibnd(thispitch,hsnotecnt,hs);
+        *hfgpranglo = max((*hfgpranghi - *hfrange),0);
+        *hfrange    = *hfgpranghi - *hfgpranglo;
+        dz->vflag[DECCENTRE] = FALSE;
+        break;              
+    default:
+        sprintf(errstr,"TEXTURE: Problem in hforientrange()\n");
+        return(PROGRAM_ERROR);
+    }
+    return(FINISHED);
+}
+
+/****************************** GETHS_ABOVE **********************************
+ *
+ *  above > pitch
+ *
+ * Find the index of the harmonic-set note that is immediately above
+ * the input pitch.
+ *
+ * NB CALL WITH geths_above((double)thisnote->pitch);
+ *
+ * If the pitch is beyond the HS, n gets the value 'hsnotecnt', which becomes
+ * the upper limit of the search range for doperm() ensuring that highest
+ * possible HSindex val is hsnotecnt-1, the highest pitch in the HS.
+ */
+
+int geths_above(double thispitch,double *hs,int hsnotecnt)
+{
+    int n;
+    for(n=0;n<hsnotecnt;n++) {
+        if(hs[n]>thispitch)
+            break;
+    }
+    return(n);                  /* 1 */
+}
+
+/****************************** GENERATE_GROUP_NOTE **********************************/
+
+int generate_group_note
+(noteptr thisnote,noteptr tsetnote,double thistime,int hfrange,int hfgpranglo,
+double *hs,int *hsindex,int gpsize,dataptr dz)
+{
+    int exit_status;
+    unsigned char thisinstr;
+    if((exit_status = do_grp_ins(tsetnote->instr,&thisinstr,dz))<0)
+        return(exit_status);
+    thisnote->instr = thisinstr;
+    thisnote->motioncentre = tsetnote->motioncentre;
+    if((exit_status = hfscat(hfrange,hfgpranglo,PM_GPPICH,hsindex,dz))<0)
+        return(exit_status);
+    thisnote->pitch  = (float)hs[*hsindex];     /* 7 */
+    thisnote->ntime  = (float)thistime; 
+    return setspace(tsetnote,thisnote,gpsize,dz);
+}
+
+/******************************* HFSCAT ***********************************
+ *
+ * A weighted version of hfscatx().
+ */
+
+int hfscat(int prange,int pbottom,int permindex,int *val,dataptr dz)
+{
+    int exit_status;
+    double bandbottom,  bandtop,  bandwidth;
+    int   ibandbottom, ibandtop, ibandwidth, k;
+    if(prange<=LAYERCNT) {
+        if((exit_status = doperm((int)prange,permindex,&k,dz))<0)
+            return(exit_status);
+        *val = k + pbottom;
+        return(FINISHED);
+
+    }
+    if((exit_status = doperm((int)BANDCNT,permindex,&k,dz))<0)
+        return(exit_status);
+    bandwidth = (double)prange/(double)LAYERCNT;
+    switch(k) {
+    case(0):
+        bandbottom = 0;
+        break;
+    case(BANDCNT-1):
+        bandbottom = (double)(LAYERCNT-1) * bandwidth;
+        break;
+    default:
+        bandbottom = bandwidth + ((double)((k-1) * 2) * bandwidth);
+        bandwidth *= 2.0;
+        break;
+    }
+    bandtop     = bandbottom + bandwidth;
+    ibandtop    = round(bandtop);
+    ibandbottom = round(bandbottom);
+    ibandwidth  = ibandtop - ibandbottom;
+    k  = (int)(drand48() * (double)ibandwidth);
+    k += ibandbottom;
+    k += pbottom;
+    *val = k;
+    return(FINISHED);
+}
+
+/****************************** GENERATE_DECOR_NOTE **********************************/
+
+int generate_decor_note(noteptr thisnote,noteptr tsetnote,
+double thispitch,double thistime,int hfrange,int hfgpranghi,int hfgpranglo,double *hs,int *hsindex,
+int hsnotecnt,double gprlow,double gprange,int gpsize,dataptr dz)
+{
+    int exit_status;
+    double val;
+    if((exit_status = do_grp_ins(tsetnote->instr,&thisnote->instr,dz))<0)
+        return(exit_status);
+    thisnote->motioncentre = tsetnote->motioncentre;
+    if(dz->vflag[DECCENTRE]) {
+        if((exit_status = dec_hfcentre
+        (thispitch,hs,hsnotecnt,hfrange,hfgpranghi,hfgpranglo,gprlow,gprange,gpsize,&val,dz))<0)
+            return(exit_status);
+        thisnote->pitch = (float)val;
+    } else {
+        if((exit_status = hfscat(hfrange,hfgpranglo,PM_GPPICH,hsindex,dz))<0)
+            return(exit_status);
+        thisnote->pitch  = (float)hs[*hsindex];
+    }
+    thisnote->ntime  = (float)(thistime); 
+    return setspace(tsetnote,thisnote,gpsize,dz);
+}
+
+/************************* DEC_HFCENTRE *******************************/
+ 
+int dec_hfcentre(double tsetpitch,double *hs,int hsnotecnt,int hfrange,int hfgpranghi,int hfgpranglo,
+double gprlow,double gprange,int gpsize,double *val,dataptr dz)
+{
+    int exit_status;
+    double a, gprhi = gprlow + gprange;
+    int s, save, k, hfcentre, n_above, n_below, hsindex;
+    if(tsetpitch-gprlow<=FLTERR || flteq(tsetpitch,gprhi)) {
+        if((exit_status = hfscatx(hfrange,hfgpranglo,PM_GPPICH,&hsindex,dz))<0)
+            return(exit_status);
+        *val = hs[hsindex];
+        return(FINISHED);                   /* 1 */
+    }
+    n_below = hfrange/2;                    /* 2 */
+    if(((n_above=n_below)+n_below)!=hfrange)
+        n_above++;
+    if(((hfcentre =geths_hibnd(tsetpitch,hsnotecnt,hs)) + n_above) > hsnotecnt)
+        n_above = hsnotecnt - hfcentre;             /* 3 */
+    if(hfcentre - n_below < 0)
+        n_below = hfcentre;                 /* 4 */
+    if(n_above<=0 || n_below<=0) { 
+        if((exit_status = hfscatx(hfrange,hfgpranglo,PM_GPPICH,&hsindex,dz))<0)
+            return(exit_status);
+        else {
+            *val = hs[hsindex];
+            return(FINISHED);                   /* 5 */
+        }
+    }
+    save = dz->iparray[TXREPETCNT][PM_DECABV];                      /* 6 */
+    k = (gpsize+1)/2;
+    if(dz->iparray[TXREPETCNT][PM_DECABV]>k)
+        dz->iparray[TXREPETCNT][PM_DECABV] = k;         
+    if((exit_status = doperm((int)2,PM_DECABV,&s,dz))<0)
+        return(exit_status);
+    if(s) {
+        if((exit_status = hfscatx(n_above,hfgpranghi - n_above,PM_GPPICH,&hsindex,dz))<0)
+            return(exit_status);
+    } else {
+        if((exit_status = hfscatx(n_below,hfgpranglo,PM_GPPICH2,&hsindex,dz))<0)
+            return(exit_status);
+    }
+    dz->iparray[TXREPETCNT][PM_DECABV] = save;
+    a = hs[hsindex];
+    if(a<MIDIBOT || a>MIDITOP) {
+        sprintf(errstr,"TEXTURE: Problem in dec_hfcentre()\n");
+        return(PROGRAM_ERROR);
+    }
+    *val = a;
+    return(FINISHED);                           
+}
+
+/******************************* HFSCATX ***********************************
+ *
+ * As pscat, but working with ranges of integers, especially the indeces
+ * of an HS.
+ */
+
+int hfscatx(int prange,int pbottom,int permindex,int *val,dataptr dz)
+{
+    int exit_status;
+    double bandbottom,  bandtop,  bandwidth;
+    int   ibandbottom, ibandtop, ibandwidth, k;
+    if(prange<=BANDCNT) {
+        if((exit_status = doperm((int)prange,permindex,val,dz))<0)
+            return(exit_status);
+        *val += pbottom;
+        return(FINISHED);
+    }
+    if((exit_status = doperm((int)BANDCNT,permindex,val,dz))<0)
+        return(exit_status);
+    k = *val;
+    bandwidth   = (double)prange/(double)BANDCNT;
+    bandbottom  = (double)k     * bandwidth;
+    bandtop     = (double)(k+1) * bandwidth;
+    ibandbottom = round(bandbottom);
+    ibandtop    = round(bandtop);
+    ibandwidth  = ibandtop - ibandbottom;
+    k  = (int)(drand48() * (double)ibandwidth);
+    k += ibandbottom;
+    *val = k + pbottom;
+    return(FINISHED);
+}
+
+/******************************** SET_SHADBIT ****************************
+ * 
+ * Set a bit in the shadow's bitfag.
+ */
+
+void set_shadbit(int k,char *shadbits)
+{
+    int bitunit  = k/CHARBITSIZE;
+    int bitshift = k % 8;
+    int mask = 1;
+    mask <<= bitshift;
+    shadbits[bitunit] |= mask;
+}
+
+/****************************** GETHS_LOBND **********************************
+ *
+ *  lobnd =< pitch
+ *
+ * Find the index of the harmonic-set note that is immediately below, or
+ * equal to the input pitch.
+ *
+ * NB CALL WITH geths_lobnd((double)thisnote->pitch);
+ *
+ * NB: If the entered pitch is lower than the entire HS, function returns -1.
+ */
+
+int geths_lobnd(double thispitch,double *hs,int hsnotecnt)
+{
+    int n;
+    for(n=0;n<hsnotecnt;n++) {
+        if(hs[n]>thispitch)
+            break;
+    }
+    return(--n);                    /* 1 */
+}
+
+/***************************** GETHFNOTE ************************************
+ *
+ * Read a note and store in harmonic field IF not already there.
+ */
+
+int gethfnote(double thispitch,double *hf,int *hfnotecnt)
+{
+    int n, OK  = 0;
+    float notetransp = (float)fmod(thispitch,SEMITONES_PER_OCTAVE);
+    if(flteq((double)notetransp,0.0))
+        notetransp = (float)(notetransp + SEMITONES_PER_OCTAVE);
+    for(n=0;n<*hfnotecnt;n++) {
+        if(flteq((double)notetransp,hf[n])) {
+            OK = 1;
+            break;
+        }
+    }
+    if(!OK)
+        hf[*hfnotecnt] = (double)notetransp;
+    (*hfnotecnt)++;
+    return(FINISHED);
+}
+
+/**************************** SETMTFPARAMS *******************************
+ * 
+ * Establish easy parameters of motif or ornament.
+ */
+
+int setmtfparams
+(noteptr thisnote,double thisamp,noteptr phrasenote,noteptr tsetnote,double ampdif,double notetime,
+int gpsize,double multiplier,dataptr dz)
+{
+    int exit_status;
+    if((exit_status = do_mtf_params(thisnote,thisamp,phrasenote,tsetnote,ampdif,notetime,multiplier,dz))<0)
+        return(exit_status);
+    return setspace(tsetnote,thisnote,gpsize,dz);
+}
+
+/**************************** INITIALISE_HFPHRASES *******************************/
+
+int initialise_hfphrases
+(int ***hfphrase,int **endhsindex,int **phrnotecnt,double **phraseamp,double **phrange,
+noteptr **phrlastnote,dataptr dz)
+{
+    if((*hfphrase = (int **)malloc(dz->tex->phrasecnt * sizeof(int *)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY for harmonic field phrases.\n");
+        return(MEMORY_ERROR);
+    }
+    if((*endhsindex = (int *)malloc(dz->tex->phrasecnt * sizeof(int)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY for harmonic set indices.\n");
+        return(MEMORY_ERROR);
+    }
+    if((*phrnotecnt = (int *)malloc(dz->tex->phrasecnt * sizeof(int)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY for harmonic field phrase notecnt.\n");
+        return(MEMORY_ERROR);
+    }
+    if((*phraseamp = (double *)malloc(dz->tex->phrasecnt * sizeof(double)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY for phrase amplitude array.\n");
+        return(MEMORY_ERROR);
+    }
+    if((*phrange  = (double *)malloc(dz->tex->phrasecnt * sizeof(double)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY for phrase range array.\n");
+        return(MEMORY_ERROR);
+    }
+    if((*phrlastnote = (noteptr *)malloc(dz->tex->phrasecnt * sizeof(noteptr)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY for phrase lastnote array.\n");
+        return(MEMORY_ERROR);
+    }
+    return(FINISHED);
+}
+
+/****************************** GET_FIRST_HS ***********************************
+ *
+ * Extract HS from input data.
+ */
+
+int get_first_hs(noteptr thisnote,double **hs,int *hsnotecnt)
+{
+    int exit_status;
+    int size = BIGARRAY;
+    noteptr startnote = thisnote;
+    double thistime = 0.0;
+    if((*hs = (double *)malloc(BIGARRAY * sizeof(double)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY for harmonic set array.\n");
+        return(MEMORY_ERROR);
+    }
+    while(thisnote!=(noteptr)0) {
+        if((exit_status = gethsnote(thisnote->pitch,*hs,hsnotecnt))<0)
+            return(exit_status);
+        if(thisnote==startnote)
+            thistime = thisnote->ntime;
+        else {
+            if(!flteq((double)thisnote->ntime,thistime)) {
+                (*hsnotecnt)--;
+                break;
+            }
+        }
+        if(*hsnotecnt >= BIGARRAY) {
+            size += BIGARRAY;
+            if((*hs=(double *)realloc((char *)(*hs),size * sizeof(double)))==NULL){
+                sprintf(errstr,"INSUFFICIENT MEMORY to reallocate harmonic set array.\n");
+                return(MEMORY_ERROR);
+            }   
+        }
+        thisnote = thisnote->next;
+    }
+    if((*hs=(double *)realloc((char *)(*hs),*hsnotecnt*sizeof(double)))==NULL){
+        sprintf(errstr,"INSUFFICIENT MEMORY to reallocate harmonic set array.\n");
+        return(MEMORY_ERROR);
+    }
+    upsort(*hs,*hsnotecnt);
+    return(FINISHED);
+}
+    
+/****************************** GET_FIRST_HF ***********************************
+ *
+ * Extract first HF from input data.
+ */
+
+int get_first_hf(noteptr thisnote,double **hf,int *hfnotecnt)
+{
+    int exit_status;
+    int size = BIGARRAY;
+    noteptr startnote = thisnote;
+    double thistime = 0.0;
+
+    if((*hf = (double *)malloc(size * sizeof(double)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY for harmonic field array.\n");
+        return(MEMORY_ERROR);
+    }
+    while(thisnote!=(noteptr)0) {
+        if((exit_status = gethfnote(thisnote->pitch,*hf,hfnotecnt))<0)
+            return(exit_status);
+        if(thisnote==startnote)
+            thistime = thisnote->ntime;
+        else {
+            if(!flteq((double)thisnote->ntime,thistime)) {
+                (*hfnotecnt)--;
+                break;
+            }
+        }
+        if(*hfnotecnt >= size) {
+            size += BIGARRAY;
+            if((*hf = (double *)realloc((char *)(*hf),size * sizeof(double)))==NULL){
+                sprintf(errstr,"INSUFFICIENT MEMORY to reallocate harmonic field array.\n");
+                return(MEMORY_ERROR);
+            }   
+        }
+        thisnote = thisnote->next;
+    }
+    if((*hf=(double *)realloc((char *)(*hf),*hfnotecnt * sizeof(double)))==NULL){
+        sprintf(errstr,"INSUFFICIENT MEMORY to reallocate harmonic field array.\n");
+        return(MEMORY_ERROR);
+    }
+    upsort(*hf,*hfnotecnt);
+    return(FINISHED);
+}
+
+/******************************** OCTEQ *************************************/
+
+int octeq(double a,double b)
+{
+    a = fmod(a,12.0);
+    b = fmod(b,12.0);
+    if(flteq(a,b)) {
+        return(1);
+    }
+    return(0);
+}

+ 1474 - 0
dev/texture/texture4.c

@@ -0,0 +1,1474 @@
+/*
+ * Copyright (c) 1983-2013 Trevor Wishart and Composers Desktop Project Ltd
+ * http://www.trevorwishart.co.uk
+ * http://www.composersdesktop.com
+ *
+ This file is part of the CDP System.
+ 
+ The CDP System is free software; you can redistribute it
+ and/or modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+ 
+ The CDP System is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU Lesser General Public License for more details.
+ 
+ You should have received a copy of the GNU Lesser General Public
+ License along with the CDP System; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA
+ *
+ */
+/* floatsam version : no changes */
+#include <stdio.h>
+#include <stdlib.h>
+#include <float.h>
+#include <structures.h>
+#include <tkglobals.h>
+#include <globcon.h>
+#include <processno.h>
+#include <modeno.h>
+#include <arrays.h>
+#include <texture.h>
+#include <cdpmain.h>
+
+#include <sfsys.h>
+#include <osbind.h>
+
+#if defined unix || defined __GNUC__
+#define round(x) lround((x))
+#endif
+
+/**** ALL FUNCTIONS WHICH ARE GLOBAL TO ALL PROCESS FUNCTIONS TYPES ***/
+
+/* Functions which are global to all texture applications.
+ */
+static void orn_subzero(double *thistime,noteptr phrlastnote,noteptr *phrasenote,
+            double *timeadjust,double multiplier,int *gpsize);
+static int  getmtfampstep
+            (double amp,double framp,double *ampstep,unsigned char *amptype,
+            unsigned char amptypestor,unsigned char amptypecnt,int gpsize,dataptr dz);
+static int  space_gpnote(noteptr thisnote,int gpsize,dataptr dz);
+static int  sp_scatter(noteptr mnote,dataptr dz);
+static int  pre_place(noteptr thisnote,int gpsize,dataptr dz);
+static int  post_place(noteptr thisnote,int gpsize,dataptr dz);
+static int  read_direction(int shi,noteptr *shadow,int shadowsize);
+
+static int  do_ev_ins(unsigned char *thisinstr,double thistime,dataptr dz);
+static int  do_ev_amp(double *thisamp,double thistime,dataptr dz);
+static int  do_ev_dur(double *thisdur,double thistime,dataptr dz);
+static int  getdirampstep
+            (double amp,unsigned char amptypecnt,double *ampstep,int gpsize,dataptr dz);
+static int  getampstep
+            (double *ampstep,double amp,unsigned char *amptype,int gpsize,unsigned char amptypecnt,
+            unsigned char amptypestor,dataptr dz);
+static int  get_dec_or_orn_pos(dataptr dz);
+ 
+static int  subzero(double *thistime,double gpdense,int *gpsize);
+
+static noteptr reverse_search_for_time(noteptr start,double reftime);
+static void    move_notelist_item(noteptr a,noteptr b);
+static double  setup_first_notelist_time(noteptr *base);
+static int     reset_mtfhead(motifptr mtf);
+static int     post_place(noteptr thisnote,int gpsize,dataptr dz);
+static int     getmtfdirampstep
+            (double amp,double framp,unsigned char amptypecnt,double *ampstep,int gpsize,dataptr dz);
+static void cyclicperm(dataptr dz);
+static void hinsert(int m,int t,int *perm,int permlen);
+static void hprefix(int m,int *perm,int permlen);
+static void hshuflup(int k,int *perm,int permlen);
+
+/***************************** OCTADJUST *****************************
+ *
+ * Check for range overflow of pitch.
+ */
+
+double octadjust(double thispitch)
+{
+    if(thispitch>MIDITOP)
+        thispitch -= SEMITONES_PER_OCTAVE;
+    if(thispitch<MIDIBOT)
+        thispitch += SEMITONES_PER_OCTAVE;
+    return(thispitch);
+}
+
+/***************************** DO_AMP_INSTR_DUR ************************************/
+
+int do_amp_instr_dur
+(double *thisamp,unsigned char *thisinstr,double *thisdur,noteptr tsetnote,double thistime,dataptr dz)
+{
+    int exit_status;
+    if((exit_status = do_ev_amp(thisamp,thistime,dz))<0)
+        return(exit_status);
+    tsetnote->amp = (float)(*thisamp);
+    if((exit_status = do_ev_ins(thisinstr,thistime,dz))<0)
+        return(exit_status);
+    tsetnote->instr = *thisinstr;
+    if((exit_status = do_ev_dur(thisdur,thistime,dz))<0)
+        return(exit_status);
+    tsetnote->dur = (float)(*thisdur);
+    return(FINISHED);
+}
+
+/********************** DO_EV_INS *******************************
+ *
+ * Set instrument of event (not group etc.).
+ *
+ * (0)  If instruments in ornament or decoration are to be relative to
+ *  input instr, return this input instrument.
+ * (1)  If there is a pre-existing timed set (pretimed = 1).
+ * (2)  Negative value causes original value to be replaced
+ *  by orig + abs(neg value).
+ *  Zero value, by default, causes orig value to be retained.
+ */
+
+int do_ev_ins(unsigned char *thisinstr,double thistime,dataptr dz)
+{
+    int exit_status;
+    int instrval;
+    if(dz->process == SIMPLE_TEX && dz->vflag[CYCLIC_TEXFLAG]) {
+        if(dz->itemcnt == dz->infilecnt)
+            dz->itemcnt = 0;
+        if(dz->vflag[PERM_TEXFLAG]) {
+            if(dz->itemcnt == 0)
+                cyclicperm(dz);
+            *thisinstr = (unsigned char)dz->peakno[dz->itemcnt];
+        } else {
+            *thisinstr = (unsigned char)dz->itemcnt;
+        }
+        dz->itemcnt++;
+    } else {
+        if((exit_status = igetvalue(TEXTURE_INSHI,TEXTURE_INSLO,thistime,PM_INSNO,&instrval,dz))<0)
+            return(exit_status);
+        *thisinstr = (unsigned char)instrval;
+    }
+    return(FINISHED);
+}
+
+/********************** DO_EV_AMP ********************************/
+
+int do_ev_amp(double *thisamp,double thistime,dataptr dz)
+{  
+    int exit_status;
+    if((exit_status = getvalue(TEXTURE_MAXAMP,TEXTURE_MINAMP,thistime,PM_AMP,thisamp,dz))<0)
+        return(exit_status);
+
+    *thisamp *= dz->param[TEXTURE_ATTEN];
+
+    if(*thisamp>MIDITOP + 0.5) {
+        sprintf(errstr,"TEXTURE: amplitude [%.1f] out of midirange at time %.2f\n",*thisamp,thistime); 
+        return(DATA_ERROR);
+    }
+    return(FINISHED);
+}
+
+/********************** DO_EV_DUR ********************************/
+
+int do_ev_dur(double *thisdur,double thistime,dataptr dz)
+{
+    int exit_status;
+    if((exit_status = getvalue(TEXTURE_MAXDUR,TEXTURE_MINDUR,thistime,PM_DUR,thisdur,dz))<0)
+        return(exit_status);
+    return(FINISHED);                   /* 4 */
+}
+
+/************************ MAKE_SHADOW ****************************
+ *
+ * Store addresses of original tset notes.
+ */
+
+int make_shadow(motifptr tset,int *shadowsize,noteptr **shadow)
+{
+    noteptr *sh, thisnote = tset->firstnote;
+    int n;
+    *shadowsize = 0;
+    while(thisnote!=(noteptr)0) {
+        (*shadowsize)++;
+        thisnote = thisnote->next;
+    }
+    if((sh = *shadow = (noteptr *)malloc((*shadowsize) * sizeof(noteptr)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY for shadow.\n");
+        return(MEMORY_ERROR);
+    }
+    thisnote = tset->firstnote;
+    n = 0;
+    while(thisnote!=(noteptr)0) {
+        sh[n++]  = thisnote;
+        thisnote = thisnote->next;
+    }
+    return(FINISHED);
+}
+
+/************************ ERASE_SHADOW ****************************
+ *
+ * Erase original tset from resultant list.
+ *
+ * (0)  Assuming shadow starts at start of tset, if first note of
+ *  shadow is deleted, del_note automatically resets motifptr (tset)
+ *  to next note (and so on).
+ * (1)  In case shadow started AFTER start of tset (should be impossible!!)
+ *  reset pointer to start of remaining motif !
+ */
+
+int erase_shadow(int shadowsize,noteptr *shadow,motifptr tset)
+{
+    int n;
+    noteptr thisnote;
+    for(n=0;n<shadowsize;n++)                   /* 0 */
+        del_note(shadow[n],tset);
+    if((thisnote = tset->firstnote->last)!=(noteptr)0) {    /* 1 */
+        sprintf(errstr,"TEXTURE: erase_shadow(): First note of shadow NOT first note of tset.\n"
+                       "This should never happen\n");
+        return(PROGRAM_ERROR);
+    /**** REMOVED FOLLOWING AUTO-CORRECTION CODE : OCT 1997 *****
+        while(thisnote->last!=(noteptr)0)
+            thisnote = thisnote->last;
+        tset->firstnote = thisnote;
+    ****/
+    }
+    return(FINISHED);
+}
+
+/************************ SETUP_DECOR ****************************/
+
+void setup_decor(double *pptop,double *ppbot,int *shadindex,noteptr *tsetnote,dataptr dz)
+{
+    *pptop = MIDITOP; 
+    *ppbot = MIDIBOT;
+    if(dz->vflag[WHICH_CHORDNOTE]==DECOR_HIGHEST)
+        *tsetnote = gethipitch(*tsetnote,shadindex);
+}
+
+/**************************** SETUP_ORNAMENT *********************************/
+
+int setup_ornament
+(double *timeadjust,double *thistime,int *gpsize,noteptr *phrlastnote,
+ double multiplier,noteptr *phrasenote,int phrno,dataptr dz)
+{
+    int exit_status;
+    double origtime;
+    if((exit_status = get_dec_or_orn_pos(dz))<0)
+        return(exit_status);
+    *timeadjust = 0.0;
+    if(dz->vflag[IS_PRE]) {
+        origtime = *thistime;
+        if((*thistime -= (phrlastnote[phrno])->ntime * multiplier)<0.0) {
+            *thistime = origtime;
+            orn_subzero(thistime,phrlastnote[phrno],phrasenote,timeadjust,multiplier,gpsize);
+        }
+    }
+    return(FINISHED);
+}
+
+/**************************** SET_MOTIF_AMP *********************************/
+
+int set_motif_amp
+(noteptr tsetnote,double *thisamp,int gpsize,double ampstep,noteptr phrasenote,double rangemult,
+double *phraseamp,int phrno,unsigned char amptype)
+{
+    double ampdif;
+    if(amptype==CRESC) {
+        *thisamp -= (double)(gpsize) * ampstep;
+        ampdif    = (phraseamp[phrno] - phrasenote->amp) * rangemult;
+        tsetnote->amp = (float)(*thisamp - ampdif);
+    }
+    return(FINISHED);
+}
+
+/**************************** SET_ORNAMENT_AMP *********************************/
+
+int set_ornament_amp
+(double *phraseamp,noteptr *phrlastnote,double *thisamp,
+noteptr phrasenote,int phrno,noteptr tsetnote,
+double ampstep,double rangemult,int gpsize,dataptr dz)
+{
+    double ampdif;
+    if(dz->vflag[IS_PRE])
+        ampdif=(phraseamp[phrno]-phrlastnote[phrno]->amp) * rangemult;
+    else
+        ampdif=(phraseamp[phrno]-phrasenote->amp) * rangemult;
+    tsetnote->amp -= (float)ampdif;
+    if(ampstep>0.0) /* CRESCENDO */
+        *thisamp -= (double)(gpsize+1) * ampstep;
+    return(FINISHED);
+}
+
+/**************************** CHECK_NEXT_PHRASENOTE_EXISTS *********************************/
+
+int check_next_phrasenote_exists(noteptr *phrasenote,int texflag,dataptr dz)
+{
+    if(texflag & IS_MOTIFS) {
+        if((*phrasenote = (*phrasenote)->next)==(noteptr)0) {
+            sprintf(errstr,"TEXTURE: Accounting Problem in check_next_phrasenote_exists()\n");
+            return(PROGRAM_ERROR);
+        }
+    } else if (texflag & IS_ORNATE){
+        if(*phrasenote==(noteptr)0) {
+            sprintf(errstr,"TEXTURE: 1st Accounting Problem in check_next_phrasenote_exists()\n");
+            return(PROGRAM_ERROR);
+        }
+        if(dz->vflag[IS_PRE] && ((*phrasenote)->next==(noteptr)0)) {
+            sprintf(errstr,"TEXTURE: 2nd Accounting Problem in check_next_phrasenote_exists()\n");
+            return(PROGRAM_ERROR);
+        }
+    }
+    return(CONTINUE);
+}
+
+/************************* GETNEXTEVENT_TO_DECORATE ***************************
+ *
+ * Get the next event in list, i.e. skip over simultaneous events
+ * (e.g. chords).
+ *
+ * (0)  If flagged as 2, ornaments/decorations are attached to EVERY note
+ *  so the next event is just the next note in the tset.
+ *  OTHERWISE we search for the next event AT A NEW TIME.
+ * (1)  If flagged, force a search for the highest note of a simultaneous
+ *  group (chord). Hence ornament/dec attaches to highest note.
+ *  Otherwise, ornament attached to first listed note of chord in input
+ *  data.
+ */
+
+noteptr getnextevent_to_decorate(noteptr tsetnote,int *shaddoindex,dataptr dz)
+{
+    if(dz->vflag[WHICH_CHORDNOTE]==DECOR_EVERY)                     /* 0 */
+        return(tsetnote->next);
+    while(tsetnote->next!=(noteptr)0) {
+        tsetnote = tsetnote->next;
+        (*shaddoindex)++;
+        if(!flteq((double)tsetnote->ntime,(double)tsetnote->last->ntime)) {
+            if(dz->vflag[WHICH_CHORDNOTE]==DECOR_HIGHEST)
+                tsetnote = gethipitch(tsetnote,shaddoindex);    /* 1 */
+            return(tsetnote);
+        }
+    }
+    return((noteptr)0);
+}
+    
+/************************** GETNOTETIME ********************************
+ *
+ * Get actual time of note, from time of tset note, and time of motif
+ * or ornament note.
+ * (a)  Time is set by an offset from the tset-note, THROUGHOUT each
+ *  motif-placement. The offset for each note is its position in the
+ *  original note (which have been set relative to zero by set_mtfs())
+ *  times the multiplier, with an adjustment if we're actually using
+ *  less than the whole motif for some reason.
+ * (b)  Time may need to be quantised.
+ * (c)  Time of note is this tset-note + offset.
+ */
+
+double getnotetime(noteptr phrasenote,double thistime,double multiplier,double timeadjust,dataptr dz)
+{   
+    int qunits;
+    double timestep = ((double)phrasenote->ntime - timeadjust) * (double)multiplier; /* a */
+    double thisgrid;
+
+    if(dz->param[TEX_PHGRID]>0.0) {  
+/* NEW  2000 */
+        thisgrid = dz->param[TEX_PHGRID] * MS_TO_SECS;
+
+        qunits    = round(timestep/thisgrid);       /* b */
+        timestep  = (double)(qunits*thisgrid);  
+    }
+    return(thistime + timestep);                /* c */
+}
+
+/************************ GETMTFDUR **********************************/
+
+int getmtfdur(noteptr tsetnote,noteptr phrasenote,double *dur,double multiplier,dataptr dz)
+{
+    if(dz->vflag[DONT_KEEP_MTFDUR])
+        *dur = tsetnote->dur;
+    else
+        *dur = phrasenote->dur * multiplier;
+    if(flteq(*dur,0.0)) {
+        sprintf(errstr,"TEXTURE: Problem 3 in getmtfdur(): Zero duration\n");
+        return(PROGRAM_ERROR);
+    }
+    return(FINISHED);
+}
+
+/***************************** ORN_OR_MTF_AMP_SETUP ************************************/
+
+int orn_or_mtf_amp_setup
+(int ampdirected,double *phrange,int phrno,double thisamp,int gpsize,double *rangemult,double *ampstep,
+unsigned char *amptype,unsigned char amptypestor,unsigned char amptypecnt,dataptr dz)
+{
+    int exit_status;
+    double kk;
+    if(phrange[phrno]>=thisamp) {
+        kk = (double)phrange[phrno]*((double)(gpsize+1)/(double)gpsize);
+        *rangemult = (double)thisamp / kk;
+        *ampstep   = 0.0;
+    } else {
+        if(ampdirected) {
+            if((exit_status = getmtfdirampstep(thisamp,phrange[phrno],amptypecnt,ampstep,gpsize,dz))<0)
+                return(exit_status);
+        } else {
+            if((exit_status = getmtfampstep(thisamp,phrange[phrno],ampstep,amptype,amptypestor,amptypecnt,gpsize,dz))<0)
+                return(exit_status);
+        }
+        *rangemult = 1.0;
+    }
+    return(FINISHED);
+}
+
+/**************************** DO_MTF_PARAMS *******************************/
+
+int do_mtf_params
+(noteptr thisnote,double thisamp,noteptr phrasenote,noteptr tsetnote,
+double ampdif,double notetime,double multiplier,dataptr dz)
+{
+    int exit_status;
+    double duration;
+    thisnote->amp   = (float)(thisamp - ampdif);
+    if((exit_status = getmtfdur(tsetnote,phrasenote,&duration,multiplier,dz))<0)
+        return(exit_status);
+    thisnote->dur = (float)duration;
+    if((exit_status = do_grp_ins(tsetnote->instr,&(thisnote->instr),dz))<0)
+        return(exit_status);
+    thisnote->motioncentre = tsetnote->motioncentre;
+    thisnote->ntime  = (float)notetime;
+    return(FINISHED);
+}
+
+/***************************** SETUP_MOTIF_OR_ORNAMENT ************************************/
+
+int setup_motif_or_ornament
+(double thistime,double *multiplier,int *phrno,noteptr *phrasenote,motifptr *phrase,dataptr dz)
+{
+    int exit_status;
+    if((exit_status = getvalue(TEX_MULTHI,TEX_MULTLO,thistime,PM_MULT,multiplier,dz))<0)
+        return(exit_status);
+    if((exit_status = doperm((int)dz->tex->phrasecnt,PM_WHICH,phrno,dz))<0)
+        return(exit_status);
+    *phrasenote    = phrase[*phrno]->firstnote;
+    return(FINISHED);
+}
+
+/****************************** POSITION_AND_SIZE_DECORATION **********************************/
+
+int position_and_size_decoration
+(double *thistime,double tsettime,double gpdense,int *gpsize,dataptr dz)
+{
+    int exit_status;
+    if((exit_status = get_dec_or_orn_pos(dz))<0)
+        return(exit_status);
+    if(dz->vflag[IS_PRE]) {
+        if((*thistime -= gpdense * (double)((*gpsize) + 1))< -gpdense) {
+            *thistime = tsettime;
+            if((exit_status = subzero(thistime,gpdense,gpsize))<0)
+                return(exit_status);
+        }
+    }
+    return(FINISHED);
+}
+
+/****************************** SET_DECOR_AMP **********************************/
+
+int set_decor_amp
+(int ampdirected,double *thisamp,double *ampstep,int gpsize,
+unsigned char *amptype,unsigned char amptypecnt,unsigned char amptypestor,dataptr dz)
+{
+    int exit_status;
+    if(ampdirected) {
+        if((exit_status = getdirampstep(*thisamp,amptypecnt,ampstep,gpsize,dz))<0)
+            return(exit_status);
+    } else  {
+        if((exit_status = getampstep(ampstep,*thisamp,amptype,gpsize,amptypecnt,amptypestor,dz))<0)
+            return(exit_status);
+    }
+    if(*ampstep>0.0)
+        *thisamp -= (double)(gpsize+1) * (*ampstep);
+    return(FINISHED);
+}
+
+/****************************** SET_GROUP_AMP **********************************/
+
+int set_group_amp
+(noteptr tsetnote,double *thisamp,unsigned char *amptype, double *ampstep,int gpsize,
+unsigned char amptypecnt,unsigned char amptypestor,dataptr dz)
+{
+    int exit_status;
+    if((exit_status = getampstep(ampstep,*thisamp,amptype,gpsize,amptypecnt,amptypestor,dz))<0)
+        return(exit_status);
+    if(*amptype==CRESC) {
+        *thisamp -= (double)(gpsize) * (*ampstep);
+        tsetnote->amp = (float)(*thisamp);
+    }
+    return(FINISHED);
+}
+
+/* LOCAL TO THESE GLOBALS */
+
+/****************************** ORN_SUBZERO *******************************
+ *
+ * Readjust the groupsize and the pointer to first note of phrase, where
+ * otherwise phrase would start before zero.
+ *
+ * (1)  Note the endtime of the phrase.
+ * (2)  For each note in the phrase.
+ * (3)  Find the duration of the phrase FROM THIS NOTE, by subtracting time of
+ *  current note from end (total) time, and adjusting by multiplier.
+ * (4)  If the duration of phrase from here, would put it's start after
+ *  zero-time, break from loop.
+ * (5)  Count number of notes rejected, and go to next phrase note.
+ * (6)  If we're at end of phrase, none of it's notes fall after zero time,
+ *  so return a gpsize of 0.
+ * (7)  Otherwise reset the event time (mifitime) to start of the group or 
+ *  part-group which 'thisnote' points to.
+ * (8)  Resert the phrase pointer to point at this note of the phrase.
+ * (9)  When note times are finally calculated, timeadjust will reset all
+ *  the note times WITHIN the ornament to run from the note from
+ *  which we're starting, rather than the true start, by subtracting
+ *  'timeadjust'.
+ * (10) Return a size for the group reduced by the number of rejected notes.
+ */
+
+void orn_subzero
+(double *thistime,noteptr phrlastnote,noteptr *phrasenote,double *timeadjust,double multiplier,int *gpsize)
+{
+    double endtime = phrlastnote->ntime;        /* 1 */
+    double phrdur = 0.0;
+    int cnt = 0;
+    noteptr thisnote = *phrasenote;
+    while(thisnote!=(noteptr)0) {               /* 2 */
+        phrdur = (endtime - thisnote->ntime) * multiplier;  /* 3 */
+        if(*thistime - phrdur >= 0.0)           /* 4 */
+            break;
+        cnt++;                                  /* 5 */
+        thisnote = thisnote->next;
+    }
+    if(thisnote==(noteptr)0) {
+        *gpsize = 0;                            /* 6 */
+        return;
+    } else {
+        *thistime -= phrdur;                    /* 7 */
+        *phrasenote = thisnote;                 /* 8 */
+        *timeadjust = thisnote->ntime;          /* 9 */
+    }
+    *gpsize -= cnt;
+    return;                                     /* 10 */
+}
+
+/*************************** GETMTFAMPSTEP ******************************
+ *
+ * Select flat, cresc or decresc, from available types, for motifs.
+ *
+ * (0)  If the amplitude is bigger than the size of amprise and the
+ *  range of the phrase, taken together, amprise is OK as it is.
+ * (00) Otherwise, amprise (set as ampstep at this point) is the amount
+ *  of the total amplitude left when the amplitude range of the phrase
+ *  has been subtracted. This ensures that no note of the phrase
+ *  can possibly end up below zero.
+ * (1)  IF the cresc will be from zero, clrzamp is 1, and this makes
+ *  the amplitude steps a little smaller, so that 1 of the notes
+ *  in sequence cannot be at amplitude zero.
+ *  OTHERWISE, clrzamp = 0,  and ampstep is as normal.
+ */
+
+int getmtfampstep(double amp,double framp,double *ampstep,unsigned char *amptype,
+unsigned char amptypestor,unsigned char amptypecnt,int gpsize,dataptr dz)
+{
+    int exit_status;
+    int clrzamp = 0;
+    int k;
+    if((exit_status = doperm((int)amptypecnt,PM_GPCNTR,&k,dz))<0)
+        return(exit_status);
+    if((exit_status=gettritype(k,amptypestor,amptype))<0)
+        return(exit_status);
+    if(*amptype==FLAT) {        /**** FLAT *****/
+        *ampstep =0.0;  
+    } else {
+        if(amp>(dz->param[TEX_AMPRISE] + framp)) /* 0 */
+            *ampstep = dz->param[TEX_AMPRISE];
+        else {
+            *ampstep = amp - framp;         /* 00 */
+            clrzamp = 1;
+        }
+        *ampstep /= (double)(gpsize+clrzamp);       /* 1 */
+        if(*amptype==DECRESC)       /** DECRESCENDO **/
+            *ampstep = -(*ampstep);
+    }
+    return(FINISHED);
+}
+
+/************************************************************************
+ *
+ * Calculating spatial orientation of motifs,groups,ornaments,decorations.
+ */
+
+/**************************** SETSPACE *******************************/
+
+int setspace(noteptr tsetnote,noteptr thisnote,int gpsize,dataptr dz)
+{
+    int exit_status;
+    if(dz->iparam[TEX_GPSPACE]!=IS_STILL) {
+        if((exit_status = space_gpnote(thisnote,gpsize,dz))<0)
+            return(exit_status);
+    } else
+        thisnote->spacepos = tsetnote->spacepos;
+    return(FINISHED);
+}
+
+/***************************** SPACE_GPNOTE *******************************
+ *
+ * (1)  OUTSIDE THE GROUP- OR PHRASE-MAKING LOOP
+ *  (a) Need to know gpsize, dectype(is_post?), gpsprange 
+ *      (which MUST be +ve!).
+ *  (b) Need to run 'init_group_spatialisation()' to establish spinit, & hence
+ *      range modifications etc.
+ *
+ *  Then this will work INSIDE the loop.
+ *
+ * (1)  NB !!!!! is_pre is defaulted to ZERO. This means that groups
+ *  or motifs which CANNOT BE pre- or post- are defaulted to
+ *  post (which means the groups start on the tset notes, rather
+ *  leading up to them).
+ */
+
+int space_gpnote(noteptr thisnote,int gpsize,dataptr dz)
+{
+    int exit_status;
+    if(dz->iparam[TEX_GPSPACE]==IS_SCATTER) {
+        if((exit_status = sp_scatter(thisnote,dz))<0)
+            return(exit_status);
+    } else {
+        if(dz->vflag[IS_PRE]) {             /* 1 */
+            if((exit_status = pre_place(thisnote,gpsize,dz))<0)
+                return(exit_status);
+        } else {
+            if((exit_status = post_place(thisnote,gpsize,dz))<0)
+                return(exit_status);
+        }
+    }
+    dz->iparam[SPINIT] = 0;     /* disable initialisation after first call to group */
+    return(FINISHED);
+}
+
+/**************************** SP_SCATTER *************************
+ *
+ * scatter group note around position of main event.
+ */
+
+int sp_scatter(noteptr mnote,dataptr dz)
+{
+    int exit_status;
+    double sptop = 1.0, spbot= 0.0, hfthissprange,val;
+    if(dz->param[THISSPRANGE]<=0.0) {     
+        mnote->spacepos = (float)dz->param[TPOSITION];
+        return(FINISHED);
+    }
+    if(dz->iparam[SPINIT]) {
+        hfthissprange = dz->param[THISSPRANGE]/(double)2.0;
+        spbot = max((dz->param[TPOSITION] - hfthissprange),0.0);
+        sptop = min((dz->param[TPOSITION] + hfthissprange),1.0);
+        dz->param[THISSPRANGE] = sptop - spbot;
+    }                                   
+    if((exit_status = pscatx(dz->param[THISSPRANGE],spbot,PM_GPSPAC,&val,dz))<0)
+        return(exit_status);
+    mnote->spacepos      = (float)val;
+    return(FINISHED);
+} 
+
+/************** MACROS FOR RANGE REORIENTATIONS AND TRUNCATIONS **************
+ *
+ *  r = group spatial range     p = position of event
+ *  c = centre of motion        d = direction of motion
+ *
+ * (1)  If position to left  of centre, reverse range.
+ * (2)  If position to right of centre, reverse range.
+ * (3)  If no motion, zero the range.
+ * (4)  If motion is right to left reverse range.
+ * (5)  If motion is left to right reverse range.
+ * (6)  avoid centre crossing
+ * (7)  avoid right-edge crossing
+ * (8)  avoid left-edge crossing
+ * (9)  avoid edge crossing
+ */
+
+#define TURNOUTWARD(r,p,c) if((p)-(c)<0.0)  (r) = -(r);                     /* 1 */
+#define TURNINWARD(r,p,c)  if((p)-(c)>0.0)  (r) = -(r);                     /* 2 */
+#define CHECKSTIL(r,d)     if((d)==0) (r) = 0.0;                            /* 3 */
+#define FOLLOW(r,d)        CHECKSTIL(r,d) else { if((d)<0) (r) = -(r); }    /* 4 */
+#define CONTRARY(r,d)      CHECKSTIL(r,d) else { if((d)>0) (r) = -(r); }    /* 5 */
+#define SET_PRE_INRANGE(r,p,c) if(p<c) r = min(p,r); else r = max(p-1.0,r);
+
+
+#define FREECENTRE(r,p,c)  if((r)>fabs((p)-(c))) (r)=fabs((p)-(c));         /* 6 */
+#define FREEREDGE(r,p)     if((p)+(r)>1.0) (r) = 1.0 - (p);                 /* 7 */
+#define FREELEDGE(r,p)     if((p)+(r)<0.0) (r) = -(p);                      /* 8 */
+#define FREEEDGES(r,p)     if((r)>=0.0) { FREEREDGE((r),(p)) } else { FREELEDGE((r),(p)) }
+                                                                            /* 9 */
+
+#define FREEREDGE_PRE(r,p) if((p)-(r)>1.0) (r) = (p) - 1.0;                 /* 7 */
+#define FREELEDGE_PRE(r,p) if((p)-(r)<0.0) (r) = (p);                       /* 8 */
+#define FREEEDGES_PRE(r,p) if((r)>=0.0) { FREELEDGE_PRE((r),(p)) } else { FREEREDGE_PRE((r),(p)) }
+                                                                            /* 9 */
+/************************* PRE_PLACE *****************************
+ *
+ * place-in-space ornaments or decorations BEFORE notes, or motifs or groups
+ * at texture points.
+ *
+ * is_pre = 1.
+ */
+
+int pre_place(noteptr thisnote,int gpsize,dataptr dz)
+{
+    if(dz->iparam[SPINIT])
+        dz->iparam[SPCNT] = 0;
+
+    switch(dz->iparam[TEX_GPSPACE]) {
+        case(IS_STILL):
+            dz->param[THISSPRANGE] = 0.0;
+            break;
+        case(IS_INWARD):
+            if(dz->iparam[SPINIT]) {
+                TURNINWARD(dz->param[THISSPRANGE],dz->param[TPOSITION],dz->param[CPOS])
+                SET_PRE_INRANGE(dz->param[THISSPRANGE],dz->param[TPOSITION],dz->param[CPOS])
+
+            }
+            break;
+        case(IS_OUTWARD):
+            if(dz->iparam[SPINIT]) {
+                FREECENTRE(dz->param[THISSPRANGE],dz->param[TPOSITION],dz->param[CPOS])
+                TURNOUTWARD(dz->param[THISSPRANGE],dz->param[TPOSITION],dz->param[CPOS])
+            }
+            break;
+        case(IS_FOLLOWING):
+            if(dz->iparam[SPINIT]) {
+                FOLLOW(dz->param[THISSPRANGE],dz->iparam[DIRECTION])
+                FREEEDGES_PRE(dz->param[THISSPRANGE],dz->param[TPOSITION])
+            }
+            break;
+        case(IS_CONTRARY):
+            if(dz->iparam[SPINIT]) {
+                CONTRARY(dz->param[THISSPRANGE],dz->iparam[DIRECTION])
+                FREEEDGES_PRE(dz->param[THISSPRANGE],dz->param[TPOSITION])
+            }
+            break;
+        default:
+        sprintf(errstr,"TEXTURE: Invalid space-type %d in pre_place()\n",dz->iparam[TEX_GPSPACE]);
+        return(PROGRAM_ERROR);
+    }
+    thisnote->spacepos = (float)(dz->param[TPOSITION] - dz->param[THISSPRANGE]
+                     + ((dz->param[THISSPRANGE]/(double)gpsize)*(double)(dz->iparam[SPCNT])));
+    dz->iparam[SPCNT]++;
+    return(FINISHED);
+}
+           
+/************************* POST_PLACE *****************************
+ *
+ * place-in-space ornaments or decorations AFTER notes, or motifs or groups
+ * at texture points.
+ *
+ * is_pre = 0, (or no ornament). 
+ */
+
+int post_place(noteptr thisnote,int gpsize,dataptr dz)
+{
+    if(dz->iparam[SPINIT])
+        dz->iparam[SPCNT] = 1;
+    switch(dz->iparam[TEX_GPSPACE]) {
+    case(IS_STILL):
+        dz->param[THISSPRANGE] = 0.0;
+        break;
+    case(IS_INWARD):
+        if(dz->iparam[SPINIT]) {
+            FREECENTRE(dz->param[THISSPRANGE],dz->param[TPOSITION],dz->param[CPOS])
+            TURNINWARD(dz->param[THISSPRANGE],dz->param[TPOSITION],dz->param[CPOS])
+        }
+        break;
+    case(IS_OUTWARD):
+        if(dz->iparam[SPINIT]) {
+            TURNOUTWARD(dz->param[THISSPRANGE],dz->param[TPOSITION],dz->param[CPOS])
+            FREEEDGES(dz->param[THISSPRANGE],dz->param[TPOSITION])
+        }
+        break;
+    case(IS_FOLLOWING):
+        if(dz->iparam[SPINIT]) {
+            FOLLOW(dz->param[THISSPRANGE],dz->iparam[DIRECTION])
+            FREEEDGES(dz->param[THISSPRANGE],dz->param[TPOSITION])
+        }
+        break;
+    case(IS_CONTRARY):
+        if(dz->iparam[SPINIT]) {
+            CONTRARY(dz->param[THISSPRANGE],dz->iparam[DIRECTION])
+            FREEEDGES(dz->param[THISSPRANGE],dz->param[TPOSITION])
+        }
+        break;
+    default:
+        sprintf(errstr,"TEXTURE: Invalid space-type %d in post_place()\n",dz->iparam[TEX_GPSPACE]);
+        return(PROGRAM_ERROR);
+    }
+    thisnote->spacepos = (float)(dz->param[TPOSITION] + 
+    ((dz->param[THISSPRANGE]/(double)gpsize)*(double)(dz->iparam[SPCNT])));
+    dz->iparam[SPCNT]++;
+
+    return(FINISHED);
+}
+
+/************************** GPSP_INIT ***********************************
+ *
+ * Initialise the space-param for each group, before calling the spatialise
+ * routines. 'spinit' causes initialisation of range etc elsewhere (in
+ * pre_place() or post_place() ).
+ */
+
+int init_group_spatialisation(noteptr tsetnote,int shaddoindex,noteptr *shadow,int shadowsize,dataptr dz)
+{
+    int exit_status;
+    dz->iparam[SPINIT] = 1;
+    dz->param[TPOSITION] = tsetnote->spacepos;
+    dz->param[CPOS]      = tsetnote->motioncentre;
+    if(dz->brksize[TEX_GRPSPRANGE]) { /* TABLE VALUES MUST BE 0 - 1 */
+        if((exit_status = read_value_from_brktable((double)tsetnote->ntime,TEX_GRPSPRANGE,dz))<0)
+            return(exit_status);
+    }
+    if(IS_DIRECTED(dz->iparam[TEX_GPSPACE]))
+        dz->iparam[DIRECTION] = read_direction(shaddoindex,shadow,shadowsize);
+    dz->param[THISSPRANGE] = dz->param[TEX_GRPSPRANGE];
+    return(FINISHED);
+}
+
+/**************************** READ_DIRECTION ****************************
+ *
+ * Read direction of motion from spatial position stored in note.
+ *
+ * NB: as the tset is in the process of being modified, we cannot
+ * refer directly to the tset linked list. We can only access the original
+ * tset through it's 'shadow'.
+ *
+ * (0)  Save the time of the current note as 'now'.
+ * (1)  Save position of current note as 'here'.
+ * (2)  Whilever we're not at the end of the tset (shadow).
+ * (a)  Note time of next note, store as 'then'.
+ * (b)  If 'then' is later than 'now'.
+ *      Note position of new note as 'there'.
+ *      Set as OK and break out of loop.
+ * (3)  If it's not OK (i.e. we were at, or came to the end of the tset 
+ *      (shadow))....
+ * (a)  Go back to where we started.
+ * (b)  Call this position 'there'.
+ * (4)  While ever we're not at beginning of tset...
+ * (a)  Note time of previous note, store as 'then'.
+ * (b)  If 'then' is 'earlier' than 'now'...
+ *      Note position of new note as 'here'.
+ *      Set as OK and break out of loop.
+ * (5)  If still not OK, then there is no more than 1 (non-simultaneous)
+ *      event in the tset, so therefore no motion, so return 0.
+ * (6)  If there>here, left-to-right motion, return 1.
+ * (7)  If here>there, right-to-left motion, return -1.
+ * (8)  Otherwise, no motion, return 0.
+ */
+
+int read_direction(int shi,noteptr *shadow,int shadowsize)
+{
+    unsigned char OK;
+    float here, there = 0.0;
+    double now, then;
+    int startshi = shi;
+    now  = (shadow[shi])->ntime;            /* 0 */
+    here = (shadow[shi])->motioncentre;     /* 1 */
+    OK = 0;
+    while(++shi<shadowsize) {           /* 2 */
+        then = (shadow[shi])->ntime;        /* a */
+        if(then>(now+FLTERR)) {         /* b */
+            there = (shadow[shi])->motioncentre;
+            OK = 1;
+            break;
+        }
+    }
+    if(!OK) {                   /* 3 */
+        shi = startshi;             /* a */
+        there = here;               /* b */
+        while(--shi>=0) {           /* 4 */
+            then = (shadow[shi])->ntime;        /* a */
+            if(then<(now-FLTERR)) {     /* b */
+                here = (shadow[shi])->motioncentre;
+                OK = 1;
+                break;
+            }
+        }
+    }       
+    if(!OK)
+        return(0);              /* 5 */
+    if(there>here)              /* 6 */
+        return(1);
+    if(there<here)              /* 7 */
+        return(-1);
+    return(0);                  /* 8 */
+}
+
+/*************************** GETAMPSTEP ******************************
+ *
+ * Select flat, cresc or decresc, from available types.
+ *
+ * (1)  IF the cresc will be from zero, clrzamp is 1, and this makes
+ *  the amplitude steps a little smaller, so that 1st note in sequence
+ *  will not be at amplitude zero.
+ *  OTHERWISE, clrzamp = 0,  and ampstep is as normal.
+ */
+
+int getampstep
+(double *ampstep,double amp,unsigned char *amptype,int gpsize,unsigned char amptypecnt,
+unsigned char amptypestor,dataptr dz)
+{
+    int exit_status;
+    int clrzamp = 0, k;
+    /*int texflag = dz->tex->txflag;*/
+    if((exit_status = doperm((int)amptypecnt,PM_GPCNTR,&k,dz))<0)
+        return(exit_status);
+    if((exit_status = gettritype(k,amptypestor,amptype))<0)
+        return(exit_status);
+
+    if(*amptype==FLAT)      /**** FLAT *****/
+        *ampstep =0.0;  
+    else {                                                              
+        *ampstep = dz->param[TEX_AMPRISE]; /* param with <|> option */
+                                                                    
+        if(*ampstep>=amp) {                                         
+            clrzamp  = 1;                                           
+            *ampstep = amp;                                         
+        }
+        *ampstep /= (double)(gpsize + clrzamp);     /* 1 */
+        if(*amptype==DECRESC)       /** DECRESCENDO **/
+            *ampstep = -(*ampstep);
+    }
+    return(FINISHED);
+}
+
+/*************************** GETDIRAMPSTEP ******************************
+ *
+ * (1)  If there are two amplitude types, in THIS CASE, these can only
+ *      be DIRECTED or FLAT. So...
+ *   (2)  Choose flat or directed via perm.
+ *   (3)  and if it's flat, return an ampstep of zero.
+ *    Otherwise, we proceed as in the normal case of a directed amp.
+ * (4)  Set initial ampstep to amprise.
+ * (5)  IF the cresc will be from zero, or decresc to zero,  clrzamp is 1,
+ *      and this makes the amplitude steps a little smaller, so that 1st note
+ *      of cresc (or last note of decresc) will not be at amplitude zero.
+ *      OTHERWISE, clrzamp = 0,  and ampstep is as normal.
+ * (6)  Divide ampstep by number of members in group.
+ * (7)  If it's a post-ornament, ampstep is negative.
+ */
+
+int getdirampstep
+(double amp,unsigned char amptypecnt,double *ampstep,int gpsize,dataptr dz)
+{
+    int exit_status;
+    int k, clrzamp = 0;
+    if(amptypecnt==2) {                                 /* 1 */
+        if((exit_status= doperm((int)2,PM_GPCNTR,&k,dz))<0) /* 2 */
+            return(exit_status);
+        if(k==0) {
+            *ampstep = 0.0;
+            return(FINISHED);                           /* 3 */
+        }
+    }
+    *ampstep = dz->param[TEX_AMPRISE];  /* param with <|> option */             /* 4 */
+    if(*ampstep>=amp) {                                 /* 5 */
+        clrzamp = 1;
+        *ampstep = amp;
+    }
+    *ampstep /= (double)(gpsize + clrzamp);             /* 6 */
+    if(!dz->vflag[IS_PRE])                              /* 7 */
+        *ampstep = -(*ampstep);
+
+    return(FINISHED);
+}
+
+/*************************** GETMTFDIRAMPSTEP *******************************
+ *
+ *  Intelligent guesswork!! Nov 4: 1997
+ */
+
+int getmtfdirampstep(double amp,double framp,unsigned char amptypecnt,double *ampstep,int gpsize,dataptr dz)
+{
+    int exit_status;
+    int k, clrzamp = 0;
+    if(amptypecnt==2) {                                 /* 1 */
+        if((exit_status= doperm((int)2,PM_GPCNTR,&k,dz))<0) /* 2 */
+            return(exit_status);
+        if(k==0) {
+            *ampstep = 0.0;
+            return(FINISHED);                           /* 3 */
+        }
+    }
+    if(amp>(dz->param[TEX_AMPRISE] + framp))
+         *ampstep = dz->param[TEX_AMPRISE];
+    else {
+        *ampstep = amp - framp; 
+        clrzamp = 1;
+    }
+    *ampstep /= (double)(gpsize + clrzamp);             /* 6 */
+    if(!dz->vflag[IS_PRE])                              /* 7 */
+        *ampstep = -(*ampstep);
+
+    return(FINISHED);
+}
+
+/*************************  GET_DEC_OR_ORN_POS ***************************
+ *
+ * Decuptype flags are selected and shifted down into the range 0-3
+ * If its 01 (1), it's a post-ornament, so set 'is_pre' = FALSE.
+ * If its 10 (2), it's a pre_ornament,  so set 'is_pre' = TRUE
+ * If its 00 (0), it's not set, so we select 'is_pre' at random using doperm on 2 (output 0S or 1).
+ *
+ * NB: If we are using a group or motif, rather than a decoration
+ *  or ornament, is_pre is BY DEFAULT set to 0.
+ */
+
+int get_dec_or_orn_pos(dataptr dz)
+{
+    int exit_status;
+    int k;
+    unsigned int dectype = dz->tex->txflag & GET_DECORNPOS;
+    switch(dectype) {
+    case(1): dz->vflag[IS_PRE] = TRUE;  break;
+    case(2): dz->vflag[IS_PRE] = FALSE; break;
+    default:
+        if((exit_status = doperm((int)2,PM_ORNPOS,&k,dz))<0)
+            return(exit_status);
+        dz->vflag[IS_PRE] = (char)k;        
+        break;
+    }
+    if(dz->vflag[IS_PRE] > 1) {
+        sprintf(errstr,"Error from perm in  get_dec_or_orn_pos()\n");
+        return(PROGRAM_ERROR);
+    }
+    return(FINISHED);
+}
+
+/**************************** SUBZERO ***********************************
+ *
+ * If start of a decoration falls before time zero, adjust its size
+ * and hence starttime(-minus-gpdense) appropriately.
+ */
+
+int subzero(double *thistime,double gpdense,int *gpsize)
+{
+    int n = -1;
+    while(*thistime>=0.0) {
+        *thistime -= gpdense;
+        n++;
+    }
+    if(n<0) {
+        sprintf(errstr,"TEXTURE: Problem in subzero()\n");
+        return(PROGRAM_ERROR);
+    }
+    *gpsize = n;
+    return(FINISHED);
+}
+
+/*************************** GETHIPITCH *********************************#
+ *
+ * Find highest pitch at current time.
+ */
+
+noteptr gethipitch(noteptr tsetnote,int *shaddoindex)
+{
+    noteptr hinote, thisnote;
+    double hipitch;
+    int zz = *shaddoindex;
+    hinote = thisnote = tsetnote;
+    hipitch = (double)hinote->pitch;
+    while(thisnote->next!=(noteptr)0) {
+        if(thisnote->next->ntime > thisnote->ntime + FLTERR)
+            return(hinote);
+        thisnote = thisnote->next;
+        zz++;
+        if((double)thisnote->pitch > hipitch) {
+            hipitch = (double)thisnote->pitch;
+            hinote  = thisnote;
+            (*shaddoindex) = zz;
+        }
+    }
+    return(hinote);
+}
+
+/****************************** DO_GRP_INS **********************************
+ *
+ * Choose instr-no within group/decoration/motif or ornament.
+ * Values of instr-no range are preset when instr is chosen for the
+ * tset, in do_ev_ins().
+ */
+
+int do_grp_ins(unsigned char thisinstr,unsigned char *val,dataptr dz)
+{
+    int exit_status;
+    int irange, ival;
+    if(dz->vflag[INS_TO_SCATTER]) {
+        if((irange = (int)(dz->iparam[TEXTURE_INSHI] - dz->iparam[TEXTURE_INSLO])) < 0) {
+            iswap((int *)&(dz->iparam[TEXTURE_INSHI]),(int *)&(dz->iparam[TEXTURE_INSLO]));
+            irange = -irange;
+        }
+        if(irange==0)
+            *val = (unsigned char)dz->iparam[TEXTURE_INSLO];
+        else {
+            if((exit_status = doperm(irange+1,PM_INSNO,&ival,dz))<0)    /* range INCLUSIVE for ints */
+                return(exit_status);
+            *val = (unsigned char)(ival + dz->iparam[TEXTURE_INSLO]);
+        }
+    } else
+        *val = thisinstr;
+    return(FINISHED);
+}
+
+/***************************** PSCATX ************************************
+ *
+ * Select a random value within 'range', by permuting one of BANDCNT equal
+ * ranges, and selecting a random value within the chosen range.
+ */
+
+int pscatx(double range,double bottom,int pindex,double *val,dataptr dz)
+{
+    int k, exit_status;
+    double bandwidth, bandbottom, x;
+    if((exit_status = doperm((int)BANDCNT,pindex,&k,dz))<0)
+        return(exit_status);
+    bandwidth   = range/(double)BANDCNT;
+    bandbottom  = (double)k * bandwidth;
+    x  = (drand48() * bandwidth);
+    x += bandbottom;
+    *val = x + bottom;
+    return(FINISHED);
+}
+
+/*************************** DEL_NOTE ************************************/
+
+void del_note(noteptr thisnote,motifptr thismotif)
+{
+    if(thisnote->next!=(noteptr)0)
+        thisnote->next->last = thisnote->last;      /* 1 */
+    if(thisnote->last!=(noteptr)0)
+        thisnote->last->next = thisnote->next;      /* 2 */
+    else
+        thismotif->firstnote = thisnote->next;      /* 3 */
+    free(thisnote);                 /* 4 */
+}
+    
+/************************** TIMESORT ****************************
+ *
+ * Timesorts notes in a list
+ *
+ * (1)  Move the item with earliest time to start of list, and set this
+ *      (minimum) time as maximum time also.
+ *  For each item in the list....
+ *   (2)   If this item is earlier than current latest item (maxtime)..
+ *     (3)    Find where it should be in the list.
+ *     (4)    move it to that location.
+ *   (5)   Otherwise, set this item's time as latest time(maxtime).
+ * (6)  Reset motifhead to start of notelist!!
+ */
+
+int arrange_notes_in_timeorder(motifptr mtf)
+{
+    noteptr base, here, there, mark;
+    double thistime, maxtime;
+    if((base = mtf->firstnote)==(noteptr)0)
+        return(FINISHED);
+    maxtime = setup_first_notelist_time(&base);         /* 1 */
+    here = base;
+    while(here!=(noteptr)0) {
+        if((thistime = here->ntime) < maxtime) {        /* 2 */
+            if((mark = here->last)==(noteptr)0) {
+                sprintf(errstr,"Problem (1) in arrange_notes_in_timeorder()\n");
+                return(PROGRAM_ERROR);
+            }
+            if((there = reverse_search_for_time(here,thistime))==(noteptr)0) {
+                sprintf(errstr,"Timing problem in arrange_notes_in_timeorder()\n");
+                return(PROGRAM_ERROR);
+            }                       /* 3 */
+            move_notelist_item(here,there);         /* 4 */
+            here = mark;
+        } else
+            maxtime = here->ntime;          /* 5 */
+        here = here->next;
+    }
+    return reset_mtfhead(mtf);                  /* 6 */
+}
+
+/************************* RESET_MTFHEAD ***************************
+ *
+ * Reset pointer to start of notelist.
+ */
+ 
+int reset_mtfhead(motifptr mtf)
+{
+    noteptr here = mtf->firstnote;
+    if(mtf->firstnote==NULL) {
+        sprintf(errstr,"Problem in reset_mrfhead()\n");
+        return(PROGRAM_ERROR);
+    }
+    while(here->last!=(noteptr)0)
+        here = here->last;
+    mtf->firstnote = here;
+
+    return(FINISHED);
+}
+
+/************************** SETUP_FIRST_NOTELIST_TIME ***************************
+ *
+ * Put the earliest timed item in a list of notes into start of list.
+ */
+
+double setup_first_notelist_time(noteptr *base)
+{
+    noteptr firstnote, here;
+    double  mintime, thistime;
+    firstnote = here = *base;
+    mintime   = (*base)->ntime;
+    while(here!=(noteptr)0) {
+        if((thistime = here->ntime)<mintime) {
+            firstnote = here;
+            mintime = thistime;
+        }
+        here = here->next;
+    }
+    if(firstnote!=(*base)) {
+        move_notelist_item(firstnote,(*base));
+        *base = firstnote;
+    }
+    return(mintime);
+}
+
+/************************* MOVE_NOTELIST_ITEM ***************************
+ *
+ * Move an item in a notelist from location a to BEFORE location b.
+ */
+
+void move_notelist_item(noteptr a,noteptr b)
+{
+    if(a->last!=(noteptr)0)
+        a->last->next = a->next;
+    if(a->next!=(noteptr)0)
+        a->next->last = a->last;
+    a->next = b;
+    a->last = b->last;
+    if(b->last!=(noteptr)0)
+        b->last->next = a;
+    b->last = a;
+}
+
+/************************** REVERSE_SEARCH_FOR_TIME *****************************
+ *
+ * Reverse search note-list using a time as index, and return address
+ * of note whose time is AFTER the input time. 
+ * WILL RETURN (noteptr)0 IF REFTIME IS OFF END OF LIST.
+ */
+
+noteptr reverse_search_for_time(noteptr start,double reftime)
+{
+    noteptr here = start;
+    while(here->ntime >= reftime) {
+        if(here->last == (noteptr)0)
+            return(here);
+        here = here->last;
+    }
+    return(here->next); 
+}
+
+/************************** ISWAP *****************************/
+
+void iswap(int *a,int *b)
+{
+    int temp;
+    temp = *a;
+    *a = *b;
+    *b = temp;
+}
+
+/****************************** SET_GROUP_PARAMS **********************************/
+
+int set_group_params
+(noteptr tsetnote,noteptr thisnote,double gpdense,double ampstep,double *thisamp,double *thistime,double thisdur,dataptr dz)
+{
+    int exit_status;
+    double thisgpdense, time_left;
+    *thisamp += ampstep;
+    thisnote->amp   = (float)*thisamp;
+    thisnote->dur   = (float)thisdur;
+    if(dz->vflag[FIXED_STEP])
+        *thistime += gpdense;
+    else {
+        if((exit_status = get_density_val(*thistime,&thisgpdense,dz))<0)
+            return(exit_status);
+        if((dz->tex->txflag & IS_DECOR) && dz->vflag[IS_PRE]) {
+            if((time_left = tsetnote->ntime - *thistime)<0.0) {
+                sprintf(errstr,"Error in assumptions: set_group_params()\n");
+                return(PROGRAM_ERROR);
+            }
+            time_left *= 0.66;
+            thisgpdense = min(time_left,thisgpdense);
+        }
+        *thistime += thisgpdense;
+    }
+    return(FINISHED);
+}
+
+/***************************** GETTRITYPE *****************************
+ *
+ * Choose a type, from up to three available types in bit-flag.
+ * e.g.
+ * Choose an amplitude type (flat,cresc,decresc) from 3 available types.
+ * Choose a decoration-orientation type (above,below,mid) from 3 types.
+ *
+ * (1)  For each type in the bitflag.
+ * (2)  If this option is flagged, count it.
+ * (3)  IF this option is chosen, return its bit-number.
+ * (4)  Advance the bitflag mask.
+ */
+
+int gettritype(int k,unsigned stor,unsigned char *val)
+{
+    int v = 0, mask = 1, n;
+    k++;
+    for(n=0;n<3;n++) {              /* 1 */
+        if(mask & stor)             /* 2 */
+            v++;
+        if(k==v) {              /* 3 */
+            *val = (unsigned char)n;
+            return(FINISHED);
+        }
+        mask <<= 1;             /* 4 */
+    }
+    sprintf(errstr,"TEXTURE: Problem in gettritype()\n");
+    return(PROGRAM_ERROR);
+}
+
+/***************************  GET_DENSITY_VAL ******************************/
+
+int get_density_val(double thistime,double *gpdense,dataptr dz)
+{
+    int exit_status;
+    if((exit_status = getvalue(TEX_GPPACKHI,TEX_GPPACKLO,thistime,PM_GPDENS,gpdense,dz))<0)
+        return(PROGRAM_ERROR);
+
+/* NEW MAR 2000 */
+    *gpdense *= MS_TO_SECS;
+
+    if(dz->param[TEX_PHGRID]>0.0)
+        *gpdense = quantise(*gpdense,dz->param[TEX_PHGRID]);
+
+    return FINISHED;
+}
+
+/**************************** SET_MOTIFS *******************************
+ *
+ * initialise all parameters of input motifs to be used for MOTIFS or
+ * ORNAMENTS.
+ *
+ * (1)For each input motif (called a 'phrase').
+ *    phrnotecnt[n] = 0;
+ * (2)  Initialise count of number of notes to 0, maximum amplitude
+ *  of phrase to 0.0, and lowest pitch to MIDITOP.
+ * (3)  Go through each note of the motif.
+ * (4)  Add up the number of notes in it.
+ * (5)  Find it's lowest pitch.
+ * (6)  Find it's loudest note (and set as phraseamp).
+ * (7)  Establish dynamic range of phrase.
+ * (8)  Transpose the motif into it's lowest possible register.
+ * (9)  Ensure motif starts at zero time.
+ * (10) Store addresses of last notes in phrases.
+ */
+
+int set_motifs
+(int phrcount,motifptr *phrase,int *phrnotecnt,double *phraseamp,double *phrange,noteptr *phrlastnote)
+{
+    int exit_status;
+    int n;
+    double minpitch, mintime, minamp;
+    noteptr thisnote, lastnote = (noteptr)0;
+    for(n=0;n<phrcount;n++) {                       /* 1 */
+        if((exit_status = arrange_notes_in_timeorder(phrase[n]))<0)
+            return(exit_status);
+        phrnotecnt[n] = 0;
+        phraseamp[n] = 0.0;                         /* 2 */
+        minamp   = DBL_MAX;
+        minpitch = MIDITOP;
+        mintime  = DBL_MAX;
+        thisnote = phrase[n]->firstnote;            /* 3 */
+        while(thisnote!=(noteptr)0) {
+            phrnotecnt[n]++;                            /* 4 */
+            if(thisnote->pitch<minpitch)
+                minpitch = thisnote->pitch;         /* 5 */
+            if(thisnote->ntime<mintime)
+                mintime  = thisnote->ntime;         /* 5 */
+            if((double)thisnote->amp>phraseamp[n])
+                phraseamp[n] = (double)thisnote->amp;/* 6 */
+            if(thisnote->amp<minamp)
+                minamp = thisnote->amp;             /* 6 */
+            thisnote = thisnote->next;
+        }
+        if(minamp  == DBL_MAX || mintime == DBL_MAX) {
+            sprintf(errstr,"Error parsing motif: set_motifs()\n");
+            return(PROGRAM_ERROR);
+        }
+        thisnote = phrase[n]->firstnote;
+        phrange[n] = phraseamp[n] - minamp;         /* 7 */
+        while(thisnote!=(noteptr)0) {
+            thisnote->pitch = (float)(thisnote->pitch - (minpitch + MIDIBOT));  /* 8 */
+            thisnote->ntime = (float)(thisnote->ntime - mintime);               /* 9 */
+            lastnote = thisnote;                                                /* 10 */
+            thisnote = thisnote->next;
+        }
+        if((phrlastnote[n] = lastnote) == (noteptr)0) {
+            sprintf(errstr,"Zero length phrase encountered: set_motifs()\n");
+            return(PROGRAM_ERROR);
+        }
+    }
+    return(FINISHED);
+}
+
+void cyclicperm(dataptr dz) 
+{
+    int n, t;
+    do {
+        for(n=0;n<dz->infilecnt;n++) {
+            t = (int)floor(drand48() * (n+1));
+            if(t==n) {
+                hprefix(n,dz->peakno,dz->infilecnt);
+            } else {
+                hinsert(n,t,dz->peakno,dz->infilecnt);
+            }
+        }
+    } while(dz->peakno[0] == dz->lastpeakno[dz->infilecnt - 1]);    // Avoid repetitions at perm boundaries.
+    for(n=0;n<dz->infilecnt;n++)
+        dz->lastpeakno[n] = dz->peakno[n];
+}
+
+void hinsert(int m,int t,int *perm,int permlen)
+{
+    hshuflup(t+1,perm,permlen);
+    perm[t+1] = m;
+}
+
+void hprefix(int m,int *perm,int permlen)
+{
+    hshuflup(0,perm,permlen);
+    perm[0] = m;
+}
+
+void hshuflup(int k,int *perm,int permlen)
+{
+    int n, *i;
+    int z = permlen - 1;
+    i = perm+z;
+    for(n = z;n > k;n--) {
+        *i = *(i-1);
+        i--;
+    }
+}
+
+#ifndef round
+
+int round(double a)
+{
+    return (int)floor(a + 0.5);
+}
+#endif

+ 627 - 0
dev/texture/texture5.c

@@ -0,0 +1,627 @@
+/*
+ * Copyright (c) 1983-2013 Trevor Wishart and Composers Desktop Project Ltd
+ * http://www.trevorwishart.co.uk
+ * http://www.composersdesktop.com
+ *
+ This file is part of the CDP System.
+ 
+ The CDP System is free software; you can redistribute it
+ and/or modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+ 
+ The CDP System is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU Lesser General Public License for more details.
+ 
+ You should have received a copy of the GNU Lesser General Public
+ License along with the CDP System; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA
+ *
+ */
+/* floatsam version */
+#include <stdio.h>
+#include <stdlib.h>
+#include <memory.h>         /*RWD*/
+#include <structures.h>
+#include <tkglobals.h>
+#include <globcon.h>
+#include <processno.h>
+#include <modeno.h>
+#include <arrays.h>
+#include <texture.h>
+#include <cdpmain.h>
+
+#include <sfsys.h>
+#ifdef _DEBUG
+#include <assert.h>
+#endif
+
+#if defined unix || defined __GNUC__
+#define round(x) lround((x))
+#endif
+
+static int setup_splice(int st_splicecnt,double **splicebuf);
+static int generate_origdur_and_frq(double **origdur,double **origfrq,dataptr dz);
+static int init_soundout_set(sndoutptr *sndout);
+static int replace_tset_by_soundout_set(noteptr thisnote,sndoutptr *sndout,
+            double *origdur,double *origfrq,double  mindur,int st_splicecnt,dataptr dz);
+static int convert_tsetnote_to_sndout_item(noteptr thisnote,sndoutptr sndout,
+            double *origdur,double *origfrq,double mindur,int st_splicecnt,int *warning_set,dataptr dz);
+static int generate_previous_sndout(sndoutptr *sndout);
+static int get_thisdur(double *thisdur,noteptr thisnote,int thisins,
+            double *origdur,double inv_trnsp,double mindur,dataptr dz);
+static int get_stereospace_compensation(double position,double *compensate);
+
+static int do_mix(sndoutptr sndout,double *splicebuf,dataptr dz);
+static int check_sequencing(sndoutptr sndout);
+static int add_samples_to_outbuf_from_inbuf(int *out_of_insamples,int * max_samp_written,
+            sndoutptr sndout,double *splicebuf,int splicelen,/*int*/float *lbuf,dataptr dz);
+static void unlink_sndoutptr_at_start_of_list(sndoutptr sndout);
+static void unlink_sndoutptr(sndoutptr sndout);
+static double get_interpd_value(unsigned int here,double ibufpos,sndoutptr sndout);
+static int  free_first_sndout(sndoutptr *sndout);
+
+//TW UPDATE 2002: to make texture from stereo sources (updated to flotsams)
+static int add_stereo_samples_to_outbuf_from_inbuf
+(int *out_of_insamples,int *max_samp_written,sndoutptr sndout,double *splicebuf,int splicelen,float *lbuffer,dataptr dz);
+static double get_interpd_value_stereo(unsigned int here,double ibufpos,double *chanval2,sndoutptr sndout);
+
+/**************************** PRODUCE_TEXTURE_SOUND *****************************/
+
+int produce_texture_sound(dataptr dz)
+{
+    int exit_status;
+    /*insamptr  *insound = dz->tex->insnd;*/
+    motifptr  tset     = dz->tex->timeset;
+    sndoutptr sndout;
+    noteptr   thisnote = tset->firstnote;
+    double *origdur, *origfrq, *splicebuf;
+    double mindur = (dz->frametime + TEXTURE_SAFETY) * MS_TO_SECS;
+    int st_splicecnt = round((dz->frametime * MS_TO_SECS) * dz->infile->srate);
+#ifdef MINDUR_OVERRIDE
+    mindur = 0.0;
+    st_splicecnt = 0;
+#endif
+    if((exit_status = setup_splice(st_splicecnt,&splicebuf))<0)
+        return(exit_status);
+    if((exit_status = generate_origdur_and_frq(&origdur,&origfrq,dz))<0)
+        return(exit_status);
+    if((exit_status = init_soundout_set(&sndout))<0)
+        return(exit_status);
+    if((exit_status = replace_tset_by_soundout_set(thisnote,&sndout,origdur,origfrq,mindur,st_splicecnt,dz))<0)
+        return(exit_status);
+    free(origdur);
+    free(origfrq);
+    return do_mix(sndout,splicebuf,dz);
+} 
+
+/************************** SETUP_SPLICE ************************/
+
+int setup_splice(int st_splicecnt,double **splicebuf)
+{
+    int n, m;
+    if((*splicebuf = (double *)malloc(st_splicecnt * sizeof(double)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY for splice buffer.\n");
+        return(MEMORY_ERROR);
+    }
+    for(m=0,n=st_splicecnt-1; n>=0; n--,m++)
+        (*splicebuf)[m] = (double)n/(double)st_splicecnt;
+    return(FINISHED);
+}
+
+/************************** GENERATE_ORIGDUR_AND_FRQ ************************/
+
+int generate_origdur_and_frq(double **origdur,double **origfrq,dataptr dz)
+{
+    int n;
+    if((*origdur = (double *)malloc(dz->infilecnt * sizeof(double)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY to store original durations.\n");
+        return(MEMORY_ERROR);
+    }
+    if((*origfrq = (double *)malloc(dz->infilecnt * sizeof(double)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY to store original frqs.\n");
+        return(MEMORY_ERROR);
+    }
+    for(n=0;n <dz->infilecnt;n++) {
+//TW UPDATE: Now allowing stereo sources to be used to make texture
+        (*origdur)[n] = (double)dz->insams[n]/(double)dz->infile->channels/(double)dz->infile->srate;
+        (*origfrq)[n] = miditohz(((dz->tex->insnd)[n])->pitch);
+    }
+    return(FINISHED);
+}
+
+/************************** INIT_SOUNDOUT_SET ************************/
+
+int init_soundout_set(sndoutptr *sndout)
+{
+    if((*sndout = (sndoutptr)malloc(sizeof(struct soundout)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY for soundout pointers.\n");
+        return(MEMORY_ERROR);
+    }
+    (*sndout)->last = (sndoutptr)0;
+    (*sndout)->next = (sndoutptr)0;
+    return(FINISHED);
+}
+
+/************************** REPLACE_TSET_BY_SOUNDOUT_SET ************************/
+
+int replace_tset_by_soundout_set
+(noteptr thisnote,sndoutptr *sndout,double *origdur,double *origfrq,double  mindur,int st_splicecnt,dataptr dz)
+{
+    int exit_status;
+    int warning_set = FALSE;
+    while((thisnote->next)!=(noteptr)0) /* go to end of tset */
+        thisnote = thisnote->next;
+    while(thisnote!=(noteptr)0) {
+        if((exit_status = convert_tsetnote_to_sndout_item
+        (thisnote,*sndout,origdur,origfrq,mindur,st_splicecnt,&warning_set,dz))<0)
+            return(exit_status);
+        if((exit_status = generate_previous_sndout(sndout))<0)
+            return(exit_status);
+        if(thisnote->last!=NULL) {
+            thisnote = thisnote->last;      /* free tset from end backwards */
+            free(thisnote->next);   
+        } else {
+            free(thisnote);
+            if((exit_status = free_first_sndout(sndout))<0) 
+                return(exit_status);
+            thisnote = NULL;
+        }
+    }
+    return(FINISHED);
+}
+
+/************************** CONVERT_TSETNOTE_TO_SNDOUT_ITEM ************************/
+
+//TW "STEREO" defined in globcon.h
+#define MAXGAIN (1.0)
+
+int convert_tsetnote_to_sndout_item
+(noteptr thisnote,sndoutptr sndout,double *origdur,double *origfrq,double mindur,int st_splicecnt,int *warning_set,dataptr dz)
+{
+    int exit_status;
+    int thisins;
+    unsigned int insampcnt, st_osampcnt;
+    double indur;
+    double thisfrq,thisdur,trnspstep,inv_trnsp,thisamp,thispos,compensate;
+
+    thisins   = thisnote->instr;
+    thisfrq   = miditohz((double)thisnote->pitch);
+    trnspstep = thisfrq/origfrq[thisins];
+    inv_trnsp = 1.0/trnspstep;
+    if((exit_status = get_thisdur(&thisdur,thisnote,thisins,origdur,inv_trnsp,mindur,dz))<0)
+        return(exit_status);
+    indur       = thisdur * trnspstep;
+//TW UPDATE now counting either mono samples or pairs-of-stereo-sample pairs (as with st_osampcnt) as possibly using stereo input
+    insampcnt   = min(dz->insams[thisins]/dz->infile->channels,round(indur * (double)dz->infile->srate));       
+    st_osampcnt = round((double)insampcnt * inv_trnsp);     
+    if(st_osampcnt <= (unsigned int)st_splicecnt) {
+        sprintf(errstr,"Error in samplecount calculations: convert_tsetnote_to_sndout_item()\n");
+        return(PROGRAM_ERROR);
+    }
+    thisamp   = thisnote->amp/(double)MIDITOP;
+    thispos   = thisnote->spacepos;
+    if((exit_status = get_stereospace_compensation(thispos,&compensate))<0)
+        return(exit_status);
+    if(thisamp > MAXGAIN) {
+#ifdef _DEBUG
+        assert(thisamp <= MAXGAIN);
+#endif
+        if(!(*warning_set)) {
+            fprintf(stdout,"WARNING: one or more events exceed max level. Adjusted.\n");
+            fflush(stdout);
+            *warning_set = TRUE;
+        }
+        thisamp = MAXGAIN;
+    }
+    sndout->inbuf       = ((dz->tex->insnd)[thisins])->buffer;
+    sndout->ibufcnt     = insampcnt;
+    sndout->st_sstttime = round(thisnote->ntime * dz->infile->srate);
+    sndout->st_sendtime = sndout->st_sstttime + st_osampcnt; /* Redundant variable: might need if func revised */
+    sndout->st_splicpos = sndout->st_sendtime - st_splicecnt;
+    sndout->ibufpos     = 0.0;
+    sndout->step        = trnspstep;
+//TW UPDATE: in stereo-input case, only 1 gain value used, as no spatialisation takes place
+    if(dz->infile->channels==STEREO) {
+        sndout->lgain       = thisamp;
+    } else {
+        sndout->lgain       = thisamp * (1.0 - thispos) * compensate;
+        sndout->rgain       = thisamp * thispos * compensate;
+    }
+    return(FINISHED);
+}
+
+/************************** GENERATE_PREVIOUS_SNDOUT ************************/
+
+int generate_previous_sndout(sndoutptr *sndout)
+{
+    sndoutptr new;
+    if((new = (sndoutptr)malloc(sizeof(struct soundout)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY for new soundout pointers.\n");
+        return(MEMORY_ERROR);
+    }
+    new->last     = (sndoutptr)0;
+    new->next     = *sndout;
+    (*sndout)->last = new;
+    *sndout = new;
+    return(FINISHED);
+}
+
+/************************** FREE_FIRST_SNDOUT ************************/
+
+int free_first_sndout(sndoutptr *sndout)
+{
+    if((*sndout = (*sndout)->next)==NULL) {
+        sprintf(errstr,"Problem in free_first_sndout()\n");
+        return(PROGRAM_ERROR);
+    }
+    free((*sndout)->last);
+    (*sndout)->last = NULL;
+    return(FINISHED);
+}
+
+/************************** GET_THISDUR ************************/
+
+int get_thisdur
+(double *thisdur,noteptr thisnote,int thisins,double *origdur,double inv_trnsp,double mindur,dataptr dz)
+{
+    double transposed_dur = origdur[thisins] * inv_trnsp;
+    *thisdur   = thisnote->dur;
+    if(*thisdur>transposed_dur)         
+        *thisdur = transposed_dur;
+    else if(dz->vflag[TEX_IGNORE_DUR])
+        *thisdur = transposed_dur;
+    if(*thisdur<mindur) {
+        sprintf(errstr,
+        "too short dur generated (%lf : mindur = %lf): get_thisdur()\n",*thisdur,mindur);
+        return(PROGRAM_ERROR);
+    }
+    return(FINISHED);
+}
+
+/************************** GET_STEREOSPACE_COMPENSATION ************************
+ *
+ * 1)   comp(ensation) is a factor which compensates for the apparent
+ *      loss of perceived amplitude as a sound moves out of the absolute
+ *      left or absolute right position (sound from a single loudspeaker)
+ *      by simple linear interpolation. 
+ *      At first we define comp to vary LINERALY from 0.0 at L or R,
+ *      to 1.0 in centre.
+ * 2)   NONLIN makes this varation nonlinear, but smooth at the centre, and
+ *      still between 0.0 and 1.0
+ * 3)   As a signal of fixed perceived level moves from left to right (or v.v.)
+ *      we wish to boost the amplitude from each loudspeaker somewhat,
+ *      using a curve of the shape now defined.
+ *      The maximum possible amplitude is 1.0. To define how much we should
+ *      boost amplitude at any point on the L-R axis, we need to define
+ *      a ratio (MAXBOOST) with which to multiply the signal.
+ *      Multiplying comp-curve by this, defines a curve of amplitude-boosting values.
+ * 4)   1.0 is now added to this curve, to give a multiplier of amplitude at
+ *      each point along the left-right axis.
+ *      And MAXBOOST is subtracted, so that the level 
+ *      from each loudspeaker when at maximum boost cannot exceed
+ *      MAXGAIN (1.0).
+ */
+
+#define NONLIN   (0.5)
+#define MAXBOOST (0.25)
+
+int get_stereospace_compensation(double position,double *compensate)
+{
+    double comp = 1.0 - (fabs((position * (double)2.0) - (double)1.0));     /* 9a */
+    comp = pow(comp,NONLIN);            /* 9b */
+    comp *= MAXBOOST;                   /* 9c */
+    comp += (1.0 - MAXBOOST);           /* 9d */
+    *compensate = comp;
+    return(FINISHED);
+}
+
+/************************** DO_MIX ************************
+ *
+ * 1)   Position, in stereo-samples, of start-of-splice in this-sndout-struct =  
+ *          sndout->st_splicpos
+ *      Position in actual-samples of ditto = 
+ *           sndout->st_splicpos * STEREO
+ *      Position relative to start of current buffer = 
+ *          (sndout->st_splicpos * STEREO) - (obufcnt * dz->buflen);
+ *      Same position expressed relative to start-of-splice (so that value 0 = start_of_splice) = 
+ *          -((sndout->st_splicpos * STEREO) - (obufcnt * dz->buflen));
+ */
+
+int do_mix(sndoutptr sndout,double *splicebuf,dataptr dz)
+{
+    int exit_status;
+    int out_of_insamples;
+    /*unsigned int totaltime = 0;*/
+    int max_samp_written, n;
+    unsigned long this_sampend, obufcnt = 0;
+    long splicelen = round((dz->frametime * MS_TO_SECS) * dz->infile->srate) * STEREO;
+    sndoutptr startsnd = sndout, endsnd = sndout;
+    /*int*/float *lbuf;
+//TW UPDATE handles stereo input files
+    int is_stereo = 0;
+#ifdef MINDUR_OVERRIDE
+    splicelen = 0;
+#endif
+    if(dz->infile->channels == STEREO)
+        is_stereo = 1;
+//TW MOVED from texprepro
+    dz->infile->channels = STEREO;  /* for output time calculations */
+    if((exit_status = create_sized_outfile(dz->outfilename,dz))<0)
+        return(exit_status);
+
+    if((lbuf = (float *)malloc(dz->buflen * sizeof(float)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY for mixing buffers.\n");
+        return(MEMORY_ERROR);
+    }
+    dz->sbufptr[0] = dz->sampbuf[0];
+/* <--SAFETY CHECK */
+    if((exit_status = check_sequencing(sndout))<0)
+        return(exit_status);
+/* SAFETY CHECK--> */
+    while(startsnd != NULL) {                                       /* until we reach end of event list */
+        this_sampend = (obufcnt+1) * dz->buflen;        /* get absolute samplecnt of end of current buf */
+                                                     /* look for NEW events starting during this outbuf */
+        if(sndout!=NULL) {
+            while(sndout->st_sstttime * STEREO < this_sampend) {     
+                sndout->obufpos  = (sndout->st_sstttime * STEREO) % dz->buflen;/* obufptr for new event */
+                sndout->st_splicpos = (sndout->st_splicpos * STEREO)-(obufcnt * dz->buflen);/* NOTE1 abv*/
+                sndout->st_splicpos = -(sndout->st_splicpos);                           /* NOTE 1 above */
+                sndout = sndout->next;
+                endsnd = sndout;                      /* update the endmarker of the active events list */
+                if(endsnd == NULL)                                      /* if all events finished,break */
+                    break;
+            }
+        }
+        sndout = startsnd;                                       /* set start to 1st event still active */
+
+        memset((char *)lbuf,0,dz->buflen * sizeof(float));                       /* empty output buffer */
+        if(sndout == endsnd) {                      /* If there are NO active events during this buffer */
+            if(endsnd != NULL)                                   /* and we are not at end of event list */
+                max_samp_written = dz->buflen;                        /* setup to write an empty buffer */
+            else {
+                sprintf(errstr,"Error in loop logic: do_mix()\n");
+                return(PROGRAM_ERROR);
+            }
+        } else
+            max_samp_written = 0;
+        while(sndout!= endsnd) {                                          /* look in all active buffers */
+            out_of_insamples = FALSE;
+
+//TW UPDATE: handles stereo input
+            if(is_stereo) {
+                if((exit_status = add_stereo_samples_to_outbuf_from_inbuf
+                (&out_of_insamples,&max_samp_written,sndout,splicebuf,splicelen,lbuf,dz))<0)
+                    return(exit_status);
+            } else {
+                if((exit_status = add_samples_to_outbuf_from_inbuf
+                (&out_of_insamples,&max_samp_written,sndout,splicebuf,splicelen,lbuf,dz))<0)
+                    return(exit_status);
+            }
+            if(out_of_insamples) {                                 /* if inbuf exhausted for THIS event */
+
+                if(sndout->next==NULL) {                                           /* if at end of list */
+                    if(sndout->last==NULL) {           /* if this is definitively the last active event */
+                         free(sndout);                                                       /* free it */     
+                         startsnd = NULL;            /* and set ptr to NULL, so we dropout of outerloop */
+                         break;
+                    } else {                                 /* BUT if some previous event still active */
+                        sndout = sndout->last;                          /* unlink final event from list */
+                        free(sndout->next);
+                        sndout->next = NULL;
+                        sndout = sndout->next;                            /* move sndout to end of list */
+                    }
+                } else if(sndout==startsnd) {                    /* if this is 1st active event in list */
+                        sndout   = sndout->next;                               /* proceed to next event */
+                        startsnd = sndout;              /* move start of active list to this next event */
+                        unlink_sndoutptr_at_start_of_list(sndout->last);
+                } else {                                /* else if this is NOT 1st active event in list */
+                        sndout   = sndout->next;                               /* proceed to next event */
+                        unlink_sndoutptr(sndout->last);/* unlink the exhausted event from (active) list */
+                }
+            } else {                            /* else there is data remaining in inbuf for THIS event */
+                sndout->obufpos = 0;                          /* so reset obufpos to start of next obuf */
+                sndout->st_splicpos += dz->buflen;/* reset relativeposition splice-start & nextbufstart */
+                sndout = sndout->next;                                     /* and proceed to next event */
+            }
+        }
+        if(startsnd!=NULL)                /* If we're not at the end of ALL events, write a full buffer */
+            max_samp_written = dz->buflen;
+
+        for(n=0;n<max_samp_written;n++)
+            dz->sampbuf[0][n] = lbuf[n];
+        if(max_samp_written > 0) {
+            if((exit_status = write_samps(dz->sampbuf[0],max_samp_written,dz))<0)
+                return(exit_status);
+        }
+        obufcnt++;
+    }
+    /*if(dz->iparam[TEX_MAXOUT] > MAXSAMP) {*/
+    if(dz->param[TEX_MAXOUT] > F_MAXSAMP) {
+        fprintf(stdout,"WARNING: OVERLOAD: suggest attenuation by < %lf\n",
+//TW UPDATE (need to factor in the attenation already being used to give correct new attenuation)
+            (((double)F_MAXSAMP/(double)dz->param[TEX_MAXOUT])) * dz->param[TEXTURE_ATTEN]);
+        fflush(stdout);
+    }
+    return(FINISHED);
+}
+
+/************************** CHECK_SEQUENCING ************************/
+
+int check_sequencing(sndoutptr sndout)
+{
+    unsigned int lasttime = sndout->st_sstttime;
+    unsigned int thistime;
+    while(sndout->next != (sndoutptr)0) {
+        sndout = sndout->next;
+        if((thistime = sndout->st_sstttime) < lasttime) {
+            sprintf(errstr,"Sequencing anomaly in sndout list: check_sequencing()\n");
+            return(PROGRAM_ERROR);
+        }
+        lasttime = thistime;
+    } 
+    return(FINISHED);
+}
+
+/************************** ADD_SAMPLES_TO_OUTBUF_FROM_INBUF ************************/
+
+int add_samples_to_outbuf_from_inbuf
+(int *out_of_insamples,int *max_samp_written,sndoutptr sndout,double *splicebuf,int splicelen,float *lbuffer,dataptr dz)
+{
+    unsigned int thisopos = sndout->obufpos;
+    unsigned int here;
+    double hereval = 0.0;
+    float *lbuf    = lbuffer + thisopos;
+    float *lbufend = lbuffer + dz->buflen;
+    int splicpos  = sndout->st_splicpos + thisopos;
+    float outval, thismaxoutval;
+    int max_set = FALSE;
+    while(lbuf < lbufend) {
+        if((here = (unsigned int) sndout->ibufpos) >= sndout->ibufcnt) {    /* TRUNCATE : get current pos in inbuf */
+            *out_of_insamples = TRUE;
+            *max_samp_written = max(*max_samp_written,lbuf - lbuffer);
+/* SAFETY CHECK--> */
+            if(splicpos < splicelen) {
+                sprintf(errstr,"BUM endsplice: add_samples_to_outbuf_from_inbuf()\n"); 
+                return(PROGRAM_ERROR);
+            }
+/* <--SAFETY CHECK */
+
+            max_set = TRUE;
+            break;
+        }
+        hereval = get_interpd_value(here,sndout->ibufpos,sndout);
+/* SAFETY FOR ARITHMETIC ROUNDING ERROS CALCULATING START OF SPLICE --> */
+        if(splicpos >= splicelen)
+            hereval = 0.0;
+/* <--SAFETY */
+
+        if(splicpos >= 0)
+            hereval *= splicebuf[splicpos >> 1];
+        splicpos += STEREO;
+        outval =(float)( *lbuf + (hereval * sndout->lgain ));
+        if((thismaxoutval = (float) fabs(outval)) > dz->param[TEX_MAXOUT])
+            dz->param[TEX_MAXOUT] = thismaxoutval;
+        *lbuf  = outval;
+        lbuf++;
+        outval = (float)(*lbuf + (hereval * sndout->rgain));
+        if((thismaxoutval = (float) fabs(outval)) > dz->param[TEX_MAXOUT])
+            dz->param[TEX_MAXOUT] =  thismaxoutval;
+        *lbuf = outval;
+        lbuf++;
+        sndout->ibufpos += sndout->step;
+    }
+    if(!max_set)
+        *max_samp_written = dz->buflen;
+    return(FINISHED);
+}
+
+//TW UPDATE: NEW FUNCTIONfor stereo input (updated for flotsams)
+/************************** ADD_STEREO_SAMPLES_TO_OUTBUF_FROM_INBUF ************************/
+
+int add_stereo_samples_to_outbuf_from_inbuf
+(int *out_of_insamples,int *max_samp_written,sndoutptr sndout,double *splicebuf,int splicelen,float *lbuffer,dataptr dz)
+{
+    unsigned int thisopos = sndout->obufpos;
+    unsigned int here;
+    double chanval1, chanval2;
+    float *lbuf    = lbuffer + thisopos;
+    float *lbufend = lbuffer + dz->buflen;
+    int splicpos  = sndout->st_splicpos + thisopos;
+    float outval, thismaxoutval;
+    int max_set = FALSE;
+    while(lbuf < lbufend) {
+        if((here = (unsigned int)sndout->ibufpos)>=sndout->ibufcnt) {   /* TRUNCATE : get current pos in inbuf */
+            *out_of_insamples = TRUE;
+            *max_samp_written = max(*max_samp_written,lbuf - lbuffer);
+            if(splicpos < splicelen) {
+                sprintf(errstr,"BUM endsplice: add_samples_to_outbuf_from_inbuf()\n"); 
+                return(PROGRAM_ERROR);
+            }
+            max_set = TRUE;
+            break;
+        }
+        chanval1 = get_interpd_value_stereo(here,sndout->ibufpos,&chanval2,sndout);
+    /* SAFETY FOR ARITHMETIC ROUNDING ERROS CALCULATING START OF SPLICE --> */
+        if(splicpos >= splicelen) {
+            chanval1 = 0.0;
+            chanval2 = 0.0;
+        }
+    /* <--SAFETY */
+        if(splicpos >= 0) {
+            chanval1 *= splicebuf[splicpos >> 1];
+            chanval2 *= splicebuf[splicpos >> 1];
+        }
+        splicpos += STEREO;
+        outval = (float)(*lbuf + (chanval1 * sndout->lgain));
+        if((thismaxoutval = (float)fabs(outval))>dz->param[TEX_MAXOUT])
+            dz->param[TEX_MAXOUT] = thismaxoutval;
+        *lbuf  = outval;
+        lbuf++;
+        outval = (float)(*lbuf + (chanval2 * sndout->lgain));   /* only one gain val for stereo inputs: kept in lgain */
+        if((thismaxoutval = (float)fabs(outval))>dz->param[TEX_MAXOUT])
+            dz->param[TEX_MAXOUT] = thismaxoutval;
+        *lbuf = outval;
+        lbuf++;
+        sndout->ibufpos += sndout->step;
+    }
+    if(!max_set)
+        *max_samp_written = dz->buflen;
+    return(FINISHED);
+}
+
+/************************** GET_INTERPD_VALUE ************************/
+
+double get_interpd_value(unsigned int here,double ibufpos,sndoutptr sndout)
+{
+    unsigned int next = here+1;         /* NB  all inbufs have a wraparound (0val) point at end */
+    double frac     = ibufpos - (double)here;
+    double hereval  = (double)(sndout->inbuf[here]);
+    double nextval  = (double)(sndout->inbuf[next]);
+    double diff     = nextval - hereval;
+    diff    *= frac;
+    return(hereval+diff);
+}
+
+//TW UPDATE NEW FUNCTION for stereo input
+/************************** GET_INTERPD_VALUE_STEREO ************************/
+
+double get_interpd_value_stereo(unsigned int here,double ibufpos,double *chanval2,sndoutptr sndout)
+{
+    unsigned int next = here+1;         /* NB  all inbufs have a wraparound (0val) point at end */
+    double frac     = ibufpos - (double)here;
+    double hereval, nextval, diff;
+    double chanval1;
+    unsigned int sthere = here * 2, stnext = next * 2;
+    hereval  = (double)(sndout->inbuf[sthere]);
+    nextval  = (double)(sndout->inbuf[stnext]);
+    diff     = (nextval - hereval) * frac;
+    chanval1 = hereval+diff;
+    sthere++;
+    stnext++;
+    hereval  = (double)(sndout->inbuf[sthere]);
+    nextval  = (double)(sndout->inbuf[stnext]);
+    diff     = (nextval - hereval) * frac;
+    *chanval2 = hereval+diff;
+    return(chanval1);
+}
+
+/************************** UNLINK_SNDOUTPTR_AT_START_OF_LIST ************************/
+
+void unlink_sndoutptr_at_start_of_list(sndoutptr sndout)
+{
+    sndout->next->last = (sndoutptr)0;
+    free(sndout);
+}
+
+/************************** UNLINK_SNDOUTPTR ************************/
+
+void unlink_sndoutptr(sndoutptr sndout)
+{
+    sndout->next->last = sndout->last;
+    sndout->last->next = sndout->next;
+    free(sndout);
+}

+ 891 - 0
dev/texture/v8/ap_texture.c

@@ -0,0 +1,891 @@
+/*
+ * 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
+ *
+ */
+/* 03/2020: TW/RWD: corrected usage message argument lists */
+
+/* floatsam version: no changes */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <structures.h>
+#include <cdpmain.h>
+#include <tkglobals.h>
+#include <pnames.h>
+#include <texture.h>
+#include <processno.h>
+#include <modeno.h>
+#include <globcon.h>
+#include <logic.h>
+#include <filetype.h>
+#include <mixxcon.h>
+#include <flags.h>
+#include <speccon.h>
+#include <arrays.h>
+#include <special.h>
+#include <formants.h>
+#include <sfsys.h>
+#include <osbind.h>
+
+#include <srates.h>
+
+/********************************************************************************************/
+/********************************** FORMERLY IN pconsistency.c ******************************/
+/********************************************************************************************/
+
+static int  texture_pconsistency(dataptr dz);
+
+/********************************************************************************************/
+/********************************** FORMERLY IN specialin.c *********************************/
+/********************************************************************************************/
+
+static int  get_the_notedatafile(char *filename,dataptr dz);
+
+/***************************************************************************************/
+/****************************** FORMERLY IN aplinit.c **********************************/
+/***************************************************************************************/
+
+/***************************** ESTABLISH_BUFPTRS_AND_EXTRA_BUFFERS **************************/
+
+int establish_bufptrs_and_extra_buffers(dataptr dz)
+{
+    /*int is_spec = FALSE;*/
+    dz->bptrcnt = 0;
+    dz->bufcnt  = 0;
+    switch(dz->process) {
+    case(SIMPLE_TEX):
+    case(TIMED):
+    case(GROUPS):
+    case(TGROUPS):
+    case(DECORATED):
+    case(PREDECOR): 
+    case(POSTDECOR):
+    case(ORNATE):
+    case(PREORNATE):
+    case(POSTORNATE):
+    case(MOTIFS):
+    case(TMOTIFS):
+    case(MOTIFSIN):
+    case(TMOTIFSIN):
+        dz->extra_bufcnt = 0;   dz->bufcnt = 1;
+        break;
+    default:
+        sprintf(errstr,"Unknown program type [%d] in establish_bufptrs_and_extra_buffers()\n",dz->process);
+        return(PROGRAM_ERROR);
+    }
+    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(SIMPLE_TEX):
+    case(TIMED):
+    case(GROUPS):
+    case(TGROUPS):
+    case(DECORATED):
+    case(PREDECOR): 
+    case(POSTDECOR):
+    case(ORNATE):
+    case(PREORNATE):
+    case(POSTORNATE):
+    case(MOTIFS):
+    case(TMOTIFS):
+    case(MOTIFSIN):
+    case(TMOTIFSIN):
+        dz->array_cnt = 1; dz->iarray_cnt = 6; 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(SIMPLE_TEX):
+    case(TIMED):
+    case(GROUPS):
+    case(TGROUPS):
+    case(DECORATED):
+    case(PREDECOR):
+    case(POSTDECOR):
+    case(ORNATE):
+    case(PREORNATE):
+    case(POSTORNATE):
+    case(MOTIFS):
+    case(TMOTIFS):
+    case(MOTIFSIN):
+    case(TMOTIFSIN):
+        setup_process_logic(ONE_OR_MANY_SNDFILES,   UNEQUAL_SNDFILE,    SNDFILE_OUT,    dz);
+        break;
+    default:
+        sprintf(errstr,"Unknown process: assign_process_logic()\n");
+        return(PROGRAM_ERROR);
+        break;
+    }
+    if(dz->has_otherfile) {
+        switch(dz->input_data_type) {
+        case(ALL_FILES):
+        case(TWO_SNDFILES):
+        case(SNDFILE_AND_ENVFILE):
+        case(SNDFILE_AND_BRKFILE):
+        case(SNDFILE_AND_UNRANGED_BRKFILE):
+        case(SNDFILE_AND_DB_BRKFILE):
+            break;
+        case(MANY_SNDFILES):
+            if(dz->process==INFO_TIMELIST)
+                break;
+            /* fall thro */
+        default:
+            sprintf(errstr,"Most processes accepting files with different properties\n"
+                           "can only take 2 sound infiles.\n");
+            return(PROGRAM_ERROR);
+        }
+    }
+    return(FINISHED);
+}
+
+/***************************** SET_LEGAL_INFILE_STRUCTURE **************************
+ *
+ * Allows 2nd infile to have different props to first infile.
+ */
+
+void set_legal_infile_structure(dataptr dz)
+{
+    switch(dz->process) {
+    default:
+        dz->has_otherfile = FALSE;
+        break;
+    }
+}
+
+/***************************************************************************************/
+/****************************** FORMERLY IN internal.c *********************************/
+/***************************************************************************************/
+
+/****************************** SET_LEGAL_INTERNALPARAM_STRUCTURE *********************************/
+
+int set_legal_internalparam_structure(int process,int mode,aplptr ap)
+{
+    int exit_status = FINISHED;
+    switch(process) {
+    case(SIMPLE_TEX):   case(TIMED):    case(GROUPS):   case(TGROUPS):
+    case(DECORATED):    case(PREDECOR): case(POSTDECOR):
+    case(ORNATE):       case(PREORNATE):case(POSTORNATE):
+    case(MOTIFS):       case(TMOTIFS):  case(MOTIFSIN): case(TMOTIFSIN):
+                        exit_status = set_internalparam_data("iiidddi",ap);         break;
+    default:
+        sprintf(errstr,"Unknown process in set_legal_internalparam_structure()\n");
+        return(PROGRAM_ERROR);
+    }
+    return(exit_status);
+}
+
+/********************************************************************************************/
+/********************************** FORMERLY IN specialin.c *********************************/
+/********************************************************************************************/
+
+/********************** READ_SPECIAL_DATA ************************/
+
+int read_special_data(char *str,dataptr dz)
+{
+/*  int exit_status = FINISHED;*/
+    aplptr ap = dz->application;
+    switch(ap->special_data) {
+    case(TEX_NOTEDATA):         return get_the_notedatafile(str,dz);
+    default:
+        sprintf(errstr,"Unknown special_data type: read_special_data()\n");
+        return(PROGRAM_ERROR);
+    }
+    return(FINISHED);   /* NOTREACHED */
+}
+
+/***************************** GET_THE_NOTEDATAFILE ****************************/
+
+int get_the_notedatafile(char *filename,dataptr dz)
+{
+    if((dz->fp = fopen(filename,"r"))==NULL) {
+        sprintf(errstr,"Failed to open notedata file %s\n",filename);
+        return(DATA_ERROR);
+    }
+    return(FINISHED);
+}
+
+/********************************************************************************************/
+/********************************** FORMERLY IN preprocess.c ********************************/
+/********************************************************************************************/
+
+/****************************** PARAM_PREPROCESS *********************************/
+
+int param_preprocess(dataptr dz)
+{
+/*  int exit_status = FINISHED;*/
+
+    switch(dz->process) {
+    case(SIMPLE_TEX):   case(TIMED):    case(GROUPS):   case(TGROUPS):
+    case(DECORATED):    case(PREDECOR): case(POSTDECOR):
+    case(ORNATE):       case(PREORNATE):case(POSTORNATE):
+    case(MOTIFS):       case(TMOTIFS):  case(MOTIFSIN): case(TMOTIFSIN):
+         return texture_preprocess(dz);
+    default:
+        sprintf(errstr,"PROGRAMMING PROBLEM: Unknown process in param_preprocess()\n");
+        return(PROGRAM_ERROR);
+    }
+    return(FINISHED);   /* NOTREACHED */
+}
+
+/********************************************************************************************/
+/********************************** FORMERLY IN procgrou.c **********************************/
+/********************************************************************************************/
+
+/**************************** GROUCHO_PROCESS_FILE ****************************/
+
+int groucho_process_file(dataptr dz)   /* FUNCTIONS FOUND IN PROCESS.C */
+{   
+    int exit_status = FINISHED;
+
+    switch(dz->process) {
+    case(SIMPLE_TEX):   case(TIMED):    case(GROUPS):   case(TGROUPS):
+    case(DECORATED):    case(PREDECOR): case(POSTDECOR):
+    case(ORNATE):       case(PREORNATE):case(POSTORNATE):
+    case(MOTIFS):       case(MOTIFSIN): case(TMOTIFS):  case(TMOTIFSIN):
+        if((exit_status = make_texture(dz))<0)
+            return(exit_status);
+        if((exit_status = produce_texture_sound(dz))<0)
+            return(exit_status);
+        break;
+    default:
+        sprintf(errstr,"Unknown case in process_file()\n");
+        return(PROGRAM_ERROR);
+    }
+    return(FINISHED);
+}
+
+/********************************************************************************************/
+/********************************** FORMERLY IN pconsistency.c ******************************/
+/********************************************************************************************/
+
+/****************************** CHECK_PARAM_VALIDITY_AND_CONSISTENCY *********************************/
+
+int check_param_validity_and_consistency(dataptr dz)
+{
+/*  int exit_status = FINISHED;*/
+    handle_pitch_zeros(dz);
+    switch(dz->process) {
+    case(SIMPLE_TEX): case(TIMED):      case(GROUPS):   case(TGROUPS):
+    case(DECORATED):  case(PREDECOR):   case(POSTDECOR):
+    case(ORNATE):     case(PREORNATE):  case(POSTORNATE):
+    case(MOTIFS):     case(TMOTIFS):    case(MOTIFSIN): case(TMOTIFSIN):
+                        return texture_pconsistency(dz);
+    }
+    return(FINISHED);
+}
+
+/***************************** PREPARE_TEXTURE_PARAMETERS ****************************/
+
+int texture_pconsistency(dataptr dz)
+{
+    double *p, *end;
+    int OK = TRUE;
+    if(dz->brksize[TEXTURE_INSLO]) {
+        p = dz->brk[TEXTURE_INSLO] + 1;
+        end = dz->brk[TEXTURE_INSLO] + (dz->brksize[TEXTURE_INSLO] * 2);
+        while(p < end) {
+            if(*p  > (double)dz->infilecnt) {
+                OK = FALSE;
+                break;
+            }
+            p += 2;
+        }
+    } else if(dz->iparam[TEXTURE_INSLO] > dz->infilecnt)
+        OK  = FALSE;
+    if(!OK) {
+        sprintf(errstr,"FIRST SND-IN-LIST TO USE > count of files entered: cannot proceed.\n");
+        return(DATA_ERROR);
+    }
+    OK = TRUE;
+    if(dz->brksize[TEXTURE_INSHI]) {
+        p = dz->brk[TEXTURE_INSHI] + 1;
+        end = dz->brk[TEXTURE_INSHI] + (dz->brksize[TEXTURE_INSHI] * 2);
+        while(p < end) {
+            if(*p  > (double)dz->infilecnt) {
+                OK = FALSE;
+                break;
+            }
+            p += 2;
+        }
+    } else if(dz->iparam[TEXTURE_INSHI] > dz->infilecnt)
+        OK  = FALSE;
+    if(!OK) {
+        sprintf(errstr,"LAST SND-IN-LIST TO USE > count of files entered: cannot proceed.\n");
+        return(DATA_ERROR);
+    }
+    return(FINISHED);
+}
+
+
+
+/********************************************************************************************/
+/********************************** FORMERLY IN buffers.c ***********************************/
+/********************************************************************************************/
+
+/**************************** ALLOCATE_LARGE_BUFFERS ******************************/
+
+int allocate_large_buffers(dataptr dz)
+{
+    switch(dz->process) {
+    case(SIMPLE_TEX):
+    case(TIMED):        case(GROUPS):       case(TGROUPS):
+    case(DECORATED):    case(PREDECOR):     case(POSTDECOR):
+    case(ORNATE):       case(PREORNATE):    case(POSTORNATE):
+    case(MOTIFS):       case(TMOTIFS):      case(MOTIFSIN): 
+    case(TMOTIFSIN):
+        return create_sndbufs(dz);
+    default:
+        sprintf(errstr,"Unknown program no. in allocate_large_buffers()\n");
+        return(PROGRAM_ERROR);
+    }
+    return(FINISHED);   /* NOTREACHED */
+}
+
+/********************************************************************************************/
+/********************************** FORMERLY IN cmdline.c ***********************************/
+/********************************************************************************************/
+
+int get_process_no(char *prog_identifier_from_cmdline,dataptr dz)
+{
+    if     (!strcmp(prog_identifier_from_cmdline,"simple"))         dz->process = SIMPLE_TEX;
+    else if(!strcmp(prog_identifier_from_cmdline,"grouped"))        dz->process = GROUPS;
+    else if(!strcmp(prog_identifier_from_cmdline,"motifs"))         dz->process = MOTIFS;
+    else if(!strcmp(prog_identifier_from_cmdline,"motifsin"))       dz->process = MOTIFSIN;
+    else if(!strcmp(prog_identifier_from_cmdline,"decorated"))      dz->process = DECORATED;
+    else if(!strcmp(prog_identifier_from_cmdline,"predecor"))       dz->process = PREDECOR;
+    else if(!strcmp(prog_identifier_from_cmdline,"postdecor"))      dz->process = POSTDECOR;
+    else if(!strcmp(prog_identifier_from_cmdline,"ornate"))         dz->process = ORNATE;
+    else if(!strcmp(prog_identifier_from_cmdline,"preornate"))      dz->process = PREORNATE;
+    else if(!strcmp(prog_identifier_from_cmdline,"postornate"))     dz->process = POSTORNATE;
+    else if(!strcmp(prog_identifier_from_cmdline,"timed"))          dz->process = TIMED;
+    else if(!strcmp(prog_identifier_from_cmdline,"tgrouped"))       dz->process = TGROUPS;
+    else if(!strcmp(prog_identifier_from_cmdline,"tmotifs"))        dz->process = TMOTIFS;
+    else if(!strcmp(prog_identifier_from_cmdline,"tmotifsin"))      dz->process = TMOTIFSIN;
+    else {
+        sprintf(errstr,"Unknown program identification string '%s'\n",prog_identifier_from_cmdline);
+        return(USAGE_ONLY);
+    }
+
+    return FINISHED;
+}
+
+/********************************************************************************************/
+/********************************** FORMERLY IN usage.c *************************************/
+/********************************************************************************************/
+
+/******************************** USAGE1 ********************************/
+
+int usage1(void)
+{
+    fprintf(stdout, /* HAs to use fprintf because of kbhit */
+    "\n"
+    "USAGE:\ntexture NAME (mode) infile (infile2..etc) outfile notedata params:\n"
+    "\n"
+    "\nwhere NAME can be any one of\n"
+    "\n"
+    "\tTEXTURE MADE FROM ONE OR SEVERAL SOUND FILES\n"
+    "\n"
+    "simple   grouped    decorated    ornate       motifs\n"
+    "                    predecor     preornate    motifsin\n"
+    "                    postdecor    postornate\n"
+    "\n"
+    "\tTIMED TEXTURES MADE FROM ONE OR SEVERAL SOUND FILES\n"
+    "\n"
+    "timed     tmotifs   tmotifsin   tgrouped\n"
+    "\n"
+    "ORNAMENTS & MOTIFS   have user-specified pitch-shapes.\n"
+    "DECORATIONS & GROUPS have random pitch-shapes.\n"
+    "\n"
+    "Type 'texture simple' for more info on simple texture option.... etc.\n"
+    "\n"
+#ifdef IS_PC
+    "MORE??? ----- (hit keyboard)\n"
+    "\n");
+
+    while(!kbhit())
+        ;
+    if(kbhit()) {
+#else
+    "\n");
+#endif
+        fprintf(stdout,
+        "\n"
+        "*********************************************************************\n"
+        "SOME SPECIAL PARAMETER VALUES\n"
+        "*********************************************************************\n"
+        "GPSPACE: spatialisation of event-groups\n"
+        "\n"
+        "     0:still            1:scattered(default) 2:towards-texture-centre\n"
+        "     3:away-from-centre 4:follow-texmotion   5:contrary-to-motion\n"
+        "     4 & 5 only function if spatial position varies in time..\n"
+        "*********************************************************************\n"
+        "CONTOUR: amplitude contour of groups\n"
+        "\n"
+        "     0:mixed(default) 1:cresc     2:flat   3:decresc    4:c_or_fl\n"
+        "     5:c_or_d         6:d_or_fl  [7:directed_to_event   8:dir_or_flat]\n"
+        "*********************************************************************\n"
+        "CENTRING: how decoration pitches centre on decorated line pitches\n"
+        "\n"
+        "     0: centred(default) 1: above       2: below\n"
+        "     3: c_and_a          4: c_and_b     5: a_and_b     6: c_and_a_and_b\n"
+        "     In all cases except 0, pitchrange shifted to tally with line pitch\n\n"
+        "\n"
+        "*********************************************************************\n"
+        "       ALL OTHER PARAMS, except outdur, MAY VARY IN TIME.\n"
+        "*********************************************************************\n"
+        "\n"
+
+#ifdef IS_PC
+        "MORE??? ----- (hit keyboard)\n");
+    }
+    _getch();
+    while(!kbhit())
+        ;
+    if(kbhit()) {
+#else
+        "\n");
+#endif
+
+        fprintf(stdout,
+        "\n"
+        "*********************************************************************\n"
+        "HARMONIC SETS   use only the pitches specified.\n"
+        "\n"
+        "HARMONIC FIELDS duplicate the specified pitches in all 8vas.\n"
+        "*********************************************************************\n"
+        "NOTEDATA is in a textfile containing.....\n"
+        "*********************************************************************\n"
+        "     assumed MIDI 'pitch' of each input snd, specified on 1st line.\n"
+        "\n"
+        "   FOLLOWED BY, where ness,  NOTELIST(S), SPECIFIED THUS:-\n"
+        "\n"
+        "     #N (where N = no. of notes in notelist: follows by N lines of...)\n"
+        "     time(SECS)   infile_no    pitch(MIDI)    amp(MIDI)   dur(SECS)\n"
+        "\n"
+        "where times within motif must increase (or remain same, during chords)\n"
+        "*********************************************************************\n"
+        "NOTELISTS REPRESENT: IN THIS ORDER..\n"
+        "*********************************************************************\n"
+        "Notelist of notes in any timed, ornamented or decorated line in texture.\n"
+        "Notelist of notes in any harmonic field(s) or set(s) specified.\n"
+        "      (For more than one  hfield(hset),\n"
+        "      data should specify chords, placed at appropriae times.)\n"
+        "Notelist(s) of notes in any ornament(s) or motif(s) specified.\n"
+        "*********************************************************************\n");
+
+#ifdef IS_PC
+    }
+#endif
+    return(USAGE_ONLY);
+}
+
+/******************************** USAGE2 ********************************/
+
+int usage2(char *str)
+{
+    if(!strcmp(str,"simple")) {
+        fprintf(stdout,
+        "USAGE:\n"
+        "texture simple mode infile [infile2...] outfile notedata outdur packing scatter\n"
+        "   tgrid sndfirst sndlast  mingain maxgain  mindur maxdur  minpich maxpich omit\n"
+        "             [-aatten] [-pposition] [-sspread] [-rseed] [-w -c -p]\n"
+        "MODES:-\n"
+        "1)  ON A GIVEN HARMONIC-FIELD        3)  ON A GIVEN HARMONIC-SET\n"
+        "2)  ON CHANGING HARMONIC-FIELDS      4)  ON CHANGING HARMONIC-SETS\n"
+        "5)  NONE\n"
+        "notedata: infofile, insnd 'pitches',harmonic fields pitches etc.\n"
+        "outdur:           (min) duration of outfile\n"
+        "packing:          (average) time between event onsets.\n"  
+        "scatter:          randomisation of event-onsets (0 - %.0lf)\n"
+        "tgrid:            minstep(MS) quantised timegrid(for grp starttimes)(default 0)\n"
+        "sndfirst,sndlast: 1st,last snd to use,from list of insnds(range:1 - no.of snds)\n"
+        "mingain,maxgain:  minimum & maximum level of input events (1-127:default 64,64)\n"
+        "mindur,maxdur:    minimum & maximum duration of events in texture\n"
+        "minpich,maxpich:  minimum & maximum pitch (MIDI VALUE):\n"
+        "omit:             1 in \"omit\" events are silent.\n"
+        "                  less and less silent events as param increases.\n"
+        "                  at 64 (as at zero) NO events are silent.\n"
+        "atten:            overall attenuation of the output\n"
+        "position:         centre of output sound-image (0(Left) 1(Right): default 0.5)\n"
+        "spread:           spatial-spread of texture events (0 - 1(full-spread))\n"
+        "seed:             same seed-no: same output on rerun(dflt 0: differs each time)\n"
+        "-w:               always play whole input-sound (ignoring duration values).\n"
+        "-c:               Choose files cyclically in listed order (ignore 'sndfirst','last').\n"
+        "-p:               Random permute each cycle (only when -c flag set).\n",MAX_SCAT_TEXTURE);
+    } else if(!strcmp(str,"timed")) {
+        fprintf(stdout,
+        "TIMED TEXTURE:  USAGE:\n"
+        "texture timed mode infile [infile2...]  outfile  notedata     outdur skiptime\n"
+        "             sndfirst sndlast mingain maxgain mindur maxdur minpitch maxpitch\n"
+        "             [-aatten] [-pposition] [-sspread] [-rseed] [-w]\n"
+        "MODES:-\n"
+        "1)  ON A GIVEN HARMONIC-FIELD        3)  ON A GIVEN HARMONIC-SET\n"
+        "2)  ON CHANGING HARMONIC-FIELDS      4)  ON CHANGING HARMONIC-SETS\n"
+        "5)  NONE\n"
+        "notedata: infofile, insnd 'pitches',texture timing,harmonic fields pitches etc.\n"
+        "outdur:            (min) duration of outfile\n"
+        "skiptime:          time between repetitions of timing motif in notedata\n"
+        "sndfirst,sndlast:  1st,last snd to use,from list of insnds(range:1 - all)\n"
+        "mingain,maxgain:   min & max level of input events (1-127:default 64,64)\n"
+        "mindur,maxdur:     min & max duration of events in texture\n"
+        "minpitch,maxpitch: min & max pitch (MIDI VALUE)\n"
+        "atten:             overall attenuation of the output\n"
+        "position:          centre of output sound-image (0(Left) 1(Right):default 0.5)\n"
+        "spread:            spatial-spread of texture events (0 - 1(full-spread))\n"
+        "seed:             same seed-no: same output on rerun(dflt 0: differs each time)\n"
+        "-w:                always play whole input-sound (ignoring duration values).\n");
+    } else if(!strcmp(str,"grouped")) {
+        fprintf(stdout,
+        "TEXTURE OF EVENT-GROUPS: USAGE: texture grouped mode infile [infile2..] outfile\n"
+        "notedata outdur packing scatter tgrid\n"
+        "sndfirst sndlast mingain maxgain mindur maxdur minpitch maxpitch phgrid gpspace\n"
+        "gpsprange amprise contour gpsizelo gpsizehi gppaklo gppakhi gpranglo gpranghi\n"
+        "                   [-aatten] [-pposition] [-sspread] [-rseed] [-w] [-d] [-i]\n"
+        "MODES:-\n"
+        "1)ON HARMONIC-FIELD 2)CHANGING HFLDS 3)HARMONIC-SET 4)CHANGING HSETS 5)NONE\n"
+        "notedata:   infofile, 'pitch' of insnds, harmonic fields etc.\n"
+        "outdur:     (min) duration of outfile\n"
+        "packing:    (average) time between group onsets.\n"  
+        "scatter:    randomisation of event-onsets (0 - %.0lf)\n"
+        "tgrid:      minstep(MS) quantised timegrid(for grp starttimes)(default 0)\n"
+        "sndfirst,sndlast: 1st,last snd to use, from list of insnds(range:1 - all)\n"
+        "mingain,maxgain:  min & max level of input events (1-127:default 64,64)\n"
+        "mindur,maxdur:    min & max duration of events in texture\n"
+        "minpitch,maxpitch:min & max pitch (MIDI VALUE)\n"
+        "phgrid:     a timegrid (MS) applying WITHIN the groups\n"
+        "gpspace:    spatialisation of event-groups (Range 0-5: default 1)\n"
+        "gpsprange:  spatial range of event-groups (Range 0-1: default 1)\n"
+        "amprise:    amplitude change within groups: (0-127: default 0)\n"
+        "contour:    amplitude contour of groups (Range 0-6: default 0)\n"
+            /* NOTE : CARE all_types is 7 AND NOT 8 here */
+        "gpsizelo,gpsizehi:smallest,largest no. of events in groups\n"
+        "gppaklo,gppakhi:  shortest,longest time between event-onsets in groups (MS)\n"
+        "gpranglo,gpranghi:min,max pitchrange grps OR (hfields) no.of hf-notes range\n"
+        "atten:      overall attenuation of output\n"
+        "position:   centre of output sound-image (0(Left) 1(Right): default 0.5)\n"
+        "spread:     spatial-spread of texture events (0 - 1(full-spread))\n"
+        "seed:       same seed-no: same output on rerun(dflt 0: differs each time)\n"
+        "-w:         always play whole input-sound (ignore maxdur,mindur vals).\n"
+        "-d:         fixed timestep between groupnotes.\n"
+        "-i:         each group not confined to a fixed instr (default:fixed)\n",MAX_SCAT_TEXTURE);
+    } else if(!strcmp(str,"tgrouped")) {
+        fprintf(stdout,
+        "TIMED TEXTURE OF EVENT-GROUPS: USAGE: texture tgrouped mode infile [infile2..]\n"
+        "outfile notedata outdur skip sndfirst sndlast mingain maxgain mindur maxdur\n"
+        "minpitch maxpitch phgrid gpspace gpsprange amprise contour gpsizelo gpsizehi\n"
+        "gppacklo gppackhi gpranglo gpranghi\n"
+        "                   [-aatten] [-pposition] [-sspread] [-rseed] [-w] [-d] [-i]\n"
+        "MODES:-\n"
+        "1)  ON A GIVEN HARMONIC-FIELD        3)  ON A GIVEN HARMONIC-SET\n"
+        "2)  ON CHANGING HARMONIC-FIELDS      4)  ON CHANGING HARMONIC-SETS\n"
+        "5)  NONE\n"
+        "notedata: infofile, 'pitch' of insnds, timings for timed textures, hfields etc\n"
+        "outdur:           (min) duration of outfile\n"
+        "skip:             time between repetitions of timing motif in notedata\n"
+        "sndfirst,sndlast: 1st,last snd to use from list of insnds(range:1 - all)\n"
+        "mingain,maxgain:  min & max level of input events (1-127:default 64,64)\n"
+        "mindur,maxdur:    min & max duration of events in texture\n"
+        "minpitch,maxpitch:min & max pitch (MIDI VALUE)\n"
+        "phgrid:           timegrid (MS) applying WITHIN the groups\n"
+        "gpspace:          spatialisation of event-groups (Range 0-5: default 1)\n"
+        "gpsprange:        spatial range of event-groups (Range 0-1: default 1)\n"
+        "amprise:          amplitude change within groups: (0-127: default 0)\n"
+        "contour:          amplitude contour of groups (Range 0-6: default 0)\n"
+            /* NOTE : CARE all_types is 7 AND NOT 8 here */
+        "gpsizelo,gpsizehi:smallest & largest numbers of events in groups\n"
+        "gppacklo,gppackhi:shortest & longest time between event-onsets in groups (MS)\n"
+        "gpranglo,gpranghi:min,max pitchrange grps OR (hfields) no.of hf-notes range\n"
+        "atten:            overall attenuation of output\n"
+        "position:         centre of output sound-image (0(Left) 1(Right): default 0.5)\n"
+        "spread:           spatial-spread of texture events (0 - 1(full-spread))\n"
+        "seed:             same seed-no: same output on rerun(dflt 0: differs each time)\n"
+        "-w:               always play whole input-sound (ignoring duration values).\n"
+        "-d:                fixed timestep between groupnotes.\n"
+        "-i:               each group not confined to a fixed instr (default:fixed)\n");
+    } else if(!strcmp(str,"decorated") || !strcmp(str,"predecor") || !strcmp(str,"postdecor")) {
+        fprintf(stdout,
+        "TEXTURE WITH DECORATIONS:USAGE:texture decorated|predecor|postdecor mode infile\n"
+        "[infile2..] outfile notedata outdur skiptime sndfirst sndlast mingain maxgain\n"
+        "mindur maxdur phgrid gpspace gpsprange amprise contour gpsizlo gpsizhi\n"
+        "gppaklo gppakhi gpranglo gpranghi centring\n"
+        "              [-aatten] [-ppos] [-ssprd] [-rseed] [-w] [-d] [-i] [-h] [-e] [-k]\n"
+        "MODES:-\n"
+        "1)ON HARMONIC-FIELD 2)CHANGING HFLDS 3)HARMONIC-SET 4)CHANGING HSETS 5)NONE\n"
+        "notedata:         infofile, 'pitch' of insnds, decoration shape etc.\n"
+        "outdur:           (min) duration outfile\n"
+        "skiptime:         time between repets of motif-to-decorate in notedata\n"
+        "sndfirst,sndlast: 1st,last snd to use, from input snds (range 1 - all)\n"
+        "mingain,maxgain:  min & max gain on input events (MIDI)\n"
+        "mindur,maxdur:    min & max duration of events in texture\n"
+        "phgrid:           timegrid (MS) applying WITHIN decors\n"
+        "gpspace:          spatialisation decor-groups (Range 0-5: default 1)\n"
+        "gpsprange:        spatial range decor-groups (Range 0-1: default 1)\n"
+        "amprise:          amplitude change within decors: (0-127: default 0)\n"
+        "contour:          amplitude contour of decors (Range 0-8: default 0)\n"
+        "gpsizlo,gpsizhi:  smallest,largest no. events in decors\n"
+        "gppaklo,gppakhi:  shortest,longest time between event-onsets in decors(MS)\n"
+        "gpranglo,gpranghi:min,max pitchrange decors OR (hfields) no.of hf-notes range\n"
+        "centring:         how decor pitches centre on line pitches(Range 0-7:default 0)\n"
+        "atten:            overall attenuation of output\n"
+        "pos:              centre of output sound-image (-1(Left) 1(Right): default 0)\n"
+        "sprd:             spatial-spread of texture events (0 - 1(full-spread))\n"
+        "seed:             same seed-no: same output on rerun(dflt 0: differs each time)\n"
+        "-w: play all insnd(ignore min,maxdur) -h: dec TOPnote chord:(dflt:1st listed)\n"
+        "-d: fixed timestep btwn decornotes    -e: dec all notes of chords\n"
+        "-i: instrs vary in decor(dflt:fixed)  -k: discard orig line, after decor\n");
+    } else if(!strcmp(str,"ornate") || !strcmp(str,"preornate") || !strcmp(str,"postornate")) {
+        fprintf(stdout,
+        "TEXTURE WITH ORNAMENTS: USAGE:\n"
+        "texture ornate|preornate|postornate mode infile [infile2...] outfile notedata\n"
+        "outdur skiptime sndfirst sndlast   mingain maxgain  mindur maxdur\n"
+        "phgrid gpspace gpsprange  amprise  contour   multlo   multhi\n"
+        "          [-aatten] [-pposition] [-sspread] [-rseed] [-w] [-d] [-i] [-h] [-e]\n"
+        "MODES:-\n"
+        "1)ON HARMONIC-FIELD 2)CHANGING HFLDS 3)HARMONIC-SET 4)CHANGING HSETS 5)NONE\n"
+        "notedata:   infofile, 'pitch' of insnds, notes in ornaments, hfields etc.\n"
+        "outdur:           (min) duration of outfile\n"
+        "skiptime:         time between repetitions of motif-to-ornament in notedata\n"
+        "sndfirst,sndlast: 1st,last snd to use, from input snds (range 1 - all)\n"
+        "mingain,maxgain:  min & max level of input events (1-127:default 64,64)\n"
+        "mindur,maxdur:    min & max duration of events in texture\n"
+        "phgrid:           a timegrid (MS) applying WITHIN the ornaments\n"
+        "gpspace:          spatialisation of event-groups (Range 0-5: default 1)\n"
+        "gpsprange:        spatial range of event-groups (Range 0-1: default 1)\n"
+        "amprise:          amplitude change within ornaments: (0-127: default 0)\n"
+        "contour:          amplitude contour of groups (Range 0-8: default 0)\n"
+        "multlo, multhi:   min & max multiplier of total input duration of motif\n"
+        "atten:            overall attenuation of the output\n"
+        "position:         centre of output sound-image (0(Left) 1(Right):default 0.5)\n"
+        "spread:           spatial-spread of texture events (0 - 1(full-spread))\n"
+        "seed:             same seed-no: same output on rerun(dflt 0: differs each time)\n"
+        "-w:               always play whole input-sound (ignoring duration values).\n"
+        "-d:               ornament notes all have same duration as ornamented note\n"
+        "-i:               orns not confined to instr of ornd-note (default:same note)\n"
+        "-h:               orns on highest note of any chord:(default:1st note listed)\n"
+        "-e:               ornaments on all notes of any chord.\n");
+    } else if(!strcmp(str,"motifsin")) {        
+        fprintf(stdout,
+        "TEXTURE OF MOTIFS, FORCED ONTO A HARMONIC FIELD: USAGE:\n"
+        "texture motifsin mode infile [infile2..] outfile notedata outdur packing\n"
+        "scatter tgrid sndfirst sndlast mingain maxgain \n"
+        "minpitch maxpitch phgrid gpspace gpsprange amprise  contour multlo multhi\n"
+        "                [-aatten] [-pposition] [-sspread] [-rseed] [-w] [-d] [-i]\n"
+        "MODES:-\n"
+        "1) ON HARMONIC-FIELD 2) CHANGING HFLDS 3) HARMONIC-SET 4) CHANGING HSETS\n"
+        "notedata: infofile,'pitch' of insnds, timings for timed textures, hfields etc\n"
+        "outdur:             (min) duration of outfile\n"
+        "packing:            (average) time between motif onsets.\n"
+        "scatter:            randomisation of event-onsets (0 - %.0lf)\n"
+        "tgrid:              minstep(MS) quantised timegrid (for mtf starttimes)(dflt 0)\n"
+        "sndfirst,sndlast:   1st,last snd to use, from input snds (range 1 - all)\n"
+        "mingain,maxgain:    min & max level of input events (1-127:default 64,64)\n"
+        "minpitch,maxpitch:  min & max pitch (MIDI VALUE)\n"
+        "phgrid:             a timegrid (MS) applying WITHIN the motifs\n"
+        "gpspace:            spatialisation of event-groups (Range 0-5: default 1)\n"
+        "gpsprange:          spatial range of event-groups (Range 0-1: default 1)\n"
+        "amprise:            amplitude change within motifs: (0-127: default 0)\n"
+        "contour:            amplitude contour of groups (Range 0-6: default 0)\n"
+            /* NOTE : CARE all_types is 7 AND NOT 8 here */
+        "multlo, multhi:     min & max multiplier of total input duration of motif\n"
+        "atten:              overall attenuation of the output\n"
+        "position:           centre of output sound-image (0(Left) 1(Right):default 0.5)\n"
+        "spread:             spatial-spread of texture events (0 - 1(full-spread))\n"
+        "seed:             same seed-no: same output on rerun(dflt 0: differs each time)\n"
+        "-w:                 always play whole input-sound (ignoring duration values).\n"
+        "-d                  notes within any one motif all have same duration.\n"
+        "-i:                 motif not each confined to fixed instr (default:fixed)\n",MAX_SCAT_TEXTURE);
+    } else if(!strcmp(str,"tmotifsin")) {       
+        fprintf(stdout,
+        "TIMED TEXTURE OF MOTIFS, FORCED ONTO A HARMONIC FIELD: USAGE:\n"
+        "texture tmotifsin mode infile [infile2...] outfile notedata sndfirst sndlast\n"
+        "mingain maxgain minpich maxpich phgrid gpspace gpsprange\n"
+        "amprise contour multlo multhi [-aatten] [-ppos] [-sspread] [-rseed] [-w] [-d]\n"
+        "MODES:-\n"
+        "1) ON HARMONIC-FIELD 2) CHANGING HFLDS 3) HARMONIC-SET 4) CHANGING HSETS\n"
+        "notedata:    infofile, 'pitch' of insnds,motifs,texture timings,hfields etc..\n"
+        "outdur:           (min) duration of outfile\n"
+        "skiptime:         time between repetitions of timing motif in notedata\n"
+        "sndfirst,sndlast: 1st,last snd to use, from input snds (range 1 - all)\n"
+        "mingain,maxgain:  minimum & maximum level of input events (1-127:default 64,64)\n"
+        "minpich,maxpich:  min & max pitch (MIDI VALUE)\n"
+        "phgrid:           a timegrid (MS) applying WITHIN the motifs\n"
+        "gpspace:          spatialisation of event-groups (Range 0-5: default 1)\n"
+        "gpsprange:        spatial range of event-groups (Range 0-1: default 1)\n"
+        "amprise:          amplitude change within motifs: (0-127: default 0)\n"
+        "contour:          amplitude contour of groups (Range 0-6: default 0)\n"
+            /* NOTE : CARE all_types is 7 AND NOT 8 here */
+        "multlo, multhi:   min & max multiplier of total input duration of motif\n"
+        "atten:            overall attenuation of the output\n"
+        "pos:              centre of output sound-image (0(Left) 1(Right):default 0.5)\n"
+        "spread:           spatial-spread of texture events (0 - 1(full-spread))\n"
+        "seed:             same seed-no: same output on rerun(dflt 0: differs each time)\n"
+        "-w:               always play whole input-sound (ignoring duration values).\n"
+        "-d:               notes in any one motif all have same duration as timing note.\n"
+        "-i:               motifs not each confined to a fixed instrument (default: fixed)\n");
+    } else if(!strcmp(str,"motifs")) {      
+        fprintf(stdout,
+        "TEXTURE OF MOTIFS, (1ST NOTES ONLY, FORCED ONTO HARMONIC FIELD/SET, IF USED)\n"
+        "USAGE: texture motifs mode infile [infile2...] outfile notedata outdur packing\n"
+        "scatter tgrid sndfirst sndlast mingain maxgain minpich maxpich\n"
+        "phgrid gpspace gpsprange amprise contour multlo multhi\n"
+        "                 [-aatten] [-pposition] [-sspread] [-rseed] [-w] [-d]\n"
+        "MODES:-\n"
+        "1)ON HARMONIC-FIELD 2)CHANGING HFLDS 3)HARMONIC-SET 4)CHANGING HSETS 5)NONE\n"
+        "notedata: infofile, 'pitch' of insnds, timings for timed textures,hfields etc.\n"
+        "outdur:             (min) duration of outfile\n"
+        "packing:            (average) time between motif onsets.\n"
+        "scatter:            randomisation of event-onsets (0 - %.0lf)\n"
+        "tgrid:              minstep(MS) quantised timegrid (for mtf starttimes)(dflt 0)\n"
+        "sndfirst,sndlast:   1st,last snd to use, from input snds (range 1 - all)\n"
+        "mingain,maxgain:    min & max level of input events (1-127:default 64,64)\n"
+        "minpich,maxpich:    min & max pitch (MIDI VALUE)\n"
+        "phgrid:             a timegrid (MS) applying WITHIN the motifs\n"
+        "gpspace:            spatialisation of event-groups (Range 0-5: default 1)\n"
+        "gpsprange:          spatial range of event-groups (Range 0-1: default 1)\n"
+        "amprise:            amplitude change within motifs: (0-127: default 0)\n"
+        "contour:            amplitude contour of groups (Range 0-6: default 0)\n"
+            /* NOTE : CARE all_types is 7 AND NOT 8 here */
+        "multlo, multhi:     min & max multiplier of total input duration of motif\n"
+        "atten:              overall attenuation of the output\n"
+        "position:           centre of output sound-image (0(Left) 1(Right):default 0.5)\n"
+        "spread:             spatial-spread of texture events (0 - 1(full-spread))\n"
+        "seed:               same seed-no: same output on rerun(dflt 0: differs each time)\n"
+        "-w:                 always play whole input-sound (ignoring duration values).\n"
+        "-d                  notes of any one motif all have same duration.\n"
+        "-i:                 motif not each confined to fixed instr (default:fixed)\n",MAX_SCAT_TEXTURE);
+    } else if(!strcmp(str,"tmotifs")) {
+        fprintf(stdout,
+        "TIMED TEXTURE OF MOTIFS, THEMSELVES NOT FORCED ONTO HARMONIC FIELD: USAGE:\n"
+        "texture tmotifs mode infile [infile2...] outfile notedata outdur skip\n"
+        "sndfirst sndlast mingain maxgain minpitch maxpitch phgrid\n"
+        "gpspace gpsprange amprise contour multlo multhi\n"
+        "                    [-aatten] [-pposition] [-sspread] [-rseed] [-w] [-d]\n"
+        "MODES:-\n"
+        "1)ON HARMONIC-FIELD 2)CHANGING HFLDS 3)HARMONIC-SET 4)CHANGING HSETS 5)NONE\n"
+        "notedata:  infofile, 'pitch' of insnds,texture timings,motifs,hfields etc....\n"
+        "outdur:             (min) duration of outfile\n"
+        "skip:               time between repetitions of timing motif in notedata\n"
+        "sndfirst,sndlast:   1st,last snd to use, from input snds (range 1 - all)\n"
+        "mingain,maxgain:    min & max level of input events (1-127:default 64,64)\n"
+        "minpitch,maxpitch:  min & max pitch (MIDI VALUE)\n"
+        "phgrid:             a timegrid (MS) applying WITHIN the motifs\n"
+        "gpspace:            spatialisation of event-groups (Range 0-5: default 1)\n"
+        "gpsprange:          spatial range of event-groups (Range 0-1: default 1)\n"
+        "amprise:            amplitude change within motifs: (0-127: default 0)\n"
+        "contour:            amplitude contour of groups (Range 0-6: default 0)\n"
+            /* NOTE : CARE all_types is 7 AND NOT 8 here */
+        "multlo, multhi:     min & max multiplier of total input duration of motif\n"
+        "atten:              overall attenuation of the output\n"
+        "position:           centre of output sound-image (0(Left) 1(Right):default 0.5)\n"
+        "spread:             spatial-spread of texture events (0 - 1(full-spread))\n"
+        "seed:             same seed-no: same output on rerun(dflt 0: differs each time)\n"
+        "-w:                 always play whole input-sound (ignoring duration values).\n"
+        "-d:                 motif notes all have same duration as ornamented note\n"
+        "-i:                 motif not each confined to fixed instr (default:fixed)\n");
+    } else
+        fprintf(stdout,"Unknown option '%s'\n",str);
+    return(USAGE_ONLY);
+}
+
+/******************************** USAGE3 ********************************/
+
+int usage3(char *str1,char *str2)
+{
+    sprintf(errstr,"Insufficient parameters on command line.\n");
+    return(USAGE_ONLY);
+}
+
+/******************************** INNER_LOOP (redundant)  ********************************/
+
+int inner_loop
+(int *peakscore,int *descnt,int *in_start_portion,int *least,int *pitchcnt,int windows_in_buf,dataptr dz)
+{
+    return(FINISHED);
+}

+ 234 - 0
dev/texture/v8/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
+ *
+ */
+/* floatsam version: no changes */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <structures.h>
+#include <tkglobals.h>
+#include <texture.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>
+
+char errstr[6000];
+
+/*extern*/ int sloom = 0;
+/*extern*/ int sloombatch = 0;
+/*extern*/ int anal_infiles = 0;
+/*extern*/ int is_converted_to_stereo = -1;
+const char* cdp_version = "8.0.1";
+
+/**************************************** MAIN *********************************************/
+
+int main(int argc,char *argv[])
+{
+    int exit_status;
+    dataptr dz = NULL;
+/*  char *special_data_string = NULL;*/
+    char **cmdline;
+    int  cmdlinecnt;
+    aplptr ap;
+    int *valid = NULL;
+    int is_launched = FALSE;
+    int  validcnt;
+
+    if(argc==2 && (strcmp(argv[1],"--version") == 0)) {
+        fprintf(stdout,"%s\n",cdp_version);
+        fflush(stdout);
+        return 0;
+    }
+                        /* CHECK FOR SOUNDLOOM */
+//TW UPDATE
+    if((sloom = sound_loom_in_use(&argc,&argv)) > 1) {
+        sloom = 0;
+        sloombatch = 1;
+    }
+
+    if(!sloom) {
+        if((exit_status = allocate_and_initialise_validity_flags(&valid,&validcnt))<0) {
+            print_messages_and_close_sndfiles(exit_status,is_launched,dz);
+            return(FAILED);
+        }
+    }
+
+    if(sflinit("cdp")){
+        sfperror("cdp: initialisation\n");
+        return(FAILED);
+    }
+
+                          /* SET UP THE PRINCIPLE DATASTRUCTURE */
+    if((exit_status = establish_datastructure(&dz))<0) {
+        print_messages_and_close_sndfiles(exit_status,is_launched,dz);
+        return(FAILED);
+    }
+                      
+    if(!sloom) {
+                              /* INITIAL CHECK OF CMDLINE DATA */
+        if((exit_status = make_initial_cmdline_check(&argc,&argv))<0) {
+            print_messages_and_close_sndfiles(exit_status,is_launched,dz);
+            return(FAILED);
+        }
+        cmdline    = argv;  /* GET PRE_DATA, ALLOCATE THE APPLICATION, CHECK FOR EXTRA INFILES */
+        cmdlinecnt = argc;
+        if((exit_status = get_process_and_mode_from_cmdline(&cmdlinecnt,&cmdline,dz))<0) {
+            print_messages_and_close_sndfiles(exit_status,is_launched,dz);
+            return(FAILED);
+        }       
+        if((exit_status = setup_particular_application(dz))<0) {
+            print_messages_and_close_sndfiles(exit_status,is_launched,dz);
+            return(FAILED);
+        }
+        if((exit_status = count_and_allocate_for_infiles(cmdlinecnt,cmdline,dz))<0) {
+            print_messages_and_close_sndfiles(exit_status,is_launched,dz);
+            return(FAILED);
+        }
+    } else {
+        if((exit_status = parse_tk_data(argc,argv,&cmdline,&cmdlinecnt,dz))<0) {    /* includes setup_particular_application()      */
+            exit_status = print_messages_and_close_sndfiles(exit_status,is_launched,dz);/* and cmdlinelength check = sees extra-infiles */
+            return(exit_status);         
+        }
+    }
+
+    ap = dz->application;
+
+/*********************************************************************************************************************
+       cmdline[0]                         2 vals                              ACTIVE         
+TK      (infile) (more-infiles) (outfile) (flag val) (formantsqksrch) (special) params  options   variant-params  flags
+CMDLINE (infile) (more-infiles) (outfile) (formants) (formantsqksrch) (special) params  POSSIBLY  POSSIBLY      POSSIBLY
+                                          1 val
+*********************************************************************************************************************/
+
+    if((exit_status = parse_infile_and_hone_type(cmdline[0],valid,dz))<0) {
+        print_messages_and_close_sndfiles(exit_status,is_launched,dz);
+        return(FAILED);
+    }
+
+    if((exit_status = setup_param_ranges_and_defaults(dz))<0) {
+        print_messages_and_close_sndfiles(exit_status,is_launched,dz);
+        return(FAILED);
+    }
+
+                    /* OPEN FIRST INFILE AND STORE DATA, AND INFORMATION, APPROPRIATELY */
+
+    if(dz->input_data_type!=NO_FILE_AT_ALL) {
+        if((exit_status = open_first_infile(cmdline[0],dz))<0) {
+            print_messages_and_close_sndfiles(exit_status,is_launched,dz);
+            return(FAILED);
+        }
+//TW UPDATE
+        cmdlinecnt--;
+        cmdline++;
+    }
+    
+/*********************************************************************************************************************
+        cmdline[0]                 2 vals                              ACTIVE
+TK      (more-infiles) (outfile) (flag val) (formantsqksrch) (special) params  options   variant-params  flags
+CMDLINE (more-infiles) (outfile) (formants) (formantsqksrch) (special) params  POSSIBLY  POSSIBLY         POSSIBLY
+                                   1 val
+*********************************************************************************************************************/
+
+    if((exit_status = handle_extra_infiles(&cmdline,&cmdlinecnt,dz))<0) {
+        print_messages_and_close_sndfiles(exit_status,is_launched,dz);
+        return(FAILED);
+    }
+
+/*********************************************************************************************************************
+        cmdline[0]    2                                 ACTIVE
+TK      (outfile) (flag val) (formantsqksrch) (special) params  options   variant-params  flags
+CMDLINE (outfile) (formants) (formantsqksrch) (special) params  POSSIBLY  POSSIBLY         POSSIBLY
+                      1
+*********************************************************************************************************************/
+
+    if((exit_status = handle_outfile(&cmdlinecnt,&cmdline,is_launched,dz))<0) {
+        print_messages_and_close_sndfiles(exit_status,is_launched,dz);
+        return(FAILED);
+    }
+
+/****************************************************************************************
+        cmdline[0]                             ACTIVE
+TK      (flag val) (formantsqksrch) (special) params  options   variant-params  flags
+CMDLINE (formants) (formantsqksrch) (special) params  POSSIBLY  POSSIBLY        POSSIBLY
+*****************************************************************************************/
+
+    if((exit_status = handle_formants(&cmdlinecnt,&cmdline,dz))<0) {
+        print_messages_and_close_sndfiles(exit_status,is_launched,dz);
+        return(FAILED);
+    }
+    if((exit_status = handle_formant_quiksearch(&cmdlinecnt,&cmdline,dz))<0) {
+        print_messages_and_close_sndfiles(exit_status,is_launched,dz);
+        return(FAILED);
+    }
+    if((exit_status = handle_special_data(&cmdlinecnt,&cmdline,dz))<0) {
+        print_messages_and_close_sndfiles(exit_status,is_launched,dz);
+        return(FAILED);
+    }
+ 
+/****************************************************************************************
+        cmdline[0]
+TK      active_params   options         variant-params  flags
+CMDLINE active_params   POSSIBLY        POSSIBLY        POSSIBLY
+*****************************************************************************************/
+
+    if((exit_status = read_parameters_and_flags(&cmdline,&cmdlinecnt,dz))<0) {
+        print_messages_and_close_sndfiles(exit_status,is_launched,dz);
+        return(FAILED);
+    }
+
+    if((exit_status = check_param_validity_and_consistency(dz))<0) {
+        print_messages_and_close_sndfiles(exit_status,is_launched,dz);
+        return(FAILED);
+    }
+
+    is_launched = TRUE;
+
+    if((exit_status = allocate_large_buffers(dz))<0){
+        print_messages_and_close_sndfiles(exit_status,is_launched,dz);
+        return(FAILED);
+    }
+    if((exit_status = param_preprocess(dz))<0){
+        print_messages_and_close_sndfiles(exit_status,is_launched,dz);
+        return(FAILED);
+    }
+    if((exit_status = groucho_process_file(dz))<0) {
+        print_messages_and_close_sndfiles(exit_status,is_launched,dz);
+        return(FAILED);
+    }
+    if((exit_status = complete_output(dz))<0) {
+        print_messages_and_close_sndfiles(exit_status,is_launched,dz);
+        return(FAILED);
+    }
+    exit_status = print_messages_and_close_sndfiles(FINISHED,is_launched,dz);
+    free(dz);
+    return(SUCCEEDED);
+}
+

+ 191 - 0
dev/texture/v8/texperm.c

@@ -0,0 +1,191 @@
+/*
+ * Copyright (c) 1983-2013 Trevor Wishart and Composers Desktop Project Ltd
+ * http://www.trevorwishart.co.uk
+ * http://www.composersdesktop.com
+ *
+ This file is part of the CDP System.
+ 
+ The CDP System is free software; you can redistribute it
+ and/or modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+ 
+ The CDP System is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU Lesser General Public License for more details.
+ 
+ You should have received a copy of the GNU Lesser General Public
+ License along with the CDP System; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA
+ *
+ */
+/* floatsam version: no changes */
+#include <stdio.h>
+#include <stdlib.h>
+#include <structures.h>
+#include <tkglobals.h>
+#include <texture.h>
+#include <globcon.h>
+#include <arrays.h>
+
+#include <osbind.h>
+
+static void rndpermm(int k,int pindex,int **permm,dataptr dz);
+static void insert(int m,int t,int pindex,int **permm,dataptr dz);
+static void prefix(int m,int pindex,int **permm,dataptr dz);
+static void shuflup(int k,int pindex, int **permm,dataptr dz);
+
+/******************************** DOPERM *********************************
+ *
+ * Either deliver next item in a permuted set, or (if set exhausted)
+ * generate a randon permutation of the set and deliver its first
+ * element.
+ *
+ * (1)  If this permset does not have the same length as the last...
+ * (2)    Set a new permset length.
+ * (3)    If a permset already exists (i.e. this is not first)
+ *    Free the permset space, and malloc a new space of correct size,
+ * (4)    Create a random permutation of elements into the permset.
+ * (5)    Set the pointer-to-the-set to 0.
+ * (6)    Set the size of the previous perm (which will be this one,
+ *    next time!) to this permset size.
+ * (6a) Whether or not a new perm set has been set up...
+ * (7)    Get the value of the next item in the current permset,
+ *    incrementing the set pointer in the process.
+ * (8)    If this has the same value as the previous-one-output-from-doperm
+ *    increment the repetition counter.
+ * (9)    Otherwise set the repetition counter to 1.
+ * (10)   If the set pointer has run beyond the permset.
+ * (11)     reset the pointer to 0.
+ * (12)     generate a new random perm (of same length).
+ * (13) Continue this process if the number of permissible repetitions
+ *  is exceeded.
+ * (14) Set the value for lastpermval, for next call.
+ * (15) Return the value.
+ */
+
+int doperm(int k,int pindex,int *val,dataptr dz)
+{
+    int i, OK;
+    int **permm = dz->tex->perm;
+    if(pindex >= PERMCNT) {
+        sprintf(errstr,"doperm(): Perm index %d too big (max = %d)\n",pindex,PERMCNT);
+        return(PROGRAM_ERROR);
+    }
+    if(k <= 1) {
+        if(k>=0) {
+            *val = 0;
+            return(FINISHED);
+        } else {
+            sprintf(errstr,"doperm(): Invalid perm count %d\n",k);
+            return(PROGRAM_ERROR);
+        }
+    }
+    if((k*dz->iparray[TXRPT][pindex])!=dz->iparray[TXLASTPERMLEN][pindex]) {    /* 1 */
+        dz->iparray[TXPERMLEN][pindex] = (int)(k * dz->iparray[TXRPT][pindex]); /* 2 */
+        if(permm[pindex]   != (int *)0)                                         /* 3 */
+            free(permm[pindex]);
+        if((permm[pindex] = (int *)malloc(dz->iparray[TXPERMLEN][pindex] * sizeof(int)))==NULL) {
+            sprintf(errstr,"INSUFFICIENT MEMORY for permutation %d\n",pindex+1);
+            return(MEMORY_ERROR);
+        }
+        rndpermm(k,pindex,permm,dz);                                            /* 4 */
+        dz->iparray[TXPERMINDEX][pindex]   = 0;                                 /* 5 */
+        dz->iparray[TXLASTPERMLEN][pindex] = dz->iparray[TXPERMLEN][pindex];    /* 6 */
+    }
+    do {                        /* 6a */
+        OK = 1;
+        i = *(permm[pindex] + (dz->iparray[TXPERMINDEX][pindex]++));            /* 7 */
+        if(i==dz->iparray[TXLASTPERMVAL][pindex]) {                             /* 8 */
+            dz->iparray[TXREPETCNT][pindex]++;
+            if(dz->iparray[TXREPETCNT][pindex]>dz->iparray[TXRPT][pindex]) {
+                dz->iparray[TXREPETCNT][pindex] = dz->iparray[TXRPT][pindex];
+                OK = 0;
+            }
+        } else {
+            dz->iparray[TXREPETCNT][pindex]=1;
+        }
+        if(dz->iparray[TXPERMINDEX][pindex]>=dz->iparray[TXPERMLEN][pindex]) {  /* 10 */
+            dz->iparray[TXPERMINDEX][pindex] = 0;                               /* 11 */
+            rndpermm(k,pindex,permm,dz);                                        /* 12 */
+        }
+    }while(!OK);                                                                /* 13 */
+    dz->iparray[TXLASTPERMVAL][pindex] = i;                                     /* 14 */
+    *val = i;
+    return(FINISHED);                                                           /* 15 */
+}
+
+/*************************** RNDPERMM *******************************
+ *
+ * Produce a permutation of k objects and store it in permutation-store
+ * number 'pindex'.
+ *
+ * (1)  permlen is the number of objects (k) times the number of repetitions
+ *      permitted (rpt[pindex]) = N.
+ * (2)  This is the efficient algorithm for distributing N objects into
+ *      a random perm.
+ * (3)  As we really only have k objects, we take the value%rpt in each
+ *      permutation location.
+ *      e.g. 3 objects repeated 3 times would give us a random perm of
+ *      nine objects such as
+ *      5 6 2 8 3 0 1 7 4
+ *      applying %3 to this we get
+ *      2 0 2 2 0 0 1 1 1
+ *      i.e. a perm of 3 objects with no more than 3 consecutive repets
+ *      of any one object!!
+ */
+
+void rndpermm(int k,int pindex,int **permm,dataptr dz)
+{
+    int n, t;
+    for(n=0;n<dz->iparray[TXPERMLEN][pindex];n++) {     /* 1 */
+        t = (int)(drand48() * (double)(n+1));       /* 2 */
+        if(t==n) {
+            prefix(n,pindex,permm,dz);
+        } else {
+            insert(n,t,pindex,permm,dz);
+        }
+    }
+    for(n=0;n<dz->iparray[TXPERMLEN][pindex];n++)       /* 3 */
+        *(permm[pindex]+n) = (int)(*(permm[pindex]+n) % k);
+}
+
+/***************************** INSERT **********************************
+ *
+ * Insert the value m AFTER the T-th element in permm[pindex].
+ */
+
+void insert(int m,int t,int pindex,int **permm,dataptr dz)
+{   
+    shuflup(t+1,pindex,permm,dz);
+    *(permm[pindex]+t+1) = m;
+}
+
+/***************************** PREFIX ************************************
+ *
+ * Insert the value m at start of the permutation permm[pindex].
+ */
+
+void prefix(int m,int pindex,int **permm,dataptr dz)
+{
+    shuflup(0,pindex,permm,dz);
+    *permm[pindex] = m;
+}
+
+/****************************** SHUFLUP ***********************************
+ *
+ * move set members in permm[pindex] upwards, starting from element k.
+ */
+
+void shuflup(int k,int pindex, int **permm,dataptr dz)
+{
+    int n, *i;
+    int z = dz->iparray[TXPERMLEN][pindex] - 1;
+    i = permm[pindex] + z;
+    for(n = z;n > k;n--) {
+        *i = *(i-1);
+        i--;
+    }
+}

+ 1661 - 0
dev/texture/v8/texprepro.c

@@ -0,0 +1,1661 @@
+/*
+ * Copyright (c) 1983-2013 Trevor Wishart and Composers Desktop Project Ltd
+ * http://www.trevorwishart.co.uk
+ * http://www.composersdesktop.com
+ *
+ This file is part of the CDP System.
+
+    The CDP System is free software; you can redistribute it
+    and/or modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    The CDP System is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with the CDP System; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+    02111-1307 USA
+ *
+ */
+/* floatsam version */
+#include <stdio.h>
+#include <stdlib.h>
+#include <memory.h>
+#include <structures.h>
+#include <tkglobals.h>
+#include <globcon.h>
+#include <processno.h>
+#include <modeno.h>
+#include <arrays.h>
+#include <texture.h>
+#include <ctype.h>
+#include <sfsys.h>
+#include <osbind.h>
+#include <cdpmain.h>
+
+#if defined unix || defined __GNUC__
+#define round(x) lround((x))
+#endif
+
+#define omit_count  is_rectified
+#define omit_item   is_mapping
+#define one_in      rampbrksize
+#define negscat     fzeroset
+
+#define SQUASH    (2.0) /* non-linearity factor */
+#define MAXPOSCNT (512) /* max no. of spatial positions between lspkrs */
+
+static int  initialise_texture_structure(dataptr dz);
+static int  set_up_and_fill_insample_buffers(insamptr **insound,dataptr dz);
+static int  setup_texflag(texptr tex,dataptr dz);
+static int  adjust_some_input_params(dataptr dz);
+static int  preset_some_internal_texture_params(dataptr dz);
+static int  install_unused_texture_flags(int *total_flags,int unused_flags,dataptr dz);
+static int  install_the_internal_flags(int total_flags,int internal_flags,dataptr dz);
+static int  get_the_notedata(texptr tex,dataptr dz);
+static int  extend_timeset(dataptr dz);
+static int  generate_timeset(dataptr dz);
+static int  do_prespace(motifptr tset,dataptr dz);
+static int  get_sample_pitches(FILE *fp,dataptr dz);
+static int  get_motifs(FILE *fp,int *motifcnt,dataptr dz);
+static int  motifchek(motifptr thismotif);
+static void convert_cmdline_instrnos_to_internal_representation(dataptr dz);
+static int  check_max_transpos_compatible_with_splicelen(dataptr dz);
+static int  set_amptype_params(dataptr dz);
+static int  set_decor_pitchposition_params(dataptr dz);
+static void copy_note(noteptr thisnote,noteptr orignote);
+static int  add_motif_to_end_of_motiflist(motifptr *new,dataptr dz);
+static int  scatter_and_quantise_tset_times(double *lasttime,noteptr *thisnote,dataptr dz);
+static int  pre_space(noteptr thisnote,dataptr dz);
+static int  getpos(double thistime,double *position,dataptr dz);
+static int  spread_and_set_cpos(double *position,double given_position,double spread,dataptr dz);
+static int  chekrang(double *val);
+static int  read_a_note_from_notedata_file
+                (noteptr thisnote,int noteno,int motifno,double *lasttime,dataptr dz);
+static int  generate_tset_times(double *thistime,noteptr *thisnote,dataptr dz);
+static int  un_link_note(noteptr thisnote);
+static int  new_motif(motifptr *thismotif);
+static int  unlink_last_motif(motifptr thismotif);
+static void subtract_one_from_brkvals(int paramno,dataptr dz);
+static int  bigscatter(noteptr *thisnote,double thistime,double timestep,double scatter,double *lasttime,dataptr dz);
+static int  get_data_item(char *q,char **p,double *val);
+static int  init_note(noteptr *thisnote);
+static void put_znote(noteptr thisnote);
+static int  assign_timeset_hfset_motifsets(dataptr dz);
+static int  massage_params(dataptr dz);
+static int  init_motifs(dataptr dz);
+
+/************************* TEXTURE_PREPROCESS ****************************
+ *
+ * (1)  Establish the bitflag which characterises the texture process.
+ * (2)  For consistency across all texture processes, all unused flags are mallocd.
+ *      This ensures that the numbering of the INTERNAL flags is consistent across all applics.
+ * (3)  Convert some input parameters to form used internally, and check some against insnd lengths.
+ */
+
+int texture_preprocess(dataptr dz)
+{
+    int exit_status;
+    int total_flags, unused_flags, n;
+    unsigned int texflag;
+
+    initialise_random_sequence(0,TEXTURE_SEED,dz);
+    if((exit_status = initialise_texture_structure(dz))<0)
+        return(exit_status);
+
+    if((exit_status = set_up_and_fill_insample_buffers(&(dz->tex->insnd),dz))<0)
+        return(exit_status);
+    
+   if((exit_status = initperm(&(dz->tex->perm),dz))<0)
+        return(exit_status);
+
+    if((exit_status = setup_texflag(dz->tex,dz))<0)                     /* 1 */
+        return(exit_status);
+
+    texflag = dz->tex->txflag;
+
+    if((exit_status = adjust_some_input_params(dz))<0)
+        return(exit_status);
+                                                                        
+    if((exit_status = preset_some_internal_texture_params(dz))<0)
+        return(exit_status);
+                                                                        /* 2 */
+    unused_flags = TOTAL_POSSIBLE_USER_FLAGS - dz->application->vflag_cnt;
+
+    if((exit_status = install_unused_texture_flags(&total_flags,unused_flags,dz))<0)
+        return(exit_status);
+
+    if((exit_status = install_the_internal_flags(total_flags,INTERNAL_FLAGS_CNT,dz))<0)
+        return(exit_status);
+
+    if((exit_status = get_the_notedata(dz->tex,dz))<0)
+        return(exit_status);
+
+    if((exit_status = assign_timeset_hfset_motifsets(dz))<0)
+        return(exit_status);
+
+    if((exit_status = massage_params(dz))<0)                            /* 3 */
+        return(exit_status);
+   if(texflag & ORN_DEC_OR_TIMED) {
+        if((exit_status = extend_timeset(dz))<0)                        /* 7 */
+            return(exit_status);
+    } else {
+        if((exit_status = generate_timeset(dz))<0)                      /* 8 */
+            return(exit_status);
+    }
+    if((exit_status = do_prespace(dz->tex->timeset,dz))<0)
+        return(exit_status);
+
+    if(dz->process == SIMPLE_TEX && dz->vflag[CYCLIC_TEXFLAG]) {
+        if(dz->infilecnt < 2)
+            dz->vflag[CYCLIC_TEXFLAG] = 0;
+        else if (dz->vflag[PERM_TEXFLAG]) {
+            if((dz->peakno = (int *)malloc(dz->infilecnt * sizeof(int))) == NULL) {
+                sprintf(errstr,"Insufficient memory for cyclic permutations of input files.\n");
+                return(MEMORY_ERROR);
+            }
+            if((dz->lastpeakno = (int *)malloc(dz->infilecnt * sizeof(int))) == NULL) {
+                sprintf(errstr,"Insufficient memory for cyclic permutations of input files.\n");
+                return(MEMORY_ERROR);
+            }
+            for(n=0;n<dz->infilecnt;n++) {
+                dz->peakno[n] = n;
+                dz->lastpeakno[n] = n;
+            }
+        }
+    }
+    /* create stereo outfile here! */
+    /* RWD 4:2002  now we can open outfile with corect params! */
+//TW UPDATE to use stereo input means that dz->infile->channels must be retained for now
+//TW Open outfile later (texture5.c)
+    return(FINISHED);
+}
+
+/*********************** INITIALISE_TEXTURE_STRUCTURE ******************************/
+
+int initialise_texture_structure(dataptr dz)
+{
+    int n;
+    if((dz->tex = (texptr)malloc(sizeof(struct textural)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY for texture structure.\n");
+        return(MEMORY_ERROR);
+    }
+
+    dz->tex->txflag     = 0;
+    dz->tex->motifhead  = (motifptr)0;
+    dz->tex->insnd      = (insamptr *)0;
+    dz->tex->timeset    = (motifptr)0;
+    dz->tex->hfldmotif  = (motifptr)0;
+    dz->tex->phrase     = (motifptr *)0;
+    dz->tex->perm       = (int **)0;
+    dz->tex->dectypstor = 0;
+    dz->tex->dectypcnt  = 0;
+    dz->tex->amptypstor = 0;
+    dz->tex->amptypcnt  = 0;
+    dz->tex->phrasecnt  = 0;
+    dz->tex->ampdirectd = FALSE;
+
+    if((dz->tex->insnd  = (insamptr *)malloc(dz->infilecnt * sizeof(insamptr)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY for texture insound structure.\n");
+        return(MEMORY_ERROR);
+    }
+    for(n=0;n<dz->infilecnt;n++) {
+        dz->tex->insnd[n] = (insamptr)0;
+        if((dz->tex->insnd[n]= (insamptr)malloc(sizeof(struct insample)))==NULL) {
+            sprintf(errstr,"INSUFFICIENT MEMORY for texture insound[%d] structure.\n",n+1);
+            return(MEMORY_ERROR);
+        }
+    }
+    return(FINISHED);
+}
+ 
+/************************** SET_UP_AND_FILL_INSAMPLE_BUFFERS ****************************
+ *
+ * 1) Set buffer pointer to zero, until it has been malloced.
+ *    This make freeing of tex structure possible.
+ */
+
+int set_up_and_fill_insample_buffers(insamptr **insound,dataptr dz)
+{
+    int n;
+    int samps_read;
+    int thisbufsize;
+    int wrap_around_samps = 1;
+    for(n=0;n<dz->infilecnt;n++) {
+        ((*insound)[n])->buffer = /*(float *)0*/NULL;                   /* 1 */
+        thisbufsize = dz->insams[n];
+        thisbufsize += wrap_around_samps; 
+        if((((*insound)[n])->buffer  = (float *)malloc(thisbufsize * sizeof(float)))==NULL) {
+            sprintf(errstr,"INSUFFICIENT MEMORY for texture insound buffer pointer %d.\n",n+1);
+            return(MEMORY_ERROR);
+        }
+        memset((char *)((*insound)[n])->buffer,0,thisbufsize * sizeof(float));
+        if((samps_read = fgetfbufEx(((*insound)[n])->buffer,thisbufsize,dz->ifd[n],0)) < 0) {
+            sprintf(errstr,"Can't read sndfile %d to buffer: set_up_and_fill_insample_buffers()\n",n+1);
+            return(SYSTEM_ERROR);
+        }
+        if(samps_read != dz->insams[n]) {
+            sprintf(errstr,"Error reading sndfile %d to buf: set_up_and_fill_insample_buffers()\n",n+1);
+            return(PROGRAM_ERROR);
+        }
+    }
+    return(FINISHED);
+}
+
+/***************************** SETUP_TEXFLAG ****************************/
+
+int setup_texflag(texptr tex,dataptr dz)
+{
+    tex->txflag = 0;
+    switch(dz->process) {
+    case(SIMPLE_TEX): break;
+    case(GROUPS):     tex->txflag |= IS_GROUPS;                                                     break;
+    case(DECORATED):  tex->txflag |= IS_DECOR;                                                      break;
+    case(PREDECOR):   tex->txflag |= IS_DECOR;  tex->txflag |= ISPRE_DECORORN;                      break;
+    case(POSTDECOR):  tex->txflag |= IS_DECOR;  tex->txflag |= ISPOST_DECORORN;                     break;
+    case(ORNATE):     tex->txflag |= IS_ORNATE;                                                     break;
+    case(PREORNATE):  tex->txflag |= IS_ORNATE; tex->txflag |= ISPRE_DECORORN;                      break;
+    case(POSTORNATE): tex->txflag |= IS_ORNATE; tex->txflag |= ISPOST_DECORORN;                     break;
+    case(MOTIFS):     tex->txflag |= IS_MOTIFS;                                                     break;
+    case(MOTIFSIN):   tex->txflag |= IS_MOTIFS; tex->txflag |= MOTIF_IN_HF;                         break;
+    case(TIMED):                                                            tex->txflag |= ISTIMED; break;
+    case(TGROUPS):    tex->txflag |= IS_GROUPS;                             tex->txflag |= ISTIMED; break;
+    case(TMOTIFS):    tex->txflag |= IS_MOTIFS;                             tex->txflag |= ISTIMED; break;
+    case(TMOTIFSIN):  tex->txflag |= IS_MOTIFS; tex->txflag |= MOTIF_IN_HF; tex->txflag |= ISTIMED; break;
+    default:
+        sprintf(errstr,"Unknown process in setup_texflag()\n");
+        return(PROGRAM_ERROR);
+    }
+    switch(dz->mode) {
+    case(TEX_NEUTRAL):  break;
+    case(TEX_HFIELD):   tex->txflag |= ISHARM;                                                          break;
+    case(TEX_HFIELDS):  tex->txflag |= ISHARM;                          tex->txflag |= ISMANY_HFLDS;    break;
+    case(TEX_HSET):     tex->txflag |= ISHARM;  tex->txflag |= IS_HS;                                   break;
+    case(TEX_HSETS):    tex->txflag |= ISHARM;  tex->txflag |= IS_HS;   tex->txflag |= ISMANY_HFLDS;    break;
+    default:
+        sprintf(errstr,"Unknown mode in setup_texflag()\n");
+        return(PROGRAM_ERROR);
+    }
+    return(FINISHED);
+}
+
+/************************** ADJUST_SOME_INPUT_PARAMS ****************************
+ *
+ * (1)  dz->vflag[WHICH_CHORDNOTE] internally carries all 3 vals (first,highest,every).
+ *
+ * (2)  Gprange, in cases with Hfields, is an integer count of HF-field notes to use.
+ */
+
+int adjust_some_input_params(dataptr dz)
+{
+    int texflag = dz->tex->txflag;
+    if((texflag & IS_ORN_OR_DEC) && dz->vflag[FORCE_EVERY]==TRUE)
+        dz->vflag[WHICH_CHORDNOTE] = DECOR_EVERY;                       /* 1 */
+
+    if((texflag & IS_DEC_OR_GRP) && (texflag & ISHARM)) {               /* 2 */
+        dz->is_int[TEX_GPRANGLO] = TRUE;
+        dz->is_int[TEX_GPRANGHI] = TRUE;
+        dz->iparam[TEX_GPRANGLO] = round(dz->param[TEX_GPRANGLO]);
+        dz->iparam[TEX_GPRANGHI] = round(dz->param[TEX_GPRANGHI]);
+    }
+    return(FINISHED);
+}
+
+/***************************** PRESET_SOME_INTERNAL_TEXTURE_PARAMS ****************************/
+
+int preset_some_internal_texture_params(dataptr dz)
+{   
+    int cnt = 0;
+    dz->iparam[SPINIT]    = 0;   cnt++; /* ALL CLUMPS */
+    dz->iparam[SPCNT]     = 0;   cnt++; 
+    dz->iparam[DIRECTION] = 0;   cnt++; 
+    dz->param[CPOS]       = 0.5; cnt++; /* for safety only */   /* SPATIALISATION */
+    dz->param[TPOSITION]  = 0.5; cnt++; /* for safety only */
+    dz->param[THISSPRANGE]= 1.0; cnt++; /* full range */
+    /*dz->iparam[TEX_MAXOUT]= 0.0;   cnt++; *//* min value */
+    dz->param[TEX_MAXOUT] = 0.0;   cnt++;         /*RWD*/
+    if(cnt != dz->application->internal_param_cnt) {
+        sprintf(errstr,"preset_some_internal_texture_params() has false count\n");
+        return(PROGRAM_ERROR);
+    }
+    dz->itemcnt = 0;
+    return(FINISHED);
+}
+
+/***************************** INSTALL_UNUSED_TEXTURE_FLAGS ****************************/
+
+int install_unused_texture_flags(int *total_flags,int unused_flags,dataptr dz)
+{
+    int n;
+    *total_flags = dz->application->vflag_cnt + unused_flags;
+    if(unused_flags > 0) {
+        if((dz->vflag  = 
+            (char *)realloc(dz->vflag,(*total_flags) * sizeof(char)))==NULL) {
+            sprintf(errstr,"INSUFFICIENT MEMORY for internal flags.\n");
+            return(MEMORY_ERROR);
+        }
+        for(n=0;n<unused_flags;n++) {
+            switch(n) {
+            case(4):    dz->vflag[2] = FALSE;   break;
+            case(3):    dz->vflag[3] = FALSE;   break;
+            case(2):    dz->vflag[4] = FALSE;   break;
+            case(1):    dz->vflag[5] = FALSE;   break;
+            case(0):    dz->vflag[6] = FALSE;   break;
+            }
+        }
+    }
+    return(FINISHED);
+}
+
+/***************************** INSTALL_THE_INTERNAL_FLAGS ****************************/
+
+int install_the_internal_flags(int total_flags,int internal_flags,dataptr dz)
+{
+        /* THESE FLAGS ARE NOT AVAILABLE TO USER : but they are used in the code */
+    total_flags += internal_flags;
+    if((dz->vflag  = 
+        (char *)realloc(dz->vflag,total_flags * sizeof(char)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY to reallocate internal flags.\n");
+        return(MEMORY_ERROR);
+    }
+    dz->iparam[DECCENTRE] = FALSE;
+    return(FINISHED);
+}
+
+/***************************** GET_THE_NOTEDATA ****************************/
+
+int get_the_notedata(texptr tex,dataptr dz)
+{
+    int exit_status;
+    unsigned int texflag = tex->txflag;
+    int motifcnt, expected_motifcnt = 0;
+
+    if(dz->fp==NULL) {
+        sprintf(errstr,"notedata fileptr not initialised: get_the_notedata()\n");
+        return(PROGRAM_ERROR);
+    }
+    if((exit_status = get_sample_pitches(dz->fp,dz))<0) {
+        sprintf(errstr,"Insufficient pitch values in notedata file.\n");
+        return(DATA_ERROR);
+    }
+    if((exit_status = get_motifs(dz->fp,&motifcnt,dz))<0)
+        return(exit_status);
+    if(texflag & ORN_DEC_OR_TIMED)  expected_motifcnt++;    /* Line to work on */
+    if(texflag & ISHARM)            expected_motifcnt++;    /* HF data         */
+    if(texflag & IS_ORN_OR_MTF)     expected_motifcnt++;    /* Ornmnts or mtfs */
+
+    if(texflag & IS_ORN_OR_MTF) {
+        if(motifcnt < expected_motifcnt) {
+            sprintf(errstr,"Insufficient motifs in notedata file.\n");
+            return(DATA_ERROR);
+        }
+    } else {
+        if(motifcnt!=expected_motifcnt) {
+            sprintf(errstr,"Incorrect number [%d] of motifs in notedata file (expected %d).\n",
+            motifcnt,expected_motifcnt);
+            return(DATA_ERROR);
+        }
+    }
+    return(FINISHED);
+}
+
+/**************************** EXTEND_TIMESET *******************************/
+
+int extend_timeset(dataptr dz)
+{
+    int exit_status;
+    int origcnt = 0, n;
+    noteptr startnote = dz->tex->motifhead->firstnote;
+    noteptr orignote, thisnote  = startnote;
+    double *timediff;
+    
+    if(startnote==(noteptr)0) {
+        sprintf(errstr,"Problem in note timings: extend_timeset()\n");
+        return(PROGRAM_ERROR);
+    }
+    while(thisnote!=(noteptr)0) {
+        if(thisnote->ntime > dz->param[TEXTURE_DUR]) {
+            delete_notes_here_and_beyond(thisnote);
+            return(FINISHED);
+        }
+        thisnote = thisnote->next;
+        origcnt++;
+    }
+
+    if((timediff = (double *)malloc(origcnt * sizeof(double)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY for timegaps array.\n");
+        return(MEMORY_ERROR);
+    }
+    n = 1;
+    thisnote = startnote;
+    while(thisnote->next !=(noteptr)0) {
+        thisnote = thisnote->next;
+        timediff[n++] = thisnote->ntime - thisnote->last->ntime;
+    }
+    if(dz->brksize[TEXTURE_SKIP]) {
+        if((exit_status = read_value_from_brktable(thisnote->ntime,TEXTURE_SKIP,dz))<0) {
+            free(timediff);
+            return(exit_status);
+        }
+    }
+    timediff[0] = dz->param[TEXTURE_SKIP];
+    n = 0;
+    orignote = startnote;
+
+    for(;;) {
+        if(thisnote->ntime > dz->param[TEXTURE_DUR] && timediff[n] > 0.0)
+            break;
+        if((exit_status = make_new_note(&thisnote))<0) {
+            free(timediff);
+            return(exit_status);
+        }
+        copy_note(thisnote,orignote);
+        thisnote->ntime = (float)(thisnote->last->ntime + timediff[n]);
+        if(++n>=origcnt) {
+            if(dz->brksize[TEXTURE_SKIP]) {
+                if((exit_status = read_value_from_brktable(thisnote->ntime,TEXTURE_SKIP,dz))<0) {
+                    free(timediff);
+                    return(exit_status);
+                }
+                timediff[0] = dz->param[TEXTURE_SKIP];
+            }
+            n = 0;
+            orignote = startnote;
+        } else
+            orignote = orignote->next;
+    }
+    dz->brksize[TEXTURE_SKIP] = 0;  /* prevent future reads */
+    free(timediff);
+    return(FINISHED);
+}
+
+
+/*********************************************************************
+ *
+ * (1)  Generating the tset (set of timed values on or around which the
+ *      texture is to be generated).
+*/
+/************************** GENERATE_TIMESET ******************************
+ *
+ * (A)  Zero all other parameters besides time.
+ */     
+
+int generate_timeset(dataptr dz)
+{
+    int exit_status;
+    double lasttime, thistime = 0.0;
+    noteptr thisnote;
+    motifptr tset;
+    if((exit_status = add_motif_to_end_of_motiflist(&(dz->tex->timeset),dz))<0)
+        return(exit_status);
+    tset =  dz->tex->timeset;
+    if((thisnote = tset->firstnote)==(noteptr)0) {
+        sprintf(errstr,"Failure to find 1st note in motif: generate_timeset()\n");
+        return(PROGRAM_ERROR);
+    }
+    put_znote(thisnote);            /* A */
+    thisnote->ntime = (float)thistime;
+    if(dz->brksize[TEXTURE_PACK]) {
+        if((exit_status = read_value_from_brktable(thistime,TEXTURE_PACK,dz))<0)
+            return(exit_status);
+    }       
+    thistime += dz->param[TEXTURE_PACK];
+    while(thistime<dz->param[TEXTURE_DUR]) {
+        if((exit_status = generate_tset_times(&thistime,&thisnote,dz))<0)
+            return(exit_status);
+        put_znote(thisnote);                /* A */
+    }
+    thisnote = tset->firstnote;
+    lasttime = thisnote->ntime;
+    thisnote = thisnote->next;
+    dz->omit_count = 0;
+    dz->omit_item  = 0;
+    dz->negscat    = -1;    // Initialisation
+    while(thisnote!=(noteptr)0) {
+        if((exit_status = scatter_and_quantise_tset_times(&lasttime,&thisnote,dz))<0)
+            return(exit_status);
+    }
+    dz->brksize[TEXTURE_PACK]  = 0; /* set these brktables to appear empty, so no read attempts later */
+    dz->brksize[TEXTURE_SCAT]  = 0;
+    dz->brksize[TEXTURE_TGRID] = 0;
+    if(dz->process == SIMPLE_TEX)
+        dz->brksize[TEX_PHGRID] = 0;
+    return(FINISHED);
+}
+
+/***************************** DO_PRESPACE ******************************
+ *
+ * Spatialise the time set, prior to output phase&/or ornamentation.
+ */
+
+int do_prespace(motifptr tset,dataptr dz)
+{
+    int exit_status;
+    noteptr thisnote = tset->firstnote;
+    while(thisnote!=(noteptr)0) {
+        if((exit_status = pre_space(thisnote,dz))<0)
+            return(exit_status);
+        thisnote = thisnote->next;
+    }
+    return(FINISHED);
+}
+
+/**************************** GET_SAMPLE_PITCHES *****************************/
+
+int get_sample_pitches(FILE *fp,dataptr dz)
+{
+    int exit_status;
+/* TW AUGUST 2006: 200--> 2000 */
+    char temp[200000], *q;
+    int pitchcnt = 0;
+    double *p;
+    int got_all_pitches = FALSE;
+/* TW AUGUST 2006: 200--> 2000 */
+    while(!got_all_pitches && (fgets(temp,200000,fp)!=NULL)) {
+        q = temp;
+        if(*q == ';')   //  Allow comments in file
+            continue;
+        p = &(((dz->tex->insnd)[pitchcnt])->pitch);
+        while((exit_status = get_float_from_within_string(&q,p))==TRUE) {
+            if(++pitchcnt >= dz->infilecnt) {
+                got_all_pitches = TRUE;
+                break;
+            }
+            p = &(((dz->tex->insnd)[pitchcnt])->pitch);
+        }
+        if(exit_status==FALSE)
+            return(DATA_ERROR);
+    }
+    if(!got_all_pitches)
+        return(DATA_ERROR);
+    return(FINISHED);
+}
+
+/**************************** GET_MOTIFS *****************************
+ * 
+ * Read data from an ascii file to notelist.
+ */
+
+int get_motifs(FILE *fp,int *motifcnt,dataptr dz)
+{
+    int exit_status;
+    motifptr thismotif;
+    noteptr thisnote;
+    char *p, temp[200];
+    double lasttime = 0.0;
+    int datalen, noteno, motifno = 0;
+    if((exit_status = init_motifs(dz))<0)       /* 8 */
+        return(exit_status);
+    thismotif = dz->tex->motifhead;
+    while(fgets(temp,200,fp)!=NULL) {
+        p = temp;
+        while(isspace(*p))
+            p++;
+        if(*p==ENDOFSTR)
+            continue;
+        if(*p!=TEXTURE_SEPARATOR) {
+//TW UPDATE
+            sprintf(errstr,"'%c' missing before datacount in notedata file: motif %d (or more notes listed than indicated by %cN)\n"
+            "check datalen is correct\n",TEXTURE_SEPARATOR,motifno+1,TEXTURE_SEPARATOR);
+            return(DATA_ERROR);
+        }
+        p++;
+        if(!isdigit(*p) || sscanf(p,"%d",&datalen)!=1) {
+            sprintf(errstr,"No datalength given: motif %d\n",motifno+1);
+            return(DATA_ERROR);
+        }
+        if(datalen <= 0) {
+            sprintf(errstr,"Invalid data length %d in notedata: motif %d\n",datalen,motifno+1);
+            return(DATA_ERROR);
+        }
+        motifno++;
+        thisnote = thismotif->firstnote;
+        for(noteno=1;noteno<=datalen;noteno++) {
+            if((exit_status = read_a_note_from_notedata_file(thisnote,noteno,motifno,&lasttime,dz))<0)
+                return(exit_status);
+            if(exit_status==CONTINUE) {
+                noteno--;
+                continue;
+            }               
+            if((exit_status = make_new_note(&thisnote))<0)
+                return(exit_status);
+        }
+        if((exit_status = un_link_note(thisnote))<0)
+            return(exit_status);
+        if((exit_status = new_motif(&thismotif))<0)
+            return(exit_status);
+    }
+    *motifcnt = motifno;
+    if(motifno > 0)
+        return unlink_last_motif(thismotif);
+    return(FINISHED);
+}
+
+/************************** MOTIFCHEK ********************************
+ *
+ * Check we've not run out of motifs.
+ */
+
+int motifchek(motifptr thismotif)
+{
+    if(thismotif == (motifptr)0) {
+        sprintf(errstr,"motifchek(): Insufficient motifs: even though correctly counted.\n");
+        return(PROGRAM_ERROR);
+    }
+    return(FINISHED);
+}
+
+/***************************** CONVERT_CMDLINE_INSTRNOS_TO_INTERNAL_REPRESENTATION ****************************/
+
+void convert_cmdline_instrnos_to_internal_representation(dataptr dz)
+{
+    if(dz->brksize[TEXTURE_INSLO])
+        subtract_one_from_brkvals(TEXTURE_INSLO,dz);
+    else
+        dz->iparam[TEXTURE_INSLO]--;
+
+    if(dz->brksize[TEXTURE_INSHI])
+        subtract_one_from_brkvals(TEXTURE_INSHI,dz);
+    else
+        dz->iparam[TEXTURE_INSHI]--;
+}
+
+/***************************** CHECK_MAX_TRANSPOS_COMPATIBLE_WITH_SPLICELEN ****************************/
+
+int check_max_transpos_compatible_with_splicelen(dataptr dz)
+{
+    int n, exit_status;
+    double max_maxpitch, max_minpitch, max_transpospitch, maxupshift, upratio, minlen;
+    double min_sndlength = (TEXTURE_SPLICELEN + TEXTURE_SAFETY) * MS_TO_SECS * (double)dz->infile->srate;
+    dz->frametime = TEXTURE_SPLICELEN;
+
+    if(dz->brksize[TEXTURE_MAXPICH]) {
+        if((exit_status = get_maxvalue_in_brktable(&max_maxpitch,TEXTURE_MAXPICH,dz))<0)
+            return(exit_status);
+    } else
+        max_maxpitch = dz->param[TEXTURE_MAXPICH];
+
+    if(dz->brksize[TEXTURE_MINPICH]) {
+        if((exit_status = get_maxvalue_in_brktable(&max_minpitch,TEXTURE_MINPICH,dz))<0)
+            return(exit_status);
+    } else
+        max_minpitch = dz->param[TEXTURE_MINPICH];
+
+    max_transpospitch = max(max_minpitch,max_maxpitch);
+
+    dz->zeroset = 0;    /* use as flag re splicelen change */
+    for(n=0;n<dz->infilecnt;n++) {
+        maxupshift = max_transpospitch - ((dz->tex->insnd)[n])->pitch;
+        upratio    = pow(2.0,(maxupshift/SEMITONES_PER_OCTAVE));
+        minlen     = (double)dz->insams[n]/upratio;
+        if(minlen < min_sndlength) {
+            dz->frametime = 2.0;    
+            min_sndlength = (dz->frametime + TEXTURE_SAFETY) * MS_TO_SECS * (double)dz->infile->srate;
+#ifdef MINDUR_OVERRIDE
+            min_sndlength = 0.0;
+#endif
+            if(minlen < min_sndlength) {
+                dz->frametime = 1.0;    
+                min_sndlength = (dz->frametime + TEXTURE_SAFETY) * MS_TO_SECS * (double)dz->infile->srate;
+                if(minlen < min_sndlength) {
+                    sprintf(errstr,"sndfile %d [%.3lf secs] too short for max upward transposition [ratio %.2lf].\n",
+                    n+1,(double)dz->insams[n]/(double)dz->infile->srate,upratio);
+                    return(DATA_ERROR);
+                }
+            }
+        }
+    }
+    return(FINISHED);
+}
+
+/************************* SET_AMPTYPE_PARAMS *******************************/
+
+int set_amptype_params(dataptr dz)
+{   int mask = 1, n;
+    dz->tex->amptypcnt  = 0;
+    dz->tex->amptypstor = 0;
+    switch(dz->iparam[TEX_AMPCONT]) {
+    case(IS_MIXED):              dz->tex->amptypstor |= 1;  dz->tex->amptypstor |= 2;                           break;
+    case(IS_CRESC):                                         dz->tex->amptypstor |= 2;                           break;
+    case(IS_FLAT):               dz->tex->amptypstor |= 1;                                                      break;
+    case(IS_DECRESC):                                                                 dz->tex->amptypstor |= 4; break;
+    case(IS_FLAT_AND_CRESC):     dz->tex->amptypstor |= 1;  dz->tex->amptypstor |= 2;                           break;
+    case(IS_CRESC_AND_DECRESC):                             dz->tex->amptypstor |= 2; dz->tex->amptypstor |= 4; break;
+    case(IS_FLAT_AND_DECRESC):   dz->tex->amptypstor |= 1;                            dz->tex->amptypstor |= 4; break;
+
+    case(IS_DIRECTIONAL):        dz->tex->ampdirectd = TRUE;    dz->tex->amptypcnt = 1;                         break;
+    case(IS_DIREC_OR_FLAT):      dz->tex->ampdirectd = TRUE;    dz->tex->amptypcnt = 2;                         break;
+    default:
+        sprintf(errstr,"Unknown case in set_amptype_params()\n");
+        return(PROGRAM_ERROR);
+    }
+    if(dz->tex->amptypstor > 0) {
+        for(n=0;n<3;n++) {
+            if(mask & dz->tex->amptypstor)
+                dz->tex->amptypcnt++;
+            mask <<= 1;
+        }
+    }
+    return(FINISHED);
+}
+
+/************************* SET_DECOR_PITCHPOSITION_PARAMS ******************************/
+
+int set_decor_pitchposition_params(dataptr dz)
+{
+    int n, mask = 1;
+    dz->tex->dectypstor = 0;
+    dz->tex->dectypcnt  = 0;
+    switch(dz->iparam[TEX_DECPCENTRE]) {
+    case(DEC_CENTRED): dz->tex->dectypstor |= 1;                                                        break;
+    case(DEC_ABOVE):                             dz->tex->dectypstor |= 2;                              break;
+    case(DEC_BELOW):                                                        dz->tex->dectypstor |= 4;   break;
+    case(DEC_C_A):     dz->tex->dectypstor |= 1; dz->tex->dectypstor |= 2;                              break;
+    case(DEC_C_B):     dz->tex->dectypstor |= 1;                            dz->tex->dectypstor |= 4;   break;
+    case(DEC_A_B):                               dz->tex->dectypstor |= 2;  dz->tex->dectypstor |= 4;   break;
+    case(DEC_C_A_B):   dz->tex->dectypstor |= 1; dz->tex->dectypstor |= 2;  dz->tex->dectypstor |= 4;   break;
+    default:
+        sprintf(errstr,"Unknown case in set_decor_pitchposition_params()\n");
+        return(PROGRAM_ERROR);
+    }
+    if(dz->tex->dectypstor > 0) {
+        for(n=0;n<3;n++) {
+            if(mask & dz->tex->dectypstor)
+                dz->tex->dectypcnt++;
+            mask <<= 1;
+        }
+    }
+    return(FINISHED);
+}
+
+/********************** DELETE_NOTES_HERE_AND_BEYOND *******************************
+
+void delete_notes_here_and_beyond(noteptr startnote)
+{
+    noteptr here = startnote;
+    if(here==(noteptr)0)
+        return;
+    while(here->next!=(noteptr)0)
+        here=here->next;
+    while(here!=startnote) {
+        here=here->last;
+        free(here->next);
+    }
+    if(startnote->last!=(noteptr)0)
+        startnote->last->next = (noteptr)0;
+    free(startnote);
+}
+****/
+
+/********************** MAKE_NEW_NOTE ****************************
+ *
+ * Create new link in note list.
+ */
+
+int make_new_note(noteptr *thisnote)
+{
+    if(((*thisnote)->next = (noteptr)malloc(sizeof(struct nnote)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY for a further note store.\n");
+        return(MEMORY_ERROR);
+    }
+    (*thisnote)->next->last = *thisnote;
+    *thisnote = (*thisnote)->next;
+    (*thisnote)->next = (noteptr)0;
+    return(FINISHED);
+}
+
+/**************************** COPY_NOTE *******************************/
+
+void copy_note(noteptr thisnote,noteptr orignote)
+{
+    thisnote->ntime = orignote->ntime;
+    thisnote->amp   = orignote->amp;
+    thisnote->pitch = orignote->pitch;
+    thisnote->dur   = orignote->dur;
+    thisnote->instr = orignote->instr;
+    thisnote->spacepos = orignote->spacepos;
+    thisnote->motioncentre = orignote->motioncentre;
+}
+
+/************************** ADD_MOTIF_TO_END_OF_MOTIFLIST ******************************
+ *
+ * Create new motif at end of list.
+ */
+
+int add_motif_to_end_of_motiflist(motifptr *new,dataptr dz)
+{
+    int exit_status;
+    motifptr here = dz->tex->motifhead;
+    while(here->next!=(motifptr)0)
+        here = here->next;
+    if((exit_status =  new_motif(&here))<0)
+        return(exit_status);
+    *new = here;
+    return(FINISHED);
+}
+    
+/************************* SCATTER_AND_QUANTISE_TSET_TIMES ******************************/
+//
+//int scatter_and_quantise_tset_times(double *lasttime,noteptr *thisnote,dataptr dz)
+//{
+//  int exit_status;
+//  double thistime = (*thisnote)->ntime;           /* 1 */
+//  double timestep = thistime - *lasttime;         /* 2 */
+//  *lasttime = thistime;                           /* 2a */
+//  if(dz->brksize[TEXTURE_SCAT]) {
+//      if((exit_status = read_value_from_brktable(thistime,TEXTURE_SCAT,dz))<0)
+//          return(exit_status);
+//  }       
+//  if(dz->param[TEXTURE_SCAT]>1.0) {               /* 3a */
+//      if((exit_status = bigscatter(thisnote,thistime,timestep,dz->param[TEXTURE_SCAT],lasttime,dz))<0)
+//          return(exit_status);
+//  } else {
+//      if(!flteq(dz->param[TEXTURE_SCAT],0.0))             /* 4 */
+//          thistime -= (float)(drand48() * dz->param[TEXTURE_SCAT] * timestep);
+//  
+//      if(dz->param[TEXTURE_TGRID]>0.0)
+//          thistime  = quantise(thistime,dz->param[TEXTURE_TGRID]);    /* 6 */
+//      (*thisnote)->ntime = (float)thistime;
+//  }
+//  *thisnote = (*thisnote)->next;
+//  return(FINISHED);               /* 8a */
+//}
+//
+/************************* SCATTER_AND_QUANTISE_TSET_TIMES ******************************/
+
+int scatter_and_quantise_tset_times(double *lasttime,noteptr *thisnote,dataptr dz)
+{
+    int exit_status;
+    double thistime = (*thisnote)->ntime;           /* 1 */
+    double timestep = thistime - *lasttime;         /* 2 */
+    noteptr lastnote, priornote;
+    *lasttime = thistime;                           /* 2a */
+    if(dz->brksize[TEXTURE_SCAT]) {
+        if((exit_status = read_value_from_brktable(thistime,TEXTURE_SCAT,dz))<0)
+            return(exit_status);
+    }       
+    if(dz->param[TEXTURE_SCAT]>1.0) {               /* 3a */
+        if((exit_status = bigscatter(thisnote,thistime,timestep,dz->param[TEXTURE_SCAT],lasttime,dz))<0)
+            return(exit_status);
+    } else {
+        if(!flteq(dz->param[TEXTURE_SCAT],0.0))             /* 4 */
+            thistime -= (float)(drand48() * dz->param[TEXTURE_SCAT] * timestep);
+    
+        if(dz->param[TEXTURE_TGRID]>0.0)
+            thistime  = quantise(thistime,dz->param[TEXTURE_TGRID]);    /* 6 */
+        (*thisnote)->ntime = (float)thistime;
+    }
+    if(dz->brksize[TEX_PHGRID]) {
+        if((exit_status = read_value_from_brktable(thistime,TEX_PHGRID,dz))<0)
+            return(exit_status);
+        dz->one_in = (int)ceil(dz->param[TEX_PHGRID]);
+    } else
+        dz->one_in = dz->iparam[TEX_PHGRID];
+    dz->one_in %= 64;                                   //  Omit 1 in 63, goes to omit none (at value 64)
+    if(dz->one_in == 0) {                               //  No omissions: go to next note
+        dz->omit_count = 0;
+        *thisnote = (*thisnote)->next;
+    } else {
+        dz->one_in = max(dz->one_in,2);                 //  dz->one_in cannot be less than 2
+        if(dz->omit_count == dz->omit_item) {           //  If this is item to omit
+            lastnote = *thisnote; 
+            *thisnote = (*thisnote)->next;              //  Go to next note
+            priornote = lastnote->last;                 //  Unlink last note
+            priornote->next = *thisnote;
+            if(*thisnote != NULL)
+                (*thisnote)->last = priornote;
+            free(lastnote);
+        } else                                          //  Else don't omit this note
+            *thisnote = (*thisnote)->next;              //  Just go to next note
+
+        dz->omit_count++;                               //  Advance counter in omit-size group.
+        if(dz->omit_count >= dz->one_in) {              //  Once the group has been used up
+            dz->omit_count = 0;                         //  Reset noteset-group counter, and determine (by random selection)
+            if(dz->param[TEXTURE_SEED] < 32)
+                dz->omit_item = (int)floor(drand48() * dz->one_in); //  event to drop in next dz->one_in events.
+        }
+        return FINISHED;
+    }
+    return(FINISHED);               /* 8a */
+}
+
+/************************* SCATTER_AND_QUANTISE_TSET_TIMES ******************************/
+//
+//int scatter_and_quantise_tset_times(double *lasttime,noteptr *thisnote,dataptr dz)
+//{
+//  int exit_status;
+//  double thistime = (*thisnote)->ntime;           /* 1 */
+//  double timestep = thistime - *lasttime;         /* 2 */
+//  noteptr lastnote, priornote;
+//  double thisscat;
+//  *lasttime = thistime;                           /* 2a */
+//  if(dz->brksize[TEXTURE_SCAT]) {
+//      dz->negscat = 0;
+//      if((exit_status = read_value_from_brktable(thistime,TEXTURE_SCAT,dz))<0)
+//          return(exit_status);
+//      if(dz->param[TEXTURE_SCAT] < 0.0)
+//          dz->negscat = 1;
+//  } else if(dz->negscat < 0) {                            // Initialise negative-scattering, where not a trime-variable pscatter param
+//      dz->negscat = 0;
+//      if(dz->param[TEXTURE_SCAT] < 0.0)
+//          dz->negscat = 1;
+//  }
+//  if (dz->negscat) {                                      //  -3.1 becomes scatter = 0.1 ,events-to-drop = 1-in-3
+//      thisscat   = -dz->param[TEXTURE_SCAT];
+//      dz->one_in = (int)floor(thisscat);                  //  Proportion of events to be dropped = 1 in dz->one_in        
+//      thisscat  -= dz->one_in;                            //  Scatter to be used
+//      dz->one_in = max(dz->one_in,2);                     //  dz->one_in cannot be less than 2
+//
+//      if(dz->omit_count == dz->omit_item) {               //  If this is item to omit
+//          lastnote = *thisnote; 
+//          *thisnote = (*thisnote)->next;                  //  Go to next note
+//          priornote = lastnote->last;                     //  Unlink last note
+//          priornote->next = *thisnote;
+//          (*thisnote)->last = priornote;
+//          free(lastnote);
+//      } else {                                        //  Otherwise, scatter event time       
+//          if(!flteq(thisscat,0.0))
+//              thistime -= (float)(drand48() * thisscat * timestep);
+//          if(dz->param[TEXTURE_TGRID]>0.0)                //  (and quantise if ness)
+//              thistime  = quantise(thistime,dz->param[TEXTURE_TGRID]);
+//          (*thisnote)->ntime = (float)thistime;
+//          *thisnote = (*thisnote)->next;                  //  and go to next note
+//      }
+//      dz->omit_count++;                                   //  Advance counter in omit-size group.
+//      if(dz->omit_count >= dz->one_in) {                  //  Once the group has been used up
+//          dz->omit_count = 0;                             //  Reset noteset-group counter, and determine (by random selection)
+//          if(dz->param[TEXTURE_SEED] < 32)
+//              dz->omit_item = (int)floor(drand48() * dz->one_in); //  event to drop in next dz->one_in events.
+//      }
+//      return FINISHED;
+//  } else if(dz->param[TEXTURE_SCAT]>1.0)  {               /* 3a */
+////TW UPDATE (original code error)
+//      if((exit_status = bigscatter(thisnote,thistime,timestep,dz->param[TEXTURE_SCAT],lasttime,dz))<0)
+//          return(exit_status);
+//  } else {
+//      if(!flteq(dz->param[TEXTURE_SCAT],0.0))             /* 4 */
+//          thistime -= (float)(drand48() * dz->param[TEXTURE_SCAT] * timestep);
+//  
+//      if(dz->param[TEXTURE_TGRID]>0.0)
+//          thistime  = quantise(thistime,dz->param[TEXTURE_TGRID]);    /* 6 */
+//      (*thisnote)->ntime = (float)thistime;
+//  }
+//  *thisnote = (*thisnote)->next;
+//  return(FINISHED);               /* 8a */
+//}
+
+/************************** PRE_SPACE ********************************
+ *
+ * Store spatial data in the tsetnote spacepos and motioncentre.
+ */
+
+int pre_space(noteptr thisnote,dataptr dz)
+{
+    int exit_status;
+    double position;
+    if((exit_status = getpos((double)thisnote->ntime,&position,dz))<0)
+        return(exit_status);
+    thisnote->spacepos     = (float)position;
+    thisnote->motioncentre = (float)dz->param[CPOS];
+    return(FINISHED);
+}
+
+/************************** GETPOS ****************************
+ *
+ * Calculate spatial position of event from it's time.
+ */
+
+int getpos(double thistime,double *position,dataptr dz)
+{
+    int exit_status;
+    if(dz->brksize[TEXTURE_POS] && (exit_status = read_value_from_brktable(thistime,TEXTURE_POS,dz))<0)
+        return(exit_status);
+    if(dz->brksize[TEXTURE_SPRD] && (exit_status = read_value_from_brktable(thistime,TEXTURE_SPRD,dz))<0)
+        return(exit_status);
+    if(dz->param[TEXTURE_SPRD] > 0.0) {
+        if((exit_status = spread_and_set_cpos(position,dz->param[TEXTURE_POS],dz->param[TEXTURE_SPRD],dz))<0)
+            return(exit_status);
+    } else {
+/* NOV 1997--> */
+        dz->param[CPOS] = dz->param[TEXTURE_POS];
+/* <--NOV 1997 */
+        *position       = dz->param[TEXTURE_POS];
+    }
+    return(FINISHED);
+}
+
+/***************************** SPREAD_AND_SET_CPOS *****************************/
+
+int spread_and_set_cpos(double *position,double given_position,double spread,dataptr dz)
+{
+    int exit_status;
+    int    posno, spswitch;
+    int    poscnt,hposcnt;
+    double hspread,spacing, closeness, squash;
+
+    /* total stereospace has MAXPOSCNT positions: calc no. & spacing of positions available at given spread */
+    poscnt  = round(spread * (double)MAXPOSCNT);
+    hposcnt = poscnt/2;
+    hspread = spread/(double)2.0;
+    if(hposcnt != 0)
+        spacing = hspread/(double)hposcnt;
+    else {
+    /* bandwidth effectively zero: return given position */ 
+        dz->param[CPOS] = given_position;
+        *position       = given_position;
+        return(FINISHED);
+    }
+    /* randomly select leftwards/rightwards of the given position */
+    if((exit_status = doperm(2,PM_SPACE,&spswitch,dz))<0)
+        return(exit_status);                    
+    if(!spswitch)
+        spswitch = -1;                              
+
+    /* randomly chose a pos (to left or right) around centre pos */
+    posno  = round(drand48() * hposcnt);                
+    posno *= spswitch;                              
+
+    /* calculate warping coefficient to avoid position-spread leaking over edges of stereo-space */
+    if(spread>(double)1.0/SQUASH)
+        squash = (double)1.0/spread;
+    else
+        squash = SQUASH;
+
+    /* If (position+spread) leaks to right of stereo-space : squeeze position */
+    if(given_position>=0.5 && (given_position + spread) > 1.0) {
+        closeness = (given_position - 0.5)/(double)0.5;
+        dz->param[CPOS] = given_position - (hspread*pow(closeness,squash));
+    /* If (position+spread) leaks to left of stereo-space : squeeze position */
+    } else if(given_position<0.5 && given_position < spread) {  
+        closeness = (0.5 - given_position)/(double)0.5;
+        dz->param[CPOS] = given_position + (hspread*pow(closeness,squash));
+    } else
+        dz->param[CPOS] = given_position;
+
+    /* generate true position, around central position */
+    *position = dz->param[CPOS] + ((double)posno * spacing);
+    return chekrang(position);
+}
+
+/*************************** CHEKRANG **************************
+ * 
+ * Check variable lies within range 0.0 to 1.0.
+ */
+
+int chekrang(double *val)
+{
+    if(flteq(*val,1.0))
+        *val = 1.0;
+    if(flteq(*val,0.0))
+        *val = 0.0;
+    if(*val<0.0 || *val>1.0) {                       
+        sprintf(errstr,"value [%f] outside range 0-1: chekrang()\n",*val);
+        return(PROGRAM_ERROR);
+    }
+    return(FINISHED);
+}
+
+/************************** READ_A_NOTE_FROM_NOTEDATA_FILE ********************************/
+
+int read_a_note_from_notedata_file(noteptr thisnote,int noteno,int motifno,double *lasttime,dataptr dz)
+{
+    int exit_status;
+    unsigned int texflag = dz->tex->txflag;
+    char temp[200], *p, *q;
+    double val;
+    int instr_no, start;
+    if(dz->fp==NULL) {
+        sprintf(errstr,"Note datafile descriptor not initialised: read_a_note_from_notedata_file()\n");
+        return(PROGRAM_ERROR);
+    }
+    if(fgets(temp,200,dz->fp)==NULL){
+        sprintf(errstr,"Note data line for note %d, motif %d missing in notedatafile\n",noteno,motifno);
+        return(DATA_ERROR);
+    }
+    p =temp;
+    while(isspace(*p))
+        p++;
+    q = p;
+    if(*q==ENDOFSTR)
+        return(CONTINUE);
+    if((exit_status = get_data_item(q,&p,&val))<0) {
+        sprintf(errstr,"No time data for note %d, motif %d in notedatafile\n",noteno,motifno); 
+        return(DATA_ERROR);
+    }
+    if(exit_status==FINISHED) {
+        sprintf(errstr,"No data after time for note %d, motif %d in notedatafile\n",noteno,motifno); 
+        return(DATA_ERROR);
+    }
+    thisnote->ntime = (float)val;
+    if((noteno > 1) && (*lasttime > thisnote->ntime)) {
+        sprintf(errstr,"Notes in reverse time order: notedata file : motif %d: notes %d & %d\n",
+        motifno,noteno,noteno-1);
+        return(DATA_ERROR);
+    }
+    *lasttime = thisnote->ntime;
+    p++;
+    q = p;
+    if((exit_status = get_data_item(q,&p,&val))<0) {
+        sprintf(errstr,"No instr_no for note %d, motif %d in notedatafile\n",noteno,motifno); 
+        return(DATA_ERROR);
+    }
+    if(exit_status==FINISHED) {
+        sprintf(errstr,"No data after instr_no for note %d, motif %d in notedatafile\n",noteno,motifno); 
+        return(DATA_ERROR);
+    }
+    instr_no = round(val);
+
+    p++;
+    q = p;
+    if((exit_status = get_data_item(q,&p,&val))<0) {
+        sprintf(errstr,"No pitch data for note %d, motif %d in notedatafile\n",noteno,motifno); 
+        return(DATA_ERROR);
+    }
+    if(exit_status==FINISHED) {
+        sprintf(errstr,"No data after pitch for note %d, motif %d in notedatafile\n",noteno,motifno); 
+        return(DATA_ERROR);
+    }
+    thisnote->pitch = (float)val;
+
+/* NEEDS TESTING FOR MIDIRANGE: EXCEPT IN TIMING SET CASE */
+    if(!(texflag & ISTIMED) || motifno!=1) {
+        if(val < MIDIMIN || val > MIDIMAX) {
+            sprintf(errstr,"pitch value [%lf] out of range (%d to %d): motif %d: note %d\n",
+            val,MIDIMIN,MIDIMAX,motifno,noteno);
+            return(DATA_ERROR);
+        }
+    }
+    p++;
+    q = p;
+    if((exit_status = get_data_item(q,&p,&val))<0) {
+        sprintf(errstr,"No amplitude data for note %d, motif %d in notedatafile\n",noteno,motifno); 
+        return(DATA_ERROR);
+    }
+    if(exit_status==FINISHED) {
+        sprintf(errstr,"No data after amp for note %d, motif %d in notedatafile\n",noteno,motifno); 
+        return(DATA_ERROR);
+    }
+    thisnote->amp = (float)val;
+/* 1999 THIS NEEDS TESTING FOR MIDIRANGE EXCEPT IN TIMING SET CASE */
+    if(!(texflag & ISTIMED) || motifno!=1) {
+        if(val < MIDIMIN || val > MIDIMAX) {
+            sprintf(errstr,"amplitude value [%lf] out of range (%d to %d): motif %d: note %d\n",
+            val,MIDIMIN,MIDIMAX,motifno,noteno);
+            return(DATA_ERROR);
+        }
+    }
+    p++;
+    q = p;
+    if((exit_status = get_data_item(q,&p,&val))<0) {
+        sprintf(errstr,"No duration data for note %d, motif %d in notedatafile\n",noteno,motifno); 
+        return(DATA_ERROR);
+    }
+    thisnote->dur = (float)val;
+    if(texflag & IS_ORN_OR_MTF) {
+        if(texflag & IS_ORNATE) {
+            start = 2;
+        } else {
+            start = 1;
+            if(texflag & ISTIMED)
+                start++;
+        }
+        if(texflag & ISHARM)
+            start++;
+        if(motifno >= start) {
+            if(val <= FLTERR) {
+                sprintf(errstr,"Duration value [%lf] is too small: motif %d: note %d\n",val,motifno,noteno);
+                return(DATA_ERROR);
+            }
+        }
+    } else {
+        thisnote->dur = 1.0f;   /* default ; redundant */
+    }
+    return(FINISHED);
+}
+
+/***************************** GENERATE_TSET_TIMES **********************************
+ *
+ * Store time initially as SECONDS.
+ *
+ * (1)  Create location for a new note.
+ * (2)  Go to that new note.
+ * (3)  Store the current time at this note.
+ * (4)  Find note-density at this time, and generate time of next event.
+ * (5)  Return nextnote.
+ */
+
+int generate_tset_times(double *thistime,noteptr *thisnote,dataptr dz)
+{
+    int exit_status;
+    if((exit_status = make_new_note(thisnote))<0)
+        return(exit_status);                        /* 1 */
+    (*thisnote)->ntime = (float)(*thistime);            /* 3 */
+    if(dz->brksize[TEXTURE_PACK]) {
+        if((exit_status = read_value_from_brktable(*thistime,TEXTURE_PACK,dz))<0)
+            return(exit_status);
+    }       
+    *thistime  += dz->param[TEXTURE_PACK];          /* 4 */
+    return(FINISHED);                               /* 5 */
+}
+
+/********************** UN_LINK_NOTE ******************************
+ *
+ * Deletes empty address space at end of notelist.
+ */
+
+int un_link_note(noteptr thisnote)
+{
+    if(thisnote->last==(noteptr)0) {
+        sprintf(errstr,"Problem in un_link_note()\n");
+        return(PROGRAM_ERROR);
+    }
+    thisnote = thisnote->last;
+    free(thisnote->next);
+    thisnote->next = (noteptr)0;
+    return(FINISHED);
+}
+
+/************************ NEW_MOTIF *****************************
+ *
+ * Set up next motif in a list of musical-motifs.
+ * Set up location of first note of this motif.
+ */
+
+int new_motif(motifptr *thismotif)
+{
+    int exit_status;
+    motifptr newmotif;
+    noteptr  thisnote;
+    
+    if((newmotif = (motifptr)malloc(sizeof (struct motif)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY to store next motif.\n");
+        return(MEMORY_ERROR);
+    }
+    (*thismotif)->next = newmotif;
+    newmotif->last = *thismotif;
+    newmotif->next = (motifptr)0;
+    if((exit_status = init_note(&thisnote))<0)
+        return(exit_status);
+    thisnote->next = (noteptr)0;   
+    thisnote->last = (noteptr)0;   
+    newmotif->firstnote = thisnote;
+    *thismotif = newmotif;
+    return(FINISHED);
+}
+
+/********************** UNLINK_LAST_MOTIF ******************************
+ *
+ * Deletes empty address space at end of motiflist.
+ */
+
+int unlink_last_motif(motifptr thismotif)
+{
+    if(thismotif->last==(motifptr)0) {
+        sprintf(errstr,"Problem in unlink_last_motif()\n");
+        return(PROGRAM_ERROR);
+    }
+    thismotif = thismotif->last;
+    free(thismotif->next);
+    thismotif->next = (motifptr)0;
+    return(FINISHED);
+}
+
+/**************************** SUBTRACT_ONE_FROM_BRKVALS ****************************/
+
+void subtract_one_from_brkvals(int paramno,dataptr dz)
+{
+    double *p = dz->brk[paramno] + 1;
+    double *pend = dz->brk[paramno] + (dz->brksize[paramno] * 2);
+    while(p < pend) {
+        *p -= 1.0;
+        p += 2;
+    }
+}
+
+/************************ BIGSCATTER *************************************
+ *
+ * (1)  The number of time-points to be randomly scattered as a group is
+ *  scatcnt.
+ * (1a) Base time is the time from which these new scattered times are offset.
+ * (2)  Save the current position in note list as 'here'.
+ * (3)  Go forward in note list until there are scatcnt notes inclusive
+ *  between here and there, or until list runs out.
+ * (3a) If the list runs out, modify scatcnt accordingly.
+ * (4)  Note the (original) time of the last of these events. This will
+ *  be returned as the new 'lasttime' for the next cycle of the
+ *  program.
+ * (5)  Make the time-step include the total duration of all these
+ *  events.
+ * (5a) Generate a set of times AT RANDOM within this large timestep,
+    sort them and store them.
+ * (6)  Replace existing times by scattered times, relative to basetime.
+ * (6a) Convert to MIDitime.
+ * (6b) Quantise if necessary.
+ * (7)  Replace the last time.
+ * (9)  Return the last note we worked on.
+ */
+
+int bigscatter(noteptr *thisnote,double thistime,double timestep,double scatter,double *lasttime,dataptr dz)
+{
+    int n, scatcnt = round(scatter);        /* 1 */
+    double *sct, *scti;
+    double basetime = thistime - timestep;  /* 1a */
+    noteptr here  = *thisnote;              /* 2 */
+    noteptr there = *thisnote;              /* 2 */
+    if((scti = (double *)malloc(scatcnt * sizeof(double)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY for scattering structure.\n");
+        return(MEMORY_ERROR);
+    }
+    sct = scti;
+    for(n=0;n < scatcnt-1; n++) {           /* 3 */
+        if(there->next==(noteptr)0) {
+            scatcnt = n+1;                  /* 3a */
+            break;
+        }
+        there = there->next;
+    }
+    *lasttime = there->ntime;               /* 4 */
+    timestep += *lasttime - thistime;       /* 5 */
+    for(n= 0;n<scatcnt;n++)                 /* 5a */
+        *sct++ = drand48() * timestep;
+    upsort(scti,scatcnt);                   
+    sct = scti;
+    while(here!=there) {                    /* 6 */
+        thistime = basetime + (*sct++);
+        if(dz->param[TEXTURE_TGRID]>0.0)
+            thistime  = quantise(thistime,dz->param[TEXTURE_TGRID]);    /* 6b */
+        here->ntime = (float)thistime;
+        here = here->next;
+    }
+    thistime = basetime + *sct;             /* 7 */
+    if(dz->param[TEXTURE_TGRID]>0.0)
+        thistime  = quantise(thistime,dz->param[TEXTURE_TGRID]);
+    there->ntime = (float)thistime;
+    free(scti);
+    *thisnote = there;
+    return(FINISHED);                   /* 9 */
+}
+
+/************************** QUANTISE *************************************
+ *
+ * Quantise time point onto a grid.
+ */
+
+double quantise(double thistime,double timegrid)
+{
+    int gridpoint;
+    timegrid *= MS_TO_SECS;
+    gridpoint = round(thistime/timegrid);
+    return((double)gridpoint * timegrid);
+}
+
+/************************* GET_DATA_ITEM ****************************/
+
+int get_data_item(char *q,char **p,double *val)
+{
+    int exit_status = CONTINUE;
+    if(*q==ENDOFSTR)
+        return(DATA_ERROR);
+    while(isspace(**p)) {
+        (*p)++;
+        if(**p == ENDOFSTR)
+            return(DATA_ERROR);
+    }
+    if(**p==TEXTURE_SEPARATOR)
+        return(DATA_ERROR);
+    while(!isspace(**p) && **p!=ENDOFSTR) {
+        (*p)++;
+    }
+    if(**p==ENDOFSTR)
+        exit_status = FINISHED;
+    **p = ENDOFSTR;
+    if(sscanf(q,"%lf",val)!=1)
+        return(DATA_ERROR);
+    return(exit_status);
+}
+
+/************************* INIT_NOTE ****************************
+ *
+ * Initialise notelist.
+ */
+
+int init_note(noteptr *thisnote)
+{
+    if((*thisnote = (noteptr)malloc(sizeof(struct nnote)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY for another note.\n");
+        return(MEMORY_ERROR);
+    }
+    (*thisnote)->next = (noteptr)0;
+    (*thisnote)->last = (noteptr)0;
+    return(FINISHED);
+}
+
+/********************** UPSORT *******************************
+ * 
+ * Sort set of doubles into ascending order.
+ */
+
+void upsort(double *scti,int scatcnt)
+{
+    double sct;
+    int n, m;
+    for(n=0;n<(scatcnt-1);n++) {
+        for(m=n+1;m<scatcnt;m++) {
+            if(*(scti+m)<*(scti+n)) {
+                sct       = *(scti+m);
+                *(scti+m) = *(scti+n);
+                *(scti+n) = sct;
+            }
+        }
+    }
+}
+
+/*********************** PUT_ZNOTE ********************************
+ *
+ * Put zero values in all parameters except time.
+ */
+
+void put_znote(noteptr thisnote)
+{
+    thisnote->amp   = 0.0f;
+    thisnote->pitch  = 0.0f;
+    thisnote->dur   = 0.0f;
+    thisnote->instr = 0;
+    thisnote->spacepos = 0.0f;
+    thisnote->motioncentre = 0.0f;
+}
+
+/************************* ASSIGN_TIMESET_HFSET_MOTIFSETS ******************************
+ *
+ * Assign appropriate pointers to input motifs.
+ *
+ * (1)  If it's a timed texture, indicate first motif in list as that
+ *      which defines the set of times (tset).
+ *      Similarly, if texture is ornamented or decorated, point to first
+ *      motif as that to BE ornamented or decorated (tset).
+ * (2)  If the texture restricted to HF(s) or HS(s), indicate next motif
+ *      as the HF-set (hfldmotif). It may be read in different ways (as HF, as
+ *      HS, or as time-varying of either type) at a later time.
+ * (3)  If texture consists of motifs, or is to use specific ornaments...
+ * (4)  count the number of motifs remaining.
+ * (5)  Set up the array of phrases to point to the appropriate motifs.
+ */
+
+int assign_timeset_hfset_motifsets(dataptr dz)
+{
+    int exit_status;
+    unsigned int texflag = dz->tex->txflag;
+    motifptr here, thismotif = dz->tex->motifhead;
+    int n;
+    dz->tex->phrasecnt = 0;    
+    if(texflag & ORN_DEC_OR_TIMED) {
+        if((exit_status = motifchek(thismotif))<0)
+            return(exit_status);
+        dz->tex->timeset = thismotif;                   /* 1 */
+        thismotif = thismotif->next;
+    }
+    if(texflag & ISHARM) {                              /* 2 */
+        if((exit_status = motifchek(thismotif))<0)
+            return(exit_status);
+        dz->tex->hfldmotif = thismotif;
+        thismotif = thismotif->next;
+    }
+    if((texflag & IS_ORNATE) || (texflag & IS_MOTIFS)) {    /* 3 */
+        if((exit_status = motifchek(thismotif))<0)
+            return(exit_status);
+        here = thismotif;
+        while(thismotif!=(motifptr)0) {                 /* 4 */
+            dz->tex->phrasecnt++;
+            thismotif = thismotif->next;
+        }                                               /* 5 */
+        if((dz->tex->phrase = (motifptr *)malloc(dz->tex->phrasecnt * sizeof(motifptr)))==NULL) {
+            sprintf(errstr,"INSUFFICIENT MEMORY for phrase array.\n");
+            return(MEMORY_ERROR);
+        }
+        thismotif = here;
+        n = -1;
+        while(thismotif!=(motifptr)0) {
+            dz->tex->phrase[++n] = thismotif;
+            thismotif = thismotif->next;
+        }
+    }
+    return(FINISHED);
+}
+
+/***************************** MASSAGE_PARAMS ****************************/
+
+int massage_params(dataptr dz)
+{
+    int exit_status;
+    unsigned int texflag = dz->tex->txflag;
+    convert_cmdline_instrnos_to_internal_representation(dz);
+    if((exit_status = check_max_transpos_compatible_with_splicelen(dz))<0)
+        return(exit_status);
+    if(texflag & IS_CLUMPED) {
+        if((exit_status = set_amptype_params(dz))<0)
+            return(exit_status);
+    }
+    if(texflag & IS_DECOR) {
+        if((exit_status = set_decor_pitchposition_params(dz))<0)
+            return(exit_status);
+    }
+    return(FINISHED);
+}
+
+/************************* INIT_MOTIFS *****************************
+ *
+ * Set up head item of a list of musical-motifs.
+ * Set up location of first note of first motif.
+ */
+
+int init_motifs(dataptr dz)
+{
+    int exit_status;
+    noteptr thisnote;
+    if((dz->tex->motifhead = (motifptr)malloc(sizeof (struct motif)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY to store any motifs.\n");
+        return(MEMORY_ERROR);
+    }
+    dz->tex->motifhead->next  = (motifptr)0;
+    dz->tex->motifhead->last  = (motifptr)0;
+    if((exit_status = init_note(&thisnote))<0)
+        return(exit_status);
+    dz->tex->motifhead->firstnote = thisnote;
+    thisnote->next = (noteptr)0;   
+    thisnote->last = (noteptr)0;   
+    return(FINISHED);
+}
+
+/******************************** INITPERM *********************************
+ *
+ * Establish storage space for permutation parameters.
+ *
+ * (1)  create pointers to the items within the permuted sets.      Initialise to zero.
+ * (2)  Create storage for current length of each perm.             Initialise to zero.
+ * (3)  Create storage for previous length of each perm.            Initialise to -1 (impossible).
+ *      If new perm different length to old, space for permuted elements will need to be re-malloced.
+ * (4)  Create pointers to storage areas for each permuted set.     Initialise to point nowhere. 
+ *      These will be malloced when the size of each set-to-permute is known.
+ * (5)  Create storage for previous outputed val in each perm.      Initialise to -1 (impossible). 
+ *      This is useful at permutation boundaries, when a particular element may be repeated more
+ *      than permitted no. of times if there's no check. These constants allow no. of repets to be counted.
+ * (6)  Create counter of current no. of consecutive repets of an element in each of the (output) perms.
+ *      Initialise to 0, though this is arbitrary, as repetcnt should always be set on any call of do_perm.
+ * (7)  Create storage for max no. of allowed consecutive repets of an element in each perm-set.
+ *      Initialise to 1, which is the default if no info is given to the contrary.
+ */
+
+int initperm(int ***permm,dataptr dz)
+{
+    int n;
+    if((dz->iparray[TXPERMINDEX] = (int *)malloc(PERMCNT * sizeof(int)))==NULL) {   /* 1 */
+        sprintf(errstr,"INSUFFICIENT MEMORY for permutation indeces.\n");
+        return(MEMORY_ERROR);
+    }
+    for(n=0;n<PERMCNT;n++)
+        dz->iparray[TXPERMINDEX][n] = 0;
+
+    if((dz->iparray[TXPERMLEN] = (int *)malloc(PERMCNT * sizeof(int)))==NULL) {   /* 2 */
+        sprintf(errstr,"INSUFFICIENT MEMORY for permutation lengths.\n");
+        return(MEMORY_ERROR);
+    }
+    for(n=0;n<PERMCNT;n++)
+        dz->iparray[TXPERMLEN][n] = 0;
+
+    if((dz->iparray[TXLASTPERMLEN] = (int *)malloc(PERMCNT * sizeof(int)))==NULL) {   /* 3 */
+        sprintf(errstr,"INSUFFICIENT MEMORY for last permutation lengths.\n");
+        return(MEMORY_ERROR);
+    }
+    for(n=0;n<PERMCNT;n++)
+        dz->iparray[TXLASTPERMLEN][n] = -1;
+
+    if((*permm = (int **)malloc(PERMCNT * sizeof(int *)))==NULL) {   /* 4 */
+        sprintf(errstr,"INSUFFICIENT MEMORY for permutations.\n");
+        return(MEMORY_ERROR);
+    }
+
+    for(n=0;n<PERMCNT;n++)
+        (*permm)[n] = (int *)0;
+
+    if((dz->iparray[TXLASTPERMVAL] = (int *)malloc(PERMCNT * sizeof(int)))==NULL) {   /* 5 */
+        sprintf(errstr,"INSUFFICIENT MEMORY for last permutation values.\n");
+        return(MEMORY_ERROR);
+    }
+    for(n=0;n<PERMCNT;n++)
+        dz->iparray[TXLASTPERMVAL][n] = -1;
+
+    if((dz->iparray[TXREPETCNT] = (int *)malloc(PERMCNT * sizeof(int)))==NULL) {   /* 6 */
+        sprintf(errstr,"INSUFFICIENT MEMORY for permutation repetition counts.\n");
+        return(MEMORY_ERROR);
+    }
+    for(n=0;n<PERMCNT;n++)
+        dz->iparray[TXREPETCNT][n] = 1;
+
+    if((dz->iparray[TXRPT] = (int *)malloc(PERMCNT * sizeof(int)))==NULL) {   /* 7 */
+        sprintf(errstr,"INSUFFICIENT MEMORY for permutation repetitions.\n");
+        return(MEMORY_ERROR);
+    }
+    /* THESE ARE THE DEFAULT NUMBER OF REPETITIONS-OF-AN-ENTITY ALLOWED IN A PERM */
+    dz->iparray[TXRPT][PM_SPACE]  = SPACE_REPETS;
+    dz->iparray[TXRPT][PM_PITCH]  = PITCH_REPETS;
+    dz->iparray[TXRPT][PM_AMP]    = AMP_REPETS;
+    dz->iparray[TXRPT][PM_DUR]    = DUR_REPETS;
+    dz->iparray[TXRPT][PM_INSNO]  = INSNO_REPETS;
+    dz->iparray[TXRPT][PM_GPRANG] = GPRANG_REPETS;
+    dz->iparray[TXRPT][PM_GPSIZE] = GPSIZE_REPETS;
+    dz->iparray[TXRPT][PM_GPDENS] = GPDENS_REPETS;
+    dz->iparray[TXRPT][PM_GPCNTR] = GPCNTR_REPETS;
+    dz->iparray[TXRPT][PM_GPPICH] = GPPICH_REPETS;
+    dz->iparray[TXRPT][PM_ORNPOS] = ORNPOS_REPETS;
+    dz->iparray[TXRPT][PM_GPSPAC] = GPSPAC_REPETS;
+    dz->iparray[TXRPT][PM_ORIENT] = ORIENT_REPETS;
+    dz->iparray[TXRPT][PM_DECABV] = DECABV_REPETS;
+    dz->iparray[TXRPT][PM_MULT]   = MULT_REPETS;
+    dz->iparray[TXRPT][PM_WHICH]  = WHICH_REPETS;
+    dz->iparray[TXRPT][PM_GPPICH2]= GPPICH2_REPETS;
+    return(FINISHED);
+}

+ 33 - 0
dev/texture/v8/texture.h

@@ -0,0 +1,33 @@
+/*
+ * 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
+ *
+ */
+#define IS_GROUCHO_COMPILE      (1)
+
+#include    <pnames.h>
+#include    <flags.h>
+#include    <txtucon.h>
+#include    <texture1.h>
+
+/**
+#define MINDUR_OVERRIDE = 1;    // used for "texture_new"
+**/

+ 220 - 0
dev/texture/v8/texture1.c

@@ -0,0 +1,220 @@
+/*
+ * Copyright (c) 1983-2013 Trevor Wishart and Composers Desktop Project Ltd
+ * http://www.trevorwishart.co.uk
+ * http://www.composersdesktop.com
+ *
+ This file is part of the CDP System.
+ 
+ The CDP System is free software; you can redistribute it
+ and/or modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+ 
+ The CDP System is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU Lesser General Public License for more details.
+ 
+ You should have received a copy of the GNU Lesser General Public
+ License along with the CDP System; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA
+ *
+ */
+/* floatsam version: no changes */
+#include <stdio.h>
+#include <stdlib.h>
+#include <structures.h>
+#include <tkglobals.h>
+#include <globcon.h>
+#include <processno.h>
+#include <modeno.h>
+#include <arrays.h>
+#include <texture.h>
+#include <cdpmain.h>
+
+#include <sfsys.h>
+
+/********************* GETTING DATA VALUES VIA RAND PERMUTATIONS *************/
+
+
+
+static int  delete_all_other_motifs(motifptr thismotif,dataptr dz);
+static int  delete_motifs_before(motifptr thismotif,dataptr dz);
+static int  delete_motifs_beyond(motifptr thismotif);
+
+/***************************** TEXTURE 1 ********************************
+ * (1)  Generating random permutations of sets of values, and delivering
+ *      the next value from one of these.
+ * (2)  Scattering values within a range.
+ */
+
+/*************************** MAKE_TEXTURE *********************************/
+
+int make_texture(dataptr dz)
+{
+    int exit_status;
+    unsigned int texflag = dz->tex->txflag;
+    display_virtual_time(0,dz);
+    if(texflag & ISHARM) {
+        if(texflag & IS_CLUMPED) {
+            if((exit_status = do_clumped_hftexture(dz))<0)
+                return(exit_status);
+        } else {
+            if((exit_status = do_simple_hftexture(dz))<0)
+                return(exit_status);
+        }
+    } else {
+        if((exit_status = do_texture(dz))<0)
+            return(exit_status);
+    }
+    if((exit_status = delete_all_other_motifs(dz->tex->timeset,dz))<0)
+        return(exit_status);
+    return(FINISHED);
+}
+
+/****************************** GETVALUE **********************************
+ *
+ * Get value of a parameter, either from table, or fixed value.
+ */
+
+int getvalue(int paramhi,int paramlo,double thistime,int z,double *val,dataptr dz)
+{   
+    int exit_status;
+    double range;
+    int is_swap = 0;
+    if(dz->is_int[paramhi] || dz->is_int[paramlo]) {
+        sprintf(errstr,"getvalue() called on integer parameter %d or %d\n",paramhi,paramlo);
+        return(PROGRAM_ERROR);
+    }
+    if(dz->brk[paramhi]) {
+        if((exit_status = read_value_from_brktable(thistime,paramhi,dz))<0)
+            return(exit_status);
+    }
+    if(dz->brk[paramlo]) {
+        if((exit_status = read_value_from_brktable(thistime,paramlo,dz))<0)
+            return(exit_status);
+    }
+    if((range = dz->param[paramhi] - dz->param[paramlo])<0.0) {
+        swap(&dz->param[paramhi],&dz->param[paramlo]);
+        range = -range;
+        is_swap = 1;
+    }
+    if(flteq(range,0.0)) {
+        *val = dz->param[paramhi];
+        if(is_swap)
+            swap(&dz->param[paramhi],&dz->param[paramlo]);
+        return(FINISHED);
+    }
+    if((exit_status = pscatx(range,dz->param[paramlo],z,val,dz))<0)
+        return(exit_status);
+    if(is_swap)
+        swap(&dz->param[paramhi],&dz->param[paramlo]);
+    return(FINISHED);
+}
+
+/****************************** IGETVALUE **********************************
+ *
+ * Get integer value of a parameter, either from table, or fixed value.
+ */
+
+int igetvalue(int paramhi,int paramlo,double thistime,int z,int *ival,dataptr dz)
+{
+    int   exit_status;
+    int  irange;
+    int   a, is_swap = 0;
+
+    if(!dz->is_int[paramhi] || !dz->is_int[paramlo]) {
+        sprintf(errstr,"igetvalue() called on non-integer parameter %d or %d\n",paramhi,paramlo);
+        return(PROGRAM_ERROR);
+    }
+    if(dz->brk[paramhi]) {
+        if((exit_status = read_value_from_brktable(thistime,paramhi,dz))<0)
+            return(exit_status);
+    }
+    if(dz->brk[paramlo]) {
+        if((exit_status = read_value_from_brktable(thistime,paramlo,dz))<0)
+            return(exit_status);
+    }
+
+    if((irange = dz->iparam[paramhi] - dz->iparam[paramlo])<0) {
+        iiswap(&dz->iparam[paramhi],&dz->iparam[paramlo]);
+        irange = -irange;
+        is_swap = 1;
+    }
+    if(irange==0) {
+        *ival = (int)dz->iparam[paramlo]; 
+        if(is_swap)
+            iiswap(&dz->iparam[paramhi],&dz->iparam[paramlo]);
+        return(FINISHED);
+/* OCT 1997 replace ****
+    } else if((exit_status = doperm(irange,z,&a,dz))<0)
+*/
+/* BY */
+    } else if((exit_status = doperm(irange+1,z,&a,dz))<0)
+/* because the range of an integer variable between(say) 3 & 7 is INCLUSIVELY 5, not 7-3) */
+        return(exit_status);
+    a = (int)(a + dz->iparam[paramlo]);
+    *ival = a;
+    if(is_swap)
+        iiswap(&dz->iparam[paramhi],&dz->iparam[paramlo]);
+    return(FINISHED);
+}
+
+/*************************** DELETE_ALL_OTHER_MOTIFS **********************************
+ *
+ * Deletes all other motifs in motif list.
+ */
+
+int delete_all_other_motifs(motifptr thismotif,dataptr dz)
+{
+    int exit_status;
+    motifptr here = thismotif->next;
+    if((exit_status = delete_motifs_before(thismotif,dz))<0)
+        return(exit_status);
+    if(here!=(motifptr)0) {
+        if((exit_status = delete_motifs_beyond(here))<0)
+            return(exit_status);
+    }
+    dz->tex->motifhead = thismotif;
+    return(exit_status);
+}
+
+/********************** DELETE_MOTIFS_BEYOND ******************************
+ *
+ * Deletes motif-space from this space onwards.
+ */
+
+int delete_motifs_beyond(motifptr thismotif)
+{
+    motifptr start = thismotif;
+    while(thismotif->next!=(motifptr)0)
+        thismotif = thismotif->next;
+    while(thismotif!=start) {
+        thismotif = thismotif->last;
+        free(thismotif->next);
+    }
+    thismotif->next = (motifptr)0;
+    return(FINISHED);
+}
+
+/*********************** DELETE_MOTIFS_BEFORE ***************************
+ *
+ * Kill all motifs BEFORE this one in the motif list.
+ */
+
+int delete_motifs_before(motifptr thismotif,dataptr dz)
+{
+    motifptr here = dz->tex->motifhead;
+    while(here!=thismotif) {
+        if((here = here->next)==(motifptr)0) {
+            sprintf(errstr,"Problem in delete_motifs_before()\n");
+            return(PROGRAM_ERROR);
+        }
+        delete_notes_here_and_beyond(here->last->firstnote);
+        free(here->last);
+        here->last = (motifptr)0;
+    }
+    dz->tex->motifhead = thismotif;
+    return(FINISHED);
+}

+ 517 - 0
dev/texture/v8/texture2.c

@@ -0,0 +1,517 @@
+/*
+ * Copyright (c) 1983-2013 Trevor Wishart and Composers Desktop Project Ltd
+ * http://www.trevorwishart.co.uk
+ * http://www.composersdesktop.com
+ *
+ This file is part of the CDP System.
+ 
+ The CDP System is free software; you can redistribute it
+ and/or modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+ 
+ The CDP System is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU Lesser General Public License for more details.
+ 
+ You should have received a copy of the GNU Lesser General Public
+ License along with the CDP System; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA
+ *
+ */
+/* floatsam version: no changes */
+#include <stdio.h>
+#include <stdlib.h>
+#include <structures.h>
+#include <tkglobals.h>
+#include <globcon.h>
+#include <processno.h>
+#include <modeno.h>
+#include <arrays.h>
+#include <texture.h>
+#include <cdpmain.h>
+#include <sfsys.h>
+#include <osbind.h>
+
+/***************************** GENERATING TEXTURES WITH NO HFIELD(S) ******************************/
+
+static int  setup_motif_params
+            (noteptr phrasenote,double tsettime,double *thisamp,double ampstep,double *phraseamp,
+            int phrno,double rangemult,noteptr thisnote,noteptr tsetnote,
+            double multiplier,double timeadjust,dataptr dz);
+static void gen_orn_pitch(noteptr thisnote,noteptr tsetnote,noteptr phrasenote,
+            float phrlpitch,float phrfirstpitch,dataptr dz);
+static void gen_mtf_pitch(noteptr thisnote,noteptr tsetnote,noteptr phrasenote,float phrfirstpitch);
+static int  dec_centre(double tsetpitch,float *val,int gpsize,double gprlow,double gprange,dataptr dz);
+static int  pscat(double range,double bottom,int pindex,double *val,dataptr dz);
+static int  initialise_phrases
+            (int **phrnotecnt,double **phraseamp,double **phrange,noteptr **phrlastnote,dataptr dz);
+static int  do_ev_pch
+            (double *thispitch,double thistime,double *pptop,double *ppbot,dataptr dz);
+static int  get_gpparams
+            (double thistime,double thispitch,unsigned char dectypecnt,double *gprange,double *gprlow,int *gpsize,
+            double *gpdense,double pptop,double ppbot,unsigned char dectypestor,int mingrpsize,dataptr dz);
+static int orientrange
+            (double thispitch,double pptop, double ppbot,double *gprange, double *gprlow,
+            unsigned char dectypestor,unsigned char dectypecnt,dataptr dz);
+static void squeezrange(double thispitch,double *gprange,double *gprlow, double pptop, double ppbot);
+
+/**************************** DO_TEXTURE *****************************/
+
+int do_texture(dataptr dz)
+{
+    int exit_status;
+    noteptr tsetnote = dz->tex->timeset->firstnote;
+    unsigned int texflag     = dz->tex->txflag;
+    unsigned char dectypestor = dz->tex->dectypstor;
+    unsigned char dectypecnt  = dz->tex->dectypcnt;
+    unsigned char amptypestor = dz->tex->amptypstor;
+    unsigned char amptypecnt  = dz->tex->amptypcnt;
+    int ampdirected           = dz->tex->ampdirectd;
+    motifptr tset             = dz->tex->timeset;
+    motifptr *phrase          = dz->tex->phrase;
+    int phrcount              = dz->tex->phrasecnt;
+    int *phrnotecnt=NULL;
+    double *phraseamp=NULL, *phrange=NULL;  
+    noteptr thisnote=NULL, nextnote=NULL, phrasenote=NULL, nextevent=NULL, *phrlastnote=NULL, *shadow=NULL;
+    float phrlpitch=0.0, phrfirstpitch=0.0;
+    unsigned char thisinstr, amptype=0;
+    double  tsettime=0.0, thistime=0.0, thispitch=0.0, ampstep=0.0, thepitch=0.0, thisamp=0.0, thisdur=0.0;
+    double  rangemult=0.0, gpdense=0.0, gprange=0.0, gprlow=0.0, multiplier=0.0;
+    double timeadjust = 0.0; /* default */
+    int phrno=0, n=0, shadowsize=0, gpsize=0, mingrpsize = 0;
+    double pptop=0.0, ppbot=0.0;
+    int shadindex = 0;
+
+    dz->iparam[SPINIT] = 0;
+    if(texflag & IS_CLUMPED) {
+        if((dz->tex->phrasecnt > 0) 
+        && (exit_status = initialise_phrases(&phrnotecnt,&phraseamp,&phrange,&phrlastnote,dz))<0)
+            return(exit_status);
+
+        if(texflag & IS_GROUPS)
+            mingrpsize = 1;         
+
+        if((exit_status= make_shadow(tset,&shadowsize,&shadow))<0)
+            return(exit_status);
+
+        if(texflag & IS_DECOR) {
+            setup_decor(&pptop,&ppbot,&shadindex,&tsetnote,dz);
+        } else if(texflag & IS_MOTIFS)  {
+            if((exit_status = set_motifs(phrcount,phrase,phrnotecnt,phraseamp,phrange,phrlastnote))<0)
+                return(exit_status);
+        } else if(texflag & IS_ORNATE) {
+            if((exit_status = set_motifs(phrcount,phrase,phrnotecnt,phraseamp,phrange,phrlastnote))<0)
+                return(exit_status);
+            if(dz->vflag[WHICH_CHORDNOTE]==DECOR_HIGHEST)
+                tsetnote = gethipitch(tsetnote,&shadindex);
+        }
+    }
+
+    while(tsetnote!=(noteptr)0) {
+        tsettime  = (double)tsetnote->ntime;
+        thistime  = tsettime;
+        if((exit_status = read_values_from_all_existing_brktables(thistime,dz))<0)
+            return(exit_status);
+        if(texflag & IS_DECOR)
+            thispitch = tsetnote->pitch;
+        if(texflag & IS_ORN_OR_MTF) {
+            if((exit_status = 
+            setup_motif_or_ornament(thistime,&multiplier,&phrno,&phrasenote,phrase,dz))<0)
+                return(exit_status);
+        }
+        if(!(texflag & IS_ORN_OR_DEC)) {
+            if((exit_status = do_ev_pch(&thispitch,thistime,&pptop,&ppbot,dz))<0)
+                return(exit_status);
+            tsetnote->pitch = (float)thispitch;
+        }
+        if((exit_status = do_amp_instr_dur(&thisamp,&thisinstr,&thisdur,tsetnote,thistime,dz))<0)
+            return(exit_status);
+        if(texflag & IS_CLUMPED) {
+            if(texflag & IS_MOTIFS) {
+                if((exit_status = getmtfdur(tsetnote,phrasenote,&thisdur,multiplier,dz))<0)
+                    return(exit_status);
+                tsetnote->dur = (float)thisdur;
+            }
+            if(texflag & IS_ORN_OR_MTF) {
+                gpsize = phrnotecnt[phrno];
+                phrfirstpitch = phrasenote->pitch;
+            } else {
+                if((exit_status = get_gpparams(thistime,thispitch,dectypecnt,
+                &gprange,&gprlow,&gpsize,&gpdense,pptop,ppbot,dectypestor,mingrpsize,dz))<0)
+                    return(exit_status);
+            }
+            if(texflag & IS_DECOR) {
+                if((exit_status = position_and_size_decoration(&thistime,tsettime,gpdense,&gpsize,dz))<0)
+                    return(exit_status);
+            } else
+                gpsize--;
+            if(texflag & IS_ORNATE) {
+                phrlpitch = (phrlastnote[phrno])->pitch;
+                if((exit_status = setup_ornament
+                (&timeadjust,&thistime,&gpsize,phrlastnote,multiplier,&phrasenote,phrno,dz))<0)
+                    return(exit_status);
+            }
+            if(!(texflag & IS_DECOR))
+                nextnote = tsetnote->next;
+            if(gpsize>0) {                      /* 3b */
+                if(texflag & IS_ORN_OR_MTF) {
+                    if((exit_status = orn_or_mtf_amp_setup
+                    (ampdirected,phrange,phrno,thisamp,gpsize,&rangemult,&ampstep,&amptype,amptypestor,amptypecnt,dz))<0)
+                        return(exit_status);
+                }
+                if(texflag & IS_MOTIFS) {
+                    if((exit_status = set_motif_amp
+                    (tsetnote,&thisamp,gpsize,ampstep,phrasenote,rangemult,phraseamp,phrno,amptype))<0)
+                        return(exit_status);
+                } else if(texflag & IS_ORNATE) {
+                    if((exit_status = set_ornament_amp
+                    (phraseamp,phrlastnote,&thisamp,phrasenote,phrno,tsetnote,ampstep,rangemult,gpsize,dz))<0)
+                        return(exit_status);
+                } else if(texflag & IS_GROUPS) {
+                    if((exit_status = set_group_amp
+                    (tsetnote,&thisamp,&amptype,&ampstep,gpsize,amptypecnt,amptypestor,dz))<0)
+                        return(exit_status);
+                } else if(texflag & IS_DECOR) {
+                    if((exit_status = set_decor_amp
+                    (ampdirected,&thisamp,&ampstep,gpsize,&amptype,amptypecnt,amptypestor,dz))<0)
+                        return(exit_status);
+                }
+                if(dz->iparam[TEX_GPSPACE]!=IS_STILL) {
+                    if((exit_status = init_group_spatialisation(tsetnote,shadindex,shadow,shadowsize,dz))<0)
+                        return(exit_status);
+                }
+                thisnote  = tsetnote;
+                if(texflag & IS_DECOR)
+                    nextnote = tsetnote->next;
+                else if(texflag & IS_ORNATE) {
+                    if(!dz->vflag[IS_PRE])
+                        phrasenote = phrasenote->next;
+                }
+                if(texflag & IS_ORN_OR_DEC)
+                    nextevent = getnextevent_to_decorate(tsetnote,&shadindex,dz);
+                for(n=0;n<gpsize;n++) {
+                    if((exit_status = make_new_note(&thisnote))<0)
+                        return(exit_status);
+                    if(texflag & IS_DEC_OR_GRP) {
+                        if((exit_status = set_group_params
+                        (tsetnote,thisnote,gpdense,ampstep,&thisamp,&thistime,thisdur,dz))<0)
+                            return(exit_status);
+                        if((exit_status = do_grp_ins(tsetnote->instr,&(thisnote->instr),dz))<0)
+                            return(exit_status);
+                        thisnote->motioncentre = tsetnote->motioncentre;
+                        if(texflag & IS_DECOR) {
+                            if((exit_status = dec_centre
+                            (thispitch,&(thisnote->pitch),gpsize,gprlow,gprange,dz))<0) 
+                                return(exit_status);
+                        } else {
+                            if((exit_status = pscat(gprange,gprlow,PM_GPPICH,&thepitch,dz))<0)
+                                return(exit_status);
+                            thisnote->pitch = (float)thepitch;
+                        }
+                        thisnote->ntime  = (float)thistime; 
+                    } else {
+                        if((exit_status = check_next_phrasenote_exists(&phrasenote,texflag,dz))<0)
+                            return(exit_status);
+                        if((exit_status = setup_motif_params(phrasenote,thistime,&thisamp,ampstep,phraseamp,phrno,
+                        rangemult,thisnote,tsetnote,multiplier,timeadjust,dz))<0)
+                            return(exit_status);
+                        if(texflag & IS_MOTIFS) {
+                            gen_mtf_pitch(thisnote,tsetnote,phrasenote,phrfirstpitch);
+                        } else {
+                            gen_orn_pitch(thisnote,tsetnote,phrasenote,phrlpitch,phrfirstpitch,dz);
+                            phrasenote = phrasenote->next;
+                        }
+                    }
+                    if((exit_status = setspace(tsetnote,thisnote,gpsize,dz))<0)
+                        return(exit_status);
+                }
+                thisnote->next = nextnote;
+                if(nextnote!=(noteptr)0)
+                    nextnote->last = thisnote;
+                if(texflag & IS_ORN_OR_DEC)
+                    tsetnote = nextevent;
+
+            } else if(texflag & IS_ORN_OR_DEC)
+                tsetnote = getnextevent_to_decorate(tsetnote,&shadindex,dz);
+
+        } else 
+            tsetnote = tsetnote->next;
+
+        if(texflag & IS_MTF_OR_GRP) {
+            tsetnote = nextnote;
+            shadindex++;
+        }
+    }
+    if((texflag & IS_DECOR) && dz->vflag[DISCARD_ORIGLINE]) {
+        if((exit_status = erase_shadow(shadowsize,shadow,tset))<0)
+            return(exit_status);
+    }
+    if(texflag & IS_CLUMPED)
+        return arrange_notes_in_timeorder(tset);
+    return(FINISHED);
+}
+
+/**************************** SETUP_MOTIF_PARAMS ****************************/
+
+int setup_motif_params
+(noteptr phrasenote,double tsettime,double *thisamp,double ampstep,double *phraseamp, int phrno,
+double rangemult,noteptr thisnote,noteptr tsetnote,double multiplier,double timeadjust,dataptr dz)
+{
+    double notetime, ampdif;
+    notetime = getnotetime(phrasenote,tsettime,multiplier,timeadjust,dz);
+    *thisamp  += ampstep;
+    ampdif    =(phraseamp[phrno] - phrasenote->amp)*rangemult;/* e */
+    return do_mtf_params(thisnote,*thisamp,phrasenote,tsetnote,ampdif,notetime,multiplier,dz);
+}
+
+/**************************** GEN_ORN_PITCH ****************************/
+
+void gen_orn_pitch
+(noteptr thisnote,noteptr tsetnote,noteptr phrasenote,float phrlpitch,float phrfirstpitch,dataptr dz)
+{
+    if(dz->vflag[IS_PRE])   
+        thisnote->pitch = (float)(tsetnote->pitch + phrasenote->pitch - phrlpitch);
+    else 
+        thisnote->pitch = (float)(tsetnote->pitch + phrasenote->pitch - phrfirstpitch);
+}
+
+/**************************** GEN_MTF_PITCH ****************************/
+
+void gen_mtf_pitch(noteptr thisnote,noteptr tsetnote,noteptr phrasenote,float phrfirstpitch)
+{
+    thisnote->pitch = (float)(tsetnote->pitch + phrasenote->pitch - phrfirstpitch);
+    thisnote->pitch = (float)octadjust((double)thisnote->pitch);
+}
+
+/************************* DEC_CENTRE ******************************
+ *
+ * Centre a decoration on the decorated pitch.
+ *
+ * (1)  For groupsize 1 or 2, k=1
+ *      For groupsize 3 or 4, k=2
+ *      For groupsize 5 or 6, k=3 etc
+ * (2)  Scatter pitches as normally.
+ * (3)  If range is NOT one-sided, proceed..otherwise return in normal way.
+ * (4)  Find ratio of upper half of range to lower. 
+ * (5)  Find distance from decorated note.
+ * (6)  Save the current value of allowed repetitions.
+ *      THese are number of times a note occurs above the decorated pitch,
+ *      before it can do so again (same for below).
+ * (7)  If the allowed repetitions are bigger than k, replace it by k.
+ *      This means that if we allow 3 repetitions but there are only
+ *      1,2,3 or 4 notes, we force, 1 repetition for 2 notes, 2 repetitions
+ *      for 3 or 4 notes etc. but allow 3 repetitions for 5,6 etc notes.
+ * (8)  Select above or below decorated pitch.
+ * (9)  If meant to be above note, but is below it, put note in other
+ *      half of range, with appropriate adjustment for relative sizes
+ *      of half-ranges.
+ * (10) If meant to be below note, but is above it, put note in other
+ *      half of range, with appropriate adjustment for relative sizes
+ *      of half-ranges.
+ * (11) Restore the repetcnt value!!
+ */
+ 
+int dec_centre(double tsetpitch,float *val,int gpsize,double gprlow,double gprange,dataptr dz)
+{
+    int exit_status;
+    double a, q, w, gprhi = gprlow + gprange, ulratio;
+    int s, save, k = (gpsize+1)/2;                              /* 1 */
+    if((exit_status = pscat(gprange,gprlow,PM_GPPICH,&a,dz))<0) /* 2 */
+        return(exit_status);
+    if((w=tsetpitch-gprlow)>FLTERR && !flteq(tsetpitch,gprhi)) {/* 3 */
+        ulratio = (gprhi-tsetpitch)/w;                          /* 4 */
+        q       = a-tsetpitch;                                  /* 5 */
+        save    = dz->iparray[TXREPETCNT][PM_DECABV];           /* 6 */
+        if(dz->iparray[TXREPETCNT][PM_DECABV]>k)                /* 7 */
+            dz->iparray[TXREPETCNT][PM_DECABV] = k;         
+        if((exit_status = doperm((int)2,PM_DECABV,&s,dz))<0)            /* 8 */
+            return(exit_status);
+        if(s && q<0.0)                                          /* 9 */
+            a = tsetpitch - (q*ulratio);
+        if(!s && q>0.0)                                         /* 10 */
+            a = tsetpitch - (q/ulratio);
+        dz->iparray[TXREPETCNT][PM_DECABV] = save;              /* 11 */
+        if(a<MIDIBOT || a>MIDITOP) {
+            sprintf(errstr,"TEXTURE: Problem in dec_centre()\n");
+            return(PROGRAM_ERROR);
+        }
+    }
+    *val = (float)a;
+    return(FINISHED);
+}
+
+/***************************** PSCAT ************************************
+ *
+ * A weighted version of pscatx().
+ *
+ * Select a random value within 'range', by permuting one of BANDCNT UNequal
+ * ranges, and selecting a random value within the chosen range. The upper
+ * and lower band are half as wide as the inner 3 bands, ensuring that
+ * values within these outer bands are squeezed into a narrow-range-of-values
+ * near the boundaries of the total range.
+ */
+
+int pscat(double range,double bottom,int pindex,double *val,dataptr dz)
+{
+    int exit_status;
+    double bandbottom, bandwidth, x;
+    int k;
+    if((exit_status = doperm((int)BANDCNT,pindex,&k,dz))<0)
+        return(exit_status);
+    bandwidth = range/(double)LAYERCNT;
+    switch(k) {
+    case(0):
+        bandbottom = 0.0;
+        break;
+    case(BANDCNT-1):
+        bandbottom = (LAYERCNT-1) * bandwidth;
+        break;
+    default:
+        bandbottom = bandwidth + ((double)((k-1) * 2) * bandwidth);
+        bandwidth *= 2.0;
+        break;
+    }
+    x  = (drand48() * bandwidth);
+    x += bandbottom;
+    *val = x + bottom;
+    return(FINISHED);
+}
+
+/**************************** INITIALISE_PHRASES *******************************/
+
+int initialise_phrases(int **phrnotecnt,double **phraseamp,double **phrange,noteptr **phrlastnote,dataptr dz)
+{
+    if((*phrnotecnt = (int *)malloc(dz->tex->phrasecnt * sizeof(int)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY for phrase notecnt array.\n");
+        return(MEMORY_ERROR);
+    }
+    if((*phraseamp = (double *)malloc(dz->tex->phrasecnt * sizeof(double)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY for phrase amplitude array.\n");
+        return(MEMORY_ERROR);
+    }
+    if((*phrange = (double *)malloc(dz->tex->phrasecnt * sizeof(double)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY for phrase range array.\n");
+        return(MEMORY_ERROR);
+    }
+    if((*phrlastnote = (noteptr *)malloc(dz->tex->phrasecnt * sizeof(noteptr)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY for phrase lastnote array.\n");
+        return(MEMORY_ERROR);
+    }
+    return(FINISHED);
+}
+
+/********************** DO_EV_PCH *******************************
+ *
+ * Set pitch of event (not group etc.).
+ */
+
+int do_ev_pch
+(double *thispitch,double thistime,double *pptop,double *ppbot,dataptr dz)
+{
+    int exit_status;
+    if((exit_status = getvalue(TEXTURE_MAXPICH,TEXTURE_MINPICH,thistime,PM_PITCH,thispitch,dz))<0)
+        return(exit_status);
+    if(*thispitch > MIDITOP || *thispitch < MIDIBOT) {
+        sprintf(errstr,"TEXTURE: pitch [%.1f] out of midirange at time %.2f\n",*thispitch,thistime); 
+        return(DATA_ERROR);
+    }
+    *pptop = dz->param[TEXTURE_MAXPICH];
+    *ppbot = dz->param[TEXTURE_MINPICH];
+    return(FINISHED);
+}
+
+/************************** GET_GPPARMAS **************************
+ *
+ * Get the parameters for a group of notes.
+ *
+ * (1)  Get gprange in normal way.
+ * (2)  Don't adjust range.
+ * (3)  For decorations, the range may be oriented, above, below
+ *      or centred on the initial note. So range is adjusted here.
+ */
+                                                                                           
+int get_gpparams(double thistime,double thispitch,unsigned char dectypecnt,
+double *gprange,double *gprlow,int *gpsize,double *gpdense,double pptop,double ppbot,
+unsigned char dectypestor,int mingrpsize,dataptr dz)
+{
+    int exit_status;
+    if((exit_status = getvalue(TEX_GPRANGHI,TEX_GPRANGLO,thistime,PM_GPRANG,gprange,dz))<0)
+        return(exit_status);                                                /* 1 */
+    if(!dectypecnt)
+        squeezrange(thispitch,gprange,gprlow,pptop,ppbot);
+    else {
+        if((exit_status = orientrange
+        (thispitch,pptop,ppbot,gprange,gprlow,dectypestor,dectypecnt,dz))<0)/* 3 */
+            return(exit_status);
+    }
+    if((exit_status = igetvalue(TEX_GPSIZEHI,TEX_GPSIZELO,thistime,PM_GPSIZE,gpsize,dz))<0)
+        return(PROGRAM_ERROR);
+
+    if(*gpsize < mingrpsize) {
+        sprintf(errstr,"Impossible GROUP SIZE value [%d]\n",*gpsize);
+        return(PROGRAM_ERROR);
+    }
+    return get_density_val(thistime,gpdense,dz);
+}
+
+/***************************  ORIENTRANGE ******************************
+ *
+ */
+
+int orientrange
+(double thispitch,double pptop, double ppbot,double *gprange, double *gprlow,
+unsigned char dectypestor,unsigned char dectypecnt,dataptr dz)
+{
+    int exit_status;
+    unsigned char dectype;
+    double top;
+    int k;
+    if((exit_status = doperm((int)dectypecnt,PM_ORIENT,&k,dz))<0)
+        return(exit_status);
+    if((exit_status = gettritype(k,dectypestor,&dectype))<0)
+        return(exit_status);
+    switch(dectype) {
+    case(0):            /* centred range */
+        squeezrange(thispitch,gprange,gprlow,pptop,ppbot);
+        dz->vflag[DECCENTRE] = TRUE;
+        break;
+    case(1):            /* range above note */
+        top      = min((thispitch + *gprange),pptop);
+        *gprlow  = max((top - *gprange),ppbot);
+        *gprange = top - *gprlow;
+        dz->vflag[DECCENTRE] = FALSE;
+        break;              
+    case(2):            /* range below note */
+        top      = thispitch;
+        *gprlow  = max((top - *gprange),ppbot);
+        *gprange = top - *gprlow;
+        dz->vflag[DECCENTRE] = FALSE;
+        break;              
+    default:
+        sprintf(errstr,"TEXTURE: Problem in orientrange()\n");
+        return(PROGRAM_ERROR);
+    }
+    return(FINISHED);
+}
+
+/***************************  SQUEEZRANGE ******************************
+ *
+ * Adjust range to lie within texture limits.
+ *
+ * (2)  Top of range is at current pitch plus half range. If this is
+ *  above current top-of-texture range (pptop) move top down.
+ * (3)  Bottom of range is gprange below top. If this is below
+ *  bottom-of-texture range (ppbot), move gprangelo up.
+ * (4)  Recalculate the true gprange within true limits.
+ */
+
+void squeezrange(double thispitch,double *gprange,double *gprlow, double pptop, double ppbot)
+{
+    double top;
+    top     = min((thispitch + (*gprange/2.0)),pptop);      /* 2 */
+    *gprlow  = max((top-*gprange),ppbot);                   /* 3 */
+    *gprange = top - *gprlow;                               /* 4 */
+}

+ 2360 - 0
dev/texture/v8/texture3.c

@@ -0,0 +1,2360 @@
+/*
+ * Copyright (c) 1983-2013 Trevor Wishart and Composers Desktop Project Ltd
+ * http://www.trevorwishart.co.uk
+ * http://www.composersdesktop.com
+ *
+ This file is part of the CDP System.
+ 
+ The CDP System is free software; you can redistribute it
+ and/or modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+ 
+ The CDP System is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU Lesser General Public License for more details.
+ 
+ You should have received a copy of the GNU Lesser General Public
+ License along with the CDP System; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA
+ *
+ */
+/* floatsam version: no changes */
+#include <stdio.h>
+#include <stdlib.h>
+#include <float.h>
+#include <structures.h>
+#include <tkglobals.h>
+#include <globcon.h>
+#include <processno.h>
+#include <modeno.h>
+#include <arrays.h>
+#include <texture.h>
+#include <cdpmain.h>
+
+#include <sfsys.h>
+#include <osbind.h>
+
+#if defined unix || defined __GNUC__
+#define round(x) lround((x))
+#endif
+
+#define CHARBITSIZE (8)     /* number of bits in a char          */
+
+struct ffit {               /* Structure for FIT of motif to HS  */
+    float transpose;
+    float fit;
+    struct ffit *next;
+    struct ffit *last;
+};
+
+typedef struct ffit *fitptr;
+
+/* RWD Feb 2014: now in sfsys,h, differently! */
+#ifdef MAXINT
+# undef MAXINT
+#endif
+#define MAXINT (2147483647)
+/***************************** GENERATING TEXTURES WITH HFIELD(S) ******************************/
+
+
+static int set_hfmotifs(double *hs,motifptr *phrase,int *phrnotecnt,double *phraseamp,
+            double *phrange, noteptr *phrlastnote,int *endhsindex,int **hfphrase,
+            int hsnotecnt,fitptr fithead,double **notestor,dataptr dz);
+static int gethfphrase
+            (double *hs,double **notestor,int z,double lopitch,double hipitch,int **hfphrase,
+            int hsnotecnt,int *phrnotecnt,motifptr *phrase,fitptr fithead);
+static int shrink_to_hs
+            (int z,int hsnotecnt,double hipitch,double lopitch,double hstop,double hsbot,
+            double *hs, int *hfphrase,motifptr *phrase,int *phrnotecnt);
+static int findhfphrase
+            (int z,double *hs,double hstop,int hsnotecnt,double lopitch,
+            double origlo,motifptr *phrase,int **hfphrase,int *phrnotecnt,fitptr fithead,double **notestor);
+static int getmtfindeces
+            (double transpose,int z,int hsnotecnt,double *hs,motifptr *phrase,int *phrnotecnt,int **hfphrase);
+static int get_fit(double *notestor,fitptr thisfit,double lopitch,double origlo,int z,
+            int hsnotecnt,int *phrnotecnt,double *hs,fitptr *newfit);
+static int put_fit(fitptr thisfit,double transval,double fitval,fitptr *newfit);
+static int best_fit(fitptr fithead,double *transpose);
+static void free_fitlist(fitptr fithead);
+static double hfadjust(double thispitch,double *hs,int x1,int x2,int texflag,int hsnotecnt);
+static int convert_pitch_to_nearest_hset_pitch(double thispitch,double *hs,int hsnotecnt);
+static int hfadj2(int hsi,int hfnotecnt,int hsnotecnt);
+static int setup_hfield(noteptr thisnote,double **hs,int *hsnotecnt,double **hf,int *hfnotecnt,int texflag);
+static int get_next_hfield
+            (double **hf,double **hs,double inputtime,int *hf_cnt,int *hs_cnt,int *hfnotecnt,
+            noteptr *thishfnote,double *thishftime,double *nexthftime,int hfdatacnt,int *hsnotecnt,
+            noteptr *thishsnote,double *thishstime,double *nexthstime,double *hft,int texflag);
+static int setup_motif_note
+            (double thisamp,int thisinstr,double thisdur,noteptr tsetnote,noteptr phrasenote,
+            double *thispitch,double thistime,int *hsindex,int hsnotecnt,double *hs,
+            double *pptop,double *ppbot,int *shadindex,char *shadbits,double multiplier,dataptr dz);
+static int setup_group_note
+            (double thisamp,int thisinstr,double thisdur,noteptr tsetnote,
+            double *thispitch,double thistime,int *hsindex,int hsnotecnt,double *hs,
+            double *pptop,double *ppbot,int *shadindex,char *shadbits,dataptr dz);
+static int setup_ornamentation
+            (int *starthsi,int *endhsi,noteptr *nextevent,noteptr tsetnote,noteptr *phrasenote,
+            int *shadindex, int *endhsindex,int *hfphrase,int phrno,dataptr dz);
+static int generate_motifin_note_pitch
+            (int n,int hsindex,int starthsindex,int hsnotecnt,double thispitch,
+            int *hfphrase,noteptr *thisnote,double *hs,int texflag);
+static int generate_motif_note_pitch
+            (noteptr tsetnote,noteptr phrasenote,double phrfirstnote,noteptr thisnote);
+static int generate_ornament_note_pitch
+            (int n,double *hs, int hsi, int endhsi,int starthsi,noteptr *thisnote,noteptr *phrasenote,
+            int *hfphrase,int hfnotecnt,int hsnotecnt,dataptr dz);
+static int do_ev_hfpch
+            (double thistime,int *hsindex,double *val,
+            int hsnotecnt,double *hs,double *pptop,double *ppbot,dataptr dz);
+static int getp_as_index
+            (double thistime,int *val,int hsnotecnt,double *hs,double *pptop,double *ppbot,dataptr dz);
+static int init_shadbits(int shadowsize,int *shshsize,char **shadbits);
+static int geths(noteptr thisnote,double **hs,int *hsnotecnt);
+static int gethf(noteptr thisnote,double **hf,int *hfnotecnt);
+static int gen_hs(double **hf,double **hs, int *hsnotecnt, int hfnotecnt);
+static int chekrepeat(noteptr thisnote,double lastpitch);
+static void set_shadbit(int k,char *shadbits);
+static int  geths_lobnd(double thispitch,double *hs,int hsnotecnt);
+static int  gethfnote(double thispitch,double *hf,int *hfnotecnt);
+static int  setmtfparams
+            (noteptr thisnote,double thisamp,noteptr phrasenote,noteptr tsetnote,double ampdif,
+            double notetime,int gpsize,double multiplier,dataptr dz);
+static int  initialise_hfphrases
+            (int ***hfphrase,int **endhsindex,int **phrnotecnt,double **phraseamp,double **phrange,
+            noteptr **phrlastnote,dataptr dz);
+static int  readhftimes(noteptr firstnote, int *hfdatacnt,double **hft);
+static int  init_fits(fitptr *thisfit);
+static int  get_hfgpparams(double thistime,double thispitch,double *hs,int hsnotecnt,
+        int *gpsize,int *hfrange,int *hfgpranglo,int *hfgpranghi,
+        double *gprange,double *gpdense,int mingrpsize,
+        double *gprlow, int dectypecnt,unsigned char dectypestor,dataptr dz);
+static int  generate_group_note(noteptr thisnote,noteptr testnote,double thistime,
+        int hfrange,int hfgpranglo,double *hs,int *hsindex,int gpsize,dataptr dz);
+static int  generate_decor_note(noteptr thisnote,noteptr tsetnote,
+        double thispitch,double thistime,int hfrange,int hfgpranghi,int hfgpranglo,
+        double *hs,int *hsindex,int hsnotecnt,double gprlow,double gprange,int gpsize,dataptr dz);
+static void del_ghosts(int shshsize,char *shadbits,noteptr *shadow,int shadowsize,motifptr tset);
+static int  geths_hibnd(double thispitch,int hsnotecnt,double *hs);
+static int  geths_above(double thispitch,double *hs,int hsnotecnt);
+static int  fit_unlink(fitptr thisfit);
+static int  new_fit(fitptr thisfit,fitptr *newfit);
+static int  getnexths(double **hs,double inputtime,int *hs_cnt,int *hsnotecnt,noteptr *thishsnote,
+        double *thishstime,double *nexthstime,int hfdatacnt,double *hft);
+static int  getnexthf(double **hf,double **hs, int *hsnotecnt,double inputtime,int *hf_cnt,
+        int *hfnotecnt,noteptr *thishfnote,double *thishftime,double *nexthftime,int hfdatacnt,double *hft);
+static int  hfscat(int prange,int pbottom,int permindex,int *val,dataptr dz);
+static int  gethsnote(double thispitch,double *thishs,int *hsnotecnt);
+static void hfsqueezrange
+        (double thispitch,int *hfrange,int *hfgpranghi,int *hfgpranglo,int hsnotecnt,double *hs);
+static int  hforientrange(double thispitch,int *hfrange,int *hfgpranghi,int *hfgpranglo,
+        int hsnotecnt,double *hs,int dectypecnt,unsigned char dectypestor,dataptr dz);
+static int  dec_hfcentre(double tsetpitch,double *hs,int hsnotecnt,
+        int hfrange,int hfgpranghi,int hfgpranglo,double gprlow,double gprange,int gpsize,
+        double *val,dataptr dz);
+static int  hfscatx(int prange,int pbottom,int permindex,int *val,dataptr dz);
+static int  get_first_hs(noteptr thisnote,double **hs,int *hsnotecnt);
+static int  get_first_hf(noteptr thisnote,double **hf,int *hfnotecnt);
+static int  setup_first_hfield
+        (noteptr thisnote,double **hs,int *hsnotecnt,double **hf,int *hfnotecnt,int texflag);
+static int octeq(double a,double b);
+
+/**************************** DO_SIMPLE_HFTEXTURE ****************************/
+
+int do_simple_hftexture(dataptr dz)
+{
+    int exit_status;
+    unsigned int texflag     = dz->tex->txflag;
+    motifptr tset             = dz->tex->timeset;
+    motifptr hfmotif          = dz->tex->hfldmotif;
+    int hsindex;
+    noteptr tsetnote = tset->firstnote;
+    noteptr nextnote;
+    double thistime, thispitch, lastpitch = -1.0;
+    noteptr thishfnote = hfmotif->firstnote;
+    noteptr thishsnote = hfmotif->firstnote;
+    double thishftime,nexthftime,thishstime,nexthstime,thisamp,thisdur;
+    unsigned char thisinstr;
+    int hf_cnt = 1, hfnotecnt = 0;
+    int hs_cnt = 1, hsnotecnt = 0, repeated = 0;
+    int hfdatacnt = 0;
+    double *hft, pptop, ppbot;
+    double *hs = (double *)0, *hf = (double *)0;
+    dz->iparam[SPINIT] = 0;
+
+    if((exit_status = readhftimes(hfmotif->firstnote,&hfdatacnt,&hft))<0)
+        return(exit_status);
+    thishftime = nexthftime = thishstime = nexthstime = hft[0];
+
+    if(texflag & ISMANY_HFLDS) {
+        if((exit_status = setup_first_hfield(hfmotif->firstnote,&hs,&hsnotecnt,&hf,&hfnotecnt,texflag))<0)
+            return(exit_status);
+    } else {
+        if((exit_status = setup_hfield(hfmotif->firstnote,&hs,&hsnotecnt,&hf,&hfnotecnt,texflag))<0)
+            return(exit_status);
+    }
+    while(tsetnote!=(noteptr)0) {                   /* 3 */
+        repeated  =  chekrepeat(tsetnote,lastpitch);
+        lastpitch = tsetnote->pitch;                                                    
+        thistime  = (double)tsetnote->ntime;        /* 5 */
+        if((exit_status = read_values_from_all_existing_brktables(thistime,dz))<0)
+            return(exit_status);
+        if(texflag & ISMANY_HFLDS) {
+            if((exit_status = get_next_hfield(&hf,&hs,thistime,&hf_cnt,&hs_cnt,
+            &hfnotecnt,&thishfnote,&thishftime,&nexthftime,hfdatacnt,
+            &hsnotecnt,&thishsnote,&thishstime,&nexthstime,hft,texflag))<0)
+                return(exit_status);
+        }
+        if((exit_status = do_amp_instr_dur(&thisamp,&thisinstr,&thisdur,tsetnote,thistime,dz))<0)
+            return(exit_status);
+        if((exit_status = do_ev_hfpch(thistime,&hsindex,&thispitch,hsnotecnt,hs,&pptop,&ppbot,dz))<0)
+            return(exit_status);
+        tsetnote->pitch = (float)thispitch;
+        if(exit_status == CONTINUE) {
+            nextnote = tsetnote->next;
+            del_note(tsetnote,tset);
+            tsetnote = nextnote;
+        } else
+            tsetnote = tsetnote->next;
+    }
+    if(tset->firstnote==(noteptr)0) {
+        sprintf(errstr,"The harmonic set specified does not tally with the range.\n");
+        return(DATA_ERROR);
+    }
+    return(FINISHED);
+}
+
+/**************************** DO_CLUMPED_HFTEXTURE ****************************/
+
+int do_clumped_hftexture(dataptr dz)
+{
+    int exit_status;
+    unsigned int texflag     = dz->tex->txflag;
+    unsigned char dectypestor = dz->tex->dectypstor;
+    unsigned char dectypecnt  = dz->tex->dectypcnt;
+    unsigned char amptypestor = dz->tex->amptypstor;
+    unsigned char amptypecnt  = dz->tex->amptypcnt;
+    int ampdirected           = dz->tex->ampdirectd;
+    motifptr tset             = dz->tex->timeset;
+    motifptr hfmotif          = dz->tex->hfldmotif;
+    motifptr *phrase          = dz->tex->phrase;
+    int **hfphrase = NULL;
+    int *endhsindex=NULL, *phrnotecnt=NULL;
+    double *phraseamp=NULL, *phrange=NULL;
+    unsigned char amptype = 0;
+    fitptr fithead = NULL;
+    noteptr tsetnote = tset->firstnote;
+    noteptr thisnote=NULL, nextnote=NULL, phrasenote=NULL, nextevent=NULL, *shadow=NULL;
+    double thispitch = 0.0, lastpitch = -1.0, ampstep = 0.0, ampdif = 0.0, notetime = 0.0, thisamp = 0.0, thisdur = 0.0;
+    unsigned char thisinstr;
+    double phrfirstnote = 0.0, thistime = 0.0, rangemult = 0.0, gprlow = 0.0;
+    double timeadjust = 0.0; /* default */
+    noteptr thishfnote = hfmotif->firstnote;
+    noteptr thishsnote = hfmotif->firstnote;
+    noteptr *phrlastnote = NULL;
+    double thishftime = 0.0,nexthftime = 0.0,thishstime = 0.0,nexthstime = 0.0,tsettime = 0.0;
+    int hf_cnt = 1, hfnotecnt = 0, mingrpsize = 0, shadindex = 0, shadowsize=0;
+    double gprange = 0.0,gpdense = 0.0,multiplier = 0.0;
+    double *notestor=NULL;
+    int hfgpranglo=0,hfgpranghi=0;
+    int hs_cnt = 1, hsnotecnt = 0, repeated = 0;
+    int hfdatacnt = 0, hfrange = 0, gpsize,shshsize = 0;
+    int phrno = 0, n=0,  hsindex=0, starthsindex=0, hfchanged=0;
+    int hsi=0, starthsi = 0, endhsi=0;
+    char *shadbits = NULL;
+    double *hft=NULL, pptop=0.0, ppbot=0.0;
+    double *hs = (double *)0, *hf = (double *)0;
+
+    if((dz->tex->phrasecnt > 0) && (exit_status = initialise_hfphrases
+    (&hfphrase,&endhsindex,&phrnotecnt,&phraseamp,&phrange,&phrlastnote,dz))<0)
+        return(exit_status);
+    dz->iparam[SPINIT] = 0;
+    if(texflag & IS_GROUPS)
+        mingrpsize = 1;
+
+    if((exit_status = readhftimes(hfmotif->firstnote,&hfdatacnt,&hft))<0)
+        return(exit_status);
+    thishftime = nexthftime = thishstime = nexthstime = hft[0];
+
+    if((exit_status = make_shadow(tset,&shadowsize,&shadow))<0)
+            return(exit_status);
+
+    if((texflag & MOTIF_IN_HF) || (texflag & IS_ORNATE)) {
+        if((exit_status = init_fits(&fithead))<0)
+            return(exit_status);
+    }
+    if(texflag & IS_DECOR)
+        setup_decor(&pptop,&ppbot,&shadindex,&tsetnote,dz);
+    else {
+        if((exit_status = init_shadbits(shadowsize,&shshsize,&shadbits))<0)
+            return(exit_status);
+    }
+    if(texflag & ISMANY_HFLDS) {
+        if((exit_status = setup_first_hfield(hfmotif->firstnote,&hs,&hsnotecnt,&hf,&hfnotecnt,texflag))<0)
+            return(exit_status);
+    } else {
+        if((exit_status = setup_hfield(hfmotif->firstnote,&hs,&hsnotecnt,&hf,&hfnotecnt,texflag))<0)
+            return(exit_status);
+    }
+    if((texflag & MOTIF_IN_HF) || ((texflag & IS_ORNATE) && !(texflag & ISMANY_HFLDS))) {
+        if((exit_status = set_hfmotifs
+        (hs,phrase,phrnotecnt,phraseamp,phrange,phrlastnote,endhsindex,hfphrase,hsnotecnt,fithead,&notestor,dz))<0)
+            return(exit_status);
+    } else if(texflag & IS_MOTIFS) {
+        if((exit_status = set_motifs
+        (dz->tex->phrasecnt,phrase,phrnotecnt,phraseamp,phrange,phrlastnote))<0)
+            return(exit_status);
+    }
+    while(tsetnote!=(noteptr)0) {
+        if(!(texflag & IS_ORNATE)) {
+            repeated =  chekrepeat(tsetnote,lastpitch);
+            lastpitch = tsetnote->pitch;
+        }
+        tsettime = thistime = (double)tsetnote->ntime;
+        if((exit_status = read_values_from_all_existing_brktables(thistime,dz))<0)
+            return(exit_status);
+        if(texflag & ISMANY_HFLDS) {
+            if((exit_status = get_next_hfield(&hf,&hs,thistime,&hf_cnt,&hs_cnt,
+            &hfnotecnt,&thishfnote,&thishftime,&nexthftime,hfdatacnt,
+            &hsnotecnt,&thishsnote,&thishstime,&nexthstime,hft,texflag))<0)
+                return(exit_status);
+            hfchanged = exit_status;
+            if(((texflag & MOTIF_IN_HF) || (texflag & IS_ORNATE)) && hfchanged) {
+                if((exit_status = set_hfmotifs
+                (hs,phrase,phrnotecnt,phraseamp,phrange,phrlastnote,endhsindex,hfphrase,hsnotecnt,fithead,&notestor,dz))<0)
+                    return(exit_status);
+            }                                                      
+        }
+        if(texflag & IS_ORN_OR_MTF) {
+            if((exit_status = setup_motif_or_ornament(thistime,&multiplier,&phrno,&phrasenote,phrase,dz))<0)
+                return(exit_status);
+        }
+        if((exit_status = do_amp_instr_dur(&thisamp,&thisinstr,&thisdur,tsetnote,thistime,dz))<0)
+            return(exit_status);
+        if(texflag & IS_DECOR)        
+            thispitch = tsetnote->pitch;
+        if(texflag & IS_MTF_OR_GRP) {
+            if(texflag & IS_GROUPS)
+                exit_status = setup_group_note
+                (thisamp,thisinstr,thisdur,tsetnote,&thispitch,
+                thistime,&hsindex,hsnotecnt,hs,&pptop,&ppbot,&shadindex,shadbits,dz);
+            else
+                exit_status = setup_motif_note
+                (thisamp,thisinstr,thisdur,tsetnote,phrasenote,&thispitch,
+                thistime,&hsindex,hsnotecnt,hs,&pptop,&ppbot,&shadindex,shadbits,multiplier,dz);
+            if(exit_status==CONTINUE)
+                continue;
+        }
+        if(texflag & IS_ORN_OR_MTF)
+            gpsize = phrnotecnt[phrno];
+        else {
+            if((exit_status = get_hfgpparams
+            (thistime,thispitch,hs,hsnotecnt,&gpsize,&hfrange,&hfgpranglo,&hfgpranghi,
+            &gprange,&gpdense,mingrpsize,&gprlow,dectypecnt,dectypestor,dz))<0)
+                return(exit_status);
+        }
+        if(texflag & IS_DECOR) {
+            if((exit_status = position_and_size_decoration(&thistime,tsettime,gpdense,&gpsize,dz))<0)
+                return(exit_status);
+        } else
+            gpsize--;
+        if(texflag & IS_MOTIFS)
+            phrfirstnote = phrasenote->pitch;
+        else if(texflag & IS_ORNATE) {
+            if((hsi = convert_pitch_to_nearest_hset_pitch((double)tsetnote->pitch,hs,hsnotecnt))<0)
+                gpsize = 0;         /* note out of bounds, ornament omitted  */
+            if((exit_status = setup_ornament
+            (&timeadjust,&thistime,&gpsize,phrlastnote,multiplier,&phrasenote,phrno,dz))<0)
+                return(exit_status);
+        }
+        if(!(texflag & IS_DECOR))
+            nextnote  = tsetnote->next;
+        if(gpsize>0) {
+            if(texflag & IS_ORN_OR_MTF) {
+                if((exit_status = orn_or_mtf_amp_setup
+                (ampdirected,phrange,phrno,thisamp,gpsize,&rangemult,&ampstep,&amptype,amptypestor,amptypecnt,dz))<0)
+                    return(exit_status);
+            }
+            if(texflag & IS_MOTIFS) {
+                if((exit_status = set_motif_amp
+                (tsetnote,&thisamp,gpsize,ampstep,phrasenote,rangemult,phraseamp,phrno,amptype))<0)
+                    return(exit_status);
+            } else if(texflag & IS_ORNATE) {
+                if((exit_status = set_ornament_amp
+                (phraseamp,phrlastnote,&thisamp,phrasenote,phrno,tsetnote,ampstep,rangemult,gpsize,dz))<0)
+                    return(exit_status);
+            } else if (texflag & IS_GROUPS) {
+                if((exit_status = set_group_amp
+                (tsetnote,&thisamp,&amptype,&ampstep,gpsize,amptypecnt,amptypestor,dz))<0)
+                    return(exit_status);
+            } else if (texflag & IS_DECOR) {
+                if((exit_status = set_decor_amp
+                (ampdirected,&thisamp,&ampstep,gpsize,&amptype,amptypecnt,amptypestor,dz))<0)
+                    return(exit_status);
+            }
+            if(dz->iparam[TEX_GPSPACE]!=IS_STILL) {
+                if((exit_status = init_group_spatialisation(tsetnote,shadindex,shadow,shadowsize,dz))<0)
+                    return(exit_status);
+            }
+            thisnote  = tsetnote;
+            if(texflag & MOTIF_IN_HF)
+                starthsindex =  *(hfphrase[phrno]);
+            else if(texflag & IS_ORNATE) {
+                if((exit_status = setup_ornamentation
+                (&starthsi,&endhsi,&nextevent,tsetnote,&phrasenote,&shadindex,endhsindex,hfphrase[phrno],phrno,dz))<0)
+                    return(exit_status);
+            } else if(texflag & IS_DECOR) {
+                nextnote = tsetnote->next;
+                nextevent = getnextevent_to_decorate(tsetnote,&shadindex,dz);
+            }
+            for(n=0;n<gpsize;n++) {
+                if((exit_status = make_new_note(&thisnote))<0)
+                    return(exit_status);
+                if(texflag & IS_ORN_OR_MTF) {
+                    if((exit_status = check_next_phrasenote_exists(&phrasenote,texflag,dz))<0)
+                        return(exit_status);
+                    notetime = getnotetime(phrasenote,thistime,multiplier,timeadjust,dz);
+                    thisamp += ampstep;
+                    ampdif   = (phraseamp[phrno]-phrasenote->amp)*rangemult;
+                    if((exit_status = setmtfparams
+                    (thisnote,thisamp,phrasenote,tsetnote,ampdif,notetime,gpsize,multiplier,dz))<0)
+                        return(exit_status);
+                } else  {
+                    if((exit_status = set_group_params
+                    (tsetnote,thisnote,gpdense,ampstep,&thisamp,&thistime,thisdur,dz))<0)
+                        return(exit_status);
+                }
+                if(texflag & MOTIF_IN_HF) {
+                    if((exit_status = generate_motifin_note_pitch
+                    (n,hsindex,starthsindex,hsnotecnt,thispitch,hfphrase[phrno],&thisnote,hs,texflag))<0)
+                        return(exit_status);
+                } else if(texflag & IS_MOTIFS) {
+                    if((exit_status = generate_motif_note_pitch(tsetnote,phrasenote,phrfirstnote,thisnote))<0)
+                        return(exit_status);
+                } else if (texflag & IS_ORNATE) {
+                    if((exit_status = generate_ornament_note_pitch
+                    (n,hs,hsi,endhsi,starthsi,&thisnote,&phrasenote,hfphrase[phrno],hfnotecnt,hsnotecnt,dz))<0)
+                        return(exit_status);
+                } else if(texflag & IS_GROUPS) {
+                    if((exit_status = generate_group_note
+                    (thisnote,tsetnote,thistime,hfrange,hfgpranglo,hs,&hsindex,gpsize,dz))<0)
+                        return(exit_status);
+                } else if(texflag & IS_DECOR) {
+                    if((exit_status = generate_decor_note
+                    (thisnote,tsetnote,thispitch,thistime,hfrange,hfgpranghi,hfgpranglo,
+                    hs,&hsindex,hsnotecnt,gprlow,gprange,gpsize,dz))<0)
+                        return(exit_status);
+                }
+                if(exit_status==CONTINUE)
+                    continue;
+            }
+            thisnote->next = nextnote;
+            if(nextnote!=(noteptr)0)
+                nextnote->last = thisnote;
+            if(texflag & IS_ORN_OR_DEC)
+                tsetnote = nextevent;
+        } else if(texflag & IS_ORN_OR_DEC)
+            tsetnote = getnextevent_to_decorate(tsetnote,&shadindex,dz);
+
+        if(texflag & IS_MTF_OR_GRP) {
+            tsetnote = nextnote;
+            shadindex++;
+        }
+    }
+    if(texflag & IS_MTF_OR_GRP) 
+        del_ghosts(shshsize,shadbits,shadow,shadowsize,tset);       /* 5 */
+
+    if(texflag & IS_DECOR) {
+        if(dz->vflag[DISCARD_ORIGLINE] && (exit_status = erase_shadow(shadowsize,shadow,tset))<0)
+            return(exit_status);
+    } else
+        free(shadbits);
+    if((texflag & MOTIF_IN_HF) || (texflag & IS_ORNATE))
+        free(fithead);
+    return arrange_notes_in_timeorder(tset);
+}
+
+/**************************** SET_HFMOTIFS *******************************
+ *
+ * initialise all parameters of input motifs to be used for MOTIFS or
+ * ORNAMENTS, including their HS indexing!!!
+ *
+ * (1)For each input motif (called a 'phrase').
+ *    phrnotecnt[n] = 0;
+ * (2)  Initialise count of number of notes to 0, maximum amplitude
+ *  of phrase to 0.0, and lowest pitch-index to hsnotecnt.
+ * (3)  Go through each note of the motif.
+ * (4)  Add up the number of notes in it.
+ * (5)  Find it's lowest pitch.
+ * (6)  Find it's loudest note (and set as phraseamp).
+ * (7)  Establish dynamic range of phrase.
+ * (9)  Ensure motif starts at zero time.
+ * (10) Generate the corresponding HS indices, in their lowest configuration.
+ * (11) Store hfindex of last note of phrase.
+ */
+
+int set_hfmotifs
+(double *hs,motifptr *phrase,int *phrnotecnt,double *phraseamp,double *phrange,noteptr *phrlastnote,
+int *endhsindex,int **hfphrase,int hsnotecnt,fitptr fithead,double **notestor,dataptr dz)
+{
+    int exit_status;
+    int n;
+    double mintime, minamp, minpitch, maxpitch;
+    noteptr thisnote, lastnote = (noteptr)0;
+    for(n=0;n<dz->tex->phrasecnt;n++) {                     /* 1 */
+        if((exit_status = arrange_notes_in_timeorder(phrase[n]))<0)
+            return(exit_status);
+        phrnotecnt[n] = 0;
+        phraseamp[n] = 0.0;                         /* 2 */
+        minamp   = DBL_MAX;
+        minpitch = DBL_MAX;
+        maxpitch = -2.0f;
+        mintime  = DBL_MAX;
+        thisnote = phrase[n]->firstnote;            /* 3 */
+        while(thisnote!=(noteptr)0) {
+            phrnotecnt[n]++;                            /* 4 */
+            if((double)thisnote->pitch<minpitch)
+                minpitch = thisnote->pitch;         /* 5 */
+            if((double)thisnote->pitch>maxpitch)
+                maxpitch = thisnote->pitch;         /* 5 */
+            if(thisnote->ntime<mintime)
+                mintime  = thisnote->ntime;         /* 5 */
+            if((double)thisnote->amp>phraseamp[n])
+                phraseamp[n] = (double)thisnote->amp;/* 6 */
+            if(thisnote->amp<minamp)
+                minamp = thisnote->amp;             /* 6 */
+            thisnote = thisnote->next;
+        }
+        if(minamp   == DBL_MAX
+        || minpitch == DBL_MAX
+        || maxpitch == -2.0f
+        || mintime  == DBL_MAX) {
+            sprintf(errstr,"Error parsing notelist: set_hfmotifs()\n");
+            return(PROGRAM_ERROR);
+        }
+        thisnote = phrase[n]->firstnote;
+        phrange[n] = phraseamp[n] - (double)minamp; /* 7 */
+        while(thisnote!=(noteptr)0) {
+            thisnote->ntime = (float)(thisnote->ntime - mintime);               /* 9 */
+            lastnote = thisnote;
+            thisnote = thisnote->next;
+        }   
+        if((phrlastnote[n] = lastnote)==(noteptr)0) {
+            sprintf(errstr,"Encountered an empty motif: set_hfmotifs()\n");
+            return(PROGRAM_ERROR);
+        }
+        if((exit_status = gethfphrase(hs,notestor,n,minpitch,maxpitch,hfphrase,hsnotecnt,phrnotecnt,phrase,fithead))<0) /* 10 */
+            return(exit_status);
+        endhsindex[n]  = *(hfphrase[n]+phrnotecnt[n]-1);            /* 11 */
+    }
+    return(FINISHED);
+}
+
+/*********************** GETHFPHRASE *********************************
+ *
+ * Get the hfphrase best corresponding to the input motif.
+ *
+ * (0)  Create storage space to store HS-indices of phrase.
+ * (1)  HIpitch of phrase higher than top of HS
+ *  AND LOpitch of phrase lower than bottom of HS.
+ *  ..Shrink the motif to size of HS, and establish hfphrase.
+ * (2)  HIpitch of phrase higher than top of HS
+ *  BUT LOpitch within HS range.
+ *  .. transpose phraselimits down onto bottom pitch of HS.
+ * (a)  If HIpitch of phrase STILL higher than top of HS
+ *  ..Shrink the motif to size of HS, and establish hfphrase.
+ * (3)  LOpitch of phrase lower than bottom of HS
+ *  BUT HIpitch within HS range.
+ *  .. transpose phraselimits up onto bottom pitch of HS.
+ * (a)  If HIpitch of phrase is NOW higher than top of HS
+ *  ..Shrink the motif to size of HS, and establish hfphrase.
+ * (4)  Phrase lies with the limits of HS.
+ *  .. transpose phraselimits down onto bottom pitch of HS.
+ * (5)  Find appropriate hfphrase.
+ */
+
+int gethfphrase
+(double *hs,double **notestor,int z,double lopitch,double hipitch,
+int **hfphrase,int hsnotecnt,int *phrnotecnt,motifptr *phrase,fitptr fithead)
+{
+    double origlo = lopitch, hstop = hs[hsnotecnt-1], hsbot = hs[0];
+    double stepdown, stepup;
+    if((hfphrase[z] = (int *)malloc(phrnotecnt[z] * sizeof(int)))==NULL) {  /* 0 */
+        sprintf(errstr,"INSUFFICIENT MEMORY for harmonic field phrase array.\n");
+        return(MEMORY_ERROR);
+    }
+    if(hipitch>=hstop) {    
+        if(lopitch<=hsbot)              /* 1 */
+            return shrink_to_hs(z,hsnotecnt,hipitch,lopitch,hstop,hsbot,hs,hfphrase[z],phrase,phrnotecnt);
+        else  {
+            stepdown = lopitch - hsbot;         /* 2 */
+            hipitch -= stepdown;
+            lopitch -= stepdown;
+            if(hipitch>hstop)               /* a */
+                return shrink_to_hs(z,hsnotecnt,hipitch,lopitch,hstop,hsbot,hs,hfphrase[z],phrase,phrnotecnt);
+        }
+    } else {
+        if(lopitch<=hsbot) {                /* 3 */
+            stepup  = hsbot - lopitch;
+            hipitch += stepup;
+            lopitch += stepup;
+            if(hipitch>hstop)               /*a */
+                return shrink_to_hs(z,hsnotecnt,hipitch,lopitch,hstop,hsbot,hs,hfphrase[z],phrase,phrnotecnt); 
+        } else {                    /* 4 */
+            stepdown = lopitch - hsbot;
+            hipitch -= stepdown;
+            lopitch -= stepdown;
+        }
+    }
+    return findhfphrase(z,hs,hstop,hsnotecnt,lopitch,origlo,phrase,hfphrase,phrnotecnt,fithead,notestor);   
+}                                           /* 5 */
+
+
+/************************* SHRINK_TO_HS **************************
+ *
+ * Shrink motif so it fits with HS, then find best HS fit.
+ *
+ * (1)  Establish pitch-shrinking ratio.
+ * (2)  For every note...
+ * (3)  Shrink intervals and thus move pitch to appropriate position inside
+ *  range of HS.
+ * (4)  Find index of the next lowest HS notes.
+ * (4a) If note falls outside field, set distance to note to maximum poss.
+ * (4b) Else find pitch distances of this note from original pitch.
+ * (5)  Find index of the next highest HS notes.
+ * (5a) If note falls outside field, set distance to note to maximum poss.
+ * (5b) Else find pitch distances of this note from original pitch.
+ * (6)  Select HSindex of nearest pitch and store in hfphrase.
+ * (7)  Save the lowest such index.
+ * (8)  Transpose all indices down to lowest possible values.
+ */
+
+int shrink_to_hs(int z,int hsnotecnt,double hipitch,double lopitch,double hstop,
+                double hsbot,double *hs, int *hfphrase, motifptr *phrase,int *phrnotecnt)
+{
+    noteptr thisnote = phrase[z]->firstnote;
+    double shrink ,thispitch, x, y;
+    int minindex = MAXINT, xx, yy, q, n = 0;
+    shrink = (hstop - hsbot)/(hipitch-lopitch);         /* 1 */
+    for(;;) {                           /* 2 */
+        thispitch = thisnote->pitch;    
+        thispitch = ((thispitch - lopitch) * shrink) + hsbot;   /* 3 */
+        if((xx = geths_lobnd(thispitch,hs,hsnotecnt))<0)            /* 4 */
+            x = DBL_MAX;                        /* 4a */
+        else
+            x = fabs(hs[xx] - thispitch);           /* 4b */
+        if((yy = geths_hibnd(thispitch,hsnotecnt,hs))>=hsnotecnt)       /* 5 */
+            y = DBL_MAX;                        /* 5a */
+        else
+            y = fabs(hs[yy] - thispitch);           /* 5b */
+        if(x<y)
+            q = xx;                     /* 6 */
+        else
+            q = yy;
+        *(hfphrase+n) = q;
+        if(q<minindex)
+            minindex = q;                   /* 7 */
+        if((thisnote = thisnote->next)==(noteptr)0)
+            break;
+        if(++n >= phrnotecnt[z]) {
+            sprintf(errstr,"accounting problem in shrink_to_hs()\n");
+            return(PROGRAM_ERROR);
+        }
+    }
+    for(n=0;n<phrnotecnt[z];n++)                    /* 8 */
+        *(hfphrase+n) -= minindex;
+    return(FINISHED);
+}
+
+/*********************** FINDHFPHRASE *********************************
+ *
+ * Extract the best fit onto the HS, and transpose it down to bottom
+ * of indices.
+ *
+ * (1)  Set the FIT-pointer to head of fits-list.
+ * (2)  Set up a store for the note values to be tested.
+ * (3)  Get interval of transposition to take motif to bottom of HS range.
+ * (4)  Store original note values of phrase transposed down to bottom of HS range.
+ * (5)  Find the fit-value for motif in its start position.
+ * (6)  Outer loop will transpose the phrase through a range...
+ *      (7) Set amount to transpose phrase (shift) to max.
+            Then for every note of the phrase.....
+ *          (8) Find the HSindex of the nearest note above the current note.
+ *              (If there isn't one break out completely).
+ *          (9)  If the difference in pitch between this and the current note
+ *              is smaller than the minimum shift, reset minimum shift.
+ *          (10)Then, for every note of the phrase...
+ *          (11)transpose it up by this minimum transposition.
+ *              If this takes any note of the phrase outside the range of HS
+ *              break out completely.
+ *      (12)Back in outer loop, find the fitting-value for this transposition
+ *          of the motif, which is a measure of how far its notes are from
+ *          the closest HS values.
+ * (13) Outside the outer loop, unlink the last unwanted member iof fitlist.
+ * (14) Find the best fitvalue, and return the amount by which orig motif
+ *      should be transposed to get onto this best fit.
+ * (15) Free the fit-list (retains fithead).
+ * (16) Get the appropriate HS indices.
+ */
+
+int findhfphrase
+(int z,double *hs,double hstop,int hsnotecnt,double lopitch,double origlo,
+motifptr *phrase,int **hfphrase,int *phrnotecnt,fitptr fithead,double **notestor)
+{
+    int exit_status;
+    int hsindex, OK = 1, n, got_transpose = 0;
+    noteptr thisnote = phrase[z]->firstnote;
+    fitptr thisfit = fithead;                                   /* 1 */
+    double shift, thisshift, transpose = 0.0, stepdown, *noteval;
+    if(*notestor!=NULL)
+        free(*notestor);                                        /* 2 */
+    if((noteval = *notestor = (double *)malloc(phrnotecnt[z] * sizeof(double)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY for note value array.\n");
+        return(MEMORY_ERROR);
+    }
+    stepdown = origlo - lopitch;                                /* 3 */
+    while(thisnote!=(noteptr)0) {                               
+        *noteval = (double)thisnote->pitch - stepdown;          /* 4 */
+        noteval++;
+        thisnote = thisnote->next;
+    }
+    if((exit_status = get_fit(*notestor,thisfit,lopitch,origlo,z,hsnotecnt,phrnotecnt,hs,&thisfit))<0)
+        return(exit_status);                                    /* 5 */
+    if(exit_status == CONTINUE) {
+        transpose = thisfit->last->transpose;
+        got_transpose = 1;
+        OK  = 0;
+    }
+    while(OK) {                                                 /* 6 */
+        shift = DBL_MAX;                                        /* 7 */
+        noteval = *notestor;
+        for(n=0;n<phrnotecnt[z];n++) {
+            if((hsindex = geths_above(*noteval,hs,hsnotecnt))>=hsnotecnt) { /* 8 */
+                OK = 0;
+                break;
+            }
+            if((thisshift  = hs[hsindex] - *noteval)<shift)
+                shift = thisshift;                              /* 9 */
+            noteval++;
+        }
+        if(shift==DBL_MAX) {
+            sprintf(errstr,"Error parsing phrase: findhfphrase()\n");
+            return(PROGRAM_ERROR);
+        }
+        if(!OK)
+            break;
+        noteval = *notestor;
+        for(n=0;n<phrnotecnt[z];n++) {                          /* 10 */
+            if((*noteval++  += (float)shift)>hstop) {
+                OK = 0;                                         /* 11 */
+                break;
+            }
+        }
+        lopitch += shift;
+        if((exit_status = get_fit(*notestor,thisfit,lopitch,origlo,z,hsnotecnt,phrnotecnt,hs,&thisfit))<0)      
+            return(exit_status);                                /* 12 */
+        if(exit_status == CONTINUE) {
+            transpose = thisfit->last->transpose;
+            got_transpose = 1;
+            break;
+        }
+    }
+    if((exit_status = fit_unlink(thisfit))<0)                   /* 13 */
+        return(exit_status);
+    if (!got_transpose) {
+        if((exit_status = best_fit(fithead,&transpose))<0)      /* 14 */
+            return(exit_status);
+    }
+    free_fitlist(fithead);                                      /* 15 */
+    return getmtfindeces(transpose,z,hsnotecnt,hs,phrase,phrnotecnt,hfphrase);  
+}                                                               /* 16 */
+
+/*************************** GETMTFINDECES *****************************
+ *
+ * Get the HS indices of the phrase, transposed to lowest position in HS.
+ *
+ * (0)  Point to start of storage space for the HS-indices of the phrase.
+ * (1)  Mark end of this storage space (for accounting purposes).
+ * (2)  For every note of the phrase...
+ *   (3)  Get the pitch..
+ *   (4)  Transpose the pitch by the input transposition.
+ *   (5)  Find the nearest HS set members above and below the note.
+ *   (6)  Decide which is nearest.
+ *   (7)  Assign index of nearest value to the HS-index store.
+ *   (8)  Keep a note of the smallest index.
+ *   (9)  Increment the index-store pointer.
+ * (10) Decrement all the indeces to tranpose them all to lowest values
+ *  in the hfphrase store.
+ */
+
+int getmtfindeces(double transpose,int z,int hsnotecnt,double *hs,motifptr *phrase,int *phrnotecnt,int **hfphrase)
+{
+    noteptr thisnote = phrase[z]->firstnote;
+    int *thisindex, xx, yy, minindex = MAXINT, *indexend;
+    double x, y, thispitch;
+    thisindex = hfphrase[z];                        /* 0 */
+    indexend  = hfphrase[z] + phrnotecnt[z];        /* 1 */
+    for(;;) {                                       /* 2 */
+        thispitch  = thisnote->pitch;               /* 3 */
+        thispitch += transpose;                     /* 4 */
+        xx = geths_lobnd(thispitch,hs,hsnotecnt);   /* 5 */
+        yy = geths_hibnd(thispitch,hsnotecnt,hs);
+        x = fabs(hs[xx] - thispitch);               /* 6 */
+        y = fabs(hs[yy] - thispitch);
+        if(x<y)
+            *thisindex = xx;                        /* 7 */
+        else
+            *thisindex = yy;
+        if(*thisindex<minindex)
+            minindex = *thisindex;                  /* 8 */
+        if((thisnote = thisnote->next)==(noteptr)0)
+            break;
+        if(++thisindex>=indexend) {                 /* 9 */
+            sprintf(errstr,"TEXTURE: Problem in getmtfindices()\n");
+            return(PROGRAM_ERROR);
+        }
+    }
+    for(thisindex = hfphrase[z];thisindex<indexend;thisindex++)
+        *thisindex -= minindex;                     /* 10 */
+    return(FINISHED);
+}
+
+/****************************** GET_FIT ************************************
+ *
+ * Create list of fit_values for motif over HS.
+ * 
+ * (1)  For every note of the phrase.
+ * (3)  Find the index of the next lowest HS note. If there is not one
+ *  something is wrong!
+ * (4)  Find the index of the next highest HS note. If there is not one
+ *  something is wrong!
+ * (5)  Find the pitch distance between these notes on the original pitch.
+ * (6)  Add the minimum of these two, to a running sum of such differences.
+ * (7)  Store the fit-value and the associated ttansposition, creating a
+ *  new storage space in the fit list, in the process.
+ */
+
+int get_fit(double *notestor,fitptr thisfit,double lopitch,double origlo,int z,
+            int hsnotecnt,int *phrnotecnt,double *hs,fitptr *newfit)
+{
+    int exit_status;
+    double x, y, sum = 0.0, *noteval = notestor;
+    int xx, yy, n;  
+    for(n=0;n<phrnotecnt[z];n++) {                              /* 1 */
+        if((xx = geths_lobnd(*noteval,hs,hsnotecnt))<0) {       /* 3 */
+            sprintf(errstr,"Problem 1 in get_fit()\n");
+            return(PROGRAM_ERROR);
+        }   
+        if((yy=geths_hibnd(*noteval,hsnotecnt,hs))>=hsnotecnt) {/* 4 */
+            sprintf(errstr,"Problem 2 in get_fit()\n");
+            return(PROGRAM_ERROR);
+        }
+        x = fabs(hs[xx] - *noteval);                            /* 5 */
+        y = fabs(hs[yy] - *noteval);
+        sum += min(x,y);                                        /* 6 */
+        noteval++;
+    }
+    if((exit_status = put_fit(thisfit,lopitch - origlo,sum,newfit))<0)
+        return(exit_status);
+    if(flteq(sum,0.0))
+        return(CONTINUE);
+    return(FINISHED);                                           /* 7 */
+}
+
+/************************* PUT_FIT *****************************
+ *
+ * Put fit value in motif-fits list.
+ */
+
+int put_fit(fitptr thisfit,double transval,double fitval,fitptr *newfit)
+{
+    int exit_status;
+    thisfit->transpose = (float)transval;
+    thisfit->fit       = (float)fitval;
+    if((exit_status = new_fit(thisfit,newfit))<0)
+        return(exit_status);
+    return(FINISHED);
+}
+
+/************************* BEST_FIT *****************************
+ *
+ * Find the appropriate transposition to move the current motif
+ * to a pitch where it has the best fit with the HS.
+ *
+ * (1)  From all available transpositions, find best (lowest) fit value.
+ * (2)  From all available transpositions, find all those which have
+ *  this bestfit value, and select the one which involves the
+ *  least transposition.
+ * (3)  Once the transpositions begin to increase, we are moving away from
+ *  the smallest transposition, so quit.
+ * (4)  Return the best transposition. 
+ */
+
+int best_fit(fitptr fithead,double *transpose)
+{
+    fitptr thisfit = fithead;
+    double bestfit = DBL_MAX, besttranspose = DBL_MAX;
+    double abstranspose = DBL_MAX, thistranspose;
+    while(thisfit!=(fitptr)0) {             /* 1 */
+        if(thisfit->fit<(float)bestfit)
+            bestfit = (double)thisfit->fit;
+        thisfit = thisfit->next;
+    }
+    thisfit = fithead;
+    while(thisfit!=(fitptr)0) {             /* 2 */
+        thistranspose = fabs((double)thisfit->transpose);
+        if(flteq((double)thisfit->fit,bestfit)) {
+            if(thistranspose<abstranspose) {
+                besttranspose = (double)thisfit->transpose;
+                abstranspose = fabs(besttranspose);
+            }
+        }
+        if(thistranspose>abstranspose+FLTERR)
+            break;                  /* 3 */
+        thisfit = thisfit->next;
+    }
+    if(besttranspose==DBL_MAX) {
+        sprintf(errstr,"Problem in best_fit()\n");
+        return(PROGRAM_ERROR);
+    }
+    *transpose = besttranspose;
+    return(FINISHED);               /* 4 */
+}
+
+/************************* INIT_FITS() *****************************
+ *
+ * Set up head item of a list of motif-fits.
+ */
+
+int init_fits(fitptr *thisfit)
+{
+    if((*thisfit = (fitptr)malloc(sizeof (struct ffit)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY for fitting array.\n");
+        return(MEMORY_ERROR);
+    }
+    (*thisfit)->next  = (fitptr)0;
+    (*thisfit)->last  = (fitptr)0;
+    return(FINISHED);
+}
+
+/************************* NEW_FIT() *****************************
+ *
+ * Set up next fit in a list of motif-fits.
+ */
+
+int new_fit(fitptr thisfit,fitptr *newfit)
+{
+    if((*newfit = (fitptr)malloc(sizeof (struct ffit)))==NULL) {
+        sprintf(errstr,"new_fit()\n");
+        return(PROGRAM_ERROR);
+    }
+    thisfit->next   = *newfit;
+    (*newfit)->last = thisfit;
+    (*newfit)->next = (fitptr)0;
+    return(FINISHED);
+}
+
+/********************** FIT_UNLINK() ******************************
+ *
+ * Deletes empty address space at end of fitlist.
+ */
+
+int fit_unlink(fitptr thisfit)
+{
+    if(thisfit->last==(fitptr)0) {
+        sprintf(errstr,"Problem in fit_unlink()\n");
+        return(PROGRAM_ERROR);
+    }
+    thisfit = thisfit->last;
+    free(thisfit->next);
+    thisfit->next = (fitptr)0;
+    return(FINISHED);
+}
+
+/********************** FREE_FITLIST() ******************************
+ *
+ * Deletes fitlist, retaining head.
+ */
+
+void free_fitlist(fitptr fithead)
+{
+    fitptr thisfit;
+    if((thisfit = fithead->next)==(fitptr)0)
+        return;
+    while(thisfit->next!=(fitptr)0) {
+        thisfit = thisfit->next;
+        free(thisfit->last);
+    }
+    free(thisfit);
+}
+
+/**************************** HFADJUST *********************************
+ *
+ * Pitch outside HS range. Adjust it.
+ *
+ * (1)  If this is a HS, there's nothing we can do about it. Return -1.0
+ *  which will cause note to be deleted in calling environment.
+ * (2)  If it's an HF however....
+ *  Set newpitch at appropriate interval from original pitch.
+ * (3)  If it's now above the HS
+ * (4)  transpose it down by octaves until it is in the HS.
+ * (5)  If still not in HS, mark for deletion.
+ * (6)  If it's BELOW the HS.
+ * (7)  transpose it up by octaves until it is in the HS.
+ * (8)  If still not in HS, mark for deletion.
+ * (9)  Return new pitch.
+ */
+
+double hfadjust(double thispitch,double *hs,int x1,int x2,int texflag,int hsnotecnt)
+{
+    double newpitch;
+    if(texflag & IS_HS)
+        return(-1.0);                               /* 1 */
+    else {                                      
+        newpitch = thispitch+hs[x1]-hs[x2];         /* 2 */
+        if(newpitch > hs[hsnotecnt-1]) {            /* 3 */
+            while(newpitch>hs[hsnotecnt-1])
+                newpitch -= SEMITONES_PER_OCTAVE;   /* 4 */
+            if(newpitch<hs[0])                      /* 5 */
+                return(-1.0);
+        } else {
+            if(newpitch<hs[0]) {                    /* 6 */
+                while(newpitch <hs[0])
+                    newpitch += SEMITONES_PER_OCTAVE;/* 7 */
+                if(newpitch>hs[hsnotecnt-1])
+                    return(-1.0);                   /* 8 */
+            }
+        }
+    }
+    return(newpitch);                               /* 9 */
+}
+
+/**************************** CONVERT_PITCH_TO_NEAREST_HSET_PITCH *********************************
+ *
+ * Convert pitch value to nearest HS value.
+ *
+ * ignores the problem of note repetitions in the tset.
+ * Note repetitions were only important where the tset notes were being
+ * forced onto an HS. Here the HS values are being extracted so the notes
+ * can be ornamented. The pitch values of the tset are NOT themselves altered.
+ */
+
+int convert_pitch_to_nearest_hset_pitch(double thispitch,double *hs,int hsnotecnt)
+{
+    int n, m;
+    if(thispitch<hs[0]) {
+        if(hs[0] - thispitch > hs[1] - hs[0])
+            return(-1);
+        else
+            return(0);
+    }
+    n = 1;
+    m = n-1;
+    while(n<hsnotecnt) {
+        if(flteq(hs[n],thispitch))
+            return(n);
+        if(hs[n]>thispitch) {
+            if(hs[n] - thispitch > thispitch - hs[m])
+                return(m);
+            else
+                return(n);
+        }
+        n++;
+        m++;
+    }
+    if(hsnotecnt>1 && (thispitch - hs[hsnotecnt-1] > hs[hsnotecnt-1] - hs[hsnotecnt-2]))
+        return(-1);
+    return(hsnotecnt-1);
+}
+
+/**************************** HFADJ2 *********************************
+ *
+ * HFindex outside HS range. Adjust it.
+ * Applies only to HF (i.e. an HS containing octave transpositions)
+ * not to HS.
+ */
+
+int hfadj2(int hsi,int hfnotecnt,int hsnotecnt)
+{
+    if(hsi<0) {
+        while(hsi<0)
+            hsi += hfnotecnt;
+    } else {
+        while(hsi>=hsnotecnt)
+            hsi -= hfnotecnt;
+    }
+    if(hsi<0 || hsi>=hsnotecnt)
+        return(-1);
+    return(hsi);
+}
+
+/**************************** SETUP_HFIELD *********************************/
+
+int setup_hfield(noteptr thisnote,double **hs,int *hsnotecnt,double **hf,int *hfnotecnt,int texflag)
+{
+    int exit_status;
+    if(texflag & IS_HS) {
+        if((exit_status = geths(thisnote,hs,hsnotecnt))<0)
+            return(exit_status);
+    } else {
+        if((exit_status = gethf(thisnote,hf,hfnotecnt))<0)                  /* 2 */
+            return(exit_status);
+        if((exit_status = gen_hs(hf,hs,hsnotecnt,*hfnotecnt))<0)
+            return(exit_status);
+    }
+    return(FINISHED);
+}
+
+/**************************** SETUP_FIRST_HFIELD *********************************/
+
+int setup_first_hfield(noteptr thisnote,double **hs,int *hsnotecnt,double **hf,int *hfnotecnt,int texflag)
+{
+    int exit_status;
+    if(texflag & IS_HS) {
+        if((exit_status = get_first_hs(thisnote,hs,hsnotecnt))<0)
+            return(exit_status);
+    } else {
+        if((exit_status = get_first_hf(thisnote,hf,hfnotecnt))<0)                   /* 2 */
+            return(exit_status);
+        if((exit_status = gen_hs(hf,hs,hsnotecnt,*hfnotecnt))<0)
+            return(exit_status);
+    }
+    return(FINISHED);
+}
+
+/**************************** GET_NEXT_HFIELD *********************************/
+
+int get_next_hfield(double **hf,double **hs,double inputtime,
+int *hf_cnt,int *hs_cnt,int *hfnotecnt,noteptr *thishfnote,double *thishftime,double *nexthftime,int hfdatacnt,
+int *hsnotecnt,noteptr *thishsnote,double *thishstime,double *nexthstime,double *hft,int texflag)
+{
+    if(texflag & IS_HS)
+        return getnexths(hs,inputtime,hs_cnt,hsnotecnt,thishsnote,thishstime,nexthstime,hfdatacnt,hft);
+    else
+        return getnexthf(hf,hs,hsnotecnt,inputtime,hf_cnt,hfnotecnt,thishfnote,thishftime,nexthftime,hfdatacnt,hft);
+}
+
+/**************************** SETUP_MOTIF_NOTE *********************************
+ *
+ * (1)  If the program is given a pitchrange OUTSIDE the bounds of the
+ *      specified HF or HS, do_ev_hfpch() returns a -ve value. In this
+ *      case, the associated tset note is marked for DELETION by setting
+ *      the bitflag associated with the shadow (address) of the tset note.
+ *      It will be deleted at the very end, by del_ghosts().
+ */
+
+int setup_motif_note
+(double thisamp,int thisinstr,double thisdur,noteptr tsetnote,noteptr phrasenote,
+double *thispitch,double thistime,int *hsindex,int hsnotecnt,double *hs,
+double *pptop,double *ppbot,int *shadindex,char *shadbits,double multiplier,dataptr dz)
+{
+    int exit_status;
+    tsetnote->amp = (float)thisamp;
+    tsetnote->instr = (unsigned char)thisinstr;
+    if(dz->vflag[DONT_KEEP_MTFDUR])
+        tsetnote->dur = (float)thisdur;
+    else
+        tsetnote->dur = (float)(phrasenote->dur * multiplier);
+    if(flteq((double)tsetnote->dur,0.0)) {
+        sprintf(errstr,"setup_motif_note(): Zero duration\n");
+        return(PROGRAM_ERROR);
+    }
+    if((exit_status = do_ev_hfpch(thistime,hsindex,thispitch,hsnotecnt,hs,pptop,ppbot,dz))<0) 
+        return(exit_status);
+    if(exit_status==CONTINUE) {
+        set_shadbit(*shadindex,shadbits);    /* 1 */
+        tsetnote = tsetnote->next;              
+        (*shadindex)++;
+        return(CONTINUE);
+    }
+    tsetnote->pitch = (float)(*thispitch);
+    return(FINISHED);
+}
+
+/**************************** SETUP_GROUP_NOTE *********************************/
+
+int setup_group_note
+(double thisamp,int thisinstr,double thisdur,noteptr tsetnote,
+double *thispitch,double thistime,int *hsindex,int hsnotecnt,double *hs,
+double *pptop,double *ppbot,int *shadindex,char *shadbits,dataptr dz)
+{
+    int exit_status;
+    tsetnote->amp = (float)thisamp;
+    tsetnote->instr = (unsigned char)thisinstr;
+    tsetnote->dur = (float)thisdur;
+    if((exit_status = do_ev_hfpch(thistime,hsindex,thispitch,hsnotecnt,hs,pptop,ppbot,dz))<0)   /* 1 */
+        return(exit_status);
+    if(exit_status==CONTINUE) {
+        set_shadbit(*shadindex,shadbits);
+        tsetnote = tsetnote->next;              
+        (*shadindex)++;
+        return(CONTINUE);
+    }
+    tsetnote->pitch = (float)(*thispitch);
+    return(FINISHED);
+}
+
+/**************************** SETUP_ORNAMENTATION *********************************/
+
+int setup_ornamentation
+(int *starthsi,int *endhsi,noteptr *nextevent,noteptr tsetnote,
+noteptr *phrasenote,int *shadindex,int *endhsindex,int *hfphrase,int phrno,dataptr dz)
+{
+    *starthsi  =  *hfphrase;            
+    *endhsi    =  endhsindex[phrno];
+    *nextevent = getnextevent_to_decorate(tsetnote,shadindex,dz);
+    if(!dz->vflag[IS_PRE])
+        *phrasenote = (*phrasenote)->next;
+    return(FINISHED);
+}
+
+/**************************** GENERATE_MOTIF_NOTE_PITCH *********************************/
+
+int generate_motifin_note_pitch(int n,int hsindex,int starthsindex,int hsnotecnt,double thispitch,
+                                int *hfphrase,noteptr *thisnote,double *hs,int texflag)
+{
+    int notehsindex, thishsindex;
+    double newpitch;
+    notehsindex = *(hfphrase+n+1);
+    thishsindex = hsindex + notehsindex - starthsindex;
+    if(thishsindex<0 || thishsindex>=hsnotecnt) {
+        if((newpitch = hfadjust(thispitch,hs,notehsindex,starthsindex,texflag,hsnotecnt))<0.0) {
+            *thisnote = (*thisnote)->last;
+            free((*thisnote)->next);
+            return(CONTINUE);
+        } else
+            (*thisnote)->pitch = (float)newpitch;
+    } else
+        (*thisnote)->pitch=(float)hs[thishsindex];
+    return(FINISHED);
+}
+
+/**************************** GENERATE_MOTIF_NOTE_PITCH *********************************/
+
+int generate_motif_note_pitch(noteptr tsetnote,noteptr phrasenote,double phrfirstnote,noteptr thisnote)
+{
+    thisnote->pitch=(float)(tsetnote->pitch + phrasenote->pitch - phrfirstnote);
+    thisnote->pitch=(float)octadjust((double)thisnote->pitch);
+    return(FINISHED);
+}
+
+/**************************** GENERATE_ORNAMENT_NOTE_PITCH *********************************
+ *
+ * hsi = harmonic-set index.
+ */
+ 
+int generate_ornament_note_pitch
+(int n,double *hs,int hsi, int endhsi,int starthsi,noteptr *thisnote,
+noteptr *phrasenote,int *hfphrase,int hfnotecnt,int hsnotecnt,dataptr dz)
+{
+    unsigned int texflag = dz->tex->txflag;
+    int thishsi, refhsi, notehsi;       
+
+    if(dz->vflag[IS_PRE]) {
+        refhsi = endhsi;
+        notehsi = *(hfphrase+n);
+    } else {
+        refhsi = starthsi;
+        notehsi = *(hfphrase+n+1);
+    }
+    thishsi = hsi + notehsi - refhsi;
+    *phrasenote = (*phrasenote)->next;
+    if(thishsi<0 || thishsi>=hsnotecnt) {
+        if((texflag & IS_HS) || (thishsi=hfadj2(thishsi,hfnotecnt,hsnotecnt))<0) {
+            *thisnote = (*thisnote)->last;      
+            free((*thisnote)->next);
+            return(CONTINUE);
+        }
+    }
+    (*thisnote)->pitch=(float)hs[thishsi];  
+    return(FINISHED);
+}
+
+/********************** DO_EV_HFPCH *******************************
+ *
+ * Generate pitch of event (note group etc.) within HS.
+ *
+ * (2)  If getp_as_index() returns -1 , this means
+ *  that the pitch range specified is outside the HS, so a value of 
+ *  -1.0 is returned to calling environment and tset note is DELETED!!
+ */
+
+int do_ev_hfpch(double thistime,int *hsindex,double *val,int hsnotecnt,double *hs,double *pptop,double *ppbot,dataptr dz)
+{
+    int exit_status;
+    if((exit_status = getp_as_index(thistime,hsindex,hsnotecnt,hs,pptop,ppbot,dz))<0)
+        return(exit_status);
+    if(*hsindex==-1)                /* a */
+        return(CONTINUE);           /* 2 */
+    *val = hs[*hsindex];
+    return(FINISHED);
+}
+
+/****************************** GETP_AS_INDEX *********************************
+ *
+ * Get integer value of a hf-pitch index, using pitch either from table,
+ * or fixed value.
+ *
+ * (1)  Read values of pitch-range limits from tables (or fixed vals).
+ * (2)  If either of pitch values is negative, if it's from a table,
+ *  reject it....
+ * (3)  But otherwise it can be regarded as a flag. Return -1 causing
+ *  the INPUT pitch to be converted to a HS pitch and returned.
+ * (4)  Check that range is not inverted.
+ * (5)  Get the note in HS which is >  upper pitch boundary. If all HS notes
+ *  are above this (function returns 0) return -1.
+ *  If all HS notes are BELOW this pitch, function returns hsnotecnt,
+ *  wehich forces upper limit of HSindex generated by doperm() to be
+ *  hsnotecnt-1, the highest pitch in the HS.
+ * (6)  Get the note in HS which is >= lower pitch boundary. If there
+ *  is no such note (function returns hsnotecnt) return -1.
+ * (7)  Return a weighted scattered value of hf-index, within the
+ *  defined range.
+ */
+
+int getp_as_index(double thistime,int *val,int hsnotecnt,double *hs,double *pptop,double *ppbot,dataptr dz)
+{
+    int exit_status;
+    int  a, b;
+    double range;
+    if(dz->brk[TEXTURE_MAXPICH]) {                      /* 1 */
+        if((exit_status = read_value_from_brktable(thistime,TEXTURE_MAXPICH,dz))<0)
+            return(exit_status);
+    }
+    if(dz->brk[TEXTURE_MINPICH]) {
+        if((exit_status = read_value_from_brktable(thistime,TEXTURE_MINPICH,dz))<0)
+            return(exit_status);
+    }
+    *pptop = dz->param[TEXTURE_MAXPICH];
+    *ppbot = dz->param[TEXTURE_MINPICH];
+    if((range = dz->param[TEXTURE_MAXPICH] - dz->param[TEXTURE_MINPICH])<0.0)       /* 4 */
+        swap (&dz->param[TEXTURE_MAXPICH],&dz->param[TEXTURE_MINPICH]);
+    if((a = geths_above(dz->param[TEXTURE_MAXPICH],hs,hsnotecnt))==0) {             /* 5 */
+        *val = -1;
+        return(FINISHED);
+    }
+    if((b = geths_hibnd(dz->param[TEXTURE_MINPICH],hsnotecnt,hs))>=hsnotecnt) {     /* 6 */
+        *val = -1;
+        return(FINISHED);
+    }
+    if((exit_status = hfscat(a-b,b,PM_PITCH,&a,dz))<0)  /* 7 */
+        return(exit_status);
+    if( a < 0 || a >= hsnotecnt) {          /* 7 */
+        sprintf(errstr,"TEXTURE: getp_as_index(): TW's logic of index generation wrong\n");
+        return(DATA_ERROR);
+    }
+    *val = a;
+    return(FINISHED);
+}
+
+/**************************** INIT_SHADBITS ****************************
+ *
+ * Set up, and initialise to zero, a bitflag with one bit for each shadow
+ * (tset address).
+ */
+
+int init_shadbits(int shadowsize,int *shshsize,char **shadbits)
+{
+    int n = shadowsize;
+    *shshsize = 1;
+    while((n -= CHARBITSIZE)>0)
+        (*shshsize)++;
+    if((*shadbits = (char *)malloc((size_t)(*shshsize)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY for shadwoing array.\n");
+        return(MEMORY_ERROR);
+    }
+    for(n=0; n<(*shshsize); n++)
+        (*shadbits)[n] = 0;
+    return(FINISHED);
+}
+
+/****************************** GETHS ***********************************
+ *
+ * Extract HS from input data.
+ */
+
+int geths(noteptr thisnote,double **hs,int *hsnotecnt)
+{
+    int exit_status;
+    int size = BIGARRAY;
+    if((*hs = (double *)malloc(BIGARRAY * sizeof(double)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY for harmonic set array.\n");
+        return(MEMORY_ERROR);
+    }
+    while(thisnote!=(noteptr)0) {
+        if((exit_status = gethsnote(thisnote->pitch,*hs,hsnotecnt))<0)
+            return(exit_status);
+        if(*hsnotecnt >= BIGARRAY) {
+            size += BIGARRAY;
+            if((*hs=(double *)realloc((char *)(*hs),size * sizeof(double)))==NULL){
+                sprintf(errstr,"INSUFFICIENT MEMORY to reallocate harmonic set array.\n");
+                return(MEMORY_ERROR);
+            }   
+        }
+        thisnote = thisnote->next;
+    }
+    if((*hs=(double *)realloc((char *)(*hs),*hsnotecnt*sizeof(double)))==NULL){
+        sprintf(errstr,"INSUFFICIENT MEMORY to reallocate harmonic set array.\n");
+        return(MEMORY_ERROR);
+    }
+    upsort(*hs,*hsnotecnt);
+    return(FINISHED);
+}
+    
+/****************************** GETHF ***********************************
+ *
+ * Extract HF from input data.
+ */
+
+int gethf(noteptr thisnote,double **hf,int *hfnotecnt)
+{
+    int exit_status;
+    int size = BIGARRAY;
+    if((*hf = (double *)malloc(size * sizeof(double)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY for harmonic field array.\n");
+        return(MEMORY_ERROR);
+    }
+    while(thisnote!=(noteptr)0) {
+        if((exit_status = gethfnote(thisnote->pitch,*hf,hfnotecnt))<0)
+            return(exit_status);
+        if(*hfnotecnt >= size) {
+            size += BIGARRAY;
+            if((*hf = (double *)realloc((char *)(*hf),size * sizeof(double)))==NULL){
+                sprintf(errstr,"INSUFFICIENT MEMORY to reallocate harmonic field array.\n");
+                return(MEMORY_ERROR);
+            }   
+        }
+        thisnote = thisnote->next;
+    }
+    if((*hf=(double *)realloc((char *)(*hf),*hfnotecnt * sizeof(double)))==NULL){
+        sprintf(errstr,"INSUFFICIENT MEMORY to reallocate harmonic field array.\n");
+        return(MEMORY_ERROR);
+    }
+    upsort(*hf,*hfnotecnt);
+    return(FINISHED);
+}
+    
+/****************************** GEN_HS ***********************************
+ *
+ * Generate HS from a HF.
+ *
+ * NB This function assumes thas HF is ordered in ascending pitch order.
+ *
+ * (1)  Eliminate octave dupliates in hf.
+ * (2)  Initialise the HS count to zero.
+ * (3)  Start in the lowest octave.
+ * (4)  Go round loop generating HS, until we're out of (MIDI) range.
+ * (5)  Each time round loop, point to start of HF.
+ * (6)  And for all HF members, put them in HS + a (loop) number of 8ves,
+ *  counting the HS as we go.
+ * (7)  Once the pitch of any note exceeds MIDI upper limit (MIDITOP), break
+ *  from inner and (OK=0) outer loops.
+ * (8)  Each time round outer loop, increment octave.
+ * (9)  Reallocate the HS to the store 'hs'
+ */
+
+int gen_hs(double **hf,double **hs, int *hsnotecnt, int hfnotecnt)
+{
+    int n, m, k, thisoct, OK = 1;
+    int size = BIGARRAY;
+    double nextpitch;
+    double *thishf;
+    if((*hs)!=(double *)0)
+        free(*hs);
+    if((*hs = (double *)malloc(size * sizeof(double)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY for harmonic set array.\n");
+        return(MEMORY_ERROR);
+    }
+    for(n=0;n<hfnotecnt-1;n++) {        /* 1 */
+        for(m=n+1;m<hfnotecnt;m++) {
+            if(octeq((*hf)[n],(*hf)[m])) {
+                k = m + 1;
+                while(k < hfnotecnt) {
+                    (*hf)[k-1] = (*hf)[k];
+                    k++;
+                }
+                hfnotecnt--;
+                m--;
+            }
+        }
+    }
+    *hsnotecnt = 0;                         /* 2 */
+    thisoct = 0;                        /* 3 */
+    while(OK) {                         /* 4 */
+        thishf = *hf;                       /* 5 */
+        for(n=0;n<hfnotecnt;n++) {                  /* 6 */
+            if((nextpitch = (*thishf++)+((double)thisoct*SEMITONES_PER_OCTAVE))<=MIDITOP) {
+                (*hs)[(*hsnotecnt)++] = nextpitch;
+                if(*hsnotecnt>=size) {
+                    size += BIGARRAY;
+                    if((*hs =(double *)realloc((char *)(*hs),size * sizeof(double)))==NULL) {
+                        sprintf(errstr,"INSUFFICIENT MEMORY to reallocate harmonic set array.\n");
+                        return(MEMORY_ERROR);
+                    }   
+                }
+            } else {
+                OK = 0;                     /* 7 */
+                break;
+            }
+        }
+        thisoct++;                      /* 8 */
+    }
+    if((*hs=(double *)realloc((char *)(*hs),*hsnotecnt * sizeof(double)))==NULL){
+        sprintf(errstr,"INSUFFICIENT MEMORY to reallocate harmonic set array.\n");
+        return(MEMORY_ERROR);
+    }
+    return(FINISHED);
+}
+    
+/**************************** CHEKREPEAT *********************************
+ *
+ * Flag if there is a repeated note in the source data.
+ */
+
+int chekrepeat(noteptr thisnote,double lastpitch)
+{ 
+    if(flteq((double)thisnote->pitch,lastpitch))
+        return(TRUE);
+    return(FALSE);
+}
+
+/****************************** GETNEXTHF ***********************************
+ *
+ * Get the harmonic field pertaining to this time, + 'hfnotecnt'.
+ *
+ * NB 2: THIS FUNCTION ASSUMES IN WILL BE ACCESSED IN TIME-INCREASING ORDER.
+ *
+ * (1)  Current time preset to zero.
+ * (2)  Nexttime to time of next hf in hf_data_motif.
+ * (3)  Static pointer points into current place in hf_data_motif.
+ * (3a) If noteptr points to zero w'ere
+    EITHER  we're at end of notelist: therefore no more HF data,
+        hence retain existing data.
+    OR  we have not initialised the noteptr, which should happen
+        on first call to this function, BUT in this case the
+        hfnotecnt will be zero as we have not yet created an HF.
+        In this case, error, exit.
+ * (4)  If time of function access still less than time of entry of next
+ *  harmonic field, do nothing (i.e. stay with current hf returning
+ *  current hfnotecnt).
+ * (5)  If time of function access is after time of next harmonic field
+ *  advance down hfs, until TOFA is before next hf (NB last time in
+ *  the hft[] is AFTER end of texture duration).
+ * (6)  Establish temporary storage space to read a new hf, and set the
+ *  hf pointer 'thishf' to point to it.
+ * (7)  Walk through the input notes until we get to notes corresponding
+ *  to time of the hf we want.
+ * (8)  Store the harmonic field in the temporary array.
+ * (9)  Free any existing hf.
+ * (10) Reallocate the new hf to the array hf[], and set the hf pointer
+ *  'thishf' to point at it.
+ * (11) Generate the associated HS !!!
+ */
+
+int getnexthf
+(double **hf,double **hs, int *hsnotecnt,double inputtime,int *hf_cnt,int *hfnotecnt,
+ noteptr *thishfnote,double *thishftime,double *nexthftime,int hfdatacnt,double *hft)
+{
+    int exit_status;
+    int size = BIGARRAY;
+    if(*thishfnote==(noteptr)0) {                   /* 3a */
+        if(*hfnotecnt==0) {
+            sprintf(errstr,"INSUFFICIENT MEMORY for hfield notecount array.\n");
+            return(PROGRAM_ERROR);
+        }
+        return(TRUE);
+    }
+    if(inputtime<*nexthftime)                   /* 4 */
+        return(FALSE);
+    while(*nexthftime<=inputtime) {             /* 5 */
+        if(*hf_cnt>=hfdatacnt) {
+            sprintf(errstr,"INSUFFICIENT MEMORY for hfield count array.\n");
+            return(PROGRAM_ERROR);
+        }
+        *thishftime = *nexthftime;
+        *nexthftime = hft[*hf_cnt];
+        (*hf_cnt)++;
+    }
+    if(*hf!=(double *)0)                        /* 9 */
+        free(*hf);                      
+    if((*hf = (double *)malloc(size * sizeof(double)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY for hfield array.\n");
+        return(MEMORY_ERROR);
+    }
+    while(!flteq((double)(*thishfnote)->ntime,*thishftime)) {       /* 7 */
+        if((*thishfnote = (*thishfnote)->next)==(noteptr)0) {
+            sprintf(errstr,"TEXTURE: Search problem in getnexthf()\n");
+            return(PROGRAM_ERROR);
+        }
+    }
+    *hfnotecnt = 0;
+    while(flteq((double)(*thishfnote)->ntime,*thishftime)) {        /* 8 */
+        if((exit_status = gethfnote((*thishfnote)->pitch,*hf,hfnotecnt))<0)
+            return(exit_status);
+        if(*hfnotecnt >= size) {
+            size += BIGARRAY;
+            if((*hf = (double *)realloc((char *)(*hf),size * sizeof(double)))==NULL) {
+                sprintf(errstr,"TEXTURE: realloc failed in getnexthf()\n");
+                return(PROGRAM_ERROR);
+            }   
+        }
+        if((*thishfnote = (*thishfnote)->next)==(noteptr)0)
+            break;
+    }
+    if((*hf=(double *)realloc((char *)(*hf),*hfnotecnt * sizeof(double)))==NULL){
+        sprintf(errstr,"TEXTURE: getnexthf(): realloc() failed\n"); /* 10 */
+        return(PROGRAM_ERROR);
+    }
+    upsort(*hf,*hfnotecnt);
+    if((exit_status = gen_hs(hf,hs,hsnotecnt,*hfnotecnt))<0)  /* 11 */
+        return(exit_status);
+    return(TRUE);
+}
+
+/****************************** GETNEXTHS ***********************************
+ *
+ * Get the harmonic set pertaining to this time.
+ *
+ * NB 2: THIS FUNCTION ASSUMES IT WILL BE ACCESSED IN TIME-INCREASING ORDER.
+ *
+ * (3)  Static pointer points into current place in hf_data_motif.
+ * (3a) If noteptr points to zero w'ere
+    EITHER  we're at end of notelist: therefore no more HF data,
+        hence retain existing data.
+    OR  we have not initialised the noteptr, which should happen
+        on first call to this function, BUT in this case the
+        hsnotecnt will be zero as we have not yet created an HS.
+        In this case, error, exit.
+ * (4)  If time of function access still less than time of entry of next
+ *  harmonic set, do nothing (i.e. stay with current hs returning 
+ *  current harmonic set cnt hsnotecnt).
+ * (5)  If time of function access is after time of next harmonic set
+ *  advance down HSs, until TOFA is before next hs (NB last time in
+ *  the hft[] is AFTER end of texture duration).
+ * (6)  Establish temporary storage space to read a new hs, and set the
+ *  hs pointer 'thishs' to point to it.
+ * (7)  Walk through the input notes until we get to notes corresponding
+ *  to time of the hs we want.
+ * (8)  Store the harmonic set in the temporary array.
+ * (9)  Free any existing hs.
+ * (10) Reallocate the new hs to the array hs[], and set the hs pointer
+ *  'thishs' to point at it.
+ */
+
+int getnexths
+(double **hs,double inputtime,int *hs_cnt,int *hsnotecnt,noteptr *thishsnote,
+double *thishstime,double *nexthstime,int hfdatacnt,double *hft)
+{
+    int exit_status;
+    int size = BIGARRAY;
+    if(*thishsnote==(noteptr)0) {               /* 3a */
+        if(*hsnotecnt==0) {
+            sprintf(errstr,"getnexths() not initialised\n");
+            return(PROGRAM_ERROR);
+        }
+        return(TRUE);
+    }
+    if(inputtime<*nexthstime)                   /* 4 */
+        return(FALSE);
+    while(*nexthstime<=inputtime) {             /* 5 */
+        if(*hs_cnt>=hfdatacnt) {
+            sprintf(errstr,"Timing problem in getnexths()\n");
+            return(PROGRAM_ERROR);
+        }
+        *thishstime = *nexthstime;
+        *nexthstime = hft[*hs_cnt];
+        (*hs_cnt)++;
+    }
+    if(*hs!=(double *)0)                        /* 9 */
+        free(*hs);                      
+    if((*hs = (double *)malloc(size * sizeof(double)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY for harmonic set array.\n");
+        return(MEMORY_ERROR);
+    }
+
+    while(!flteq((double)(*thishsnote)->ntime,*thishstime)) {           /* 7 */
+        if((*thishsnote = (*thishsnote)->next)==(noteptr)0) {
+            sprintf(errstr,"TEXTURE: Search problem in getnexths()\n");
+            return(PROGRAM_ERROR);
+        }
+    }
+    *hsnotecnt = 0;
+    while(flteq((double)(*thishsnote)->ntime,*thishstime)) {            /* 8 */
+        if((exit_status = gethsnote((*thishsnote)->pitch,*hs,hsnotecnt))<0)
+            return(exit_status);
+        if(*hsnotecnt >= size) {
+            size += BIGARRAY;
+            if((*hs =(double *)realloc((char *)(*hs),size * sizeof(double)))==NULL) {
+                sprintf(errstr,"TEXTURE: realloc failed in getnexths()\n");
+                return(PROGRAM_ERROR);
+            }   
+        }
+        if((*thishsnote = (*thishsnote)->next)==(noteptr)0)
+            break;
+    }
+    if((*hs=(double *)realloc((char *)(*hs),*hsnotecnt * sizeof(double)))==NULL){
+        sprintf(errstr,"TEXTURE: getnexths(): realloc() failed\n");/* 10 */
+        return(PROGRAM_ERROR);
+    }
+    upsort(*hs,*hsnotecnt);
+    return(TRUE);
+}
+
+/***************************** GETHSNOTE ************************************
+ *
+ * Read a note and store in harmonic SET,  IF not already there.
+ */
+
+int gethsnote(double thispitch,double *thishs,int *hsnotecnt)
+{
+    int n, OK = 0;
+    for(n=0;n<*hsnotecnt;n++) {
+        if(flteq(thispitch,thishs[n])) {
+            OK = 1;
+            break;
+        }
+    }
+    if(!OK)
+        thishs[*hsnotecnt] = (double)thispitch;
+    (*hsnotecnt)++;
+    return(FINISHED);
+}
+
+/***************************** READHFTIMES ************************************
+ *
+ * Read times at which successive harmonic fields(sets) enter, and store as list.
+ */
+
+int readhftimes(noteptr firstnote, int *hfdatacnt,double **hft)
+{
+    double lasttime, firsttime;
+    int arraysize = BIGARRAY;
+    noteptr thisnote = firstnote;
+    *hfdatacnt = 0;
+    if((*hft = (double *)malloc(arraysize * sizeof(double)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY for harmonic field times array.\n");
+        return(MEMORY_ERROR);
+    }
+    lasttime = thisnote->ntime;
+    (*hft)[0] = lasttime;
+    while(thisnote!=(noteptr)0) {
+        if(!flteq((double)thisnote->ntime,lasttime)) {
+            if(++(*hfdatacnt)>=arraysize-1) {
+                arraysize += BIGARRAY;
+                if((*hft = (double *)realloc((char *)(*hft),arraysize * sizeof(double)))==NULL) {
+                    sprintf(errstr,"INSUFFICIENT MEMORY to reallocate harmonic field times array.\n");
+                    return(PROGRAM_ERROR);
+                }   
+            }
+            (*hft)[*hfdatacnt] = thisnote->ntime;
+            lasttime = thisnote->ntime;
+        }
+        thisnote = thisnote->next;
+    }
+    (*hft)[++(*hfdatacnt)] = DBL_MAX;                   /* 1 */
+    (*hfdatacnt)++;
+    if((*hft = (double *)realloc((char *)(*hft),(*hfdatacnt) * sizeof(double)))==NULL){
+        sprintf(errstr,"INSUFFICIENT MEMORY to reallocate harmonic field times array.\n");
+        return(PROGRAM_ERROR);
+    }
+    if(!flteq(**hft,0.0)) {
+        fprintf(stdout,"WARNING: Harmonic Field Data: No field at ZERO time.\n"
+                       "ADJUSTING FIRST FIELD TO ZERO TIME\n");
+        fflush(stdout);
+        thisnote  = firstnote;
+        firsttime = thisnote->ntime;
+        while(flteq(firsttime,**hft)) {
+            thisnote->ntime = 0.0f;
+            if((thisnote = thisnote->next)==(noteptr)0)
+                break;
+        }
+        **hft = 0.0;
+    }
+    return(FINISHED);
+}
+
+/***************************** DEL_GHOSTS ******************************
+ *
+ * Delete all tset notes MARKED for deletion in shadbits bitflag.
+ *
+ * (1)  For each byte in the bitflag...
+ * (2)  Set the bitmask to the first bit.
+ *   (3)  For every bit in this byte....
+ *   (4)  If this bit is set, delete the associated shadow (tset) note.
+ *   (5)  Advance the bitflag internal to the byte leftwards.
+ *   (6)  Advance the count of shadows, and if it reaches the total number
+ *    of shadows, exit, because remaining bits in this byte (if any)
+ *    have no meaning.
+ */
+
+void del_ghosts(int shshsize,char *shadbits,noteptr *shadow,int shadowsize,motifptr tset)
+{
+    int n,m,mask,k = 0;
+    for(n=0;n<shshsize;n++) {               /* 1 */
+        mask = 1;                           /* 2 */
+        for(m=0;m<CHARBITSIZE;m++) {        /* 3 */
+            if(shadbits[n] & mask)          /* 4 */
+                del_note(shadow[k],tset);
+            mask <<= 1;                     /* 5 */
+            if(++k >= shadowsize)           /* 6 */
+                return;
+        }
+    }
+}
+
+/************************** GET_HFGPPARAMS **************************
+ *
+ * Get the parameters for a group of notes.
+ *
+ * (0)  If pitch to decorate lies outside the HF range, return with gpsize
+ *  set to zero.
+ * (1)  If group range is expressed in HS-note units..
+ *   (a) Read the gprange as an integer number of (HS) notes.
+ *   (b) If HS-range exceeds HS limits, squeeze it.
+ *   (c) If HS-range is to be oriented about note, orient it appropriately.
+ * (2)  Otherwise...
+ *   (a) Read group range in normal way.
+ *   (b) If range exceeds HS limits, squeeze it.
+ *   (c) If range is to be oriented about note, orient it appropriately.
+ *   (d) If the range lies outside range of the HS,
+ *   set the groupsize to ZERO and return.
+ *   (e) Otherwise set the HS-range.
+ * (3)  Read group size.
+ * (4)  Read group density.
+ * (5)  number of midicliks in a gpdense time-interval.
+ * (6)  number of quantisation units, rounded.
+ * (7)  readjust gpdense to be number of units * length of units,
+ *  and reconvert to seconds.
+ */
+                                        
+int get_hfgpparams(double thistime,double thispitch,double *hs,int hsnotecnt,
+int *gpsize,int *hfrange,int *hfgpranglo,int *hfgpranghi,double *gprange,double *gpdense,int mingrpsize,
+double *gprlow, int dectypecnt,unsigned char dectypestor,dataptr dz)
+{
+    int exit_status;
+    if(thispitch<hs[0] || thispitch>hs[hsnotecnt-1]) {
+        *gpsize = 0;                        /* 0 */
+        return(FINISHED);
+    }
+    if((exit_status = igetvalue(TEX_GPRANGHI,TEX_GPRANGLO,thistime,PM_GPRANG,hfrange,dz))<0)
+        return(exit_status);
+
+    if(!dectypecnt) {   
+        hfsqueezrange(thispitch,hfrange,hfgpranghi,hfgpranglo,hsnotecnt,hs);                    /* b */
+        dz->vflag[DECCENTRE] = FALSE;
+    } else {
+        if((exit_status = hforientrange
+        (thispitch,hfrange,hfgpranghi,hfgpranglo,hsnotecnt,hs,dectypecnt,dectypestor,dz))<0) /* c */
+            return(exit_status);
+    }
+/* OCT 17 : hfgpranghi,lo are max & min INDECES within the harmonic field */
+
+    *hfrange = *hfgpranghi - *hfgpranglo;           /* e */
+
+/* OCT 17 : FROM hfgpranghi,lo the actual PITCH values can be deduced */
+    *gprlow  = hs[*hfgpranglo];
+    *gprange = hs[*hfgpranghi] - hs[*hfgpranglo];
+
+    if((exit_status  = igetvalue(TEX_GPSIZEHI,TEX_GPSIZELO,thistime,PM_GPSIZE,gpsize,dz))<0)
+        return(exit_status);
+
+    if(*gpsize  < mingrpsize) {
+        sprintf(errstr,"TEXTURE: Impossible GROUP SIZE value [%d]: get_hfgpparams()\n",*gpsize);
+        return(PROGRAM_ERROR);
+    }
+
+    if((exit_status = getvalue(TEX_GPPACKHI,TEX_GPPACKLO,thistime,PM_GPDENS,gpdense,dz))<0)
+        return(exit_status);
+/* NEW MAR 2000 */
+    *gpdense *= MS_TO_SECS;
+
+    if(dz->param[TEX_PHGRID]>0.0)
+        *gpdense = quantise(*gpdense,dz->param[TEX_PHGRID]);
+    return(FINISHED);
+}
+
+/***************************  HFSQUEEZRANGE ******************************
+ *
+ * Adjust range to lie within HF limits.
+ *
+ * (2)  Top of range is at current pitch's HF index (approx). If this is
+ *  above current top-of-HF range (hsnotecnt) move top down.
+ * (3)  Bottom of range is igprange below top. If this is below
+ *  bottom-of-HF (0), move igprlow up.
+ * (4)  Recalculate the true igprange within true limits.
+ */
+
+void hfsqueezrange(double thispitch,int *hfrange,int *hfgpranghi,int *hfgpranglo,int hsnotecnt,double *hs) 
+{
+    int halfrange = *hfrange/2;
+    if(halfrange * 2 != *hfrange)
+        halfrange++;
+    *hfgpranghi = min((geths_hibnd(thispitch,hsnotecnt,hs)+halfrange),hsnotecnt);   /* 2 */
+    *hfgpranglo = max((*hfgpranghi - *hfrange),0);                          /* 3 */
+    *hfrange = *hfgpranghi - *hfgpranglo;                                   /* 4 */
+}
+
+/****************************** GETHS_HIBND **********************************
+ *
+ *  hibnd >= pitch
+ *
+ * Find the index of the harmonic-set note that is immediately above or
+ * equal to the input pitch.
+ *
+ * NB CALL WITH geths_hibnd((double)thisnote->pitch);
+ *
+ * If the pitch is beyond the HS, n returns the value 'hsnotecnt'.
+ */
+
+int geths_hibnd(double thispitch,int hsnotecnt,double *hs)
+{
+    int n;
+    for(n=0;n<hsnotecnt;n++) {
+        if(hs[n]>thispitch || flteq(hs[n],thispitch))
+            break;
+    }
+    return(n);              /* 1 */
+}
+
+/***************************  HFORIENTRANGE ******************************
+ *
+ * As orientrange() but applied to HF/HS case.
+ */
+
+int hforientrange
+(double thispitch,int *hfrange,
+int *hfgpranghi,int *hfgpranglo,int hsnotecnt,double *hs,int dectypecnt,unsigned char dectypestor,dataptr dz)
+{
+    int exit_status;
+    unsigned char dectype;
+    int k;
+    if((exit_status=doperm((int)dectypecnt,PM_ORIENT,&k,dz))<0)
+        return(exit_status);
+    if((exit_status=gettritype(k,dectypestor,&dectype))<0)
+        return(exit_status);
+    switch(dectype) {
+    case(0):            /* centred range */
+        hfsqueezrange(thispitch,hfrange,hfgpranghi,hfgpranglo,hsnotecnt,hs);
+        dz->vflag[DECCENTRE] = TRUE;
+        break;
+    case(1):            /* range above note */
+        *hfgpranghi = min((geths_hibnd(thispitch,hsnotecnt,hs) + *hfrange),hsnotecnt);
+        *hfgpranglo = max((*hfgpranghi - *hfrange),0);
+        *hfrange    = *hfgpranghi - *hfgpranglo;
+        dz->vflag[DECCENTRE] = FALSE;
+        break;              
+    case(2):            /* range below note */
+        *hfgpranghi = geths_hibnd(thispitch,hsnotecnt,hs);
+        *hfgpranglo = max((*hfgpranghi - *hfrange),0);
+        *hfrange    = *hfgpranghi - *hfgpranglo;
+        dz->vflag[DECCENTRE] = FALSE;
+        break;              
+    default:
+        sprintf(errstr,"TEXTURE: Problem in hforientrange()\n");
+        return(PROGRAM_ERROR);
+    }
+    return(FINISHED);
+}
+
+/****************************** GETHS_ABOVE **********************************
+ *
+ *  above > pitch
+ *
+ * Find the index of the harmonic-set note that is immediately above
+ * the input pitch.
+ *
+ * NB CALL WITH geths_above((double)thisnote->pitch);
+ *
+ * If the pitch is beyond the HS, n gets the value 'hsnotecnt', which becomes
+ * the upper limit of the search range for doperm() ensuring that highest
+ * possible HSindex val is hsnotecnt-1, the highest pitch in the HS.
+ */
+
+int geths_above(double thispitch,double *hs,int hsnotecnt)
+{
+    int n;
+    for(n=0;n<hsnotecnt;n++) {
+        if(hs[n]>thispitch)
+            break;
+    }
+    return(n);                  /* 1 */
+}
+
+/****************************** GENERATE_GROUP_NOTE **********************************/
+
+int generate_group_note
+(noteptr thisnote,noteptr tsetnote,double thistime,int hfrange,int hfgpranglo,
+double *hs,int *hsindex,int gpsize,dataptr dz)
+{
+    int exit_status;
+    unsigned char thisinstr;
+    if((exit_status = do_grp_ins(tsetnote->instr,&thisinstr,dz))<0)
+        return(exit_status);
+    thisnote->instr = thisinstr;
+    thisnote->motioncentre = tsetnote->motioncentre;
+    if((exit_status = hfscat(hfrange,hfgpranglo,PM_GPPICH,hsindex,dz))<0)
+        return(exit_status);
+    thisnote->pitch  = (float)hs[*hsindex];     /* 7 */
+    thisnote->ntime  = (float)thistime; 
+    return setspace(tsetnote,thisnote,gpsize,dz);
+}
+
+/******************************* HFSCAT ***********************************
+ *
+ * A weighted version of hfscatx().
+ */
+
+int hfscat(int prange,int pbottom,int permindex,int *val,dataptr dz)
+{
+    int exit_status;
+    double bandbottom,  bandtop,  bandwidth;
+    int   ibandbottom, ibandtop, ibandwidth, k;
+    if(prange<=LAYERCNT) {
+        if((exit_status = doperm((int)prange,permindex,&k,dz))<0)
+            return(exit_status);
+        *val = k + pbottom;
+        return(FINISHED);
+
+    }
+    if((exit_status = doperm((int)BANDCNT,permindex,&k,dz))<0)
+        return(exit_status);
+    bandwidth = (double)prange/(double)LAYERCNT;
+    switch(k) {
+    case(0):
+        bandbottom = 0;
+        break;
+    case(BANDCNT-1):
+        bandbottom = (double)(LAYERCNT-1) * bandwidth;
+        break;
+    default:
+        bandbottom = bandwidth + ((double)((k-1) * 2) * bandwidth);
+        bandwidth *= 2.0;
+        break;
+    }
+    bandtop     = bandbottom + bandwidth;
+    ibandtop    = round(bandtop);
+    ibandbottom = round(bandbottom);
+    ibandwidth  = ibandtop - ibandbottom;
+    k  = (int)(drand48() * (double)ibandwidth);
+    k += ibandbottom;
+    k += pbottom;
+    *val = k;
+    return(FINISHED);
+}
+
+/****************************** GENERATE_DECOR_NOTE **********************************/
+
+int generate_decor_note(noteptr thisnote,noteptr tsetnote,
+double thispitch,double thistime,int hfrange,int hfgpranghi,int hfgpranglo,double *hs,int *hsindex,
+int hsnotecnt,double gprlow,double gprange,int gpsize,dataptr dz)
+{
+    int exit_status;
+    double val;
+    if((exit_status = do_grp_ins(tsetnote->instr,&thisnote->instr,dz))<0)
+        return(exit_status);
+    thisnote->motioncentre = tsetnote->motioncentre;
+    if(dz->vflag[DECCENTRE]) {
+        if((exit_status = dec_hfcentre
+        (thispitch,hs,hsnotecnt,hfrange,hfgpranghi,hfgpranglo,gprlow,gprange,gpsize,&val,dz))<0)
+            return(exit_status);
+        thisnote->pitch = (float)val;
+    } else {
+        if((exit_status = hfscat(hfrange,hfgpranglo,PM_GPPICH,hsindex,dz))<0)
+            return(exit_status);
+        thisnote->pitch  = (float)hs[*hsindex];
+    }
+    thisnote->ntime  = (float)(thistime); 
+    return setspace(tsetnote,thisnote,gpsize,dz);
+}
+
+/************************* DEC_HFCENTRE *******************************/
+ 
+int dec_hfcentre(double tsetpitch,double *hs,int hsnotecnt,int hfrange,int hfgpranghi,int hfgpranglo,
+double gprlow,double gprange,int gpsize,double *val,dataptr dz)
+{
+    int exit_status;
+    double a, gprhi = gprlow + gprange;
+    int s, save, k, hfcentre, n_above, n_below, hsindex;
+    if(tsetpitch-gprlow<=FLTERR || flteq(tsetpitch,gprhi)) {
+        if((exit_status = hfscatx(hfrange,hfgpranglo,PM_GPPICH,&hsindex,dz))<0)
+            return(exit_status);
+        *val = hs[hsindex];
+        return(FINISHED);                   /* 1 */
+    }
+    n_below = hfrange/2;                    /* 2 */
+    if(((n_above=n_below)+n_below)!=hfrange)
+        n_above++;
+    if(((hfcentre =geths_hibnd(tsetpitch,hsnotecnt,hs)) + n_above) > hsnotecnt)
+        n_above = hsnotecnt - hfcentre;             /* 3 */
+    if(hfcentre - n_below < 0)
+        n_below = hfcentre;                 /* 4 */
+    if(n_above<=0 || n_below<=0) { 
+        if((exit_status = hfscatx(hfrange,hfgpranglo,PM_GPPICH,&hsindex,dz))<0)
+            return(exit_status);
+        else {
+            *val = hs[hsindex];
+            return(FINISHED);                   /* 5 */
+        }
+    }
+    save = dz->iparray[TXREPETCNT][PM_DECABV];                      /* 6 */
+    k = (gpsize+1)/2;
+    if(dz->iparray[TXREPETCNT][PM_DECABV]>k)
+        dz->iparray[TXREPETCNT][PM_DECABV] = k;         
+    if((exit_status = doperm((int)2,PM_DECABV,&s,dz))<0)
+        return(exit_status);
+    if(s) {
+        if((exit_status = hfscatx(n_above,hfgpranghi - n_above,PM_GPPICH,&hsindex,dz))<0)
+            return(exit_status);
+    } else {
+        if((exit_status = hfscatx(n_below,hfgpranglo,PM_GPPICH2,&hsindex,dz))<0)
+            return(exit_status);
+    }
+    dz->iparray[TXREPETCNT][PM_DECABV] = save;
+    a = hs[hsindex];
+    if(a<MIDIBOT || a>MIDITOP) {
+        sprintf(errstr,"TEXTURE: Problem in dec_hfcentre()\n");
+        return(PROGRAM_ERROR);
+    }
+    *val = a;
+    return(FINISHED);                           
+}
+
+/******************************* HFSCATX ***********************************
+ *
+ * As pscat, but working with ranges of integers, especially the indeces
+ * of an HS.
+ */
+
+int hfscatx(int prange,int pbottom,int permindex,int *val,dataptr dz)
+{
+    int exit_status;
+    double bandbottom,  bandtop,  bandwidth;
+    int   ibandbottom, ibandtop, ibandwidth, k;
+    if(prange<=BANDCNT) {
+        if((exit_status = doperm((int)prange,permindex,val,dz))<0)
+            return(exit_status);
+        *val += pbottom;
+        return(FINISHED);
+    }
+    if((exit_status = doperm((int)BANDCNT,permindex,val,dz))<0)
+        return(exit_status);
+    k = *val;
+    bandwidth   = (double)prange/(double)BANDCNT;
+    bandbottom  = (double)k     * bandwidth;
+    bandtop     = (double)(k+1) * bandwidth;
+    ibandbottom = round(bandbottom);
+    ibandtop    = round(bandtop);
+    ibandwidth  = ibandtop - ibandbottom;
+    k  = (int)(drand48() * (double)ibandwidth);
+    k += ibandbottom;
+    *val = k + pbottom;
+    return(FINISHED);
+}
+
+/******************************** SET_SHADBIT ****************************
+ * 
+ * Set a bit in the shadow's bitfag.
+ */
+
+void set_shadbit(int k,char *shadbits)
+{
+    int bitunit  = k/CHARBITSIZE;
+    int bitshift = k % 8;
+    int mask = 1;
+    mask <<= bitshift;
+    shadbits[bitunit] |= mask;
+}
+
+/****************************** GETHS_LOBND **********************************
+ *
+ *  lobnd =< pitch
+ *
+ * Find the index of the harmonic-set note that is immediately below, or
+ * equal to the input pitch.
+ *
+ * NB CALL WITH geths_lobnd((double)thisnote->pitch);
+ *
+ * NB: If the entered pitch is lower than the entire HS, function returns -1.
+ */
+
+int geths_lobnd(double thispitch,double *hs,int hsnotecnt)
+{
+    int n;
+    for(n=0;n<hsnotecnt;n++) {
+        if(hs[n]>thispitch)
+            break;
+    }
+    return(--n);                    /* 1 */
+}
+
+/***************************** GETHFNOTE ************************************
+ *
+ * Read a note and store in harmonic field IF not already there.
+ */
+
+int gethfnote(double thispitch,double *hf,int *hfnotecnt)
+{
+    int n, OK  = 0;
+    float notetransp = (float)fmod(thispitch,SEMITONES_PER_OCTAVE);
+    if(flteq((double)notetransp,0.0))
+        notetransp = (float)(notetransp + SEMITONES_PER_OCTAVE);
+    for(n=0;n<*hfnotecnt;n++) {
+        if(flteq((double)notetransp,hf[n])) {
+            OK = 1;
+            break;
+        }
+    }
+    if(!OK)
+        hf[*hfnotecnt] = (double)notetransp;
+    (*hfnotecnt)++;
+    return(FINISHED);
+}
+
+/**************************** SETMTFPARAMS *******************************
+ * 
+ * Establish easy parameters of motif or ornament.
+ */
+
+int setmtfparams
+(noteptr thisnote,double thisamp,noteptr phrasenote,noteptr tsetnote,double ampdif,double notetime,
+int gpsize,double multiplier,dataptr dz)
+{
+    int exit_status;
+    if((exit_status = do_mtf_params(thisnote,thisamp,phrasenote,tsetnote,ampdif,notetime,multiplier,dz))<0)
+        return(exit_status);
+    return setspace(tsetnote,thisnote,gpsize,dz);
+}
+
+/**************************** INITIALISE_HFPHRASES *******************************/
+
+int initialise_hfphrases
+(int ***hfphrase,int **endhsindex,int **phrnotecnt,double **phraseamp,double **phrange,
+noteptr **phrlastnote,dataptr dz)
+{
+    if((*hfphrase = (int **)malloc(dz->tex->phrasecnt * sizeof(int *)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY for harmonic field phrases.\n");
+        return(MEMORY_ERROR);
+    }
+    if((*endhsindex = (int *)malloc(dz->tex->phrasecnt * sizeof(int)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY for harmonic set indices.\n");
+        return(MEMORY_ERROR);
+    }
+    if((*phrnotecnt = (int *)malloc(dz->tex->phrasecnt * sizeof(int)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY for harmonic field phrase notecnt.\n");
+        return(MEMORY_ERROR);
+    }
+    if((*phraseamp = (double *)malloc(dz->tex->phrasecnt * sizeof(double)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY for phrase amplitude array.\n");
+        return(MEMORY_ERROR);
+    }
+    if((*phrange  = (double *)malloc(dz->tex->phrasecnt * sizeof(double)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY for phrase range array.\n");
+        return(MEMORY_ERROR);
+    }
+    if((*phrlastnote = (noteptr *)malloc(dz->tex->phrasecnt * sizeof(noteptr)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY for phrase lastnote array.\n");
+        return(MEMORY_ERROR);
+    }
+    return(FINISHED);
+}
+
+/****************************** GET_FIRST_HS ***********************************
+ *
+ * Extract HS from input data.
+ */
+
+int get_first_hs(noteptr thisnote,double **hs,int *hsnotecnt)
+{
+    int exit_status;
+    int size = BIGARRAY;
+    noteptr startnote = thisnote;
+    double thistime = 0.0;
+    if((*hs = (double *)malloc(BIGARRAY * sizeof(double)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY for harmonic set array.\n");
+        return(MEMORY_ERROR);
+    }
+    while(thisnote!=(noteptr)0) {
+        if((exit_status = gethsnote(thisnote->pitch,*hs,hsnotecnt))<0)
+            return(exit_status);
+        if(thisnote==startnote)
+            thistime = thisnote->ntime;
+        else {
+            if(!flteq((double)thisnote->ntime,thistime)) {
+                (*hsnotecnt)--;
+                break;
+            }
+        }
+        if(*hsnotecnt >= BIGARRAY) {
+            size += BIGARRAY;
+            if((*hs=(double *)realloc((char *)(*hs),size * sizeof(double)))==NULL){
+                sprintf(errstr,"INSUFFICIENT MEMORY to reallocate harmonic set array.\n");
+                return(MEMORY_ERROR);
+            }   
+        }
+        thisnote = thisnote->next;
+    }
+    if((*hs=(double *)realloc((char *)(*hs),*hsnotecnt*sizeof(double)))==NULL){
+        sprintf(errstr,"INSUFFICIENT MEMORY to reallocate harmonic set array.\n");
+        return(MEMORY_ERROR);
+    }
+    upsort(*hs,*hsnotecnt);
+    return(FINISHED);
+}
+    
+/****************************** GET_FIRST_HF ***********************************
+ *
+ * Extract first HF from input data.
+ */
+
+int get_first_hf(noteptr thisnote,double **hf,int *hfnotecnt)
+{
+    int exit_status;
+    int size = BIGARRAY;
+    noteptr startnote = thisnote;
+    double thistime = 0.0;
+
+    if((*hf = (double *)malloc(size * sizeof(double)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY for harmonic field array.\n");
+        return(MEMORY_ERROR);
+    }
+    while(thisnote!=(noteptr)0) {
+        if((exit_status = gethfnote(thisnote->pitch,*hf,hfnotecnt))<0)
+            return(exit_status);
+        if(thisnote==startnote)
+            thistime = thisnote->ntime;
+        else {
+            if(!flteq((double)thisnote->ntime,thistime)) {
+                (*hfnotecnt)--;
+                break;
+            }
+        }
+        if(*hfnotecnt >= size) {
+            size += BIGARRAY;
+            if((*hf = (double *)realloc((char *)(*hf),size * sizeof(double)))==NULL){
+                sprintf(errstr,"INSUFFICIENT MEMORY to reallocate harmonic field array.\n");
+                return(MEMORY_ERROR);
+            }   
+        }
+        thisnote = thisnote->next;
+    }
+    if((*hf=(double *)realloc((char *)(*hf),*hfnotecnt * sizeof(double)))==NULL){
+        sprintf(errstr,"INSUFFICIENT MEMORY to reallocate harmonic field array.\n");
+        return(MEMORY_ERROR);
+    }
+    upsort(*hf,*hfnotecnt);
+    return(FINISHED);
+}
+
+/******************************** OCTEQ *************************************/
+
+int octeq(double a,double b)
+{
+    a = fmod(a,12.0);
+    b = fmod(b,12.0);
+    if(flteq(a,b)) {
+        return(1);
+    }
+    return(0);
+}

+ 1474 - 0
dev/texture/v8/texture4.c

@@ -0,0 +1,1474 @@
+/*
+ * Copyright (c) 1983-2013 Trevor Wishart and Composers Desktop Project Ltd
+ * http://www.trevorwishart.co.uk
+ * http://www.composersdesktop.com
+ *
+ This file is part of the CDP System.
+ 
+ The CDP System is free software; you can redistribute it
+ and/or modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+ 
+ The CDP System is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU Lesser General Public License for more details.
+ 
+ You should have received a copy of the GNU Lesser General Public
+ License along with the CDP System; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA
+ *
+ */
+/* floatsam version : no changes */
+#include <stdio.h>
+#include <stdlib.h>
+#include <float.h>
+#include <structures.h>
+#include <tkglobals.h>
+#include <globcon.h>
+#include <processno.h>
+#include <modeno.h>
+#include <arrays.h>
+#include <texture.h>
+#include <cdpmain.h>
+
+#include <sfsys.h>
+#include <osbind.h>
+
+#if defined unix || defined __GNUC__
+#define round(x) lround((x))
+#endif
+
+/**** ALL FUNCTIONS WHICH ARE GLOBAL TO ALL PROCESS FUNCTIONS TYPES ***/
+
+/* Functions which are global to all texture applications.
+ */
+static void orn_subzero(double *thistime,noteptr phrlastnote,noteptr *phrasenote,
+            double *timeadjust,double multiplier,int *gpsize);
+static int  getmtfampstep
+            (double amp,double framp,double *ampstep,unsigned char *amptype,
+            unsigned char amptypestor,unsigned char amptypecnt,int gpsize,dataptr dz);
+static int  space_gpnote(noteptr thisnote,int gpsize,dataptr dz);
+static int  sp_scatter(noteptr mnote,dataptr dz);
+static int  pre_place(noteptr thisnote,int gpsize,dataptr dz);
+static int  post_place(noteptr thisnote,int gpsize,dataptr dz);
+static int  read_direction(int shi,noteptr *shadow,int shadowsize);
+
+static int  do_ev_ins(unsigned char *thisinstr,double thistime,dataptr dz);
+static int  do_ev_amp(double *thisamp,double thistime,dataptr dz);
+static int  do_ev_dur(double *thisdur,double thistime,dataptr dz);
+static int  getdirampstep
+            (double amp,unsigned char amptypecnt,double *ampstep,int gpsize,dataptr dz);
+static int  getampstep
+            (double *ampstep,double amp,unsigned char *amptype,int gpsize,unsigned char amptypecnt,
+            unsigned char amptypestor,dataptr dz);
+static int  get_dec_or_orn_pos(dataptr dz);
+ 
+static int  subzero(double *thistime,double gpdense,int *gpsize);
+
+static noteptr reverse_search_for_time(noteptr start,double reftime);
+static void    move_notelist_item(noteptr a,noteptr b);
+static double  setup_first_notelist_time(noteptr *base);
+static int     reset_mtfhead(motifptr mtf);
+static int     post_place(noteptr thisnote,int gpsize,dataptr dz);
+static int     getmtfdirampstep
+            (double amp,double framp,unsigned char amptypecnt,double *ampstep,int gpsize,dataptr dz);
+static void cyclicperm(dataptr dz);
+static void hinsert(int m,int t,int *perm,int permlen);
+static void hprefix(int m,int *perm,int permlen);
+static void hshuflup(int k,int *perm,int permlen);
+
+/***************************** OCTADJUST *****************************
+ *
+ * Check for range overflow of pitch.
+ */
+
+double octadjust(double thispitch)
+{
+    if(thispitch>MIDITOP)
+        thispitch -= SEMITONES_PER_OCTAVE;
+    if(thispitch<MIDIBOT)
+        thispitch += SEMITONES_PER_OCTAVE;
+    return(thispitch);
+}
+
+/***************************** DO_AMP_INSTR_DUR ************************************/
+
+int do_amp_instr_dur
+(double *thisamp,unsigned char *thisinstr,double *thisdur,noteptr tsetnote,double thistime,dataptr dz)
+{
+    int exit_status;
+    if((exit_status = do_ev_amp(thisamp,thistime,dz))<0)
+        return(exit_status);
+    tsetnote->amp = (float)(*thisamp);
+    if((exit_status = do_ev_ins(thisinstr,thistime,dz))<0)
+        return(exit_status);
+    tsetnote->instr = *thisinstr;
+    if((exit_status = do_ev_dur(thisdur,thistime,dz))<0)
+        return(exit_status);
+    tsetnote->dur = (float)(*thisdur);
+    return(FINISHED);
+}
+
+/********************** DO_EV_INS *******************************
+ *
+ * Set instrument of event (not group etc.).
+ *
+ * (0)  If instruments in ornament or decoration are to be relative to
+ *  input instr, return this input instrument.
+ * (1)  If there is a pre-existing timed set (pretimed = 1).
+ * (2)  Negative value causes original value to be replaced
+ *  by orig + abs(neg value).
+ *  Zero value, by default, causes orig value to be retained.
+ */
+
+int do_ev_ins(unsigned char *thisinstr,double thistime,dataptr dz)
+{
+    int exit_status;
+    int instrval;
+    if(dz->process == SIMPLE_TEX && dz->vflag[CYCLIC_TEXFLAG]) {
+        if(dz->itemcnt == dz->infilecnt)
+            dz->itemcnt = 0;
+        if(dz->vflag[PERM_TEXFLAG]) {
+            if(dz->itemcnt == 0)
+                cyclicperm(dz);
+            *thisinstr = (unsigned char)dz->peakno[dz->itemcnt];
+        } else {
+            *thisinstr = (unsigned char)dz->itemcnt;
+        }
+        dz->itemcnt++;
+    } else {
+        if((exit_status = igetvalue(TEXTURE_INSHI,TEXTURE_INSLO,thistime,PM_INSNO,&instrval,dz))<0)
+            return(exit_status);
+        *thisinstr = (unsigned char)instrval;
+    }
+    return(FINISHED);
+}
+
+/********************** DO_EV_AMP ********************************/
+
+int do_ev_amp(double *thisamp,double thistime,dataptr dz)
+{  
+    int exit_status;
+    if((exit_status = getvalue(TEXTURE_MAXAMP,TEXTURE_MINAMP,thistime,PM_AMP,thisamp,dz))<0)
+        return(exit_status);
+
+    *thisamp *= dz->param[TEXTURE_ATTEN];
+
+    if(*thisamp>MIDITOP + 0.5) {
+        sprintf(errstr,"TEXTURE: amplitude [%.1f] out of midirange at time %.2f\n",*thisamp,thistime); 
+        return(DATA_ERROR);
+    }
+    return(FINISHED);
+}
+
+/********************** DO_EV_DUR ********************************/
+
+int do_ev_dur(double *thisdur,double thistime,dataptr dz)
+{
+    int exit_status;
+    if((exit_status = getvalue(TEXTURE_MAXDUR,TEXTURE_MINDUR,thistime,PM_DUR,thisdur,dz))<0)
+        return(exit_status);
+    return(FINISHED);                   /* 4 */
+}
+
+/************************ MAKE_SHADOW ****************************
+ *
+ * Store addresses of original tset notes.
+ */
+
+int make_shadow(motifptr tset,int *shadowsize,noteptr **shadow)
+{
+    noteptr *sh, thisnote = tset->firstnote;
+    int n;
+    *shadowsize = 0;
+    while(thisnote!=(noteptr)0) {
+        (*shadowsize)++;
+        thisnote = thisnote->next;
+    }
+    if((sh = *shadow = (noteptr *)malloc((*shadowsize) * sizeof(noteptr)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY for shadow.\n");
+        return(MEMORY_ERROR);
+    }
+    thisnote = tset->firstnote;
+    n = 0;
+    while(thisnote!=(noteptr)0) {
+        sh[n++]  = thisnote;
+        thisnote = thisnote->next;
+    }
+    return(FINISHED);
+}
+
+/************************ ERASE_SHADOW ****************************
+ *
+ * Erase original tset from resultant list.
+ *
+ * (0)  Assuming shadow starts at start of tset, if first note of
+ *  shadow is deleted, del_note automatically resets motifptr (tset)
+ *  to next note (and so on).
+ * (1)  In case shadow started AFTER start of tset (should be impossible!!)
+ *  reset pointer to start of remaining motif !
+ */
+
+int erase_shadow(int shadowsize,noteptr *shadow,motifptr tset)
+{
+    int n;
+    noteptr thisnote;
+    for(n=0;n<shadowsize;n++)                   /* 0 */
+        del_note(shadow[n],tset);
+    if((thisnote = tset->firstnote->last)!=(noteptr)0) {    /* 1 */
+        sprintf(errstr,"TEXTURE: erase_shadow(): First note of shadow NOT first note of tset.\n"
+                       "This should never happen\n");
+        return(PROGRAM_ERROR);
+    /**** REMOVED FOLLOWING AUTO-CORRECTION CODE : OCT 1997 *****
+        while(thisnote->last!=(noteptr)0)
+            thisnote = thisnote->last;
+        tset->firstnote = thisnote;
+    ****/
+    }
+    return(FINISHED);
+}
+
+/************************ SETUP_DECOR ****************************/
+
+void setup_decor(double *pptop,double *ppbot,int *shadindex,noteptr *tsetnote,dataptr dz)
+{
+    *pptop = MIDITOP; 
+    *ppbot = MIDIBOT;
+    if(dz->vflag[WHICH_CHORDNOTE]==DECOR_HIGHEST)
+        *tsetnote = gethipitch(*tsetnote,shadindex);
+}
+
+/**************************** SETUP_ORNAMENT *********************************/
+
+int setup_ornament
+(double *timeadjust,double *thistime,int *gpsize,noteptr *phrlastnote,
+ double multiplier,noteptr *phrasenote,int phrno,dataptr dz)
+{
+    int exit_status;
+    double origtime;
+    if((exit_status = get_dec_or_orn_pos(dz))<0)
+        return(exit_status);
+    *timeadjust = 0.0;
+    if(dz->vflag[IS_PRE]) {
+        origtime = *thistime;
+        if((*thistime -= (phrlastnote[phrno])->ntime * multiplier)<0.0) {
+            *thistime = origtime;
+            orn_subzero(thistime,phrlastnote[phrno],phrasenote,timeadjust,multiplier,gpsize);
+        }
+    }
+    return(FINISHED);
+}
+
+/**************************** SET_MOTIF_AMP *********************************/
+
+int set_motif_amp
+(noteptr tsetnote,double *thisamp,int gpsize,double ampstep,noteptr phrasenote,double rangemult,
+double *phraseamp,int phrno,unsigned char amptype)
+{
+    double ampdif;
+    if(amptype==CRESC) {
+        *thisamp -= (double)(gpsize) * ampstep;
+        ampdif    = (phraseamp[phrno] - phrasenote->amp) * rangemult;
+        tsetnote->amp = (float)(*thisamp - ampdif);
+    }
+    return(FINISHED);
+}
+
+/**************************** SET_ORNAMENT_AMP *********************************/
+
+int set_ornament_amp
+(double *phraseamp,noteptr *phrlastnote,double *thisamp,
+noteptr phrasenote,int phrno,noteptr tsetnote,
+double ampstep,double rangemult,int gpsize,dataptr dz)
+{
+    double ampdif;
+    if(dz->vflag[IS_PRE])
+        ampdif=(phraseamp[phrno]-phrlastnote[phrno]->amp) * rangemult;
+    else
+        ampdif=(phraseamp[phrno]-phrasenote->amp) * rangemult;
+    tsetnote->amp -= (float)ampdif;
+    if(ampstep>0.0) /* CRESCENDO */
+        *thisamp -= (double)(gpsize+1) * ampstep;
+    return(FINISHED);
+}
+
+/**************************** CHECK_NEXT_PHRASENOTE_EXISTS *********************************/
+
+int check_next_phrasenote_exists(noteptr *phrasenote,int texflag,dataptr dz)
+{
+    if(texflag & IS_MOTIFS) {
+        if((*phrasenote = (*phrasenote)->next)==(noteptr)0) {
+            sprintf(errstr,"TEXTURE: Accounting Problem in check_next_phrasenote_exists()\n");
+            return(PROGRAM_ERROR);
+        }
+    } else if (texflag & IS_ORNATE){
+        if(*phrasenote==(noteptr)0) {
+            sprintf(errstr,"TEXTURE: 1st Accounting Problem in check_next_phrasenote_exists()\n");
+            return(PROGRAM_ERROR);
+        }
+        if(dz->vflag[IS_PRE] && ((*phrasenote)->next==(noteptr)0)) {
+            sprintf(errstr,"TEXTURE: 2nd Accounting Problem in check_next_phrasenote_exists()\n");
+            return(PROGRAM_ERROR);
+        }
+    }
+    return(CONTINUE);
+}
+
+/************************* GETNEXTEVENT_TO_DECORATE ***************************
+ *
+ * Get the next event in list, i.e. skip over simultaneous events
+ * (e.g. chords).
+ *
+ * (0)  If flagged as 2, ornaments/decorations are attached to EVERY note
+ *  so the next event is just the next note in the tset.
+ *  OTHERWISE we search for the next event AT A NEW TIME.
+ * (1)  If flagged, force a search for the highest note of a simultaneous
+ *  group (chord). Hence ornament/dec attaches to highest note.
+ *  Otherwise, ornament attached to first listed note of chord in input
+ *  data.
+ */
+
+noteptr getnextevent_to_decorate(noteptr tsetnote,int *shaddoindex,dataptr dz)
+{
+    if(dz->vflag[WHICH_CHORDNOTE]==DECOR_EVERY)                     /* 0 */
+        return(tsetnote->next);
+    while(tsetnote->next!=(noteptr)0) {
+        tsetnote = tsetnote->next;
+        (*shaddoindex)++;
+        if(!flteq((double)tsetnote->ntime,(double)tsetnote->last->ntime)) {
+            if(dz->vflag[WHICH_CHORDNOTE]==DECOR_HIGHEST)
+                tsetnote = gethipitch(tsetnote,shaddoindex);    /* 1 */
+            return(tsetnote);
+        }
+    }
+    return((noteptr)0);
+}
+    
+/************************** GETNOTETIME ********************************
+ *
+ * Get actual time of note, from time of tset note, and time of motif
+ * or ornament note.
+ * (a)  Time is set by an offset from the tset-note, THROUGHOUT each
+ *  motif-placement. The offset for each note is its position in the
+ *  original note (which have been set relative to zero by set_mtfs())
+ *  times the multiplier, with an adjustment if we're actually using
+ *  less than the whole motif for some reason.
+ * (b)  Time may need to be quantised.
+ * (c)  Time of note is this tset-note + offset.
+ */
+
+double getnotetime(noteptr phrasenote,double thistime,double multiplier,double timeadjust,dataptr dz)
+{   
+    int qunits;
+    double timestep = ((double)phrasenote->ntime - timeadjust) * (double)multiplier; /* a */
+    double thisgrid;
+
+    if(dz->param[TEX_PHGRID]>0.0) {  
+/* NEW  2000 */
+        thisgrid = dz->param[TEX_PHGRID] * MS_TO_SECS;
+
+        qunits    = round(timestep/thisgrid);       /* b */
+        timestep  = (double)(qunits*thisgrid);  
+    }
+    return(thistime + timestep);                /* c */
+}
+
+/************************ GETMTFDUR **********************************/
+
+int getmtfdur(noteptr tsetnote,noteptr phrasenote,double *dur,double multiplier,dataptr dz)
+{
+    if(dz->vflag[DONT_KEEP_MTFDUR])
+        *dur = tsetnote->dur;
+    else
+        *dur = phrasenote->dur * multiplier;
+    if(flteq(*dur,0.0)) {
+        sprintf(errstr,"TEXTURE: Problem 3 in getmtfdur(): Zero duration\n");
+        return(PROGRAM_ERROR);
+    }
+    return(FINISHED);
+}
+
+/***************************** ORN_OR_MTF_AMP_SETUP ************************************/
+
+int orn_or_mtf_amp_setup
+(int ampdirected,double *phrange,int phrno,double thisamp,int gpsize,double *rangemult,double *ampstep,
+unsigned char *amptype,unsigned char amptypestor,unsigned char amptypecnt,dataptr dz)
+{
+    int exit_status;
+    double kk;
+    if(phrange[phrno]>=thisamp) {
+        kk = (double)phrange[phrno]*((double)(gpsize+1)/(double)gpsize);
+        *rangemult = (double)thisamp / kk;
+        *ampstep   = 0.0;
+    } else {
+        if(ampdirected) {
+            if((exit_status = getmtfdirampstep(thisamp,phrange[phrno],amptypecnt,ampstep,gpsize,dz))<0)
+                return(exit_status);
+        } else {
+            if((exit_status = getmtfampstep(thisamp,phrange[phrno],ampstep,amptype,amptypestor,amptypecnt,gpsize,dz))<0)
+                return(exit_status);
+        }
+        *rangemult = 1.0;
+    }
+    return(FINISHED);
+}
+
+/**************************** DO_MTF_PARAMS *******************************/
+
+int do_mtf_params
+(noteptr thisnote,double thisamp,noteptr phrasenote,noteptr tsetnote,
+double ampdif,double notetime,double multiplier,dataptr dz)
+{
+    int exit_status;
+    double duration;
+    thisnote->amp   = (float)(thisamp - ampdif);
+    if((exit_status = getmtfdur(tsetnote,phrasenote,&duration,multiplier,dz))<0)
+        return(exit_status);
+    thisnote->dur = (float)duration;
+    if((exit_status = do_grp_ins(tsetnote->instr,&(thisnote->instr),dz))<0)
+        return(exit_status);
+    thisnote->motioncentre = tsetnote->motioncentre;
+    thisnote->ntime  = (float)notetime;
+    return(FINISHED);
+}
+
+/***************************** SETUP_MOTIF_OR_ORNAMENT ************************************/
+
+int setup_motif_or_ornament
+(double thistime,double *multiplier,int *phrno,noteptr *phrasenote,motifptr *phrase,dataptr dz)
+{
+    int exit_status;
+    if((exit_status = getvalue(TEX_MULTHI,TEX_MULTLO,thistime,PM_MULT,multiplier,dz))<0)
+        return(exit_status);
+    if((exit_status = doperm((int)dz->tex->phrasecnt,PM_WHICH,phrno,dz))<0)
+        return(exit_status);
+    *phrasenote    = phrase[*phrno]->firstnote;
+    return(FINISHED);
+}
+
+/****************************** POSITION_AND_SIZE_DECORATION **********************************/
+
+int position_and_size_decoration
+(double *thistime,double tsettime,double gpdense,int *gpsize,dataptr dz)
+{
+    int exit_status;
+    if((exit_status = get_dec_or_orn_pos(dz))<0)
+        return(exit_status);
+    if(dz->vflag[IS_PRE]) {
+        if((*thistime -= gpdense * (double)((*gpsize) + 1))< -gpdense) {
+            *thistime = tsettime;
+            if((exit_status = subzero(thistime,gpdense,gpsize))<0)
+                return(exit_status);
+        }
+    }
+    return(FINISHED);
+}
+
+/****************************** SET_DECOR_AMP **********************************/
+
+int set_decor_amp
+(int ampdirected,double *thisamp,double *ampstep,int gpsize,
+unsigned char *amptype,unsigned char amptypecnt,unsigned char amptypestor,dataptr dz)
+{
+    int exit_status;
+    if(ampdirected) {
+        if((exit_status = getdirampstep(*thisamp,amptypecnt,ampstep,gpsize,dz))<0)
+            return(exit_status);
+    } else  {
+        if((exit_status = getampstep(ampstep,*thisamp,amptype,gpsize,amptypecnt,amptypestor,dz))<0)
+            return(exit_status);
+    }
+    if(*ampstep>0.0)
+        *thisamp -= (double)(gpsize+1) * (*ampstep);
+    return(FINISHED);
+}
+
+/****************************** SET_GROUP_AMP **********************************/
+
+int set_group_amp
+(noteptr tsetnote,double *thisamp,unsigned char *amptype, double *ampstep,int gpsize,
+unsigned char amptypecnt,unsigned char amptypestor,dataptr dz)
+{
+    int exit_status;
+    if((exit_status = getampstep(ampstep,*thisamp,amptype,gpsize,amptypecnt,amptypestor,dz))<0)
+        return(exit_status);
+    if(*amptype==CRESC) {
+        *thisamp -= (double)(gpsize) * (*ampstep);
+        tsetnote->amp = (float)(*thisamp);
+    }
+    return(FINISHED);
+}
+
+/* LOCAL TO THESE GLOBALS */
+
+/****************************** ORN_SUBZERO *******************************
+ *
+ * Readjust the groupsize and the pointer to first note of phrase, where
+ * otherwise phrase would start before zero.
+ *
+ * (1)  Note the endtime of the phrase.
+ * (2)  For each note in the phrase.
+ * (3)  Find the duration of the phrase FROM THIS NOTE, by subtracting time of
+ *  current note from end (total) time, and adjusting by multiplier.
+ * (4)  If the duration of phrase from here, would put it's start after
+ *  zero-time, break from loop.
+ * (5)  Count number of notes rejected, and go to next phrase note.
+ * (6)  If we're at end of phrase, none of it's notes fall after zero time,
+ *  so return a gpsize of 0.
+ * (7)  Otherwise reset the event time (mifitime) to start of the group or 
+ *  part-group which 'thisnote' points to.
+ * (8)  Resert the phrase pointer to point at this note of the phrase.
+ * (9)  When note times are finally calculated, timeadjust will reset all
+ *  the note times WITHIN the ornament to run from the note from
+ *  which we're starting, rather than the true start, by subtracting
+ *  'timeadjust'.
+ * (10) Return a size for the group reduced by the number of rejected notes.
+ */
+
+void orn_subzero
+(double *thistime,noteptr phrlastnote,noteptr *phrasenote,double *timeadjust,double multiplier,int *gpsize)
+{
+    double endtime = phrlastnote->ntime;        /* 1 */
+    double phrdur = 0.0;
+    int cnt = 0;
+    noteptr thisnote = *phrasenote;
+    while(thisnote!=(noteptr)0) {               /* 2 */
+        phrdur = (endtime - thisnote->ntime) * multiplier;  /* 3 */
+        if(*thistime - phrdur >= 0.0)           /* 4 */
+            break;
+        cnt++;                                  /* 5 */
+        thisnote = thisnote->next;
+    }
+    if(thisnote==(noteptr)0) {
+        *gpsize = 0;                            /* 6 */
+        return;
+    } else {
+        *thistime -= phrdur;                    /* 7 */
+        *phrasenote = thisnote;                 /* 8 */
+        *timeadjust = thisnote->ntime;          /* 9 */
+    }
+    *gpsize -= cnt;
+    return;                                     /* 10 */
+}
+
+/*************************** GETMTFAMPSTEP ******************************
+ *
+ * Select flat, cresc or decresc, from available types, for motifs.
+ *
+ * (0)  If the amplitude is bigger than the size of amprise and the
+ *  range of the phrase, taken together, amprise is OK as it is.
+ * (00) Otherwise, amprise (set as ampstep at this point) is the amount
+ *  of the total amplitude left when the amplitude range of the phrase
+ *  has been subtracted. This ensures that no note of the phrase
+ *  can possibly end up below zero.
+ * (1)  IF the cresc will be from zero, clrzamp is 1, and this makes
+ *  the amplitude steps a little smaller, so that 1 of the notes
+ *  in sequence cannot be at amplitude zero.
+ *  OTHERWISE, clrzamp = 0,  and ampstep is as normal.
+ */
+
+int getmtfampstep(double amp,double framp,double *ampstep,unsigned char *amptype,
+unsigned char amptypestor,unsigned char amptypecnt,int gpsize,dataptr dz)
+{
+    int exit_status;
+    int clrzamp = 0;
+    int k;
+    if((exit_status = doperm((int)amptypecnt,PM_GPCNTR,&k,dz))<0)
+        return(exit_status);
+    if((exit_status=gettritype(k,amptypestor,amptype))<0)
+        return(exit_status);
+    if(*amptype==FLAT) {        /**** FLAT *****/
+        *ampstep =0.0;  
+    } else {
+        if(amp>(dz->param[TEX_AMPRISE] + framp)) /* 0 */
+            *ampstep = dz->param[TEX_AMPRISE];
+        else {
+            *ampstep = amp - framp;         /* 00 */
+            clrzamp = 1;
+        }
+        *ampstep /= (double)(gpsize+clrzamp);       /* 1 */
+        if(*amptype==DECRESC)       /** DECRESCENDO **/
+            *ampstep = -(*ampstep);
+    }
+    return(FINISHED);
+}
+
+/************************************************************************
+ *
+ * Calculating spatial orientation of motifs,groups,ornaments,decorations.
+ */
+
+/**************************** SETSPACE *******************************/
+
+int setspace(noteptr tsetnote,noteptr thisnote,int gpsize,dataptr dz)
+{
+    int exit_status;
+    if(dz->iparam[TEX_GPSPACE]!=IS_STILL) {
+        if((exit_status = space_gpnote(thisnote,gpsize,dz))<0)
+            return(exit_status);
+    } else
+        thisnote->spacepos = tsetnote->spacepos;
+    return(FINISHED);
+}
+
+/***************************** SPACE_GPNOTE *******************************
+ *
+ * (1)  OUTSIDE THE GROUP- OR PHRASE-MAKING LOOP
+ *  (a) Need to know gpsize, dectype(is_post?), gpsprange 
+ *      (which MUST be +ve!).
+ *  (b) Need to run 'init_group_spatialisation()' to establish spinit, & hence
+ *      range modifications etc.
+ *
+ *  Then this will work INSIDE the loop.
+ *
+ * (1)  NB !!!!! is_pre is defaulted to ZERO. This means that groups
+ *  or motifs which CANNOT BE pre- or post- are defaulted to
+ *  post (which means the groups start on the tset notes, rather
+ *  leading up to them).
+ */
+
+int space_gpnote(noteptr thisnote,int gpsize,dataptr dz)
+{
+    int exit_status;
+    if(dz->iparam[TEX_GPSPACE]==IS_SCATTER) {
+        if((exit_status = sp_scatter(thisnote,dz))<0)
+            return(exit_status);
+    } else {
+        if(dz->vflag[IS_PRE]) {             /* 1 */
+            if((exit_status = pre_place(thisnote,gpsize,dz))<0)
+                return(exit_status);
+        } else {
+            if((exit_status = post_place(thisnote,gpsize,dz))<0)
+                return(exit_status);
+        }
+    }
+    dz->iparam[SPINIT] = 0;     /* disable initialisation after first call to group */
+    return(FINISHED);
+}
+
+/**************************** SP_SCATTER *************************
+ *
+ * scatter group note around position of main event.
+ */
+
+int sp_scatter(noteptr mnote,dataptr dz)
+{
+    int exit_status;
+    double sptop = 1.0, spbot= 0.0, hfthissprange,val;
+    if(dz->param[THISSPRANGE]<=0.0) {     
+        mnote->spacepos = (float)dz->param[TPOSITION];
+        return(FINISHED);
+    }
+    if(dz->iparam[SPINIT]) {
+        hfthissprange = dz->param[THISSPRANGE]/(double)2.0;
+        spbot = max((dz->param[TPOSITION] - hfthissprange),0.0);
+        sptop = min((dz->param[TPOSITION] + hfthissprange),1.0);
+        dz->param[THISSPRANGE] = sptop - spbot;
+    }                                   
+    if((exit_status = pscatx(dz->param[THISSPRANGE],spbot,PM_GPSPAC,&val,dz))<0)
+        return(exit_status);
+    mnote->spacepos      = (float)val;
+    return(FINISHED);
+} 
+
+/************** MACROS FOR RANGE REORIENTATIONS AND TRUNCATIONS **************
+ *
+ *  r = group spatial range     p = position of event
+ *  c = centre of motion        d = direction of motion
+ *
+ * (1)  If position to left  of centre, reverse range.
+ * (2)  If position to right of centre, reverse range.
+ * (3)  If no motion, zero the range.
+ * (4)  If motion is right to left reverse range.
+ * (5)  If motion is left to right reverse range.
+ * (6)  avoid centre crossing
+ * (7)  avoid right-edge crossing
+ * (8)  avoid left-edge crossing
+ * (9)  avoid edge crossing
+ */
+
+#define TURNOUTWARD(r,p,c) if((p)-(c)<0.0)  (r) = -(r);                     /* 1 */
+#define TURNINWARD(r,p,c)  if((p)-(c)>0.0)  (r) = -(r);                     /* 2 */
+#define CHECKSTIL(r,d)     if((d)==0) (r) = 0.0;                            /* 3 */
+#define FOLLOW(r,d)        CHECKSTIL(r,d) else { if((d)<0) (r) = -(r); }    /* 4 */
+#define CONTRARY(r,d)      CHECKSTIL(r,d) else { if((d)>0) (r) = -(r); }    /* 5 */
+#define SET_PRE_INRANGE(r,p,c) if(p<c) r = min(p,r); else r = max(p-1.0,r);
+
+
+#define FREECENTRE(r,p,c)  if((r)>fabs((p)-(c))) (r)=fabs((p)-(c));         /* 6 */
+#define FREEREDGE(r,p)     if((p)+(r)>1.0) (r) = 1.0 - (p);                 /* 7 */
+#define FREELEDGE(r,p)     if((p)+(r)<0.0) (r) = -(p);                      /* 8 */
+#define FREEEDGES(r,p)     if((r)>=0.0) { FREEREDGE((r),(p)) } else { FREELEDGE((r),(p)) }
+                                                                            /* 9 */
+
+#define FREEREDGE_PRE(r,p) if((p)-(r)>1.0) (r) = (p) - 1.0;                 /* 7 */
+#define FREELEDGE_PRE(r,p) if((p)-(r)<0.0) (r) = (p);                       /* 8 */
+#define FREEEDGES_PRE(r,p) if((r)>=0.0) { FREELEDGE_PRE((r),(p)) } else { FREEREDGE_PRE((r),(p)) }
+                                                                            /* 9 */
+/************************* PRE_PLACE *****************************
+ *
+ * place-in-space ornaments or decorations BEFORE notes, or motifs or groups
+ * at texture points.
+ *
+ * is_pre = 1.
+ */
+
+int pre_place(noteptr thisnote,int gpsize,dataptr dz)
+{
+    if(dz->iparam[SPINIT])
+        dz->iparam[SPCNT] = 0;
+
+    switch(dz->iparam[TEX_GPSPACE]) {
+        case(IS_STILL):
+            dz->param[THISSPRANGE] = 0.0;
+            break;
+        case(IS_INWARD):
+            if(dz->iparam[SPINIT]) {
+                TURNINWARD(dz->param[THISSPRANGE],dz->param[TPOSITION],dz->param[CPOS])
+                SET_PRE_INRANGE(dz->param[THISSPRANGE],dz->param[TPOSITION],dz->param[CPOS])
+
+            }
+            break;
+        case(IS_OUTWARD):
+            if(dz->iparam[SPINIT]) {
+                FREECENTRE(dz->param[THISSPRANGE],dz->param[TPOSITION],dz->param[CPOS])
+                TURNOUTWARD(dz->param[THISSPRANGE],dz->param[TPOSITION],dz->param[CPOS])
+            }
+            break;
+        case(IS_FOLLOWING):
+            if(dz->iparam[SPINIT]) {
+                FOLLOW(dz->param[THISSPRANGE],dz->iparam[DIRECTION])
+                FREEEDGES_PRE(dz->param[THISSPRANGE],dz->param[TPOSITION])
+            }
+            break;
+        case(IS_CONTRARY):
+            if(dz->iparam[SPINIT]) {
+                CONTRARY(dz->param[THISSPRANGE],dz->iparam[DIRECTION])
+                FREEEDGES_PRE(dz->param[THISSPRANGE],dz->param[TPOSITION])
+            }
+            break;
+        default:
+        sprintf(errstr,"TEXTURE: Invalid space-type %d in pre_place()\n",dz->iparam[TEX_GPSPACE]);
+        return(PROGRAM_ERROR);
+    }
+    thisnote->spacepos = (float)(dz->param[TPOSITION] - dz->param[THISSPRANGE]
+                     + ((dz->param[THISSPRANGE]/(double)gpsize)*(double)(dz->iparam[SPCNT])));
+    dz->iparam[SPCNT]++;
+    return(FINISHED);
+}
+           
+/************************* POST_PLACE *****************************
+ *
+ * place-in-space ornaments or decorations AFTER notes, or motifs or groups
+ * at texture points.
+ *
+ * is_pre = 0, (or no ornament). 
+ */
+
+int post_place(noteptr thisnote,int gpsize,dataptr dz)
+{
+    if(dz->iparam[SPINIT])
+        dz->iparam[SPCNT] = 1;
+    switch(dz->iparam[TEX_GPSPACE]) {
+    case(IS_STILL):
+        dz->param[THISSPRANGE] = 0.0;
+        break;
+    case(IS_INWARD):
+        if(dz->iparam[SPINIT]) {
+            FREECENTRE(dz->param[THISSPRANGE],dz->param[TPOSITION],dz->param[CPOS])
+            TURNINWARD(dz->param[THISSPRANGE],dz->param[TPOSITION],dz->param[CPOS])
+        }
+        break;
+    case(IS_OUTWARD):
+        if(dz->iparam[SPINIT]) {
+            TURNOUTWARD(dz->param[THISSPRANGE],dz->param[TPOSITION],dz->param[CPOS])
+            FREEEDGES(dz->param[THISSPRANGE],dz->param[TPOSITION])
+        }
+        break;
+    case(IS_FOLLOWING):
+        if(dz->iparam[SPINIT]) {
+            FOLLOW(dz->param[THISSPRANGE],dz->iparam[DIRECTION])
+            FREEEDGES(dz->param[THISSPRANGE],dz->param[TPOSITION])
+        }
+        break;
+    case(IS_CONTRARY):
+        if(dz->iparam[SPINIT]) {
+            CONTRARY(dz->param[THISSPRANGE],dz->iparam[DIRECTION])
+            FREEEDGES(dz->param[THISSPRANGE],dz->param[TPOSITION])
+        }
+        break;
+    default:
+        sprintf(errstr,"TEXTURE: Invalid space-type %d in post_place()\n",dz->iparam[TEX_GPSPACE]);
+        return(PROGRAM_ERROR);
+    }
+    thisnote->spacepos = (float)(dz->param[TPOSITION] + 
+    ((dz->param[THISSPRANGE]/(double)gpsize)*(double)(dz->iparam[SPCNT])));
+    dz->iparam[SPCNT]++;
+
+    return(FINISHED);
+}
+
+/************************** GPSP_INIT ***********************************
+ *
+ * Initialise the space-param for each group, before calling the spatialise
+ * routines. 'spinit' causes initialisation of range etc elsewhere (in
+ * pre_place() or post_place() ).
+ */
+
+int init_group_spatialisation(noteptr tsetnote,int shaddoindex,noteptr *shadow,int shadowsize,dataptr dz)
+{
+    int exit_status;
+    dz->iparam[SPINIT] = 1;
+    dz->param[TPOSITION] = tsetnote->spacepos;
+    dz->param[CPOS]      = tsetnote->motioncentre;
+    if(dz->brksize[TEX_GRPSPRANGE]) { /* TABLE VALUES MUST BE 0 - 1 */
+        if((exit_status = read_value_from_brktable((double)tsetnote->ntime,TEX_GRPSPRANGE,dz))<0)
+            return(exit_status);
+    }
+    if(IS_DIRECTED(dz->iparam[TEX_GPSPACE]))
+        dz->iparam[DIRECTION] = read_direction(shaddoindex,shadow,shadowsize);
+    dz->param[THISSPRANGE] = dz->param[TEX_GRPSPRANGE];
+    return(FINISHED);
+}
+
+/**************************** READ_DIRECTION ****************************
+ *
+ * Read direction of motion from spatial position stored in note.
+ *
+ * NB: as the tset is in the process of being modified, we cannot
+ * refer directly to the tset linked list. We can only access the original
+ * tset through it's 'shadow'.
+ *
+ * (0)  Save the time of the current note as 'now'.
+ * (1)  Save position of current note as 'here'.
+ * (2)  Whilever we're not at the end of the tset (shadow).
+ * (a)  Note time of next note, store as 'then'.
+ * (b)  If 'then' is later than 'now'.
+ *      Note position of new note as 'there'.
+ *      Set as OK and break out of loop.
+ * (3)  If it's not OK (i.e. we were at, or came to the end of the tset 
+ *      (shadow))....
+ * (a)  Go back to where we started.
+ * (b)  Call this position 'there'.
+ * (4)  While ever we're not at beginning of tset...
+ * (a)  Note time of previous note, store as 'then'.
+ * (b)  If 'then' is 'earlier' than 'now'...
+ *      Note position of new note as 'here'.
+ *      Set as OK and break out of loop.
+ * (5)  If still not OK, then there is no more than 1 (non-simultaneous)
+ *      event in the tset, so therefore no motion, so return 0.
+ * (6)  If there>here, left-to-right motion, return 1.
+ * (7)  If here>there, right-to-left motion, return -1.
+ * (8)  Otherwise, no motion, return 0.
+ */
+
+int read_direction(int shi,noteptr *shadow,int shadowsize)
+{
+    unsigned char OK;
+    float here, there = 0.0;
+    double now, then;
+    int startshi = shi;
+    now  = (shadow[shi])->ntime;            /* 0 */
+    here = (shadow[shi])->motioncentre;     /* 1 */
+    OK = 0;
+    while(++shi<shadowsize) {           /* 2 */
+        then = (shadow[shi])->ntime;        /* a */
+        if(then>(now+FLTERR)) {         /* b */
+            there = (shadow[shi])->motioncentre;
+            OK = 1;
+            break;
+        }
+    }
+    if(!OK) {                   /* 3 */
+        shi = startshi;             /* a */
+        there = here;               /* b */
+        while(--shi>=0) {           /* 4 */
+            then = (shadow[shi])->ntime;        /* a */
+            if(then<(now-FLTERR)) {     /* b */
+                here = (shadow[shi])->motioncentre;
+                OK = 1;
+                break;
+            }
+        }
+    }       
+    if(!OK)
+        return(0);              /* 5 */
+    if(there>here)              /* 6 */
+        return(1);
+    if(there<here)              /* 7 */
+        return(-1);
+    return(0);                  /* 8 */
+}
+
+/*************************** GETAMPSTEP ******************************
+ *
+ * Select flat, cresc or decresc, from available types.
+ *
+ * (1)  IF the cresc will be from zero, clrzamp is 1, and this makes
+ *  the amplitude steps a little smaller, so that 1st note in sequence
+ *  will not be at amplitude zero.
+ *  OTHERWISE, clrzamp = 0,  and ampstep is as normal.
+ */
+
+int getampstep
+(double *ampstep,double amp,unsigned char *amptype,int gpsize,unsigned char amptypecnt,
+unsigned char amptypestor,dataptr dz)
+{
+    int exit_status;
+    int clrzamp = 0, k;
+    /*int texflag = dz->tex->txflag;*/
+    if((exit_status = doperm((int)amptypecnt,PM_GPCNTR,&k,dz))<0)
+        return(exit_status);
+    if((exit_status = gettritype(k,amptypestor,amptype))<0)
+        return(exit_status);
+
+    if(*amptype==FLAT)      /**** FLAT *****/
+        *ampstep =0.0;  
+    else {                                                              
+        *ampstep = dz->param[TEX_AMPRISE]; /* param with <|> option */
+                                                                    
+        if(*ampstep>=amp) {                                         
+            clrzamp  = 1;                                           
+            *ampstep = amp;                                         
+        }
+        *ampstep /= (double)(gpsize + clrzamp);     /* 1 */
+        if(*amptype==DECRESC)       /** DECRESCENDO **/
+            *ampstep = -(*ampstep);
+    }
+    return(FINISHED);
+}
+
+/*************************** GETDIRAMPSTEP ******************************
+ *
+ * (1)  If there are two amplitude types, in THIS CASE, these can only
+ *      be DIRECTED or FLAT. So...
+ *   (2)  Choose flat or directed via perm.
+ *   (3)  and if it's flat, return an ampstep of zero.
+ *    Otherwise, we proceed as in the normal case of a directed amp.
+ * (4)  Set initial ampstep to amprise.
+ * (5)  IF the cresc will be from zero, or decresc to zero,  clrzamp is 1,
+ *      and this makes the amplitude steps a little smaller, so that 1st note
+ *      of cresc (or last note of decresc) will not be at amplitude zero.
+ *      OTHERWISE, clrzamp = 0,  and ampstep is as normal.
+ * (6)  Divide ampstep by number of members in group.
+ * (7)  If it's a post-ornament, ampstep is negative.
+ */
+
+int getdirampstep
+(double amp,unsigned char amptypecnt,double *ampstep,int gpsize,dataptr dz)
+{
+    int exit_status;
+    int k, clrzamp = 0;
+    if(amptypecnt==2) {                                 /* 1 */
+        if((exit_status= doperm((int)2,PM_GPCNTR,&k,dz))<0) /* 2 */
+            return(exit_status);
+        if(k==0) {
+            *ampstep = 0.0;
+            return(FINISHED);                           /* 3 */
+        }
+    }
+    *ampstep = dz->param[TEX_AMPRISE];  /* param with <|> option */             /* 4 */
+    if(*ampstep>=amp) {                                 /* 5 */
+        clrzamp = 1;
+        *ampstep = amp;
+    }
+    *ampstep /= (double)(gpsize + clrzamp);             /* 6 */
+    if(!dz->vflag[IS_PRE])                              /* 7 */
+        *ampstep = -(*ampstep);
+
+    return(FINISHED);
+}
+
+/*************************** GETMTFDIRAMPSTEP *******************************
+ *
+ *  Intelligent guesswork!! Nov 4: 1997
+ */
+
+int getmtfdirampstep(double amp,double framp,unsigned char amptypecnt,double *ampstep,int gpsize,dataptr dz)
+{
+    int exit_status;
+    int k, clrzamp = 0;
+    if(amptypecnt==2) {                                 /* 1 */
+        if((exit_status= doperm((int)2,PM_GPCNTR,&k,dz))<0) /* 2 */
+            return(exit_status);
+        if(k==0) {
+            *ampstep = 0.0;
+            return(FINISHED);                           /* 3 */
+        }
+    }
+    if(amp>(dz->param[TEX_AMPRISE] + framp))
+         *ampstep = dz->param[TEX_AMPRISE];
+    else {
+        *ampstep = amp - framp; 
+        clrzamp = 1;
+    }
+    *ampstep /= (double)(gpsize + clrzamp);             /* 6 */
+    if(!dz->vflag[IS_PRE])                              /* 7 */
+        *ampstep = -(*ampstep);
+
+    return(FINISHED);
+}
+
+/*************************  GET_DEC_OR_ORN_POS ***************************
+ *
+ * Decuptype flags are selected and shifted down into the range 0-3
+ * If its 01 (1), it's a post-ornament, so set 'is_pre' = FALSE.
+ * If its 10 (2), it's a pre_ornament,  so set 'is_pre' = TRUE
+ * If its 00 (0), it's not set, so we select 'is_pre' at random using doperm on 2 (output 0S or 1).
+ *
+ * NB: If we are using a group or motif, rather than a decoration
+ *  or ornament, is_pre is BY DEFAULT set to 0.
+ */
+
+int get_dec_or_orn_pos(dataptr dz)
+{
+    int exit_status;
+    int k;
+    unsigned int dectype = dz->tex->txflag & GET_DECORNPOS;
+    switch(dectype) {
+    case(1): dz->vflag[IS_PRE] = TRUE;  break;
+    case(2): dz->vflag[IS_PRE] = FALSE; break;
+    default:
+        if((exit_status = doperm((int)2,PM_ORNPOS,&k,dz))<0)
+            return(exit_status);
+        dz->vflag[IS_PRE] = (char)k;        
+        break;
+    }
+    if(dz->vflag[IS_PRE] > 1) {
+        sprintf(errstr,"Error from perm in  get_dec_or_orn_pos()\n");
+        return(PROGRAM_ERROR);
+    }
+    return(FINISHED);
+}
+
+/**************************** SUBZERO ***********************************
+ *
+ * If start of a decoration falls before time zero, adjust its size
+ * and hence starttime(-minus-gpdense) appropriately.
+ */
+
+int subzero(double *thistime,double gpdense,int *gpsize)
+{
+    int n = -1;
+    while(*thistime>=0.0) {
+        *thistime -= gpdense;
+        n++;
+    }
+    if(n<0) {
+        sprintf(errstr,"TEXTURE: Problem in subzero()\n");
+        return(PROGRAM_ERROR);
+    }
+    *gpsize = n;
+    return(FINISHED);
+}
+
+/*************************** GETHIPITCH *********************************#
+ *
+ * Find highest pitch at current time.
+ */
+
+noteptr gethipitch(noteptr tsetnote,int *shaddoindex)
+{
+    noteptr hinote, thisnote;
+    double hipitch;
+    int zz = *shaddoindex;
+    hinote = thisnote = tsetnote;
+    hipitch = (double)hinote->pitch;
+    while(thisnote->next!=(noteptr)0) {
+        if(thisnote->next->ntime > thisnote->ntime + FLTERR)
+            return(hinote);
+        thisnote = thisnote->next;
+        zz++;
+        if((double)thisnote->pitch > hipitch) {
+            hipitch = (double)thisnote->pitch;
+            hinote  = thisnote;
+            (*shaddoindex) = zz;
+        }
+    }
+    return(hinote);
+}
+
+/****************************** DO_GRP_INS **********************************
+ *
+ * Choose instr-no within group/decoration/motif or ornament.
+ * Values of instr-no range are preset when instr is chosen for the
+ * tset, in do_ev_ins().
+ */
+
+int do_grp_ins(unsigned char thisinstr,unsigned char *val,dataptr dz)
+{
+    int exit_status;
+    int irange, ival;
+    if(dz->vflag[INS_TO_SCATTER]) {
+        if((irange = (int)(dz->iparam[TEXTURE_INSHI] - dz->iparam[TEXTURE_INSLO])) < 0) {
+            iswap((int *)&(dz->iparam[TEXTURE_INSHI]),(int *)&(dz->iparam[TEXTURE_INSLO]));
+            irange = -irange;
+        }
+        if(irange==0)
+            *val = (unsigned char)dz->iparam[TEXTURE_INSLO];
+        else {
+            if((exit_status = doperm(irange+1,PM_INSNO,&ival,dz))<0)    /* range INCLUSIVE for ints */
+                return(exit_status);
+            *val = (unsigned char)(ival + dz->iparam[TEXTURE_INSLO]);
+        }
+    } else
+        *val = thisinstr;
+    return(FINISHED);
+}
+
+/***************************** PSCATX ************************************
+ *
+ * Select a random value within 'range', by permuting one of BANDCNT equal
+ * ranges, and selecting a random value within the chosen range.
+ */
+
+int pscatx(double range,double bottom,int pindex,double *val,dataptr dz)
+{
+    int k, exit_status;
+    double bandwidth, bandbottom, x;
+    if((exit_status = doperm((int)BANDCNT,pindex,&k,dz))<0)
+        return(exit_status);
+    bandwidth   = range/(double)BANDCNT;
+    bandbottom  = (double)k * bandwidth;
+    x  = (drand48() * bandwidth);
+    x += bandbottom;
+    *val = x + bottom;
+    return(FINISHED);
+}
+
+/*************************** DEL_NOTE ************************************/
+
+void del_note(noteptr thisnote,motifptr thismotif)
+{
+    if(thisnote->next!=(noteptr)0)
+        thisnote->next->last = thisnote->last;      /* 1 */
+    if(thisnote->last!=(noteptr)0)
+        thisnote->last->next = thisnote->next;      /* 2 */
+    else
+        thismotif->firstnote = thisnote->next;      /* 3 */
+    free(thisnote);                 /* 4 */
+}
+    
+/************************** TIMESORT ****************************
+ *
+ * Timesorts notes in a list
+ *
+ * (1)  Move the item with earliest time to start of list, and set this
+ *      (minimum) time as maximum time also.
+ *  For each item in the list....
+ *   (2)   If this item is earlier than current latest item (maxtime)..
+ *     (3)    Find where it should be in the list.
+ *     (4)    move it to that location.
+ *   (5)   Otherwise, set this item's time as latest time(maxtime).
+ * (6)  Reset motifhead to start of notelist!!
+ */
+
+int arrange_notes_in_timeorder(motifptr mtf)
+{
+    noteptr base, here, there, mark;
+    double thistime, maxtime;
+    if((base = mtf->firstnote)==(noteptr)0)
+        return(FINISHED);
+    maxtime = setup_first_notelist_time(&base);         /* 1 */
+    here = base;
+    while(here!=(noteptr)0) {
+        if((thistime = here->ntime) < maxtime) {        /* 2 */
+            if((mark = here->last)==(noteptr)0) {
+                sprintf(errstr,"Problem (1) in arrange_notes_in_timeorder()\n");
+                return(PROGRAM_ERROR);
+            }
+            if((there = reverse_search_for_time(here,thistime))==(noteptr)0) {
+                sprintf(errstr,"Timing problem in arrange_notes_in_timeorder()\n");
+                return(PROGRAM_ERROR);
+            }                       /* 3 */
+            move_notelist_item(here,there);         /* 4 */
+            here = mark;
+        } else
+            maxtime = here->ntime;          /* 5 */
+        here = here->next;
+    }
+    return reset_mtfhead(mtf);                  /* 6 */
+}
+
+/************************* RESET_MTFHEAD ***************************
+ *
+ * Reset pointer to start of notelist.
+ */
+ 
+int reset_mtfhead(motifptr mtf)
+{
+    noteptr here = mtf->firstnote;
+    if(mtf->firstnote==NULL) {
+        sprintf(errstr,"Problem in reset_mrfhead()\n");
+        return(PROGRAM_ERROR);
+    }
+    while(here->last!=(noteptr)0)
+        here = here->last;
+    mtf->firstnote = here;
+
+    return(FINISHED);
+}
+
+/************************** SETUP_FIRST_NOTELIST_TIME ***************************
+ *
+ * Put the earliest timed item in a list of notes into start of list.
+ */
+
+double setup_first_notelist_time(noteptr *base)
+{
+    noteptr firstnote, here;
+    double  mintime, thistime;
+    firstnote = here = *base;
+    mintime   = (*base)->ntime;
+    while(here!=(noteptr)0) {
+        if((thistime = here->ntime)<mintime) {
+            firstnote = here;
+            mintime = thistime;
+        }
+        here = here->next;
+    }
+    if(firstnote!=(*base)) {
+        move_notelist_item(firstnote,(*base));
+        *base = firstnote;
+    }
+    return(mintime);
+}
+
+/************************* MOVE_NOTELIST_ITEM ***************************
+ *
+ * Move an item in a notelist from location a to BEFORE location b.
+ */
+
+void move_notelist_item(noteptr a,noteptr b)
+{
+    if(a->last!=(noteptr)0)
+        a->last->next = a->next;
+    if(a->next!=(noteptr)0)
+        a->next->last = a->last;
+    a->next = b;
+    a->last = b->last;
+    if(b->last!=(noteptr)0)
+        b->last->next = a;
+    b->last = a;
+}
+
+/************************** REVERSE_SEARCH_FOR_TIME *****************************
+ *
+ * Reverse search note-list using a time as index, and return address
+ * of note whose time is AFTER the input time. 
+ * WILL RETURN (noteptr)0 IF REFTIME IS OFF END OF LIST.
+ */
+
+noteptr reverse_search_for_time(noteptr start,double reftime)
+{
+    noteptr here = start;
+    while(here->ntime >= reftime) {
+        if(here->last == (noteptr)0)
+            return(here);
+        here = here->last;
+    }
+    return(here->next); 
+}
+
+/************************** ISWAP *****************************/
+
+void iswap(int *a,int *b)
+{
+    int temp;
+    temp = *a;
+    *a = *b;
+    *b = temp;
+}
+
+/****************************** SET_GROUP_PARAMS **********************************/
+
+int set_group_params
+(noteptr tsetnote,noteptr thisnote,double gpdense,double ampstep,double *thisamp,double *thistime,double thisdur,dataptr dz)
+{
+    int exit_status;
+    double thisgpdense, time_left;
+    *thisamp += ampstep;
+    thisnote->amp   = (float)*thisamp;
+    thisnote->dur   = (float)thisdur;
+    if(dz->vflag[FIXED_STEP])
+        *thistime += gpdense;
+    else {
+        if((exit_status = get_density_val(*thistime,&thisgpdense,dz))<0)
+            return(exit_status);
+        if((dz->tex->txflag & IS_DECOR) && dz->vflag[IS_PRE]) {
+            if((time_left = tsetnote->ntime - *thistime)<0.0) {
+                sprintf(errstr,"Error in assumptions: set_group_params()\n");
+                return(PROGRAM_ERROR);
+            }
+            time_left *= 0.66;
+            thisgpdense = min(time_left,thisgpdense);
+        }
+        *thistime += thisgpdense;
+    }
+    return(FINISHED);
+}
+
+/***************************** GETTRITYPE *****************************
+ *
+ * Choose a type, from up to three available types in bit-flag.
+ * e.g.
+ * Choose an amplitude type (flat,cresc,decresc) from 3 available types.
+ * Choose a decoration-orientation type (above,below,mid) from 3 types.
+ *
+ * (1)  For each type in the bitflag.
+ * (2)  If this option is flagged, count it.
+ * (3)  IF this option is chosen, return its bit-number.
+ * (4)  Advance the bitflag mask.
+ */
+
+int gettritype(int k,unsigned stor,unsigned char *val)
+{
+    int v = 0, mask = 1, n;
+    k++;
+    for(n=0;n<3;n++) {              /* 1 */
+        if(mask & stor)             /* 2 */
+            v++;
+        if(k==v) {              /* 3 */
+            *val = (unsigned char)n;
+            return(FINISHED);
+        }
+        mask <<= 1;             /* 4 */
+    }
+    sprintf(errstr,"TEXTURE: Problem in gettritype()\n");
+    return(PROGRAM_ERROR);
+}
+
+/***************************  GET_DENSITY_VAL ******************************/
+
+int get_density_val(double thistime,double *gpdense,dataptr dz)
+{
+    int exit_status;
+    if((exit_status = getvalue(TEX_GPPACKHI,TEX_GPPACKLO,thistime,PM_GPDENS,gpdense,dz))<0)
+        return(PROGRAM_ERROR);
+
+/* NEW MAR 2000 */
+    *gpdense *= MS_TO_SECS;
+
+    if(dz->param[TEX_PHGRID]>0.0)
+        *gpdense = quantise(*gpdense,dz->param[TEX_PHGRID]);
+
+    return FINISHED;
+}
+
+/**************************** SET_MOTIFS *******************************
+ *
+ * initialise all parameters of input motifs to be used for MOTIFS or
+ * ORNAMENTS.
+ *
+ * (1)For each input motif (called a 'phrase').
+ *    phrnotecnt[n] = 0;
+ * (2)  Initialise count of number of notes to 0, maximum amplitude
+ *  of phrase to 0.0, and lowest pitch to MIDITOP.
+ * (3)  Go through each note of the motif.
+ * (4)  Add up the number of notes in it.
+ * (5)  Find it's lowest pitch.
+ * (6)  Find it's loudest note (and set as phraseamp).
+ * (7)  Establish dynamic range of phrase.
+ * (8)  Transpose the motif into it's lowest possible register.
+ * (9)  Ensure motif starts at zero time.
+ * (10) Store addresses of last notes in phrases.
+ */
+
+int set_motifs
+(int phrcount,motifptr *phrase,int *phrnotecnt,double *phraseamp,double *phrange,noteptr *phrlastnote)
+{
+    int exit_status;
+    int n;
+    double minpitch, mintime, minamp;
+    noteptr thisnote, lastnote = (noteptr)0;
+    for(n=0;n<phrcount;n++) {                       /* 1 */
+        if((exit_status = arrange_notes_in_timeorder(phrase[n]))<0)
+            return(exit_status);
+        phrnotecnt[n] = 0;
+        phraseamp[n] = 0.0;                         /* 2 */
+        minamp   = DBL_MAX;
+        minpitch = MIDITOP;
+        mintime  = DBL_MAX;
+        thisnote = phrase[n]->firstnote;            /* 3 */
+        while(thisnote!=(noteptr)0) {
+            phrnotecnt[n]++;                            /* 4 */
+            if(thisnote->pitch<minpitch)
+                minpitch = thisnote->pitch;         /* 5 */
+            if(thisnote->ntime<mintime)
+                mintime  = thisnote->ntime;         /* 5 */
+            if((double)thisnote->amp>phraseamp[n])
+                phraseamp[n] = (double)thisnote->amp;/* 6 */
+            if(thisnote->amp<minamp)
+                minamp = thisnote->amp;             /* 6 */
+            thisnote = thisnote->next;
+        }
+        if(minamp  == DBL_MAX || mintime == DBL_MAX) {
+            sprintf(errstr,"Error parsing motif: set_motifs()\n");
+            return(PROGRAM_ERROR);
+        }
+        thisnote = phrase[n]->firstnote;
+        phrange[n] = phraseamp[n] - minamp;         /* 7 */
+        while(thisnote!=(noteptr)0) {
+            thisnote->pitch = (float)(thisnote->pitch - (minpitch + MIDIBOT));  /* 8 */
+            thisnote->ntime = (float)(thisnote->ntime - mintime);               /* 9 */
+            lastnote = thisnote;                                                /* 10 */
+            thisnote = thisnote->next;
+        }
+        if((phrlastnote[n] = lastnote) == (noteptr)0) {
+            sprintf(errstr,"Zero length phrase encountered: set_motifs()\n");
+            return(PROGRAM_ERROR);
+        }
+    }
+    return(FINISHED);
+}
+
+void cyclicperm(dataptr dz) 
+{
+    int n, t;
+    do {
+        for(n=0;n<dz->infilecnt;n++) {
+            t = (int)floor(drand48() * (n+1));
+            if(t==n) {
+                hprefix(n,dz->peakno,dz->infilecnt);
+            } else {
+                hinsert(n,t,dz->peakno,dz->infilecnt);
+            }
+        }
+    } while(dz->peakno[0] == dz->lastpeakno[dz->infilecnt - 1]);    // Avoid repetitions at perm boundaries.
+    for(n=0;n<dz->infilecnt;n++)
+        dz->lastpeakno[n] = dz->peakno[n];
+}
+
+void hinsert(int m,int t,int *perm,int permlen)
+{
+    hshuflup(t+1,perm,permlen);
+    perm[t+1] = m;
+}
+
+void hprefix(int m,int *perm,int permlen)
+{
+    hshuflup(0,perm,permlen);
+    perm[0] = m;
+}
+
+void hshuflup(int k,int *perm,int permlen)
+{
+    int n, *i;
+    int z = permlen - 1;
+    i = perm+z;
+    for(n = z;n > k;n--) {
+        *i = *(i-1);
+        i--;
+    }
+}
+
+#ifndef round
+
+int round(double a)
+{
+    return (int)floor(a + 0.5);
+}
+#endif

+ 627 - 0
dev/texture/v8/texture5.c

@@ -0,0 +1,627 @@
+/*
+ * Copyright (c) 1983-2013 Trevor Wishart and Composers Desktop Project Ltd
+ * http://www.trevorwishart.co.uk
+ * http://www.composersdesktop.com
+ *
+ This file is part of the CDP System.
+ 
+ The CDP System is free software; you can redistribute it
+ and/or modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+ 
+ The CDP System is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU Lesser General Public License for more details.
+ 
+ You should have received a copy of the GNU Lesser General Public
+ License along with the CDP System; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA
+ *
+ */
+/* floatsam version */
+#include <stdio.h>
+#include <stdlib.h>
+#include <memory.h>         /*RWD*/
+#include <structures.h>
+#include <tkglobals.h>
+#include <globcon.h>
+#include <processno.h>
+#include <modeno.h>
+#include <arrays.h>
+#include <texture.h>
+#include <cdpmain.h>
+
+#include <sfsys.h>
+#ifdef _DEBUG
+#include <assert.h>
+#endif
+
+#if defined unix || defined __GNUC__
+#define round(x) lround((x))
+#endif
+
+static int setup_splice(int st_splicecnt,double **splicebuf);
+static int generate_origdur_and_frq(double **origdur,double **origfrq,dataptr dz);
+static int init_soundout_set(sndoutptr *sndout);
+static int replace_tset_by_soundout_set(noteptr thisnote,sndoutptr *sndout,
+            double *origdur,double *origfrq,double  mindur,int st_splicecnt,dataptr dz);
+static int convert_tsetnote_to_sndout_item(noteptr thisnote,sndoutptr sndout,
+            double *origdur,double *origfrq,double mindur,int st_splicecnt,int *warning_set,dataptr dz);
+static int generate_previous_sndout(sndoutptr *sndout);
+static int get_thisdur(double *thisdur,noteptr thisnote,int thisins,
+            double *origdur,double inv_trnsp,double mindur,dataptr dz);
+static int get_stereospace_compensation(double position,double *compensate);
+
+static int do_mix(sndoutptr sndout,double *splicebuf,dataptr dz);
+static int check_sequencing(sndoutptr sndout);
+static int add_samples_to_outbuf_from_inbuf(int *out_of_insamples,int * max_samp_written,
+            sndoutptr sndout,double *splicebuf,int splicelen,/*int*/float *lbuf,dataptr dz);
+static void unlink_sndoutptr_at_start_of_list(sndoutptr sndout);
+static void unlink_sndoutptr(sndoutptr sndout);
+static double get_interpd_value(unsigned int here,double ibufpos,sndoutptr sndout);
+static int  free_first_sndout(sndoutptr *sndout);
+
+//TW UPDATE 2002: to make texture from stereo sources (updated to flotsams)
+static int add_stereo_samples_to_outbuf_from_inbuf
+(int *out_of_insamples,int *max_samp_written,sndoutptr sndout,double *splicebuf,int splicelen,float *lbuffer,dataptr dz);
+static double get_interpd_value_stereo(unsigned int here,double ibufpos,double *chanval2,sndoutptr sndout);
+
+/**************************** PRODUCE_TEXTURE_SOUND *****************************/
+
+int produce_texture_sound(dataptr dz)
+{
+    int exit_status;
+    /*insamptr  *insound = dz->tex->insnd;*/
+    motifptr  tset     = dz->tex->timeset;
+    sndoutptr sndout;
+    noteptr   thisnote = tset->firstnote;
+    double *origdur, *origfrq, *splicebuf;
+    double mindur = (dz->frametime + TEXTURE_SAFETY) * MS_TO_SECS;
+    int st_splicecnt = round((dz->frametime * MS_TO_SECS) * dz->infile->srate);
+#ifdef MINDUR_OVERRIDE
+    mindur = 0.0;
+    st_splicecnt = 0;
+#endif
+    if((exit_status = setup_splice(st_splicecnt,&splicebuf))<0)
+        return(exit_status);
+    if((exit_status = generate_origdur_and_frq(&origdur,&origfrq,dz))<0)
+        return(exit_status);
+    if((exit_status = init_soundout_set(&sndout))<0)
+        return(exit_status);
+    if((exit_status = replace_tset_by_soundout_set(thisnote,&sndout,origdur,origfrq,mindur,st_splicecnt,dz))<0)
+        return(exit_status);
+    free(origdur);
+    free(origfrq);
+    return do_mix(sndout,splicebuf,dz);
+} 
+
+/************************** SETUP_SPLICE ************************/
+
+int setup_splice(int st_splicecnt,double **splicebuf)
+{
+    int n, m;
+    if((*splicebuf = (double *)malloc(st_splicecnt * sizeof(double)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY for splice buffer.\n");
+        return(MEMORY_ERROR);
+    }
+    for(m=0,n=st_splicecnt-1; n>=0; n--,m++)
+        (*splicebuf)[m] = (double)n/(double)st_splicecnt;
+    return(FINISHED);
+}
+
+/************************** GENERATE_ORIGDUR_AND_FRQ ************************/
+
+int generate_origdur_and_frq(double **origdur,double **origfrq,dataptr dz)
+{
+    int n;
+    if((*origdur = (double *)malloc(dz->infilecnt * sizeof(double)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY to store original durations.\n");
+        return(MEMORY_ERROR);
+    }
+    if((*origfrq = (double *)malloc(dz->infilecnt * sizeof(double)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY to store original frqs.\n");
+        return(MEMORY_ERROR);
+    }
+    for(n=0;n <dz->infilecnt;n++) {
+//TW UPDATE: Now allowing stereo sources to be used to make texture
+        (*origdur)[n] = (double)dz->insams[n]/(double)dz->infile->channels/(double)dz->infile->srate;
+        (*origfrq)[n] = miditohz(((dz->tex->insnd)[n])->pitch);
+    }
+    return(FINISHED);
+}
+
+/************************** INIT_SOUNDOUT_SET ************************/
+
+int init_soundout_set(sndoutptr *sndout)
+{
+    if((*sndout = (sndoutptr)malloc(sizeof(struct soundout)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY for soundout pointers.\n");
+        return(MEMORY_ERROR);
+    }
+    (*sndout)->last = (sndoutptr)0;
+    (*sndout)->next = (sndoutptr)0;
+    return(FINISHED);
+}
+
+/************************** REPLACE_TSET_BY_SOUNDOUT_SET ************************/
+
+int replace_tset_by_soundout_set
+(noteptr thisnote,sndoutptr *sndout,double *origdur,double *origfrq,double  mindur,int st_splicecnt,dataptr dz)
+{
+    int exit_status;
+    int warning_set = FALSE;
+    while((thisnote->next)!=(noteptr)0) /* go to end of tset */
+        thisnote = thisnote->next;
+    while(thisnote!=(noteptr)0) {
+        if((exit_status = convert_tsetnote_to_sndout_item
+        (thisnote,*sndout,origdur,origfrq,mindur,st_splicecnt,&warning_set,dz))<0)
+            return(exit_status);
+        if((exit_status = generate_previous_sndout(sndout))<0)
+            return(exit_status);
+        if(thisnote->last!=NULL) {
+            thisnote = thisnote->last;      /* free tset from end backwards */
+            free(thisnote->next);   
+        } else {
+            free(thisnote);
+            if((exit_status = free_first_sndout(sndout))<0) 
+                return(exit_status);
+            thisnote = NULL;
+        }
+    }
+    return(FINISHED);
+}
+
+/************************** CONVERT_TSETNOTE_TO_SNDOUT_ITEM ************************/
+
+//TW "STEREO" defined in globcon.h
+#define MAXGAIN (1.0)
+
+int convert_tsetnote_to_sndout_item
+(noteptr thisnote,sndoutptr sndout,double *origdur,double *origfrq,double mindur,int st_splicecnt,int *warning_set,dataptr dz)
+{
+    int exit_status;
+    int thisins;
+    unsigned int insampcnt, st_osampcnt;
+    double indur;
+    double thisfrq,thisdur,trnspstep,inv_trnsp,thisamp,thispos,compensate;
+
+    thisins   = thisnote->instr;
+    thisfrq   = miditohz((double)thisnote->pitch);
+    trnspstep = thisfrq/origfrq[thisins];
+    inv_trnsp = 1.0/trnspstep;
+    if((exit_status = get_thisdur(&thisdur,thisnote,thisins,origdur,inv_trnsp,mindur,dz))<0)
+        return(exit_status);
+    indur       = thisdur * trnspstep;
+//TW UPDATE now counting either mono samples or pairs-of-stereo-sample pairs (as with st_osampcnt) as possibly using stereo input
+    insampcnt   = min(dz->insams[thisins]/dz->infile->channels,round(indur * (double)dz->infile->srate));       
+    st_osampcnt = round((double)insampcnt * inv_trnsp);     
+    if(st_osampcnt <= (unsigned int)st_splicecnt) {
+        sprintf(errstr,"Error in samplecount calculations: convert_tsetnote_to_sndout_item()\n");
+        return(PROGRAM_ERROR);
+    }
+    thisamp   = thisnote->amp/(double)MIDITOP;
+    thispos   = thisnote->spacepos;
+    if((exit_status = get_stereospace_compensation(thispos,&compensate))<0)
+        return(exit_status);
+    if(thisamp > MAXGAIN) {
+#ifdef _DEBUG
+        assert(thisamp <= MAXGAIN);
+#endif
+        if(!(*warning_set)) {
+            fprintf(stdout,"WARNING: one or more events exceed max level. Adjusted.\n");
+            fflush(stdout);
+            *warning_set = TRUE;
+        }
+        thisamp = MAXGAIN;
+    }
+    sndout->inbuf       = ((dz->tex->insnd)[thisins])->buffer;
+    sndout->ibufcnt     = insampcnt;
+    sndout->st_sstttime = round(thisnote->ntime * dz->infile->srate);
+    sndout->st_sendtime = sndout->st_sstttime + st_osampcnt; /* Redundant variable: might need if func revised */
+    sndout->st_splicpos = sndout->st_sendtime - st_splicecnt;
+    sndout->ibufpos     = 0.0;
+    sndout->step        = trnspstep;
+//TW UPDATE: in stereo-input case, only 1 gain value used, as no spatialisation takes place
+    if(dz->infile->channels==STEREO) {
+        sndout->lgain       = thisamp;
+    } else {
+        sndout->lgain       = thisamp * (1.0 - thispos) * compensate;
+        sndout->rgain       = thisamp * thispos * compensate;
+    }
+    return(FINISHED);
+}
+
+/************************** GENERATE_PREVIOUS_SNDOUT ************************/
+
+int generate_previous_sndout(sndoutptr *sndout)
+{
+    sndoutptr new;
+    if((new = (sndoutptr)malloc(sizeof(struct soundout)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY for new soundout pointers.\n");
+        return(MEMORY_ERROR);
+    }
+    new->last     = (sndoutptr)0;
+    new->next     = *sndout;
+    (*sndout)->last = new;
+    *sndout = new;
+    return(FINISHED);
+}
+
+/************************** FREE_FIRST_SNDOUT ************************/
+
+int free_first_sndout(sndoutptr *sndout)
+{
+    if((*sndout = (*sndout)->next)==NULL) {
+        sprintf(errstr,"Problem in free_first_sndout()\n");
+        return(PROGRAM_ERROR);
+    }
+    free((*sndout)->last);
+    (*sndout)->last = NULL;
+    return(FINISHED);
+}
+
+/************************** GET_THISDUR ************************/
+
+int get_thisdur
+(double *thisdur,noteptr thisnote,int thisins,double *origdur,double inv_trnsp,double mindur,dataptr dz)
+{
+    double transposed_dur = origdur[thisins] * inv_trnsp;
+    *thisdur   = thisnote->dur;
+    if(*thisdur>transposed_dur)         
+        *thisdur = transposed_dur;
+    else if(dz->vflag[TEX_IGNORE_DUR])
+        *thisdur = transposed_dur;
+    if(*thisdur<mindur) {
+        sprintf(errstr,
+        "too short dur generated (%lf : mindur = %lf): get_thisdur()\n",*thisdur,mindur);
+        return(PROGRAM_ERROR);
+    }
+    return(FINISHED);
+}
+
+/************************** GET_STEREOSPACE_COMPENSATION ************************
+ *
+ * 1)   comp(ensation) is a factor which compensates for the apparent
+ *      loss of perceived amplitude as a sound moves out of the absolute
+ *      left or absolute right position (sound from a single loudspeaker)
+ *      by simple linear interpolation. 
+ *      At first we define comp to vary LINERALY from 0.0 at L or R,
+ *      to 1.0 in centre.
+ * 2)   NONLIN makes this varation nonlinear, but smooth at the centre, and
+ *      still between 0.0 and 1.0
+ * 3)   As a signal of fixed perceived level moves from left to right (or v.v.)
+ *      we wish to boost the amplitude from each loudspeaker somewhat,
+ *      using a curve of the shape now defined.
+ *      The maximum possible amplitude is 1.0. To define how much we should
+ *      boost amplitude at any point on the L-R axis, we need to define
+ *      a ratio (MAXBOOST) with which to multiply the signal.
+ *      Multiplying comp-curve by this, defines a curve of amplitude-boosting values.
+ * 4)   1.0 is now added to this curve, to give a multiplier of amplitude at
+ *      each point along the left-right axis.
+ *      And MAXBOOST is subtracted, so that the level 
+ *      from each loudspeaker when at maximum boost cannot exceed
+ *      MAXGAIN (1.0).
+ */
+
+#define NONLIN   (0.5)
+#define MAXBOOST (0.25)
+
+int get_stereospace_compensation(double position,double *compensate)
+{
+    double comp = 1.0 - (fabs((position * (double)2.0) - (double)1.0));     /* 9a */
+    comp = pow(comp,NONLIN);            /* 9b */
+    comp *= MAXBOOST;                   /* 9c */
+    comp += (1.0 - MAXBOOST);           /* 9d */
+    *compensate = comp;
+    return(FINISHED);
+}
+
+/************************** DO_MIX ************************
+ *
+ * 1)   Position, in stereo-samples, of start-of-splice in this-sndout-struct =  
+ *          sndout->st_splicpos
+ *      Position in actual-samples of ditto = 
+ *           sndout->st_splicpos * STEREO
+ *      Position relative to start of current buffer = 
+ *          (sndout->st_splicpos * STEREO) - (obufcnt * dz->buflen);
+ *      Same position expressed relative to start-of-splice (so that value 0 = start_of_splice) = 
+ *          -((sndout->st_splicpos * STEREO) - (obufcnt * dz->buflen));
+ */
+
+int do_mix(sndoutptr sndout,double *splicebuf,dataptr dz)
+{
+    int exit_status;
+    int out_of_insamples;
+    /*unsigned int totaltime = 0;*/
+    int max_samp_written, n;
+    unsigned long this_sampend, obufcnt = 0;
+    long splicelen = round((dz->frametime * MS_TO_SECS) * dz->infile->srate) * STEREO;
+    sndoutptr startsnd = sndout, endsnd = sndout;
+    /*int*/float *lbuf;
+//TW UPDATE handles stereo input files
+    int is_stereo = 0;
+#ifdef MINDUR_OVERRIDE
+    splicelen = 0;
+#endif
+    if(dz->infile->channels == STEREO)
+        is_stereo = 1;
+//TW MOVED from texprepro
+    dz->infile->channels = STEREO;  /* for output time calculations */
+    if((exit_status = create_sized_outfile(dz->outfilename,dz))<0)
+        return(exit_status);
+
+    if((lbuf = (float *)malloc(dz->buflen * sizeof(float)))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY for mixing buffers.\n");
+        return(MEMORY_ERROR);
+    }
+    dz->sbufptr[0] = dz->sampbuf[0];
+/* <--SAFETY CHECK */
+    if((exit_status = check_sequencing(sndout))<0)
+        return(exit_status);
+/* SAFETY CHECK--> */
+    while(startsnd != NULL) {                                       /* until we reach end of event list */
+        this_sampend = (obufcnt+1) * dz->buflen;        /* get absolute samplecnt of end of current buf */
+                                                     /* look for NEW events starting during this outbuf */
+        if(sndout!=NULL) {
+            while(sndout->st_sstttime * STEREO < this_sampend) {     
+                sndout->obufpos  = (sndout->st_sstttime * STEREO) % dz->buflen;/* obufptr for new event */
+                sndout->st_splicpos = (sndout->st_splicpos * STEREO)-(obufcnt * dz->buflen);/* NOTE1 abv*/
+                sndout->st_splicpos = -(sndout->st_splicpos);                           /* NOTE 1 above */
+                sndout = sndout->next;
+                endsnd = sndout;                      /* update the endmarker of the active events list */
+                if(endsnd == NULL)                                      /* if all events finished,break */
+                    break;
+            }
+        }
+        sndout = startsnd;                                       /* set start to 1st event still active */
+
+        memset((char *)lbuf,0,dz->buflen * sizeof(float));                       /* empty output buffer */
+        if(sndout == endsnd) {                      /* If there are NO active events during this buffer */
+            if(endsnd != NULL)                                   /* and we are not at end of event list */
+                max_samp_written = dz->buflen;                        /* setup to write an empty buffer */
+            else {
+                sprintf(errstr,"Error in loop logic: do_mix()\n");
+                return(PROGRAM_ERROR);
+            }
+        } else
+            max_samp_written = 0;
+        while(sndout!= endsnd) {                                          /* look in all active buffers */
+            out_of_insamples = FALSE;
+
+//TW UPDATE: handles stereo input
+            if(is_stereo) {
+                if((exit_status = add_stereo_samples_to_outbuf_from_inbuf
+                (&out_of_insamples,&max_samp_written,sndout,splicebuf,splicelen,lbuf,dz))<0)
+                    return(exit_status);
+            } else {
+                if((exit_status = add_samples_to_outbuf_from_inbuf
+                (&out_of_insamples,&max_samp_written,sndout,splicebuf,splicelen,lbuf,dz))<0)
+                    return(exit_status);
+            }
+            if(out_of_insamples) {                                 /* if inbuf exhausted for THIS event */
+
+                if(sndout->next==NULL) {                                           /* if at end of list */
+                    if(sndout->last==NULL) {           /* if this is definitively the last active event */
+                         free(sndout);                                                       /* free it */     
+                         startsnd = NULL;            /* and set ptr to NULL, so we dropout of outerloop */
+                         break;
+                    } else {                                 /* BUT if some previous event still active */
+                        sndout = sndout->last;                          /* unlink final event from list */
+                        free(sndout->next);
+                        sndout->next = NULL;
+                        sndout = sndout->next;                            /* move sndout to end of list */
+                    }
+                } else if(sndout==startsnd) {                    /* if this is 1st active event in list */
+                        sndout   = sndout->next;                               /* proceed to next event */
+                        startsnd = sndout;              /* move start of active list to this next event */
+                        unlink_sndoutptr_at_start_of_list(sndout->last);
+                } else {                                /* else if this is NOT 1st active event in list */
+                        sndout   = sndout->next;                               /* proceed to next event */
+                        unlink_sndoutptr(sndout->last);/* unlink the exhausted event from (active) list */
+                }
+            } else {                            /* else there is data remaining in inbuf for THIS event */
+                sndout->obufpos = 0;                          /* so reset obufpos to start of next obuf */
+                sndout->st_splicpos += dz->buflen;/* reset relativeposition splice-start & nextbufstart */
+                sndout = sndout->next;                                     /* and proceed to next event */
+            }
+        }
+        if(startsnd!=NULL)                /* If we're not at the end of ALL events, write a full buffer */
+            max_samp_written = dz->buflen;
+
+        for(n=0;n<max_samp_written;n++)
+            dz->sampbuf[0][n] = lbuf[n];
+        if(max_samp_written > 0) {
+            if((exit_status = write_samps(dz->sampbuf[0],max_samp_written,dz))<0)
+                return(exit_status);
+        }
+        obufcnt++;
+    }
+    /*if(dz->iparam[TEX_MAXOUT] > MAXSAMP) {*/
+    if(dz->param[TEX_MAXOUT] > F_MAXSAMP) {
+        fprintf(stdout,"WARNING: OVERLOAD: suggest attenuation by < %lf\n",
+//TW UPDATE (need to factor in the attenation already being used to give correct new attenuation)
+            (((double)F_MAXSAMP/(double)dz->param[TEX_MAXOUT])) * dz->param[TEXTURE_ATTEN]);
+        fflush(stdout);
+    }
+    return(FINISHED);
+}
+
+/************************** CHECK_SEQUENCING ************************/
+
+int check_sequencing(sndoutptr sndout)
+{
+    unsigned int lasttime = sndout->st_sstttime;
+    unsigned int thistime;
+    while(sndout->next != (sndoutptr)0) {
+        sndout = sndout->next;
+        if((thistime = sndout->st_sstttime) < lasttime) {
+            sprintf(errstr,"Sequencing anomaly in sndout list: check_sequencing()\n");
+            return(PROGRAM_ERROR);
+        }
+        lasttime = thistime;
+    } 
+    return(FINISHED);
+}
+
+/************************** ADD_SAMPLES_TO_OUTBUF_FROM_INBUF ************************/
+
+int add_samples_to_outbuf_from_inbuf
+(int *out_of_insamples,int *max_samp_written,sndoutptr sndout,double *splicebuf,int splicelen,float *lbuffer,dataptr dz)
+{
+    unsigned int thisopos = sndout->obufpos;
+    unsigned int here;
+    double hereval = 0.0;
+    float *lbuf    = lbuffer + thisopos;
+    float *lbufend = lbuffer + dz->buflen;
+    int splicpos  = sndout->st_splicpos + thisopos;
+    float outval, thismaxoutval;
+    int max_set = FALSE;
+    while(lbuf < lbufend) {
+        if((here = (unsigned int) sndout->ibufpos) >= sndout->ibufcnt) {    /* TRUNCATE : get current pos in inbuf */
+            *out_of_insamples = TRUE;
+            *max_samp_written = max(*max_samp_written,lbuf - lbuffer);
+/* SAFETY CHECK--> */
+            if(splicpos < splicelen) {
+                sprintf(errstr,"BUM endsplice: add_samples_to_outbuf_from_inbuf()\n"); 
+                return(PROGRAM_ERROR);
+            }
+/* <--SAFETY CHECK */
+
+            max_set = TRUE;
+            break;
+        }
+        hereval = get_interpd_value(here,sndout->ibufpos,sndout);
+/* SAFETY FOR ARITHMETIC ROUNDING ERROS CALCULATING START OF SPLICE --> */
+        if(splicpos >= splicelen)
+            hereval = 0.0;
+/* <--SAFETY */
+
+        if(splicpos >= 0)
+            hereval *= splicebuf[splicpos >> 1];
+        splicpos += STEREO;
+        outval =(float)( *lbuf + (hereval * sndout->lgain ));
+        if((thismaxoutval = (float) fabs(outval)) > dz->param[TEX_MAXOUT])
+            dz->param[TEX_MAXOUT] = thismaxoutval;
+        *lbuf  = outval;
+        lbuf++;
+        outval = (float)(*lbuf + (hereval * sndout->rgain));
+        if((thismaxoutval = (float) fabs(outval)) > dz->param[TEX_MAXOUT])
+            dz->param[TEX_MAXOUT] =  thismaxoutval;
+        *lbuf = outval;
+        lbuf++;
+        sndout->ibufpos += sndout->step;
+    }
+    if(!max_set)
+        *max_samp_written = dz->buflen;
+    return(FINISHED);
+}
+
+//TW UPDATE: NEW FUNCTIONfor stereo input (updated for flotsams)
+/************************** ADD_STEREO_SAMPLES_TO_OUTBUF_FROM_INBUF ************************/
+
+int add_stereo_samples_to_outbuf_from_inbuf
+(int *out_of_insamples,int *max_samp_written,sndoutptr sndout,double *splicebuf,int splicelen,float *lbuffer,dataptr dz)
+{
+    unsigned int thisopos = sndout->obufpos;
+    unsigned int here;
+    double chanval1, chanval2;
+    float *lbuf    = lbuffer + thisopos;
+    float *lbufend = lbuffer + dz->buflen;
+    int splicpos  = sndout->st_splicpos + thisopos;
+    float outval, thismaxoutval;
+    int max_set = FALSE;
+    while(lbuf < lbufend) {
+        if((here = (unsigned int)sndout->ibufpos)>=sndout->ibufcnt) {   /* TRUNCATE : get current pos in inbuf */
+            *out_of_insamples = TRUE;
+            *max_samp_written = max(*max_samp_written,lbuf - lbuffer);
+            if(splicpos < splicelen) {
+                sprintf(errstr,"BUM endsplice: add_samples_to_outbuf_from_inbuf()\n"); 
+                return(PROGRAM_ERROR);
+            }
+            max_set = TRUE;
+            break;
+        }
+        chanval1 = get_interpd_value_stereo(here,sndout->ibufpos,&chanval2,sndout);
+    /* SAFETY FOR ARITHMETIC ROUNDING ERROS CALCULATING START OF SPLICE --> */
+        if(splicpos >= splicelen) {
+            chanval1 = 0.0;
+            chanval2 = 0.0;
+        }
+    /* <--SAFETY */
+        if(splicpos >= 0) {
+            chanval1 *= splicebuf[splicpos >> 1];
+            chanval2 *= splicebuf[splicpos >> 1];
+        }
+        splicpos += STEREO;
+        outval = (float)(*lbuf + (chanval1 * sndout->lgain));
+        if((thismaxoutval = (float)fabs(outval))>dz->param[TEX_MAXOUT])
+            dz->param[TEX_MAXOUT] = thismaxoutval;
+        *lbuf  = outval;
+        lbuf++;
+        outval = (float)(*lbuf + (chanval2 * sndout->lgain));   /* only one gain val for stereo inputs: kept in lgain */
+        if((thismaxoutval = (float)fabs(outval))>dz->param[TEX_MAXOUT])
+            dz->param[TEX_MAXOUT] = thismaxoutval;
+        *lbuf = outval;
+        lbuf++;
+        sndout->ibufpos += sndout->step;
+    }
+    if(!max_set)
+        *max_samp_written = dz->buflen;
+    return(FINISHED);
+}
+
+/************************** GET_INTERPD_VALUE ************************/
+
+double get_interpd_value(unsigned int here,double ibufpos,sndoutptr sndout)
+{
+    unsigned int next = here+1;         /* NB  all inbufs have a wraparound (0val) point at end */
+    double frac     = ibufpos - (double)here;
+    double hereval  = (double)(sndout->inbuf[here]);
+    double nextval  = (double)(sndout->inbuf[next]);
+    double diff     = nextval - hereval;
+    diff    *= frac;
+    return(hereval+diff);
+}
+
+//TW UPDATE NEW FUNCTION for stereo input
+/************************** GET_INTERPD_VALUE_STEREO ************************/
+
+double get_interpd_value_stereo(unsigned int here,double ibufpos,double *chanval2,sndoutptr sndout)
+{
+    unsigned int next = here+1;         /* NB  all inbufs have a wraparound (0val) point at end */
+    double frac     = ibufpos - (double)here;
+    double hereval, nextval, diff;
+    double chanval1;
+    unsigned int sthere = here * 2, stnext = next * 2;
+    hereval  = (double)(sndout->inbuf[sthere]);
+    nextval  = (double)(sndout->inbuf[stnext]);
+    diff     = (nextval - hereval) * frac;
+    chanval1 = hereval+diff;
+    sthere++;
+    stnext++;
+    hereval  = (double)(sndout->inbuf[sthere]);
+    nextval  = (double)(sndout->inbuf[stnext]);
+    diff     = (nextval - hereval) * frac;
+    *chanval2 = hereval+diff;
+    return(chanval1);
+}
+
+/************************** UNLINK_SNDOUTPTR_AT_START_OF_LIST ************************/
+
+void unlink_sndoutptr_at_start_of_list(sndoutptr sndout)
+{
+    sndout->next->last = (sndoutptr)0;
+    free(sndout);
+}
+
+/************************** UNLINK_SNDOUTPTR ************************/
+
+void unlink_sndoutptr(sndoutptr sndout)
+{
+    sndout->next->last = sndout->last;
+    sndout->last->next = sndout->next;
+    free(sndout);
+}