richarddobson 3 лет назад
Родитель
Сommit
2616b93144
10 измененных файлов с 4466 добавлено и 0 удалено
  1. 20 0
      dev/sndinfo/CMakeLists.txt
  2. 33 0
      dev/sndinfo/Makefiled.osx
  3. 724 0
      dev/sndinfo/ap_sndinfo.c
  4. 1490 0
      dev/sndinfo/compare.c
  5. 240 0
      dev/sndinfo/main.c
  6. 668 0
      dev/sndinfo/musunit.c
  7. 20 0
      dev/spec/CMakeLists.txt
  8. 578 0
      dev/spec/ap_simple.c
  9. 234 0
      dev/spec/main.c
  10. 459 0
      dev/spec/simple.c

+ 20 - 0
dev/sndinfo/CMakeLists.txt

@@ -0,0 +1,20 @@
+if(APPLE)
+  set(CMAKE_C_FLAGS "-O2 -Wall -mmacosx-version-min=10.8 -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(sndinfo main.c ap_sndinfo.c compare.c musunit.c)
+
+target_link_libraries(sndinfo cdp2k sfsys ${EXTRA_LIBRARIES})
+
+my_install(sndinfo)
+

+ 33 - 0
dev/sndinfo/Makefiled.osx

@@ -0,0 +1,33 @@
+#
+#	OSX debug (with PVOCEX support) Makefile for sndinfo � Richard Dobson, CDP Ltd 2014,2022
+#
+#
+CC=cc
+OPT = -g
+CFLAGS= $(OPT) -Wall -mmacosx-version-min=10.8 -Dunix -I../newinclude -I../include
+LIBDIR = ../../lib
+LIBS = -lsfsysd -lcdp2kd -lpvxio2d
+
+PROG=sndinfo
+BINS= main.o ap_sndinfo.o compare.o musunit.o
+.c.o:
+	$(CC) $(CFLAGS) -c $<
+#
+#	targets
+#
+all:	$(PROG)
+
+$(PROG):	$(BINS)
+	$(CC) $(CFLAGS) $(BINS) -o $(PROG) -L$(LIBDIR) $(LIBS)
+
+clean:
+	rm -f $(PROG)
+	
+veryclean:	clean
+	rm -f *.o
+
+install:	$(PROG)
+	cp $(PROG) ../Release
+#
+#	dependencies
+#

+ 724 - 0
dev/sndinfo/ap_sndinfo.c

@@ -0,0 +1,724 @@
+/*
+ * Copyright (c) 1983-2013 Trevor Wishart and Composers Desktop Project Ltd
+ * http://www.trevorwishart.co.uk
+ * http://www.composersdesktop.com
+ *
+ This file is part of the CDP System.
+
+    The CDP System is free software; you can redistribute it
+    and/or modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    The CDP System is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with the CDP System; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+    02111-1307 USA
+ *
+ */
+
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <structures.h>
+#include <cdpmain.h>
+#include <tkglobals.h>
+#include <pnames.h>
+#include <sndinfo.h>
+#include <processno.h>
+#include <modeno.h>
+#include <globcon.h>
+#include <logic.h>
+#include <filetype.h>
+#include <mixxcon.h>
+#include <flags.h>
+#include <speccon.h>
+#include <arrays.h>
+#include <special.h>
+#include <formants.h>
+#include <sfsys.h>
+#include <osbind.h>
+#include <string.h>
+#include <ctype.h>
+#include <math.h>
+
+/********************************************************************************************/
+/********************************** FORMERLY IN specialin.c *********************************/
+/********************************************************************************************/
+
+static int  interval_to_semitones(char *str,dataptr dz);
+static int  readnote_as_midi(char *str,dataptr dz);
+
+/***************************************************************************************/
+/****************************** FORMERLY IN aplinit.c **********************************/
+/***************************************************************************************/
+
+/***************************** ESTABLISH_BUFPTRS_AND_EXTRA_BUFFERS **************************/
+
+int establish_bufptrs_and_extra_buffers(dataptr dz)
+{
+    int exit_status;
+    dz->extra_bufcnt = -1;  /* ENSURE EVERY CASE HAS A PAIR OF ENTRIES !! */
+    dz->bptrcnt = 0;
+    dz->bufcnt  = 0;
+    switch(dz->process) {
+    case(INFO_PROPS):           dz->extra_bufcnt = 0;   dz->bufcnt = 0;                         break;
+    case(INFO_SFLEN):           dz->extra_bufcnt = 0;   dz->bufcnt = 0;                         break;
+    case(INFO_TIMELIST):        dz->extra_bufcnt = 0;   dz->bufcnt = 0;                         break;
+    case(INFO_TIMESUM):         dz->extra_bufcnt = 0;   dz->bufcnt = 0;                         break;
+    case(INFO_TIMEDIFF):        dz->extra_bufcnt = 0;   dz->bufcnt = 0;                         break;
+    case(INFO_SAMPTOTIME):      dz->extra_bufcnt = 0;   dz->bufcnt = 0;                         break;
+    case(INFO_TIMETOSAMP):      dz->extra_bufcnt = 0;   dz->bufcnt = 0;                         break;
+    case(INFO_MAXSAMP):
+    case(INFO_MAXSAMP2):        dz->extra_bufcnt = 0;   dz->bufcnt = 1;                         break;
+    case(INFO_LOUDCHAN):        dz->extra_bufcnt = 0;   dz->bufcnt = 1;                         break;
+    case(INFO_FINDHOLE):        dz->extra_bufcnt = 0;   dz->bufcnt = 1;                         break;
+    case(INFO_DIFF):            dz->extra_bufcnt = 0;   dz->bufcnt = 2; dz->bptrcnt = 2;        break;
+    case(INFO_CDIFF):           dz->extra_bufcnt = 0;   dz->bufcnt = 4;                         break;
+    case(INFO_PRNTSND):         dz->extra_bufcnt = 0;   dz->bufcnt = 1;                         break;
+    case(INFO_MUSUNITS):        dz->extra_bufcnt = 0;   dz->bufcnt = 0;                         break;
+    case(INFO_LOUDLIST):        dz->extra_bufcnt = 0;   dz->bufcnt = 1;                         break;
+    case(ZCROSS_RATIO):         dz->extra_bufcnt = 0;   dz->bufcnt = 1;                         break;
+        
+    default:
+        sprintf(errstr,"Unknown program type [%d] in establish_bufptrs_and_extra_buffers()\n",dz->process);
+        return(PROGRAM_ERROR);
+    }
+
+    if(dz->extra_bufcnt < 0) {
+        sprintf(errstr,"bufcnts have not been set: establish_bufptrs_and_extra_buffers()\n");
+        return(PROGRAM_ERROR);
+    }
+    if((dz->process==HOUSE_SPEC && dz->mode==HOUSE_CONVERT) || dz->process==INFO_DIFF) {
+        if((exit_status = establish_spec_bufptrs_and_extra_buffers(dz))<0)
+            return(exit_status);
+    }
+    return establish_groucho_bufptrs_and_extra_buffers(dz);
+}
+
+/***************************** SETUP_INTERNAL_ARRAYS_AND_ARRAY_POINTERS **************************/
+
+int setup_internal_arrays_and_array_pointers(dataptr dz)
+{
+    int n;       
+    dz->ptr_cnt    = -1;        /* base constructor...process */
+    dz->array_cnt  = -1;
+    dz->iarray_cnt = -1;
+    dz->larray_cnt = -1;
+    switch(dz->process) {
+    case(INFO_PROPS):      
+        dz->array_cnt=1; dz->iarray_cnt=0; dz->larray_cnt=0; dz->ptr_cnt= 0; dz->fptr_cnt = 0; 
+        break;
+    case(INFO_SFLEN):       case(INFO_TIMELIST):    case(INFO_TIMESUM):     case(INFO_TIMEDIFF):    
+    case(INFO_SAMPTOTIME):  case(INFO_TIMETOSAMP):  case(INFO_MAXSAMP):     case(INFO_LOUDCHAN):    
+    case(INFO_FINDHOLE):    case(INFO_DIFF):        case(INFO_CDIFF):       case(INFO_PRNTSND):
+    case(INFO_MUSUNITS):    case(INFO_LOUDLIST):    case(INFO_MAXSAMP2):    case(ZCROSS_RATIO):   
+        dz->array_cnt=0; dz->iarray_cnt=0; dz->larray_cnt=0; dz->ptr_cnt= 0; dz->fptr_cnt = 0; 
+        break;
+    }
+
+/*** WARNING ***
+ANY APPLICATION DEALING WITH A NUMLIST INPUT: MUST establish AT LEAST 1 double array: i.e. dz->array_cnt = at least 1
+**** WARNING ***/
+
+
+    if(dz->array_cnt < 0 || dz->iarray_cnt < 0 || dz->larray_cnt < 0 || dz->ptr_cnt < 0 || dz->fptr_cnt < 0) {
+        sprintf(errstr,"array_cnt not set in setup_internal_arrays_and_array_pointers()\n");       
+        return(PROGRAM_ERROR);
+    }
+
+    if(dz->array_cnt > 0) {  
+        if((dz->parray  = (double **)malloc(dz->array_cnt * sizeof(double *)))==NULL) {
+            sprintf(errstr,"INSUFFICIENT MEMORY for internal double arrays.\n");
+            return(MEMORY_ERROR);
+        }
+        for(n=0;n<dz->array_cnt;n++)
+            dz->parray[n] = NULL;
+    }
+    if(dz->iarray_cnt > 0) {
+        if((dz->iparray = (int     **)malloc(dz->iarray_cnt * sizeof(int *)))==NULL) {
+            sprintf(errstr,"INSUFFICIENT MEMORY for internal int arrays.\n");
+            return(MEMORY_ERROR);
+        }
+        for(n=0;n<dz->iarray_cnt;n++)
+            dz->iparray[n] = NULL;
+    }
+    if(dz->larray_cnt > 0) {      
+        if((dz->lparray = (int    **)malloc(dz->larray_cnt * sizeof(int *)))==NULL) {
+            sprintf(errstr,"INSUFFICIENT MEMORY for internal long arrays.\n");
+            return(MEMORY_ERROR);
+        }
+        for(n=0;n<dz->larray_cnt;n++)
+            dz->lparray[n] = NULL;
+    }
+    if(dz->ptr_cnt > 0)   {       
+        if((dz->ptr     = (double  **)malloc(dz->ptr_cnt  * sizeof(double *)))==NULL) {
+            sprintf(errstr,"INSUFFICIENT MEMORY for internal pointer arrays.\n");
+            return(MEMORY_ERROR);
+        }
+        for(n=0;n<dz->ptr_cnt;n++)
+            dz->ptr[n] = NULL;
+    }
+    if(dz->fptr_cnt > 0)   {      
+        if((dz->fptr = (float  **)malloc(dz->fptr_cnt * sizeof(float *)))==NULL) {
+            sprintf(errstr,"INSUFFICIENT MEMORY for internal float-pointer arrays.\n");
+            return(MEMORY_ERROR);
+        }
+        for(n=0;n<dz->fptr_cnt;n++)
+            dz->fptr[n] = NULL;
+    }
+    return(FINISHED);
+}
+
+/****************************** ASSIGN_PROCESS_LOGIC *********************************/
+
+int assign_process_logic(dataptr dz)
+{                        
+    switch(dz->process) {
+    case(INFO_PROPS):           setup_process_logic(ALL_FILES,      OTHER_PROCESS,      NO_OUTPUTFILE,  dz);    break;
+    case(INFO_SFLEN):           setup_process_logic(ALL_FILES,      OTHER_PROCESS,      NO_OUTPUTFILE,  dz);    break;
+//TW UPDATE
+    case(INFO_TIMELIST):
+        if(sloom)
+            setup_process_logic(MANY_SNDFILES,  TO_TEXTFILE,        TEXTFILE_OUT,   dz);
+        else
+            setup_process_logic(MANY_SNDFILES,  OTHER_PROCESS,      NO_OUTPUTFILE,  dz);    
+        break;
+    case(INFO_TIMESUM):         setup_process_logic(MANY_SNDFILES,  OTHER_PROCESS,      NO_OUTPUTFILE,  dz);    break;
+    case(INFO_TIMEDIFF):        setup_process_logic(TWO_SNDFILES,   OTHER_PROCESS,      NO_OUTPUTFILE,  dz);    break;
+    case(INFO_SAMPTOTIME):      setup_process_logic(SNDFILES_ONLY,  OTHER_PROCESS,      NO_OUTPUTFILE,  dz);    break;
+    case(INFO_TIMETOSAMP):      setup_process_logic(SNDFILES_ONLY,  OTHER_PROCESS,      NO_OUTPUTFILE,  dz);    break;
+    case(INFO_MAXSAMP):
+    case(INFO_MAXSAMP2):        setup_process_logic(ALL_FILES,      OTHER_PROCESS,      NO_OUTPUTFILE,  dz);    break;
+    case(INFO_LOUDCHAN):        setup_process_logic(SNDFILES_ONLY,  OTHER_PROCESS,      NO_OUTPUTFILE,  dz);    break;
+    case(INFO_FINDHOLE):        setup_process_logic(SNDFILES_ONLY,  OTHER_PROCESS,      NO_OUTPUTFILE,  dz);    break;
+    case(INFO_DIFF):            setup_process_logic(ALL_FILES,      OTHER_PROCESS,      NO_OUTPUTFILE,  dz);    break;
+    case(INFO_CDIFF):           setup_process_logic(SNDFILES_ONLY,  OTHER_PROCESS,      NO_OUTPUTFILE,  dz);    break;
+    case(INFO_PRNTSND):         setup_process_logic(SNDFILES_ONLY,  TO_TEXTFILE,        TEXTFILE_OUT,   dz);    break;
+    case(INFO_MUSUNITS):        setup_process_logic(NO_FILE_AT_ALL, OTHER_PROCESS,      NO_OUTPUTFILE,  dz);    break;
+    case(INFO_LOUDLIST):        setup_process_logic(MANY_SNDFILES,  TO_TEXTFILE,        TEXTFILE_OUT,   dz);    break;
+    case(ZCROSS_RATIO):         setup_process_logic(SNDFILES_ONLY,  OTHER_PROCESS,      NO_OUTPUTFILE,  dz);    break;
+
+    default:
+        sprintf(errstr,"Unknown process: assign_process_logic()\n");
+        return(PROGRAM_ERROR);
+        break;
+    }
+    if(dz->has_otherfile) {
+        switch(dz->input_data_type) {
+        case(ALL_FILES):
+        case(TWO_SNDFILES):
+        case(SNDFILE_AND_ENVFILE):
+        case(SNDFILE_AND_BRKFILE):
+        case(SNDFILE_AND_UNRANGED_BRKFILE):
+        case(SNDFILE_AND_DB_BRKFILE):
+            break;
+        case(MANY_SNDFILES):
+            if(dz->process==INFO_TIMELIST || dz->process==INFO_LOUDLIST)
+                break;
+            /* fall thro */
+        default:
+            sprintf(errstr,"Most processes accepting files with different properties\n"
+                           "can only take 2 sound infiles.\n");
+            return(PROGRAM_ERROR);
+        }
+    }
+    return(FINISHED);
+}
+
+/***************************** SET_LEGAL_INFILE_STRUCTURE **************************
+ *
+ * Allows 2nd infile to have different props to first infile.
+ */
+
+void set_legal_infile_structure(dataptr dz)
+{
+    switch(dz->process) {
+    case(INFO_DIFF):
+    case(INFO_TIMEDIFF):
+    case(INFO_TIMELIST):
+    case(INFO_LOUDLIST):
+        dz->has_otherfile = TRUE;
+        break;
+    default:
+        dz->has_otherfile = FALSE;
+        break;
+    }
+}
+
+/****************************** FORMERLY IN internal.c *********************************/
+/***************************************************************************************/
+
+/****************************** SET_LEGAL_INTERNALPARAM_STRUCTURE *********************************/
+
+int set_legal_internalparam_structure(int process,int mode,aplptr ap)
+{
+    int exit_status = FINISHED;
+    
+    switch(process) {
+    case(INFO_PROPS):       case(INFO_SFLEN):       case(INFO_TIMELIST):    case(INFO_TIMESUM):
+    case(INFO_TIMEDIFF):    case(INFO_SAMPTOTIME):  case(INFO_TIMETOSAMP):  case(INFO_MAXSAMP):
+    case(INFO_LOUDCHAN):    case(INFO_FINDHOLE):    case(INFO_DIFF):        case(INFO_CDIFF):
+    case(INFO_PRNTSND):     case(INFO_MUSUNITS):    case(INFO_LOUDLIST):    case(INFO_MAXSAMP2):
+    case(ZCROSS_RATIO):
+                            exit_status = set_internalparam_data("",ap);        break;
+    default:
+        sprintf(errstr,"Unknown process in set_legal_internalparam_structure()\n");
+        return(PROGRAM_ERROR);
+    }
+    return(exit_status);        
+}
+
+/********************************************************************************************/
+/********************************** FORMERLY IN specialin.c *********************************/
+/********************************************************************************************/
+
+/********************** READ_SPECIAL_DATA ************************/
+
+int read_special_data(char *str,dataptr dz)    
+{
+    aplptr ap = dz->application;
+
+    switch(ap->special_data) {
+    case(NOTE_REPRESENTATION):      return readnote_as_midi(str,dz);
+    case(INTERVAL_REPRESENTATION):  return interval_to_semitones(str,dz);
+    default:
+        sprintf(errstr,"Unknown special_data type: read_special_data()\n");
+        return(PROGRAM_ERROR);
+    }
+    return(FINISHED);   /* NOTREACHED */
+}
+
+/********************** INTERVAL_TO_SEMITONES **********************/
+
+int interval_to_semitones(char *str,dataptr dz)
+{   
+    char *p, *q;
+    double d = 0, direction = 1.0;
+    p = str + strlen(str) - 1;
+
+    switch(*p) {
+    case('u'):    case('U'):    d = .5;  break;
+    case('d'):    case('D'):    d = -.5; break;
+    }
+    q = str;
+    if(*q=='-') {
+        direction = -1.0;
+        q++;
+    }
+    if     (!strncmp(q,"m2",2))  dz->scalefact = (1.0+d)*direction;  
+    else if(!strncmp(q,"2",1))   dz->scalefact = (2.0+d)*direction;  
+    else if(!strncmp(q,"m3",2))  dz->scalefact = (3.0+d)*direction;
+    else if(!strncmp(q,"3",1))   dz->scalefact = (4.0+d)*direction;
+    else if(!strncmp(q,"4",1))   dz->scalefact = (5.0+d)*direction;
+    else if(!strncmp(q,"#4",2))  dz->scalefact = (6.0+d)*direction;
+    else if(!strncmp(q,"5",1))   dz->scalefact = (7.0+d)*direction;
+    else if(!strncmp(q,"m6",2))  dz->scalefact = (8.0+d)*direction;
+    else if(!strncmp(q,"6",1))   dz->scalefact = (9.0+d)*direction;
+    else if(!strncmp(q,"m7",2))  dz->scalefact = (10.0+d)*direction;
+    else if(!strncmp(q,"7",1))   dz->scalefact = (11.0+d)*direction;
+    else if(!strncmp(q,"8",1))   dz->scalefact = (12.0+d)*direction;
+    else if(!strncmp(q,"m9",2))  dz->scalefact = (13.0+d)*direction;
+    else if(!strncmp(q,"9",1))   dz->scalefact = (14.0+d)*direction;
+    else if(!strncmp(q,"m10",3)) dz->scalefact = (15.0+d)*direction;
+    else if(!strncmp(q,"10",2))  dz->scalefact = (16.0+d)*direction;
+    else if(!strncmp(q,"11",2))  dz->scalefact = (17.0+d)*direction;
+    else if(!strncmp(q,"#11",3)) dz->scalefact = (18.0+d)*direction;
+    else if(!strncmp(q,"12",2))  dz->scalefact = (19.0+d)*direction;
+    else if(!strncmp(q,"m13",3)) dz->scalefact = (20.0+d)*direction;
+    else if(!strncmp(q,"13",2))  dz->scalefact = (21.0+d)*direction;
+    else if(!strncmp(q,"m14",3)) dz->scalefact = (22.0+d)*direction;
+    else if(!strncmp(q,"14",2))  dz->scalefact = (23.0+d)*direction;
+    else if(!strncmp(q,"15",2))  dz->scalefact = (24.0+d)*direction;
+    else {
+        sprintf(errstr,"Unknown interval.\n");
+        return(GOAL_FAILED);
+    } return FINISHED;
+}
+
+/************************ READNOTE_AS_MIDI *************************/
+
+int readnote_as_midi(char *str,dataptr dz)
+{
+    int oct, isquarter = 0;
+    int flat = 0, sharp = 0, accidental = 0, quarter = 0;
+    char *p = str + strlen(str) - 1;
+
+    if(!isdigit(*p)) {
+        if(*p=='u' || *p=='d') {
+            sprintf(errstr,"'u' or 'd' come BEFORE 8va-number in note-representation.\n");
+            return(GOAL_FAILED);
+        } else {
+            sprintf(errstr,"Invalid note-representation.\n");
+            return(GOAL_FAILED);
+        }
+    }
+    if(*(str+1)=='b') {
+        flat = 1;
+        accidental = 1;
+    } else {
+        if(*(str+1)=='#') {
+            sharp = 1;
+            accidental = 1;
+        }
+    }
+    if(*(str+1+accidental)=='u') {
+        quarter = 1;
+        isquarter = 1;
+    } else {
+        if(*(str+1+accidental)=='d') {
+            quarter = -1;
+            isquarter = 1;
+        }
+    }
+    if(sscanf(str+1+accidental+isquarter,"%d",&oct)!=1) {
+        sprintf(errstr,"Note octave not specified.\n");
+        return(GOAL_FAILED);
+    }
+    switch(*str) {
+    case('c'): case('C'): dz->scalefact = 0.0; break;
+    case('d'): case('D'): dz->scalefact = 2.0; break;
+    case('e'): case('E'): dz->scalefact = 4.0; break;
+    case('f'): case('F'): dz->scalefact = 5.0; break;
+    case('g'): case('G'): dz->scalefact = 7.0; break;
+    case('a'): case('A'): dz->scalefact = 9.0; break;
+    case('b'): case('B'): dz->scalefact = 11.0; break;
+    default:
+        sprintf(errstr,"Unknown note '%c'\n",*str);
+        return(GOAL_FAILED);
+    }
+    if(flat)    dz->scalefact -= 1.0;
+    if(sharp)   dz->scalefact += 1.0;
+    oct     += 5;
+    dz->scalefact += ((double)oct     * 12.0);    
+    dz->scalefact += ((double)quarter * 0.5);
+    return(FINISHED);
+}
+
+
+/********************************************************************************************/
+/********************************** FORMERLY IN preprocess.c ********************************/
+/********************************************************************************************/
+
+/****************************** PARAM_PREPROCESS *********************************/
+
+int param_preprocess(dataptr dz)    
+{
+    double  temp;
+
+    switch(dz->process) {
+    case(INFO_PROPS):       case(INFO_SFLEN):       case(INFO_TIMELIST):
+    case(INFO_TIMESUM):     case(INFO_TIMEDIFF):    case(INFO_SAMPTOTIME):
+    case(INFO_TIMETOSAMP):  case(INFO_LOUDCHAN):
+    case(INFO_FINDHOLE):    case(INFO_DIFF):        case(INFO_CDIFF):
+    case(INFO_PRNTSND):     case(INFO_MUSUNITS):    case(INFO_LOUDLIST):    
+    case(INFO_MAXSAMP):
+        break;
+    case(ZCROSS_RATIO):
+        if(flteq(dz->param[ZC_START],dz->param[ZC_END])) {
+            sprintf(errstr,"Start and Endtime of search are too close.\n");
+            return(DATA_ERROR);
+        }
+        if(dz->param[ZC_START] < 0.0)
+            dz->param[ZC_START] = 0.0;
+        if(dz->param[ZC_END] > dz->duration)
+            dz->param[ZC_END] = dz->duration;
+        if(dz->param[ZC_START] > dz->param[ZC_END]) {
+            temp = dz->param[ZC_START];
+            dz->param[ZC_START] = dz->param[ZC_END];
+            dz->param[ZC_END] = temp;
+        }
+        break;
+    case(INFO_MAXSAMP2):
+        if(flteq(dz->param[MAX_ETIME],dz->param[MAX_STIME])) {
+            sprintf(errstr,"Start and Endtime of search are too close.\n");
+            return(DATA_ERROR);
+        }
+        if(dz->param[MAX_ETIME] < dz->param[MAX_STIME]) {
+            temp = dz->param[MAX_ETIME];
+            dz->param[MAX_ETIME] = dz->param[MAX_STIME];
+            dz->param[MAX_STIME] = temp;
+        }
+        break;
+    default:
+        sprintf(errstr,"PROGRAMMING PROBLEM: Unknown process in param_preprocess()\n");
+        return(PROGRAM_ERROR);
+    }
+    return(FINISHED);
+}
+
+/********************************************************************************************/
+/********************************** FORMERLY IN procgrou.c **********************************/
+/********************************************************************************************/
+
+/**************************** GROUCHO_PROCESS_FILE ****************************/
+
+int groucho_process_file(dataptr dz)   /* FUNCTIONS FOUND IN PROCESS.C */
+{   
+    switch(dz->process) {
+    case(INFO_PROPS):       case(INFO_SFLEN):       case(INFO_TIMELIST):    case(INFO_TIMESUM): 
+    case(INFO_TIMEDIFF):    case(INFO_SAMPTOTIME):  case(INFO_TIMETOSAMP):  case(INFO_MAXSAMP):
+    case(INFO_LOUDCHAN):    case(INFO_FINDHOLE):    case(INFO_DIFF):        case(INFO_CDIFF):
+    case(INFO_PRNTSND):     case(INFO_LOUDLIST):    case(INFO_MAXSAMP2):    case(ZCROSS_RATIO):
+        return do_sndinfo(dz);
+    case(INFO_MUSUNITS):
+        return do_musunits(dz);
+    default:
+        sprintf(errstr,"Unknown case in process_file()\n");
+        return(PROGRAM_ERROR);
+    }
+    return(FINISHED);   /* NOTREACHED */
+}
+
+/********************************************************************************************/
+/********************************** FORMERLY IN pconsistency.c ******************************/
+/********************************************************************************************/
+
+/****************************** CHECK_PARAM_VALIDITY_AND_CONSISTENCY *********************************/
+
+int check_param_validity_and_consistency(dataptr dz)
+{
+    handle_pitch_zeros(dz);
+    return(FINISHED);
+}
+
+/********************************************************************************************/
+/********************************** FORMERLY IN buffers.c ***********************************/
+/********************************************************************************************/
+
+/**************************** ALLOCATE_LARGE_BUFFERS ******************************/
+
+int allocate_large_buffers(dataptr dz)
+{
+    int exit_status;
+    int orig_chancnt = 0;
+    switch(dz->process) {
+    case(INFO_PROPS):       case(INFO_TIMESUM):     case(INFO_SAMPTOTIME):      case(INFO_TIMETOSAMP):
+    case(INFO_SFLEN):       case(INFO_TIMELIST):    case(INFO_TIMEDIFF):        case(INFO_MUSUNITS):
+        break;
+    case(INFO_MAXSAMP):     case(INFO_FINDHOLE):    case(INFO_PRNTSND):   case(INFO_MAXSAMP2):
+    case(INFO_LOUDCHAN):    case(INFO_LOUDLIST):
+    case(ZCROSS_RATIO):
+        return create_sndbufs(dz);
+    case(INFO_DIFF):        case(INFO_CDIFF):
+        if(dz->infile->filetype == ANALFILE) {
+            orig_chancnt = dz->infile->channels;
+            dz->infile->channels = 1;
+        }
+        if ((exit_status = create_sndbufs(dz))<0)
+            return exit_status;
+        if(dz->infile->filetype == ANALFILE)
+            dz->infile->channels = orig_chancnt;
+        return FINISHED;
+    default:
+        sprintf(errstr,"Unknown program no. in allocate_large_buffers()\n");
+        return(PROGRAM_ERROR);
+    }
+    return(FINISHED);
+}
+
+/********************************************************************************************/
+/********************************** FORMERLY IN cmdline.c ***********************************/
+/********************************************************************************************/
+
+int get_process_no(char *prog_identifier_from_cmdline,dataptr dz)
+{
+    if     (!strcmp(prog_identifier_from_cmdline,"props"))      dz->process = INFO_PROPS;
+    else if(!strcmp(prog_identifier_from_cmdline,"len"))        dz->process = INFO_SFLEN;
+    else if(!strcmp(prog_identifier_from_cmdline,"lens"))       dz->process = INFO_TIMELIST;
+    else if(!strcmp(prog_identifier_from_cmdline,"sumlen"))     dz->process = INFO_TIMESUM;
+    else if(!strcmp(prog_identifier_from_cmdline,"timediff"))   dz->process = INFO_TIMEDIFF;
+    else if(!strcmp(prog_identifier_from_cmdline,"smptime"))    dz->process = INFO_SAMPTOTIME;
+    else if(!strcmp(prog_identifier_from_cmdline,"timesmp"))    dz->process = INFO_TIMETOSAMP;
+    else if(!strcmp(prog_identifier_from_cmdline,"maxsamp"))    dz->process = INFO_MAXSAMP;
+    else if(!strcmp(prog_identifier_from_cmdline,"maxsamp2"))   dz->process = INFO_MAXSAMP2;
+    else if(!strcmp(prog_identifier_from_cmdline,"loudchan"))   dz->process = INFO_LOUDCHAN;
+    else if(!strcmp(prog_identifier_from_cmdline,"findhole"))   dz->process = INFO_FINDHOLE;
+    else if(!strcmp(prog_identifier_from_cmdline,"diff"))       dz->process = INFO_DIFF;
+    else if(!strcmp(prog_identifier_from_cmdline,"chandiff"))   dz->process = INFO_CDIFF;
+    else if(!strcmp(prog_identifier_from_cmdline,"prntsnd"))    dz->process = INFO_PRNTSND;
+    else if(!strcmp(prog_identifier_from_cmdline,"units"))      dz->process = INFO_MUSUNITS;
+    else if(!strcmp(prog_identifier_from_cmdline,"maxi"))       dz->process = INFO_LOUDLIST;
+    else if(!strcmp(prog_identifier_from_cmdline,"zcross"))     dz->process = ZCROSS_RATIO;
+    else {
+        sprintf(errstr,"Unknown program identification string '%s'\n",prog_identifier_from_cmdline);
+        return(USAGE_ONLY);
+    }
+    return FINISHED;
+}
+
+/********************************************************************************************/
+/********************************** FORMERLY IN usage.c *************************************/
+/********************************************************************************************/
+
+/******************************** USAGE1 ********************************/
+
+int usage1(void)
+{
+    sprintf(errstr,
+    "USAGE: sndreport NAME (mode) infile(s) (outfile) (parameters)\n"
+    "\n"
+    "where NAME can be any one of\n"
+    "\n"
+    "props     len        lens      sumlen      timediff\n"
+    "smptime   timesmp    maxsamp   maxsamp2    loudchan    findhole\n"
+    "diff      chandiff   prntsnd   units       maxi        zcross\n"
+    "\n"
+    "Type 'sndreport timediff'  for more info on info timediff option... ETC.\n");
+    return(USAGE_ONLY);
+}
+
+/******************************** USAGE2 ********************************/
+
+int usage2(char *str)
+{
+    if(!strcmp(str,"props")) {
+        sprintf(errstr,
+        "DISPLAY PROPERTIES OF A SNDFILING-SYSTEM FILE\n\n"
+        "USAGE: sndreport props infile\n");
+    } else if(!strcmp(str,"len")) {
+        sprintf(errstr,
+        "DISPLAY DURATION OF A SNDFILING-SYSTEM FILE\n\n"
+        "USAGE: sndreport len infile\n");
+    } else if(!strcmp(str,"lens")) {
+        sprintf(errstr,
+        "LIST DURATIONS OF SEVERAL SNDFILING-SYSTEM FILES\n\n"
+        "USAGE: sndreport lens infile [infile2..]\n");
+    } else if(!strcmp(str,"maxi")) {
+        sprintf(errstr,
+        "LIST LEVELS OF SEVERAL SOUNDFILES\n\n"
+//TW UPDATE
+        "USAGE: sndreport maxi infile infile2 [infile3..] outfile\n");
+    } else if(!strcmp(str,"sumlen")) {
+        sprintf(errstr,
+        "SUM DURATIONS OF SEVERAL SNDFILING-SYSTEM FILES\n\n"
+        "USAGE: sndreport sumlen infile infile2 [infile3..] [-ssplicelen]\n\n"
+        "      SPLICELEN is in milliseconds. (Default: 15ms)\n");
+    } else if(!strcmp(str,"timediff")) {
+        sprintf(errstr,
+        "FIND DIFFERENCE IN DURATION OF TWO SOUND FILES\n\n"
+        "USAGE: sndreport timediff infile1 infile2\n");
+    } else if(!strcmp(str,"smptime")) {
+        sprintf(errstr,
+        "CONVERT SAMPLE COUNT TO TIME IN SOUNDFILE\n\n"
+        "USAGE: sndreport smptime infile samplecnt [-g]\n\n"
+        "-g   sample count is count of GROUPED samples\n"
+        "     e.g. stereo file: sample-PAIRS counted.\n");
+    } else if(!strcmp(str,"timesmp")) {
+        sprintf(errstr,
+        "CONVERT TIME TO SAMPLE COUNT IN SOUNDFILE\n\n"
+        "USAGE: sndreport timesmp infile time [-g]\n\n"
+        "-g   sample count is count of GROUPED samples\n"
+        "     e.g. stereo file: sample-PAIRS counted.\n");
+    } else if(!strcmp(str,"maxsamp")) {
+        sprintf(errstr,
+        "FIND MAXIMUM SAMPLE IN SOUNDFILE OR BINARY DATA FILE\n\n"
+        "USAGE: sndreport maxsamp infile [-f]\n"
+        "-f   Force file to be scanned\n"
+        "     (Ignore any header info about max sample)\n");
+    } else if(!strcmp(str,"maxsamp2")) {
+        sprintf(errstr,
+        "FIND MAXIMUM SAMPLE WITHIN TIMERANGE IN SOUNDFILE\n\n"
+        "USAGE: sndreport maxsamp2 infile start end\n\n"
+        "start  starttime of search in file\n"
+        "end    endtime of search in file\n");
+    } else if(!strcmp(str,"loudchan")) {
+        sprintf(errstr,
+        "FIND LOUDEST CHANNEL IN A STEREO SOUNDFILE\n\n"
+        "USAGE: sndreport loudchan infile\n");
+    } else if(!strcmp(str,"findhole")) {
+        sprintf(errstr,
+        "FIND LARGEST LOW LEVEL HOLE IN A SOUNDFILE\n\n"
+        "USAGE: sndreport findhole infile [-tthreshold]\n\n"
+        "THRESHOLD  hole only if level falls and stays below threshold (default: 0).\n");
+    } else if(!strcmp(str,"diff")) {
+        sprintf(errstr,
+        "COMPARE 2 SOUND,ANALYSIS,PITCH,TRANSPOSITION,ENVELOPE OR FORMANT FILES\n\n"
+        "USAGE: sndreport diff infile1 infile2 [-tthreshold] [-ncnt] [-l] [-c]\n\n"
+        "THRESHOLD  max permissible difference in data values:\n"
+        "CNT        MAX NUMBER of differences to accept (default 1).\n"
+        "-l         continue, even if files are not same LENGTH\n"
+        "-c         continue, even if (snd)files don't have same no of CHANNELS\n\n"
+        "This process works with binary (non-text) files only.\n");
+    } else if(!strcmp(str,"chandiff")) {
+        sprintf(errstr,
+        "COMPARE CHANNELS IN A STEREO SOUNDFILE\n\n"
+        "USAGE: sndreport chandiff infile [-tthreshold] [-ncnt]\n\n"
+        "THRESHOLD  max permissible difference in data values.\n"
+        "CNT        MAX NUMBER of differences to accept (default 1).\n"
+        "   NB: The output sample display is counted in sample-pairs.\n");
+    } else if(!strcmp(str,"prntsnd")) {
+        sprintf(errstr,
+        "PRINT SOUND SAMPLE DATA TO A TEXTFILE\n\n"
+        "USAGE: sndreport prntsnd infile outtextfile starttime endtime\n\n"
+        "CARE!!! large quantities of data.\n");
+    } else if(!strcmp(str,"units")) {
+        fprintf(stdout,
+        "CONVERT BETWEEN DIFFERENT UNITS\n\n"
+        "USAGE: sndreport units mode value\n\n"
+        "                           MODES ARE\n\n"
+        "       PITCH                  INTERVAL                       SPEED\n"
+        "       -----                  --------                       -----\n"
+        "(1) MIDI to FRQ   (7)  FRQ RATIO  to SEMITONES (16) FRQ RATIO  to TIME RATIO\n"
+        "(2) FRQ  to MIDI  (8)  FRQ RATIO  to INTERVAL  (17) SEMITONES  to TIME RATIO\n"
+        "(3) NOTE to FRQ   (9)  INTERVAL   to FRQ RATIO (18) OCTAVES    to TIME RATIO\n"
+        "(4) NOTE to MIDI  (10) SEMITONES to FRQ RATIO  (19) INTERVAL   to TIME RATIO\n"
+        "(5) FRQ to NOTE   (11) OCTAVES    to FRQ RATIO (20) TIME RATIO to FRQ RATIO\n"
+        "(6) MIDI to NOTE  (12) OCTAVES   to SEMITONES  (21) TIME RATIO to SEMITONES\n"
+        "                  (13) FRQ RATIO to OCTAVES    (22) TIME RATIO to OCTAVES\n"
+        "                  (14) SEMITONES to OCTAVES    (23) TIME RATIO to INTERVAL\n"
+        "                  (15) SEMITONES to INTERVAL\n"
+        "\n"
+        "                                LOUDNESS\n"
+        "                                --------\n"
+        "                  (24) GAIN FACTOR to DB GAIN\n"
+        "                  (25) DB GAIN     to GAIN FACTOR\n"
+        "\n"
+        "NOTE REPRESENTATION ..... A1 = A in octave 1\n"
+        "                          Ebu4 is E flat,   + (Up) quartertone  in octave 4\n"
+        "                          F#d-2 is F sharp, - (Dn) quartertone, in octave -2\n\n"
+        "INTERVAL REPRESENTATION.. 3 = a 3rd     -m3 = minor 3rd DOWN\n"
+        "                          m3u = minor 3rd + (Up) quartertone\n"
+        "                          #4d = tritone   - (Dn) quartertone\n"
+        "                          15  = a fifteenth (max permissible interval)\n");
+    } else if(!strcmp(str,"zcross")) {
+        sprintf(errstr,
+        "DISPLAY FRACTION OF ZERO-CROSSINGS IN FILE\n\n"
+        "USAGE: sndreport ZCROSS infile [-sstarttime -eendtime]\n");
+    } else
+        sprintf(errstr,"Unknown option '%s'\n",str);
+    return(USAGE_ONLY);
+}
+
+/******************************** USAGE3 ********************************/
+
+int usage3(char *str1,char *str2)
+{
+    if(!strcmp(str1,"props"))           return(CONTINUE);
+    else if(!strcmp(str1,"len"))        return(CONTINUE);
+    else if(!strcmp(str1,"timediff"))   return(CONTINUE);
+    else if(!strcmp(str1,"smptime"))    return(CONTINUE);
+    else if(!strcmp(str1,"timesmp"))    return(CONTINUE);
+    else if(!strcmp(str1,"loudchan"))   return(CONTINUE);
+    else if(!strcmp(str1,"maxsamp"))    return(CONTINUE);
+    else if(!strcmp(str1,"maxsamp2"))   return(CONTINUE);
+    else if(!strcmp(str1,"findhole"))   return(CONTINUE);
+    else if(!strcmp(str1,"chandiff"))   return(CONTINUE);
+    else
+        sprintf(errstr,"Insufficient parameters on command line.\n");
+    return(USAGE_ONLY);
+}
+
+
+/******************************** INNER_LOOP (redundant)  ********************************/
+
+int inner_loop(int *peakscore,int *descnt,int *in_start_portion,int *least,int *pitchcnt,int windows_in_buf,dataptr dz)
+{
+    return(FINISHED);
+}

+ 1490 - 0
dev/sndinfo/compare.c

@@ -0,0 +1,1490 @@
+/*
+ * Copyright (c) 1983-2013 Trevor Wishart and Composers Desktop Project Ltd
+ * http://www.trevorwishart.co.uk
+ * http://www.composersdesktop.com
+ *
+ This file is part of the CDP System.
+
+    The CDP System is free software; you can redistribute it
+    and/or modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    The CDP System is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with the CDP System; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+    02111-1307 USA
+ *
+ */
+
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <structures.h>
+#include <tkglobals.h>
+#include <globcon.h>
+#include <cdpmain.h>
+#include <sndinfo.h>
+#include <processno.h>
+#include <modeno.h>
+#include <pnames.h>
+#include <filetype.h>
+#include <flags.h>
+#include <float.h>
+#include <time.h>
+#include <sfsys.h>
+#include <string.h>
+#include <math.h>
+
+#define SPACECNT    (32)
+
+static int  try_header(int chans,double inverse_sr,dataptr dz);
+static void make_time_display(char temp[],char timestr[],double secs);
+static int  get_and_set_float_maxmina(float *flbuf,dataptr dz);
+static int  get_and_set_float_maxmin(float *buf,int chans, double inverse_sr,dataptr dz);
+
+static int  compare_sndfile_properties(char temp[],dataptr dz);
+static int  compare_analfile_properties(dataptr dz);
+static int  read_both_the_files(int samesize,dataptr dz);
+static int  read_samps_for_cdiff(dataptr dz);
+static void compare_samps(char temp[],int *badmatch,int *limitcnt,double threshold,dataptr dz);
+static void anal_file_time(char temp[],int n,dataptr dz);
+static void snd_file_time(char temp[],int n,dataptr dz);
+static int  sfdiff_process(char temp[],int samesize,dataptr dz);
+static int  compare_infile_sizes(int *same_size,dataptr dz);
+
+static int  do_sfdiff(char temp[],dataptr dz);
+static int  prntprops(SFPROPS *prop, dataptr dz);
+static int  get_float_maxmin(float *buf,int chans, double inverse_sr,dataptr dz);
+/*RWD 6:2001 */
+static int getpeakdata(int ifd, float *peakval,SFPROPS *props);
+
+static int do_zcross_ratio(dataptr dz);
+
+/****************************** DO_SNDINFO ******************************/
+
+int do_sndinfo(dataptr dz)
+{
+    int exit_status;
+    float *flbuf;
+    float *buf;
+    double sr = (double)dz->infile->srate;
+    int chans = dz->infile->channels, maxpos;
+    double other_sr = (double)dz->otherfile->srate;
+    int other_chans = dz->otherfile->channels;
+    double inverse_sr = 1.0, secs;
+    int thisspace, m;
+    float *chanmax;
+    int ftype = dz->infile->filetype;
+    int is_a_text_file = FALSE;
+    int n, k, j;
+    fileptr fptr = dz->infile;
+    char timestr[64];
+    char temp[200];
+    int holesize = 0, holesamp = 0;
+    int maxholesize = 0;
+    int maxholesamp = 0;
+    double maxholelen, maxholetime;
+    double threshold, level = 0.0;
+    int orig_ifd0;
+    SFPROPS props = {0};
+    infileptr ifp;
+    double maxamp, maxloc;
+    int maxrep;
+    int getmax = 0, getmaxinfo = 0;
+
+    if(sr > 0.0)
+        inverse_sr = 1.0/sr;
+    switch(dz->process) {
+
+    case(INFO_TIMESUM):
+        secs = 0.0;
+        for(n=0;n<dz->infilecnt;n++) {
+            secs += (double)(dz->insams[n]/chans) * inverse_sr;
+            secs -= dz->param[TIMESUM_SPLEN] * MS_TO_SECS;
+        }
+        sprintf(errstr,"TOTAL TIME ");
+        make_time_display(temp,timestr,secs);
+        strcat(errstr,timestr);
+        strcat(errstr,"\n");
+        print_outmessage(errstr);
+        break;
+
+    case(INFO_TIMELIST):    
+        if((ifp = (infileptr)malloc(sizeof(struct filedata)))==NULL) {
+            sprintf(errstr,"INSUFFICIENT MEMORY to store data on file.\n");
+            return(MEMORY_ERROR);
+        }
+        secs = (double)(dz->insams[0]/chans) * inverse_sr;
+        sprintf(errstr,"%s",dz->wordstor[0]);
+        thisspace = SPACECNT - strlen(dz->wordstor[0]);
+        thisspace = max(thisspace,2);
+        for(m=0;m<thisspace;m++)
+            strcat(errstr,".");
+        make_time_display(temp,timestr,secs);
+        strcat(errstr,timestr);
+        strcat(errstr,"\n");
+        print_outmessage(errstr);
+//TW UPDATE
+        if(sloom) {
+            sprintf(errstr,"%lf\n",secs);
+            if(fputs(errstr,dz->fp)<0) {
+                sprintf(errstr,"Cannot output data to file\n");
+                return(SYSTEM_ERROR);
+            }
+        }
+
+        for(n=1;n<dz->infilecnt;n++) {
+            if((exit_status = readhead(ifp,dz->ifd[n],dz->wordstor[n],&maxamp,&maxloc,&maxrep,getmax,getmaxinfo))<0) {
+                sprintf(errstr,"Cannot re-read file %d header.\n",n+1);
+                return(PROGRAM_ERROR);
+            }
+            copy_to_fileptr(ifp,dz->infile);
+            secs = (double)(dz->insams[n]/dz->infile->channels)/(double)dz->infile->srate;
+            sprintf(errstr,"%s",dz->wordstor[n]);
+            thisspace = SPACECNT - strlen(dz->wordstor[n]);
+            thisspace = max(thisspace,2);
+            for(m=0;m<thisspace;m++)
+                strcat(errstr,".");
+            make_time_display(temp,timestr,secs);
+            strcat(errstr,timestr);
+            strcat(errstr,"\n");
+            print_outmessage(errstr);
+//TW UPDATE
+            if(sloom) {
+                sprintf(errstr,"%lf\n",secs);
+                if(fputs(errstr,dz->fp)<0) {
+                    sprintf(errstr,"Cannot output data to file\n");
+                    return(SYSTEM_ERROR);
+                }
+            }
+
+        }
+        break;
+    case(INFO_LOUDLIST):    
+        orig_ifd0 = dz->ifd[0];
+        for(m=0;m<dz->infilecnt;m++) {
+            float fmaxamp = 0.0f;       /*RWD 6:2001 */
+            int gotpeak = 0;
+            /*RWD 6:2001 try to read PEAK chunk too! */
+            if(getpeakdata(dz->ifd[m],&fmaxamp,&props)){
+                level = fmaxamp;
+                gotpeak = 1;
+            }
+            
+            else {
+                /* RWD impossible to report int values without lot of hoohaa */
+                /* just look as if its floatsam file, for now */
+                if(sndgetprop(dz->ifd[m],"fmaxamp",(char *)&fmaxamp,sizeof(float)) < 0 ) {
+                    dz->samps_left = dz->insams[m];             
+                    dz->ifd[0] = dz->ifd[m];
+                    while(dz->samps_left) {
+                        if((exit_status = read_samps(dz->bigbuf,dz))<0)
+                            return(exit_status);
+                        for(n=0;n<dz->ssampsread;n++)
+                            fmaxamp = (float)max(fmaxamp,fabs(dz->bigbuf[n]));
+                    }
+                }
+            }
+            if(!gotpeak) /*RWD 6:2001 */                
+                level = (double)fmaxamp/F_MAXSAMP;
+
+            sprintf(errstr,"%s\t",dz->wordstor[m]);
+            sprintf(timestr,"%lf\n",level);
+            strcat(errstr,timestr);
+            print_outmessage(errstr);
+            if(fputs(timestr,dz->fp)<0) {
+                sprintf(errstr,"Cannot output data to file\n");
+                return(SYSTEM_ERROR);
+            }
+            dz->ifd[0] = orig_ifd0;
+        }
+        break;
+
+
+    case(INFO_TIMEDIFF):
+        sprintf(errstr,"DIFFERENCE IS ");
+        secs  = (dz->insams[0]/chans) * inverse_sr;
+        secs -= (dz->insams[1]/other_chans)/other_sr;
+        secs  = fabs(secs);
+        make_time_display(temp,timestr,secs);
+        strcat(errstr,timestr);
+        strcat(errstr,"\n");
+        print_outmessage(errstr);
+        break;
+    
+    case(INFO_SFLEN):
+        switch(dz->infile->filetype) {
+        case(SNDFILE):
+            print_outmessage("A soundfile\n");
+            sprintf(errstr,"DURATION: ");
+            secs = (double)(dz->insams[0]/dz->infile->channels) * inverse_sr;
+            make_time_display(temp,timestr,secs);
+            strcat(errstr,timestr);
+            sprintf(temp,"samples %d\n",dz->insams[0]);
+            strcat(errstr,temp);
+            break;
+        case(ANALFILE):
+            print_outmessage("An analysis data file\n");
+            sprintf(errstr,"DURATION: ");
+            secs = (double)dz->wlength * dz->frametime;
+            make_time_display(temp,timestr,secs);
+            strcat(errstr,timestr);
+            sprintf(temp,"windows %d : floats %d\n",dz->wlength,dz->insams[0]);
+            strcat(errstr,temp);
+            break;
+        case(PITCHFILE):
+            print_outmessage("A binary pitch data file\n");
+            sprintf(errstr,"DURATION: ");
+            secs = (double)dz->insams[0] * dz->frametime;
+            make_time_display(temp,timestr,secs);
+            strcat(errstr,timestr);
+            sprintf(temp,"windows %d : floats %d\n",dz->insams[0],dz->insams[0]);
+            strcat(errstr,temp);
+            break;
+        case(TRANSPOSFILE):
+            print_outmessage("A binary transposition data file\n");
+            sprintf(errstr,"DURATION: ");
+            secs = (double)dz->insams[0] * dz->frametime;
+            make_time_display(temp,timestr,secs);
+            strcat(errstr,timestr);
+            sprintf(temp,"windows %d : floats %d\n",dz->insams[0],dz->insams[0]);
+            strcat(errstr,temp);
+            break;
+        case(ENVFILE):
+            print_outmessage("A binary envelope file\n");
+            sprintf(errstr,"DURATION: ");
+            secs = (double)dz->insams[0] * dz->infile->window_size * MS_TO_SECS;
+            make_time_display(temp,timestr,secs);
+            strcat(errstr,timestr);
+            sprintf(temp,"windows %d : floats %d\n",dz->wlength,dz->insams[0]);
+            strcat(errstr,temp);
+            break;
+        case(FORMANTFILE):
+            print_outmessage("A formant data file\n");
+            sprintf(errstr,"DURATION: ");
+            dz->wlength  = (dz->insams[0]/dz->specenvcnt) - DESCRIPTOR_DATA_BLOKS;
+            secs = (double)dz->wlength * dz->frametime;
+            make_time_display(temp,timestr,secs);
+            strcat(errstr,timestr);
+            n = dz->insams[0] - (dz->specenvcnt * DESCRIPTOR_DATA_BLOKS);
+            sprintf(temp,"windows %d : floats %d\n",dz->wlength,n);
+            strcat(errstr,temp);
+            break;
+        default:
+            sprintf(errstr,"This process only works with soundfiling-system files.\n");
+            return(DATA_ERROR);
+        }
+        print_outmessage(errstr);
+        break;
+
+    case(INFO_LOUDCHAN):
+        if(dz->infile->channels==MONO) {
+            sprintf(errstr,"This program does not works with MONO files.\n");
+            return(GOAL_FAILED);
+        }
+        if((chanmax = (float *)malloc(chans *sizeof(float)))==NULL) {
+            sprintf(errstr,"INSUFFICIENT MEMORY to store channel maximi.\n");
+            return(MEMORY_ERROR);
+        }
+        for(m=0;m<chans;m++)
+            chanmax[m] = 0;
+        while(dz->samps_left) {
+            if((exit_status = read_samps(dz->bigbuf,dz))<0)
+                return(exit_status);
+            for(n=0;n<dz->ssampsread;n+=chans) {
+                for(m=0;m<chans;m++)
+                    chanmax[m] = (float)max(chanmax[m],(float) fabs(dz->bigbuf[n+m]));
+            }
+        }
+        maxpos = 0;
+        for(m=1;m<chans;m++) {
+            if(chanmax[m] > chanmax[maxpos])
+                maxpos = m;
+        }
+        sprintf(errstr,"LOUDEST CHANNEL is %d\n",maxpos+1);                         
+        print_outmessage(errstr);
+        free(chanmax);
+        break;
+
+    case(INFO_SAMPTOTIME):
+        if(!dz->vflag[CHAN_GROUPED])
+            dz->iparam[INFO_SAMPS] /= chans;
+        secs = dz->iparam[INFO_SAMPS] * inverse_sr;
+        make_time_display(temp,timestr,secs);
+        sprintf(errstr,"TIME %s",timestr);
+        strcat(errstr,"\n");
+        print_outmessage(errstr);
+        break;
+
+    case(INFO_TIMETOSAMP):
+        n = round(dz->param[INFO_TIME] * sr);
+        if(!dz->vflag[CHAN_GROUPED])
+            n *= chans;
+        sprintf(errstr,"SAMPLE %d\n",n);
+        print_outmessage(errstr);
+        break;
+
+    case(INFO_PROPS):
+        errstr[0] = ENDOFSTR;
+        switch(ftype) {
+        case(SNDFILE):      
+            sprintf(errstr,"A SOUND file.\n");                  break;
+        case(ANALFILE): 
+            sprintf(errstr,"An ANALYSIS file.\n");              break;
+        case(PITCHFILE):
+            sprintf(errstr,"A binary PITCH file.\n");           break;
+        case(TRANSPOSFILE): 
+            sprintf(errstr,"A binary TRANSPOSITION file.\n");   break;
+        case(FORMANTFILE):
+            sprintf(errstr,"A FORMANT data file.\n");           break;
+        case(ENVFILE):  
+            sprintf(errstr,"A binary ENVELOPE file.\n");        break;
+        default:            
+            if(is_a_textfile_type(ftype))    {
+                sprintf(errstr,"A TEXT data file.\n");              
+                is_a_text_file = TRUE;
+            } else {                                
+                print_outmessage("UNKNOWN input file type.\n");
+                return(FINISHED);
+            }
+            break;
+        }
+        print_outmessage(errstr);
+        if(is_a_text_file) {
+            sprintf(errstr,"Contains %d LINES\n",dz->linecnt);
+            print_outmessage(errstr);
+            sprintf(errstr,"Contains %d WORDS\n",dz->all_words);
+            print_outmessage(errstr);
+            if(ftype==MIXFILE) {
+                sprintf(errstr,"Could be a MIXFILE with output channel cnt %d\n",dz->out_chans);
+                print_outmessage(errstr);
+            } else if(ftype==SYNCLIST) {
+                sprintf(errstr,"Could be a LIST OF SOUNDFILES TO SYNCHRONISE.\n");
+                print_outmessage(errstr);
+            } else if(ftype==SNDLIST) {
+                sprintf(errstr,"Could be a LIST OF SOUNDFILES.\n");
+                print_outmessage(errstr);
+            }
+            if(dz->tempsize >0 || (dz->extrabrkno >= 0  && dz->brksize[dz->extrabrkno] > 0)) {
+                sprintf(errstr,"Could be a BREAKPOINT FILE:\n");
+                print_outmessage(errstr);
+                sprintf(errstr,"length %d minval %lf maxval %lf  duration %lf\n",
+                    dz->numsize/2,dz->minbrk,dz->maxbrk,dz->duration);
+                print_outmessage(errstr);
+            }
+            if(dz->numsize > 0) {
+                sprintf(errstr,"Could be a NUMBER LIST:\n");
+                print_outmessage(errstr);
+                sprintf(errstr,"length %d minval %lf maxval %lf\n",dz->numsize,dz->minnum,dz->maxnum);
+                print_outmessage(errstr);
+            }
+        } else {
+            sprintf(errstr,"samples: ............ %d\n",dz->insams[0]);
+            print_outmessage(errstr);
+            if(ftype!=SNDFILE) {
+                switch(ftype) {
+                case(ANALFILE): 
+                    sprintf(errstr,"file type: .......... ANALYSIS DATA\n");                break;
+                case(PITCHFILE):
+                    sprintf(errstr,"file type: .......... PITCH DATA (binary)\n");          break;
+                case(TRANSPOSFILE): 
+                    sprintf(errstr,"file type: .......... TRANSPOSITION DATA (binary)\n");  break;
+                case(FORMANTFILE):
+                    sprintf(errstr,"file type: .......... FORMANT DATA (binary)\n");        break;
+                case(ENVFILE):  
+                    sprintf(errstr,"file type: .......... ENVELOPE DATA (binary)\n");       break;
+                }
+                print_outmessage(errstr);
+//TW UPDATE: moved srate & chans, as ENVFILES have srate and channels
+                sprintf(errstr,"sample rate: ........ %d\n",fptr->srate);
+                print_outmessage(errstr);
+                sprintf(errstr,"channels: ........... %d\n",fptr->channels);
+                print_outmessage(errstr);
+                if(fptr->filetype==ENVFILE) {
+                    sprintf(errstr,"window size: ........ %f ms\n",fptr->window_size);
+                    print_outmessage(errstr);
+                    return(FINISHED);               
+                }
+                if(fptr->filetype==FORMANTFILE) {
+                    sprintf(errstr,"formant envelope cnt: %d\n",fptr->specenvcnt);
+                    print_outmessage(errstr);
+                }
+                /*RWD*/
+//TW NOW REDUNDANT: flagging changed
+//              if(fptr->filetype!=SNDFILE){
+                sprintf(errstr,"original sampsize: .. %d\n",fptr->origstype);
+                print_outmessage(errstr);
+                sprintf(errstr,"original sample rate: %d\n",fptr->origrate);
+                print_outmessage(errstr);
+                sprintf(errstr,"analysis rate: ...... %f\n",fptr->arate);
+                print_outmessage(errstr);
+                sprintf(errstr,"analysis window len:  %d\n",fptr->Mlen);
+                print_outmessage(errstr);
+                sprintf(errstr,"decimation factor: .. %d\n",fptr->Dfac);
+                print_outmessage(errstr);
+//              }
+                if(fptr->filetype==PITCHFILE || fptr->filetype==TRANSPOSFILE) {
+                    sprintf(errstr,"original channels: .. %d\n",fptr->origchans);
+                    print_outmessage(errstr);
+                }
+            } else {
+                sprintf(errstr,"file type: ........... SOUND\n");
+                print_outmessage(errstr);
+                sprintf(errstr,"sample rate: ........ %d\n",fptr->srate);
+                print_outmessage(errstr);
+                sprintf(errstr,"channels: ........... %d\n",fptr->channels);
+                print_outmessage(errstr);
+            }
+            if((exit_status = prntprops(&props,dz))<0)
+                return(exit_status);
+        }
+        break;
+    case(INFO_MAXSAMP):
+        if(is_a_text_input_filetype(dz->infile->filetype)) {
+            sprintf(errstr,"This is a text file.\n");
+            return(GOAL_FAILED);
+        }
+        /* RWD 2022 this hangs if user supplies anal file */
+        if(dz->infile->filetype == ANALFILE){
+            sprintf(errstr,"This is an anlysis file.\n");
+            return(GOAL_FAILED);
+        }
+        flbuf = (float *)dz->bigbuf;
+        buf   = dz->bigbuf;
+        if(!dz->vflag[FORCE_SCAN] && try_header(chans,inverse_sr,dz)==FINISHED)
+            break;
+        else {
+            if(dz->infile->filetype != SNDFILE)  {
+                if((exit_status = get_and_set_float_maxmina(flbuf,dz))<0)
+                        return(exit_status);                                
+            } else {
+                if((exit_status = get_and_set_float_maxmin(buf,chans,inverse_sr,dz))<0)
+                    return(exit_status);
+            }
+        }
+        break;
+    case(INFO_MAXSAMP2):
+        buf   = dz->bigbuf;
+        if((exit_status = get_float_maxmin(buf,chans,inverse_sr,dz))<0)
+            return(exit_status);
+        break;
+    
+    case(INFO_PRNTSND):
+        dz->ssampsread = 0;
+        dz->iparam[PRNT_START] = round(dz->param[PRNT_START] * sr) * chans;
+        dz->iparam[PRNT_END]   = round(dz->param[PRNT_END] * sr)  * chans;
+        if(dz->iparam[PRNT_START] >= dz->iparam[PRNT_END]) {
+            sprintf(errstr,"Incompatible start and end times.\n");
+            return(DATA_ERROR);
+        }
+        if(dz->iparam[PRNT_START] >= dz->insams[0]) {
+            sprintf(errstr,"Start time is at end of file: can't proceed.\n");
+            return(DATA_ERROR);
+        }
+        
+        dz->total_samps_read = 0;
+        for(;;) {
+            if((exit_status = read_samps(dz->bigbuf,dz))<0)
+                return(exit_status);
+            if(dz->iparam[PRNT_START] > dz->ssampsread) {
+                dz->iparam[PRNT_START] -= dz->ssampsread;
+                dz->iparam[PRNT_END]   -= dz->ssampsread;
+            } else
+                break;
+        }
+        k = 0;
+        j = (dz->total_samps_read - dz->ssampsread + dz->iparam[PRNT_START])/chans;
+        display_virtual_time(0L,dz);
+        for(n=dz->iparam[PRNT_START];n<dz->iparam[PRNT_END];n+=chans,k+=chans,j++) {
+            fprintf(dz->fp,"[%d]\t",j);
+            for(m=0;m<chans;m++)
+                fprintf(dz->fp,"%.6f\t",(float) dz->bigbuf[n+m]);               /*RWD 12:2003 was %d */
+            fprintf(dz->fp,"\n");
+            if(n >= dz->ssampsread) {
+                if((exit_status = read_samps(dz->bigbuf,dz))<0)
+                    return(exit_status);
+//TW CHANGED to samps
+                display_virtual_time(k,dz);
+                dz->iparam[PRNT_END] -= dz->ssampsread;
+                n = 0;
+            }
+        }
+//TW CHANGED to samps
+        display_virtual_time(k,dz);
+        break;
+    case(INFO_FINDHOLE):
+        threshold = dz->param[HOLE_THRESH] * (double)F_MAXSAMP;
+        while(dz->samps_left) {
+            if((exit_status = read_samps(dz->bigbuf,dz))<0)
+                return(exit_status);
+            for(n = 0; n < dz->ssampsread; n++)  {
+                if(holesize==0) {
+                    if(fabs(dz->bigbuf[n])<threshold) {
+                        holesize = 1;
+                        holesamp = dz->total_samps_read - dz->ssampsread + n;
+                    }
+                } else {
+                    if(fabs(dz->bigbuf[n])<threshold)
+                        holesize++;
+                    else {
+                        if(holesize > maxholesize) {
+                            maxholesize = holesize;
+                            maxholesamp = holesamp;
+                        }
+                        holesize = 0;
+                    }
+                }
+            }
+        }
+        maxholelen  = (double)(maxholesize/chans) * inverse_sr;
+        maxholetime = (double)(maxholesamp/chans) * inverse_sr;
+        sprintf(errstr,"Maximum holesize is %.6lf at time %.6lf\n",maxholelen,maxholetime);
+        print_outmessage(errstr);
+        break;
+    case(INFO_CDIFF):
+    case(INFO_DIFF):
+        if((exit_status = do_sfdiff(temp,dz))<0)
+            return(exit_status);
+        break;
+    case(ZCROSS_RATIO):
+        if((exit_status = do_zcross_ratio(dz))<0)
+            return(exit_status);
+        break;
+    default:
+        sprintf(errstr,"Unknown process in do_sndinfo()\n");
+        return(PROGRAM_ERROR);
+    }
+    fflush(stdout);
+    return(FINISHED);
+}
+
+/************************** TRY_HEADER ************************/
+
+int try_header(int chans,double inverse_sr,dataptr dz)
+{
+    int pos_repeats, neg_repeats, repeats, maxloc, maxamp = -1;
+    float maxpfamp, maxnfamp;
+    double gain, dbgain;
+    float newmaxamp = 0.0f;
+    if(dz->infile->filetype != SNDFILE) {
+//TW SUBSTITUTED SNDgetprop
+        if( sndgetprop(dz->ifd[0],"maxpfamp",(char *)&maxpfamp,sizeof(float)) < 0 )
+            return(CONTINUE);
+        if( sndgetprop(dz->ifd[0],"maxnfamp",(char *)&maxnfamp,sizeof(float)) < 0 )
+            return(CONTINUE);
+        if(sndgetprop(dz->ifd[0],"maxprep",(char *)&pos_repeats,sizeof(float)) < 0 )
+            return(CONTINUE);
+        if(sndgetprop(dz->ifd[0],"maxnrep",(char *)&neg_repeats,sizeof(int)) < 0 )
+            return(CONTINUE);
+        sprintf(errstr,"maximum float value: %f\n",maxpfamp);
+        print_outmessage(errstr);
+        sprintf(errstr,"occurs: ............ %d times\n",pos_repeats);
+        print_outmessage(errstr);
+        sprintf(errstr,"minimum float value: %f\n",maxnfamp);
+        print_outmessage(errstr);
+        sprintf(errstr,"occurs: ............ %d times\n",neg_repeats);
+        print_outmessage(errstr);
+    } else {
+        if( sndgetprop(dz->ifd[0],"maxamp",(char *)&maxamp,sizeof(int)) < 0         /* old files */
+        &&  sndgetprop(dz->ifd[0],"maxpfamp",(char *)&newmaxamp,sizeof(float)) < 0) /* new files */
+            return(CONTINUE);
+        if( sndgetprop(dz->ifd[0],"maxloc",(char *)&maxloc,sizeof(int)) < 0 )
+            return(CONTINUE);
+        if( sndgetprop(dz->ifd[0],"maxrep",(char *)&repeats,sizeof(int)) < 0 )
+            return(CONTINUE);
+        if(maxamp>=0)
+            newmaxamp = (float)(maxamp/(double)MAXSAMP);
+        sprintf(errstr,"maximum abs value:.. %f\n",newmaxamp);
+        print_outmessage(errstr);
+        sprintf(errstr,"at: ................ %d samples\n",maxloc);
+        print_outmessage(errstr);
+        sprintf(errstr,"time: .............. %.4lf secs\n",(double)(maxloc/chans) *inverse_sr);
+        print_outmessage(errstr);
+        sprintf(errstr,"repeated: .......... %d times\n",repeats);
+        print_outmessage(errstr);
+        if(newmaxamp>=0.0) {
+            gain   = 1.0/(double)maxamp;
+            dbgain = log10(gain) * 20.0;
+            sprintf(errstr,"max possible gain:.. %.4lf\n",gain);
+            print_outmessage(errstr);
+            sprintf(errstr,"max dB gain:........ %.4lf\n",dbgain);
+            print_outmessage(errstr);
+        }
+    }
+    return(FINISHED);
+}
+
+/************************** MAKE_TIME_DISPLAY ************************/
+
+void make_time_display(char temp[],char timestr[],double secs)
+{
+    int mins = 0, hrs = 0;
+    if(secs > 60.0) {
+        mins  = round(floor(secs/60.0));
+        secs -= (double)(mins * 60);
+    }
+    if(mins > 60) {
+        hrs   = round(floor((double)mins/60.0));
+        mins -= hrs * 60;
+    }           
+    timestr[0] = ENDOFSTR;
+    if(hrs) {       
+        sprintf(temp,"%d hrs ",hrs);
+        strcat(timestr,temp);
+    }
+    if(mins) {
+        sprintf(temp,"%d mins ",mins);
+        strcat(timestr,temp);
+    }
+    sprintf(temp,"%.6lf secs ",secs);
+    strcat(timestr,temp);
+}
+
+/************************** GET_AND_SET_FLOAT_MAXMIN ************************/
+/* RWD assumes analysis ?*/
+int get_and_set_float_maxmina(float *flbuf,dataptr dz)
+{
+    int exit_status;
+    double maxpdamp = DBL_MIN;
+    double maxndamp = DBL_MAX;
+    float maxpfamp, maxnfamp;
+    int   maxprep = 1, maxnrep = 1;
+    int n;
+    dz->samps_left = dz->insams[0];
+    if(sndseekEx(dz->ifd[0],0,0)<0) {
+        sprintf(errstr,"sndseek() failed. get_and_set_float_maxmin()\n");
+        return(SYSTEM_ERROR);
+    }
+    while(dz->samps_left > 0) {
+        if((exit_status = read_samps(flbuf,dz))<0)
+            return(exit_status);
+        for(n=0;n<dz->ssampsread;n++) {
+            if(flbuf[n] < maxpdamp)     /* IF < max, ignore */
+                ; 
+            else if(flbuf[n] > maxpdamp) {  
+                maxpdamp = flbuf[n];    /* IF > max, reset max and count */
+                maxprep  = 1;
+            } else                      /* else must be EQUAL to max; incr counter */
+                maxprep++;
+    
+            if(flbuf[n] > maxndamp)
+                ; 
+            else if(flbuf[n] < maxndamp) {
+                maxndamp = flbuf[n];
+                maxnrep  = 1;
+            } else
+                maxnrep++;
+        }
+    }
+    maxpfamp = (float)maxpdamp;
+    maxnfamp = (float)maxndamp;
+//TW cannot reset header of a read-in file
+//  if( sndputprop(dz->ifd[0],"maxpfamp",(char *)&maxpfamp,sizeof(float)) < 0 )
+//      fprintf(stdout,"WARNING: Cannot write maximum float value to header\n");
+//  if(sndputprop(dz->ifd[0],"maxprep",(char *)&maxprep,sizeof(long)) < 0 )
+//      fprintf(stdout,"WARNING: Cannot write maxfloat repeats-count to header\n");
+//  if( sndputprop(dz->ifd[0],"maxnfamp",(char *)&maxnfamp,sizeof(float)) < 0 )
+//      fprintf(stdout,"WARNING: Cannot write mimimum float value to header\n");
+//  if(sndputprop(dz->ifd[0],"maxnrep",(char *)&maxnrep,sizeof(long)) < 0 )
+//      fprintf(stdout,"WARNING: Cannot write minfloat repeats-count to header\n");
+
+    sprintf(errstr,"maximum float value: %f\n",maxpfamp);
+    print_outmessage(errstr);
+    sprintf(errstr,"occurs: ...........  %d times\n",maxprep);
+    print_outmessage(errstr);
+    sprintf(errstr,"minimum float value: %f\n",maxnfamp);
+    print_outmessage(errstr);
+    sprintf(errstr,"occurs: ...........  %d times\n",maxnrep);
+    print_outmessage(errstr);
+    return(FINISHED);
+}
+
+/************************** GET_AND_SET_SHORT_MAXMIN ************************/
+
+int get_and_set_float_maxmin(float *buf,int chans, double inverse_sr,dataptr dz)
+{
+    int exit_status;
+    /*int maxamp = MINSAMP, mag;*/
+    float maxamp = F_MINSAMP, mag;
+    int maxloc = 0;
+    int maxrep = 1;
+    int n;
+    double gain = 0.0, dbgain = 0.0;
+    while(dz->samps_left) {
+        if((exit_status = read_samps(buf,dz))<0)
+            return(exit_status);
+        for(n=0;n<dz->ssampsread;n++) {
+            mag = (float) fabs(buf[n]);
+            if(mag > maxamp) {
+                maxloc = dz->total_samps_read - dz->ssampsread + n;
+                maxamp = mag;
+                maxrep = 1;
+            } else if(mag==maxamp)
+                maxrep++;
+        }
+    }
+//TW Cannot alter heqader of an input file
+//  if(sndputprop(dz->ifd[0],"maxamp",(char *)&maxamp,sizeof(float)) < 0 )
+//  if(sndputprop(dz->ifd[0],"maxpfamp",(char *)&maxamp,sizeof(float)) < 0 )
+//      fprintf(stdout,"WARNING: Cannot write maximum value to header.\n");
+//  if(sndputprop(dz->ifd[0],"maxloc",(char *)&maxloc,sizeof(long)) < 0 )
+//      fprintf(stdout,"WARNING: Cannot write location of maximum value to header.\n");
+//  if(sndputprop(dz->ifd[0],"maxrep",(char *)&maxrep,sizeof(long)) < 0 )
+//      fprintf(stdout,"WARNING: Cannot write maximum repeats to header.\n");
+
+    if(maxamp>0.0f) {
+        gain   = F_MAXSAMP/(double)maxamp;
+        dbgain = log10(gain) * 20.0;
+    }
+    sprintf(errstr,"maximum abs value:.. %f\n",maxamp);
+    print_outmessage(errstr);
+    sprintf(errstr,"at: ................ %d samples\n",maxloc);
+    print_outmessage(errstr);
+    sprintf(errstr,"time: .............. %.4lf secs\n",(double)(maxloc/chans) *inverse_sr);
+    print_outmessage(errstr);
+    sprintf(errstr,"repeated: .......... %d times\n",maxrep);
+    print_outmessage(errstr);
+    if(maxamp>0.0f) {
+        sprintf(errstr,"max possible gain:.. %.4lf\n",gain);
+        print_outmessage(errstr);
+        sprintf(errstr,"max dB gain:........ %.4lf\n",dbgain);
+        print_outmessage(errstr);
+    }
+    return(FINISHED);
+}
+
+/************************ COMPARE_INFILE_SIZES ***********************/
+
+int compare_infile_sizes(int *samesize,dataptr dz)
+{   
+    if(dz->insams[0] != dz->insams[1]) {
+        print_outmessage_flush("Files are not same size.\n");
+        if(!dz->vflag[IGNORE_LENDIFF])
+            return(FINISHED);
+        else {
+            dz->insams[0] = min(dz->insams[0],dz->insams[1]);
+            *samesize = FALSE;  
+        }
+    }
+    dz->samps_left = dz->insams[0];
+    return(CONTINUE);
+}
+
+/************************** COMPARE_SNDFILE_PROPERTIES *********************/
+
+int compare_sndfile_properties(char temp[],dataptr dz)
+{
+    errstr[0] = ENDOFSTR;
+    if(dz->infile->srate != dz->otherfile->srate) {
+        sprintf(errstr,"Files don't have same sample rate.\n");
+        return(FINISHED);
+    }
+    if(dz->infile->channels != dz->otherfile->channels) {
+        sprintf(errstr,"Files don't have same number of channels. ");
+        if(dz->vflag[IGNORE_CHANDIFF]) {
+            sprintf(temp,"1st has %d : 2nd has %d\n",dz->infile->channels,dz->otherfile->channels);
+            strcat(errstr,temp);
+        } else {
+            strcat(errstr,"\n");
+            return(FINISHED);
+        }
+        print_outmessage(errstr);
+    }
+    return(CONTINUE);
+}
+
+/*************************** SFDIFF_PROCESS **************************/
+
+int sfdiff_process(char temp[],int samesize,dataptr dz)
+{
+    int exit_status;
+    int limitcnt = 0, badmatch = 0;
+    double threshold = dz->param[SFDIFF_THRESH] /* * (double)MAXSAMP*/;
+
+    display_virtual_time(0L,dz);
+    if(sndseekEx(dz->ifd[0],0,0)<0) {
+        sprintf(errstr,"sndseekEx() problem in sfdiff_process()\n");
+        return(SYSTEM_ERROR);
+    }
+    if(dz->process==INFO_DIFF && sndseekEx(dz->ifd[1],0,0)<0) {
+        sprintf(errstr,"sndseekEx() problem 2 in sfdiff_process()\n");
+        return(SYSTEM_ERROR);
+    }
+    while(dz->samps_left > 0) {
+        if(dz->process==INFO_CDIFF) {
+            if((exit_status = read_samps_for_cdiff(dz))<0)
+                return(exit_status);
+        } else {
+            if((exit_status = read_both_the_files(samesize,dz))<0)
+                return(exit_status);
+        }
+        compare_samps(temp,&badmatch,&limitcnt,threshold,dz);
+        display_virtual_time(dz->total_samps_read,dz);
+        fflush(stdout);
+    }
+    if(limitcnt == 0) {
+        if(dz->process==INFO_CDIFF)
+            sprintf(errstr,"Channels are IDENTICAL");
+        else {
+            if(samesize)
+                sprintf(errstr,"Files are IDENTICAL");
+            else
+                sprintf(errstr,"Files are otherwise IDENTICAL");
+        }
+        if(dz->process==INFO_CDIFF) {
+            if(dz->param[SFDIFF_THRESH] > 0) {
+                sprintf(temp," to within %lf\n",dz->param[SFDIFF_THRESH]);
+                strcat(errstr,temp);
+            }else 
+                strcat(errstr,"\n");
+        } else {
+            switch(dz->infile->filetype) {
+            case(SNDFILE):
+                if(dz->param[SFDIFF_THRESH] > 0) {
+                    sprintf(temp," to within %lf\n",dz->param[SFDIFF_THRESH]);
+                    strcat(errstr,temp);
+                } else 
+                    strcat(errstr,"\n");
+                break;
+            default:
+                if(dz->param[SFDIFF_THRESH] > 0.0) {
+                    sprintf(temp," to within %lf\n",dz->param[SFDIFF_THRESH]);
+                    strcat(errstr,temp);
+                } else
+                    strcat(errstr,"\n");
+                break;
+            }
+        }
+
+    } else if(badmatch) {
+        if(limitcnt < dz->iparam[SFDIFF_CNT])
+            strcat(errstr," : as far as end of file.\n");
+        else
+            strcat(errstr," : comparison stopped here.\n");
+    }
+    return(FINISHED);
+}
+
+/************************ READ_BOTH_THE_FILES *******************************/
+
+int read_both_the_files(int samesize,dataptr dz)
+{   
+    int samps_read2;
+    if((dz->ssampsread = fgetfbufEx(dz->sampbuf[0], /*dz->bigbufsize*/dz->buflen,dz->ifd[0],0)) < 0) {
+        sprintf(errstr, "Can't read samps from 1st soundfile\n");
+        return(SYSTEM_ERROR);
+    }
+    if((samps_read2 = fgetfbufEx(dz->sampbuf[1], dz->buflen,dz->ifd[1],0)) < 0) {
+        sprintf(errstr, "Can't read samps from 2nd soundfile\n");
+        return(SYSTEM_ERROR);
+    }
+    if((dz->ssampsread != samps_read2)) {
+        if(samesize) {
+            sprintf(errstr, "Anomaly in soundfile read.\n");
+            return(PROGRAM_ERROR);
+        } else
+            dz->ssampsread = min(dz->ssampsread,samps_read2);
+    }
+    dz->total_samps_read += dz->ssampsread;
+    dz->samps_left       -= dz->ssampsread;
+    return(FINISHED);
+}
+
+/************************ READ_SAMPS_FOR_CDIFF *******************************/
+
+int read_samps_for_cdiff(dataptr dz)
+{   
+    int n, m;
+    if((dz->ssampsread = fgetfbufEx(dz->sampbuf[2], dz->buflen * 2,dz->ifd[0],0)) < 0) {
+        sprintf(errstr, "Can't read samples from soundfile\n");
+        return(SYSTEM_ERROR);
+    }
+    
+    for(n=0,m=0;m<dz->ssampsread;n++,m+=2) {
+        dz->sampbuf[0][n] = dz->sampbuf[2][m];
+        dz->sampbuf[1][n] = dz->sampbuf[2][m+1];
+    }
+    dz->total_samps_read += dz->ssampsread;
+    dz->samps_left       -= dz->ssampsread;
+    return(FINISHED);
+}
+
+/**************************** COMPARE_SAMPS ***************************/
+
+void compare_samps(char temp[],int *badmatch,int *limitcnt,double threshold,dataptr dz)
+{   
+    int   n;
+    int   sampsread = dz->ssampsread;
+    switch(dz->infile->filetype) {
+    case(SNDFILE):
+        if(dz->process==INFO_CDIFF)
+            sampsread /= STEREO;
+        for(n=0;n<sampsread;n++) {
+            if(fabs(dz->sampbuf[0][n]-dz->sampbuf[1][n]) > threshold) { 
+                if(*badmatch==0) {
+                    sprintf(errstr,"Badmatch from ");
+                    snd_file_time(temp,n,dz);
+                    *badmatch = 1;
+                    if(++(*limitcnt) >= dz->iparam[SFDIFF_CNT]) {
+                        dz->samps_left = 0;  /* force calling loop to end */
+                        return;
+                    }
+                }
+            } else {
+                if(*badmatch) {
+                    strcat(errstr," as far as ");
+                    snd_file_time(temp,n,dz);
+                    strcat(errstr,"\n");
+                    print_outmessage(errstr);
+                    *badmatch = 0;
+                }
+            }
+        }
+        break;
+    case(ANALFILE):
+        dz->ssampsread = sampsread;
+        for(n=0;n<dz->ssampsread;n+=2) {
+            if(fabs(dz->flbufptr[0][n]-dz->flbufptr[1][n]) > threshold) {   
+                if(*badmatch==0) {
+                    sprintf(errstr,"Bad frq match from ");
+                    anal_file_time(temp,n,dz);
+                    *badmatch = 1;
+                    if(++(*limitcnt) >= dz->iparam[SFDIFF_CNT]) {
+                        dz->samps_left = 0;
+                        return;
+                    }
+                }
+            } else {
+                if(*badmatch) {
+                    strcat(errstr," as far as ");
+                    anal_file_time(temp,n,dz);
+                    strcat(errstr,"\n");
+                    print_outmessage(errstr);
+                    *badmatch = 0;
+                }
+            }
+        }       
+        if(*badmatch) {
+            strcat(errstr," as far as ");
+            anal_file_time(temp,n,dz);
+            strcat(errstr,"\n");
+            print_outmessage(errstr);
+            *badmatch = 0;
+        }
+        for(n=1;n<dz->ssampsread;n+=2) {
+            if(fabs(dz->flbufptr[0][n]-dz->flbufptr[1][n]) > threshold) {   
+                if(*badmatch==0) {
+                    sprintf(errstr,"Bad amp match from ");
+                    anal_file_time(temp,n,dz);
+                    *badmatch = 1;
+                    if(++(*limitcnt) >= dz->iparam[SFDIFF_CNT]) {
+                        dz->samps_left = 0;
+                        return;
+                    }
+                }
+            } else {
+                if(*badmatch) {
+                    strcat(errstr," as far as ");
+                    anal_file_time(temp,n,dz);
+                    strcat(errstr,"\n");
+                    print_outmessage(errstr);
+                    *badmatch = 0;
+                }
+            }
+        }       
+        if(*badmatch) {
+            strcat(errstr," to buffer end ");
+            anal_file_time(temp,n,dz);
+            strcat(errstr,"\n");
+            print_outmessage(errstr);
+            *badmatch = 0;
+        }
+        break;
+    default:    /* float files */
+        dz->ssampsread = sampsread;
+        for(n=0;n<dz->ssampsread;n++) {
+            if(fabs(dz->flbufptr[0][n]-dz->flbufptr[1][n]) > threshold) {   
+                if(*badmatch==0) {
+                    sprintf(errstr,"Badmatch from ");
+                    anal_file_time(temp,n,dz);
+                    *badmatch = 1;
+                    if(++(*limitcnt) >= dz->iparam[SFDIFF_CNT]) {
+                        dz->samps_left = 0;
+                        return;
+                    }
+                }
+            } else {
+                if(*badmatch) {
+                    strcat(errstr," as far as ");
+                    anal_file_time(temp,n,dz);
+                    strcat(errstr,"\n");
+                    print_outmessage(errstr);
+                    *badmatch = 0;
+                }
+            }
+        }       
+        break;
+    }
+}
+
+/***************************** ANAL_FILE_TIME *************************/
+
+void anal_file_time(char temp[],int n,dataptr dz)
+{   
+    int this_channel;
+    double this_time;
+    int  wanted;
+    int this_sample = (dz->total_samps_read - dz->ssampsread) + n;
+    int this_window;
+    switch(dz->infile->filetype) {
+    case(ANALFILE):
+        wanted = dz->infile->Mlen + 2;
+        this_window  = this_sample/wanted;   /* TRUNCATE */
+        this_sample  = this_sample%wanted;   /* sample count from window base */
+        this_channel = this_sample/2;
+        this_time    = (double)this_window/(double)dz->infile->arate;
+        sprintf(temp,"  channel %d: window %d: time %.4lf ",this_channel,this_window,this_time);
+        break;
+    case(PITCHFILE):
+    case(TRANSPOSFILE):
+        this_window = this_sample;
+        this_time   = (double)this_window/(double)dz->infile->arate;
+        sprintf(temp,"  window %d: time %.4lf ",this_window,this_time);
+        break;
+    case(ENVFILE):
+        this_window = this_sample;
+        this_time   = (double)this_window * dz->infile->window_size * MS_TO_SECS;
+        sprintf(temp,"  window %d: time %.4lf ",this_window,this_time);
+        break;
+    case(FORMANTFILE):
+        this_sample -= dz->specenvcnt * DESCRIPTOR_DATA_BLOKS;
+        this_window  = this_sample/dz->specenvcnt; /* TRUNCATE */
+        this_channel = this_sample%dz->specenvcnt;
+        this_time   = (double)this_window/(double)dz->infile->arate;
+        sprintf(temp,"  channel %d: window %d: time %.4lf ",this_channel,this_window,this_time);
+        break;
+    }
+    strcat(errstr,temp);
+}
+
+/**************************** SND_FILE_TIME ***************************/
+
+void snd_file_time(char temp [],int n,dataptr dz)
+{   
+    int   this_sample;
+    double this_time, sr = (double)dz->infile->srate;
+    if(dz->process==INFO_CDIFF) {
+        this_sample = ((dz->total_samps_read - dz->ssampsread)/STEREO) + n;
+        this_time   = (double)this_sample/sr;
+    } else {
+        this_sample = (dz->total_samps_read - dz->ssampsread) + n;
+        this_time   = (double)this_sample/(sr * (double)dz->infile->channels);
+    }
+    sprintf(temp,"sample %d: time %.4lf ",this_sample,this_time);
+    strcat(errstr,temp);
+}
+
+/**************************** COMPARE_ANALFILE_PROPERTIES ***************************/
+
+int compare_analfile_properties(dataptr dz)
+{
+    errstr[0] = ENDOFSTR;
+    switch(dz->infile->filetype) {
+    case(ENVFILE):
+        if(dz->infile->window_size != dz->otherfile->window_size) {
+            sprintf(errstr,"Files do not have same WINDOW_SIZE.\n");
+            return(FINISHED);
+        }
+        break;
+    case(FORMANTFILE):
+        if(dz->infile->specenvcnt != dz->otherfile->specenvcnt) {
+            sprintf(errstr,"Files do not have same FORMANT WINDOW CNT.\n");
+            return(FINISHED);
+        }
+        break;
+    case(PITCHFILE):
+    case(TRANSPOSFILE):
+        if(dz->infile->origchans != dz->otherfile->origchans) {
+            sprintf(errstr,"Files do not have same ORIGINAL NO. OF CHANNELS.\n");
+            return(FINISHED);
+        }
+        break;
+    }
+    if(dz->infile->stype != dz->otherfile->stype) {
+        sprintf(errstr,"Files do not have same SAMPLE TYPE.\n");
+        return(FINISHED);
+    }
+    if(dz->infile->srate != dz->otherfile->srate) {
+        sprintf(errstr,"Files do not have same SAMPLING RATE.\n");
+        return(FINISHED);
+    }
+    if(dz->infile->channels != dz->otherfile->channels) {
+        sprintf(errstr,"Files do not have same NO. OF CHANNELS.\n");
+        return(FINISHED);
+    }
+    if(dz->infile->filetype!=ENVFILE) {
+        if(dz->infile->origstype != dz->otherfile->origstype) {
+            sprintf(errstr,"Files do not have same ORIGINAL SAMPLE TYPE.\n");
+            return(FINISHED);
+        }
+        if(dz->infile->origrate != dz->otherfile->origrate) {
+            sprintf(errstr,"Files do not have same ORIGINAL SAMPLING RATE.\n");
+            return(FINISHED);
+        }
+        if(dz->infile->arate != dz->otherfile->arate) {
+            sprintf(errstr,"Files do not have same ANALYSIS RATE.\n");
+            return(FINISHED);
+        }
+        if(dz->infile->Mlen != dz->otherfile->Mlen) {
+            sprintf(errstr,"Files do not have same ANALYSIS WINDOW LENGTH.\n");
+            return(FINISHED);
+        }
+        if(dz->infile->Dfac != dz->otherfile->Dfac) {
+            sprintf(errstr,"Files do not have same DECIMATION FACTOR.\n");  
+            return(FINISHED);   
+        }
+    }
+    return(CONTINUE);
+}
+
+/********************************* DO_SFDIFF ***********************************/
+
+int do_sfdiff(char temp[],dataptr dz)
+{
+    int exit_status;
+    int samesize = TRUE;
+
+    switch(dz->process) {
+    case(INFO_CDIFF):
+        if(dz->infile->channels!=2) {
+            sprintf(errstr,"Process only works with STEREO files.\n");
+            return(DATA_ERROR);
+        }
+        break;
+    default:
+        if(is_a_text_input_filetype(dz->infile->filetype)
+        || is_a_text_input_filetype(dz->otherfile->filetype)) {
+            sprintf(errstr,"Program only works with soundfiling system files.\n");
+            return(DATA_ERROR);
+        }
+        if(dz->infile->filetype != dz->otherfile->filetype) {
+            print_outmessage_flush("Files are not of the same type.\n");
+            return(FINISHED);
+        }
+        if(compare_infile_sizes(&samesize,dz)!=CONTINUE)
+            return(FINISHED);
+
+        switch(dz->infile->filetype) {      
+        case(SNDFILE):
+            if(compare_sndfile_properties(temp,dz)!=CONTINUE) {
+                print_outmessage_flush(errstr);
+                return(FINISHED);
+            }
+            break; 
+        default:
+            if(compare_analfile_properties(dz)!=CONTINUE) {
+                print_outmessage_flush(errstr);
+                return(FINISHED);
+            }
+            dz->flbufptr[0] = dz->sampbuf[0];
+            dz->flbufptr[1] = dz->sampbuf[1];
+            break;
+        }
+        break; 
+    }
+    if((exit_status = sfdiff_process(temp,samesize,dz))<0)
+        return(exit_status);
+
+    print_outmessage_flush(errstr);
+    return(FINISHED);
+}
+
+/********************************* PRNTPROPS ***********************************/
+/* RWD much adapted to report PEAK data if available */
+int prntprops(SFPROPS *props,dataptr dz)
+{
+    char *prop;
+    time_t thistime;
+    char *p;
+    CHPEAK peaks[2000];
+    int chans, peaktime;
+
+    if((prop = (char *)malloc(max(sizeof(unsigned int),sizeof(double))))==NULL) {
+        sprintf(errstr,"INSUFFICIENT MEMORY to get properties.\n");
+        return(MEMORY_ERROR);
+    }
+
+    /*RWD find PEAK chunk as priority */
+    
+    if(snd_headread(dz->ifd[0],props)){
+        if((*props).type == wt_wave) {
+            switch(props->samptype){      /*RWD Nov 2003 show sample type now we have so many possibilities! */
+            case(SHORT16):
+                sprintf(errstr,"sample type:  16bit\n");
+                break;
+            case(FLOAT32):
+                sprintf(errstr,"sample type:  32bit floats\n");
+                break;          
+            case(INT2424):
+                sprintf(errstr,"sample type:  24bit packed\n");
+                break;
+            case(SHORT8):
+                sprintf(errstr,"sample type:  8bit\n");
+                break;
+            case(INT2432):
+                sprintf(errstr,"sample type:  24bit in 32bit frames\n");
+                break;
+            case(INT_32):
+                sprintf(errstr,"sample type:  32bit integer\n");
+                break;
+            default:
+                sprintf(errstr,"sample type unknown (custom format)\n");
+                break;
+            }
+            print_outmessage(errstr);
+            chans = (*props).chans; 
+            if(sndreadpeaks(dz->ifd[0],chans,peaks,&peaktime)>0){
+                int i;
+                thistime = (time_t) peaktime;
+                sprintf(errstr,"PEAK data at: %s\n",ctime(&thistime));
+                print_outmessage(errstr);
+                for(i=0;i < chans;i++){
+                    sprintf(errstr,"CH %d:\tamp = %.4f (%.2f dB)\tFrame %u\n",
+                        i+1,peaks[i].value,20 * log10(peaks[i].value),peaks[i].position); 
+                    print_outmessage(errstr);
+                }
+            }
+            else {
+                sprintf(errstr,"No PEAK chunk in this file");
+                print_outmessage(errstr);
+            }
+        }
+    }
+
+    if(sndgetprop(dz->ifd[0], "date", prop, sizeof(unsigned int))>=0
+    || sndgetprop(dz->ifd[0], "DATE", prop, sizeof(unsigned int))>=0) {
+        thistime = (time_t) *(int*)prop;
+        p = ctime(&thistime);
+        
+        sprintf(errstr,"Date: %s\n",p);
+        print_outmessage(errstr);
+    }
+    fflush(stdout);
+    return(FINISHED);
+}       
+
+/************************** GET_SHORT_MAXMIN ************************/
+
+int get_float_maxmin(float *buf,int chans, double inverse_sr,dataptr dz)
+{
+    int exit_status;
+    /*int maxamp = MINSAMP;*/
+    float maxamp = F_MINSAMP,mag;
+    int maxloc = 0;
+    int maxrep = 1;
+    int n;
+    double gain = 0.0, dbgain = 0.0;
+    double convertor = (double)(chans * dz->infile->srate);
+    int startsamp = round(dz->param[MAX_STIME] * convertor);
+    int endsamp = round(dz->param[MAX_ETIME] * convertor);
+    int last_total_samps_read;
+    int startsrch, endsrch;
+    dz->total_samps_read = 0;   /* REDUNDANT ? */
+    while(dz->samps_left) {
+        last_total_samps_read = dz->total_samps_read;
+        if((exit_status = read_samps(buf,dz))<0)
+            return(exit_status);
+        if(dz->total_samps_read <= startsamp)
+            continue;
+        else
+            startsrch = max(0,startsamp - last_total_samps_read);
+        if(dz->total_samps_read > endsamp) {
+            if((endsrch = endsamp - last_total_samps_read) < 0)
+                break;
+        } else
+            endsrch = dz->ssampsread;
+        for(n=startsrch;n<endsrch;n++) {
+            mag = (float) fabs(buf[n]);
+            if(mag > maxamp) {
+                maxloc = last_total_samps_read + n;
+                maxamp = mag;
+                maxrep = 1;
+            } else if(mag==maxamp)
+                maxrep++;
+        }
+    }
+    if(maxamp>0.0f) {
+        gain   = (double)F_MAXSAMP/(double)maxamp;
+        dbgain = log10(gain) * 20.0;
+    }
+    sprintf(errstr,"maximum abs value:.. %f\n",maxamp);
+    print_outmessage(errstr);
+    sprintf(errstr,"at: ................ %d samples\n",maxloc);
+    print_outmessage(errstr);
+    sprintf(errstr,"time: .............. %.4lf secs\n",(double)(maxloc/chans) *inverse_sr);
+    print_outmessage(errstr);
+    sprintf(errstr,"repeated: .......... %d times\n",maxrep);
+    print_outmessage(errstr);
+    if(maxamp>0.0f) {
+        sprintf(errstr,"max possible gain:.. %.4lf\n",gain);
+        print_outmessage(errstr);
+        sprintf(errstr,"max dB gain:........ %.4lf\n",dbgain);
+        print_outmessage(errstr);
+    }
+    return(FINISHED);
+}
+
+/*RWD 6:2001 read PEAK chunk */
+int getpeakdata(int ifd, float *peakval,SFPROPS *props)
+{
+    CHPEAK peaks[16];
+    int chans, peaktime;
+    float maxamp = 0.0f;
+    
+    if(snd_headread(ifd,props)){
+        chans = (*props).chans; 
+        if(sndreadpeaks(ifd,chans,peaks,&peaktime)){
+            int i;
+            for(i=0;i < chans;i++)
+                maxamp = max(maxamp,peaks[i].value);
+            *peakval = maxamp;
+            return 1;
+        }       
+    }
+    /* sf_headread error; but can't do much about it */
+    return 0;
+}
+
+/************************** DO_ZCROSS_RATIO ************************/
+
+int do_zcross_ratio(dataptr dz)
+{
+    int exit_status;
+    int chans = dz->infile->channels, *phase, k, m;
+    int n, *cnt, cntsum = 0, zc0, zc1, lastzc0, lastzc1, bufstart, bufend, bufskip, skipsamps, totsams, total_samps_processed;
+    double zc_ratio;
+    float *buf = dz->sampbuf[0];
+    double srate = dz->infile->srate;
+    if((cnt = (int *)malloc(chans * sizeof(int)))==NULL) {
+        sprintf(errstr,"NO MEMORY TO STORE ZERO-CROSSING COUNTERS.\n");
+        return(MEMORY_ERROR);
+    }
+    if((phase = (int *)malloc(chans * sizeof(int)))==NULL) {
+        sprintf(errstr,"NO MEMORY TO STORE PHASE MARKERS.\n");
+        return(MEMORY_ERROR);
+    }
+    dz->iparam[ZC_START] = (int)round(dz->param[ZC_START] * srate) * chans;
+    bufend               = (int)round(dz->param[ZC_END]   * srate) * chans;
+    totsams = bufend - dz->iparam[ZC_START];
+    dz->tempsize = totsams;
+    bufstart = dz->iparam[ZC_START] % dz->buflen;
+    if((bufskip = dz->iparam[ZC_START] / dz->buflen) > 0) {
+        skipsamps = bufskip * dz->buflen;
+        sndseekEx(dz->ifd[0],skipsamps,0);
+        bufend   -= skipsamps;
+    }
+    if((exit_status = read_samps(buf,dz)) < 0)
+        return(exit_status);
+    if(dz->ssampsread < chans * 2) {
+        sprintf(errstr,"INSUFFICIENT DATA TO COUNT ZERO-CROSSINGS.\n");
+        return(DATA_ERROR);
+    }
+    total_samps_processed = 0;
+    for(m=0,n = bufstart;m<chans;m++,n++) {
+        if(buf[n] > 0)
+            phase[m] = 1;
+        else if(buf[n] < 0)
+            phase[m] = -1;
+        else
+            phase[m] = 0;
+        cnt[m] = 0;
+    }
+    k = bufstart + chans;
+    while(bufend > dz->buflen)  {
+        for(n = k; n < dz->ssampsread;n+=chans) {
+            for(m=0;m<chans;m++) {
+                switch(phase[m]) {
+                case(0):
+                    if(buf[n+m] > 0)
+                        phase[m] = 1;
+                    else if(buf[n+m] < 0)
+                        phase[m] = -1;
+                    break;
+                case(1):
+                    if(buf[n+m] < 0) {
+                        cnt[m]++;
+                        phase[m] = -1;
+                    }
+                    break;
+                case(-1):
+                    if(buf[n+m] > 0) {
+                        cnt[m]++;
+                        phase[m] = 1;
+                    }
+                    break;
+                }
+            }
+        }
+        total_samps_processed += (dz->ssampsread - k);
+        display_virtual_time(total_samps_processed,dz);
+        if((exit_status = read_samps(buf,dz)) < 0)
+            return(exit_status);
+        bufend -= dz->buflen;
+        k = 0;
+    }
+    if(bufend > 0) {
+        for(n = k; n < bufend;n+=chans) {
+            for(m=0;m<chans;m++) {
+                switch(phase[m]) {
+                case(0):
+                    if(buf[n+m] > 0)
+                        phase[m] = 1;
+                    else if(buf[n+m] < 0)
+                        phase[m] = -1;
+                    break;
+                case(1):
+                    if(buf[n+m] < 0) {
+                        cnt[m]++;
+                        phase[m] = -1;
+                    }
+                    break;
+                case(-1):
+                    if(buf[n+m] > 0) {
+                        cnt[m]++;
+                        phase[m] = 1;
+                    }
+                    break;
+                }
+            }
+        }
+        total_samps_processed += (bufend - k);
+        display_virtual_time(total_samps_processed,dz);
+    }
+    for(m=0;m<chans;m++)
+        cntsum += cnt[m];
+    zc_ratio = (double)cntsum/(double)totsams;
+    zc1 = 32768;
+    zc0 = (int)round(zc_ratio * zc1);
+    do {
+        lastzc0 = zc0;
+        lastzc1 = zc1;
+        zc1 /= 2;
+        zc0 = (int)round(zc_ratio * zc1);
+    } while(zc0 > 0 && zc1 >= 64);
+    zc0 = lastzc0;
+    zc1 = lastzc1;
+    while(EVEN(zc0)) {
+        zc0 /= 2;
+        zc1 /= 2;
+    }
+    fprintf(stdout,"INFO: Proportion of zero-crossings = %lf or approx %d:%d\n",zc_ratio,zc0,zc1);
+    fflush(stdout);
+    return FINISHED;
+}

+ 240 - 0
dev/sndinfo/main.c

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

+ 668 - 0
dev/sndinfo/musunit.c

@@ -0,0 +1,668 @@
+/*
+ * Copyright (c) 1983-2013 Trevor Wishart and Composers Desktop Project Ltd
+ * http://www.trevorwishart.co.uk
+ * http://www.composersdesktop.com
+ *
+ This file is part of the CDP System.
+
+    The CDP System is free software; you can redistribute it
+    and/or modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    The CDP System is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with the CDP System; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+    02111-1307 USA
+ *
+ */
+
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <structures.h>
+#include <tkglobals.h>
+#include <pnames.h>
+#include <sndinfo.h>
+#include <globcon.h>
+#include <modeno.h>
+#include <math.h>
+#include <string.h>
+#include <ctype.h>
+#include <sfsys.h>
+
+#if defined unix || defined __GNUC__
+#define round(x) lround((x))
+#endif
+
+#define NOTEMIN                 ("A-4")
+#define NOTEMAX                 ("G5")
+#define FRQMAX                  (12543)    /* Approx frequency at MIDI 127 */
+#define CONVERT_LOG10_TO_LOG2   (3.321928)
+#define my_LOG2(x)              (log10(x) * CONVERT_LOG10_TO_LOG2)
+#define my_ANTILOG2(x)          (pow(2.0,x))
+#define LOG_SEMITONE_INTERVAL   (0.0250858329719984)
+#define QTONE_PER_OCT           (24)
+
+//static double readnote(char *note,dataptr dz);
+static int  midi_to_frq(double midi);
+static int  frq_to_midi(double frq);
+static void note_to_frq(double midi);
+//static void note_to_midi(int argc,char *argv[]);
+static int  ratio_to_semitones(double ratio);
+static int  ratio_to_interval(double ratio);
+static int  r_to_i(double ratio);
+static void semitones_to_ratio(double semitone_cnt);
+//static int  interval_to_semitones(char *str,double *semitiones);
+static void semitones_to_oct(double semitone_cnt);
+static void oct_to_semitones(double oct);
+static void oct_to_ratio(double oct);
+static int  ratio_to_oct(double ratio);
+static int  do_fraction(double val);
+static int  ratio_to_time(double ratio);
+static int  time_to_ratio(double timestr);
+static void semitones_to_time(double timestr);
+static void oct_to_time(double oct);
+static int  time_to_semitones(double timestr);
+static int  time_to_intervals(double timestr);
+static int  time_to_oct(double timestr);
+static int  semitones_to_interval(double sc);
+static void gain_to_db(double gain);
+static void db_to_gain(double dbgain);
+static int  midi_to_note(double val,dataptr dz);
+static void delay_to_frq(double val);
+static int  delay_to_midi(double val);
+static void frq_to_delay(double val);
+static int  midi_to_delay(double val);
+static int  tempo_to_delay(double val);
+static int  delay_to_tempo(double val);
+
+/************************ DO_MUSUNITS *************************/
+
+int do_musunits(dataptr dz)
+{
+
+    int exit_status = FINISHED, k;
+    switch(dz->mode) {
+    case(MU_MIDI_TO_FRQ):           exit_status = midi_to_frq(dz->param[MUSUNIT]);              break;
+    case(MU_FRQ_TO_MIDI):           exit_status = frq_to_midi(dz->param[MUSUNIT]);              break;
+    case(MU_NOTE_TO_FRQ):           note_to_frq(dz->scalefact);                                 break;
+    case(MU_NOTE_TO_MIDI):
+        k = round(dz->scalefact);
+        if(!flteq((double)k,dz->scalefact))
+            sprintf(errstr,"MIDI value = %lf or approx %d\n",dz->scalefact,k);      
+        else
+            sprintf(errstr,"MIDI value = %d\n",k);      
+        break;
+    case(MU_FRQ_TO_NOTE):
+    case(MU_MIDI_TO_NOTE):          midi_to_note(dz->param[MUSUNIT],dz);                        break;
+    case(MU_FRQRATIO_TO_SEMIT):     exit_status = ratio_to_semitones(dz->param[MUSUNIT]);       break;
+    case(MU_FRQRATIO_TO_INTVL):     exit_status = ratio_to_interval(dz->param[MUSUNIT]);        break;
+    case(MU_INTVL_TO_FRQRATIO):     semitones_to_ratio(dz->scalefact);                          break;
+    case(MU_SEMIT_TO_FRQRATIO):     semitones_to_ratio(dz->param[MUSUNIT]);                     break;
+    case(MU_OCTS_TO_FRQRATIO):      oct_to_ratio(dz->param[MUSUNIT]);                           break;
+    case(MU_OCTS_TO_SEMIT):         oct_to_semitones(dz->param[MUSUNIT]);                       break;
+    case(MU_FRQRATIO_TO_OCTS):      exit_status = ratio_to_oct(dz->param[MUSUNIT]);             break;
+    case(MU_SEMIT_TO_OCTS):         semitones_to_oct(dz->param[MUSUNIT]);                       break;
+    case(MU_SEMIT_TO_INTVL):        exit_status = semitones_to_interval(dz->param[MUSUNIT]);    break;
+    case(MU_FRQRATIO_TO_TSTRETH):   exit_status = ratio_to_time(dz->param[MUSUNIT]);            break;
+    case(MU_SEMIT_TO_TSTRETCH):     semitones_to_time(dz->param[MUSUNIT]);                      break;
+    case(MU_OCTS_TO_TSTRETCH):      oct_to_time(dz->param[MUSUNIT]);                            break;
+    case(MU_INTVL_TO_TSTRETCH):     semitones_to_time(dz->scalefact);                           break;
+    case(MU_TSTRETCH_TO_FRQRATIO):  exit_status = time_to_ratio(dz->param[MUSUNIT]);            break;
+    case(MU_TSTRETCH_TO_SEMIT):     exit_status = time_to_semitones(dz->param[MUSUNIT]);        break;
+    case(MU_TSTRETCH_TO_OCTS):      exit_status = time_to_oct(dz->param[MUSUNIT]);              break;
+    case(MU_TSTRETCH_TO_INTVL):     exit_status = time_to_intervals(dz->param[MUSUNIT]);        break;
+    case(MU_GAIN_TO_DB):            gain_to_db(dz->param[MUSUNIT]);                             break;
+    case(MU_DB_TO_GAIN):            db_to_gain(dz->param[MUSUNIT]);                             break;
+    case(MU_DELAY_TO_FRQ):          delay_to_frq(dz->param[MUSUNIT]);                           break;
+    case(MU_DELAY_TO_MIDI):         exit_status = delay_to_midi(dz->param[MUSUNIT]);            break;
+    case(MU_FRQ_TO_DELAY):          frq_to_delay(dz->param[MUSUNIT]);                           break;
+    case(MU_MIDI_TO_DELAY):         exit_status = midi_to_delay(dz->param[MUSUNIT]);            break;
+    case(MU_NOTE_TO_DELAY):         exit_status = midi_to_delay(dz->scalefact);                 break;
+    case(MU_TEMPO_TO_DELAY):        exit_status = tempo_to_delay(dz->param[MUSUNIT]);           break;
+    case(MU_DELAY_TO_TEMPO):        exit_status = delay_to_tempo(dz->param[MUSUNIT]);           break;
+    default:
+        sprintf(errstr,"Unknown mode in do_musunits()\n");
+        return(PROGRAM_ERROR);
+    }
+    sprintf(errstr,"%s",errstr);
+    print_outmessage_flush(errstr);
+    return(exit_status);
+}
+
+/**************************** MIDI_TO_FRQ **************************/
+
+int midi_to_frq(double midi)
+{
+    double frq;
+    if(midi<(double)MIDIMIN || midi >(double)MIDIMAX) {
+        sprintf(errstr,"MIDI value out of range %d - %d\n",MIDIMIN,MIDIMAX);
+        return(GOAL_FAILED);
+    }
+    frq  = midi;
+    frq += 3.0;
+    frq /= SEMITONES_PER_OCTAVE;
+    frq  = pow((double)2,frq);
+    frq *= LOW_A;
+    sprintf(errstr,"frequency = %lf\n",frq);
+    return(FINISHED);
+}
+
+/************************ FRQ_TO_MIDI *****************/
+
+int frq_to_midi(double frq)
+{
+    double midi;
+    if(frq<MINPITCH || frq >(double)FRQMAX) {
+        sprintf(errstr,"Frq value out of range %ld - %d\n",round(MINPITCH),FRQMAX);
+        return(GOAL_FAILED);
+    }
+    midi  = frq;
+    midi /= LOW_A;
+    midi  = my_LOG2(midi);
+    midi *= SEMITONES_PER_OCTAVE;
+    midi -= 3.0;
+    sprintf(errstr,"MIDI value = %lf or approx %ld\n",midi,round(midi));
+    return(FINISHED);
+}
+
+/************************** NOTE_TO_FRQ *************************/
+
+void note_to_frq(double midi)
+{
+    double frq;
+    frq  = midi;
+    frq += 3.0;
+    frq /= SEMITONES_PER_OCTAVE;
+    frq  = pow((double)2,frq);
+    frq *= LOW_A;
+    sprintf(errstr,"Frequency = %lf\n",frq);
+}
+
+/************************* RATIO_TO_SEMITONES **********************/
+
+int ratio_to_semitones(double ratio)
+{  
+    double semitone_cnt;
+    if(ratio <= 0.0) {
+        sprintf(errstr,"Freq ratio <= 0.0 : impossible.\n");
+        return(GOAL_FAILED);
+    }
+    semitone_cnt = fabs(log10(ratio)/(double)LOG_SEMITONE_INTERVAL);
+//TW UPDATE
+    if(ratio < 1.0)
+        semitone_cnt = -semitone_cnt;
+    sprintf(errstr,"%lf semitones\n",semitone_cnt);
+    return(FINISHED);
+}
+
+/************************* RATIO_TO_SEMITONES **********************/
+
+int ratio_to_interval(double ratio)
+{
+    if(ratio <= 0.0) {
+        sprintf(errstr,"Freq ratio <= 0.0 : impossible.\n");
+        return(GOAL_FAILED);
+    }
+    return r_to_i(ratio);
+}
+
+/************************* R_TO_I **********************/
+
+int r_to_i(double ratio)
+{   
+    double semitone_cnt;
+    int oct_cnt, qtone_cnt;
+    semitone_cnt = fabs(log10(ratio)/(double)LOG_SEMITONE_INTERVAL);
+    qtone_cnt = round(semitone_cnt * 2);
+    oct_cnt = qtone_cnt/QTONE_PER_OCT;
+    qtone_cnt -= oct_cnt * QTONE_PER_OCT;
+    switch(oct_cnt) {
+    case(1): sprintf(errstr,"1 octave");          break;
+    case(0):                                      break;
+    default: 
+        sprintf(errstr,"%d octaves",oct_cnt);           
+        break;
+    }
+    if(qtone_cnt && oct_cnt)
+        strcat(errstr," and a ");
+    switch(qtone_cnt) {
+    case(0):
+        if(oct_cnt==0) {
+            sprintf(errstr,"Unison.\n");
+            return(FINISHED);
+        }
+        break;
+    case(1):    strcat(errstr,"minor 2nd-\n");      break;
+    case(2):    strcat(errstr,"minor 2nd\n");       break;
+    case(3):    strcat(errstr,"minor 2nd+\n");      break;
+    case(4):    strcat(errstr,"major 2nd\n");       break;
+    case(5):    strcat(errstr,"major 2nd+\n");      break;
+    case(6):    strcat(errstr,"minor 3rd\n");       break;
+    case(7):    strcat(errstr,"minor 3rd+\n");      break;
+    case(8):    strcat(errstr,"major 3rd\n");       break;
+    case(9):    strcat(errstr,"major 3rd+\n");      break;
+    case(10):   strcat(errstr,"4th\n");             break;
+    case(11):   strcat(errstr,"4th+\n");            break;
+    case(12):   strcat(errstr,"augmented 4th\n");   break;
+    case(13):   strcat(errstr,"augmented 4th+\n");  break;
+    case(14):   strcat(errstr,"5th\n");             break;
+    case(15):   strcat(errstr,"5th+\n");            break;
+    case(16):   strcat(errstr,"minor 6th\n");       break;
+    case(17):   strcat(errstr,"minor 6th+\n");      break;
+    case(18):   strcat(errstr,"major 6th\n");       break;
+    case(19):   strcat(errstr,"major 6th+\n");      break;
+    case(20):   strcat(errstr,"minor 7th\n");       break;
+    case(21):   strcat(errstr,"minor 7th+\n");      break;
+    case(22):   strcat(errstr,"major 7th\n");       break;
+    case(23):   strcat(errstr,"major 7th+\n");      break;
+    }
+    return(FINISHED);
+}
+
+/************************ SEMITONES_TO_RATIO *******************/
+
+void semitones_to_ratio(double semitone_cnt)
+{
+    double ratio;
+    ratio = pow((double)SEMITONE_INTERVAL,semitone_cnt);
+    sprintf(errstr,"frequency ratio is %.8lf\n",ratio);
+}
+    
+/******************************** SEMITONES_TO_OCT ***********************/
+
+void semitones_to_oct(double semitone_cnt)
+{
+    double oct;
+    oct = (double)semitone_cnt/SEMITONES_PER_OCTAVE;
+    sprintf(errstr,"octave_distance is %.8lf\n",oct);
+}
+
+/******************************** OCT_TO_SEMITONES ***********************/
+
+void oct_to_semitones(double oct)
+{
+    double semitone_cnt;
+    semitone_cnt = oct * SEMITONES_PER_OCTAVE;
+    sprintf(errstr,"semitone count  is %.8lf\n",semitone_cnt);
+}
+
+/******************************** OCT_TO_RATIO ***********************/
+
+void oct_to_ratio(double oct)
+{
+    double ratio = my_ANTILOG2(oct);
+    sprintf(errstr,"Frequency ratio is %.8lf\n",ratio);
+}
+
+/******************************** RATIO_TO_OCT ***********************/
+
+int ratio_to_oct(double ratio)
+{
+    int exit_status;
+    double oct;
+    if(ratio <= FLTERR) {
+        sprintf(errstr,"Interval ratio too small or negative (Impossible).\n");
+        return(GOAL_FAILED);
+    }
+    oct = my_LOG2(ratio);
+    sprintf(errstr,"Octave distance is ");
+    if((exit_status = do_fraction(oct))<0)
+        return(exit_status);
+    strcat(errstr,"\n");
+    return(FINISHED);
+}
+
+/*********************************** DO_FRACTION ******************************/
+
+int do_fraction(double val)
+{
+    int n, m, k = 0;
+    int is_neg = 0;
+    double d, test, thisval = val;
+    char temp[64];
+    if(val <0.0)  {
+        thisval = -thisval;
+        is_neg = 1;
+    }
+    for(n=1;n<5;n*=2) {
+        d = 1.0/(double)n;
+        if((test = fmod(thisval,d))< FLTERR || d - test < FLTERR) {
+            m = (int)(thisval/d);   /* truncate */
+            if(!flteq((double)m * d,thisval))
+                m++;            
+            if(!flteq((double)m * d,thisval)) {
+                m-=2;           
+                if(!flteq((double)m * d,thisval)) {
+                    sprintf(errstr,"Problem in fractions\n");
+                    return(PROGRAM_ERROR);
+                }
+            }
+            k = 0L;         
+            if(m >= n) {
+                k  = m/n;       /* truncate */
+                m -= k * n;
+            }
+            if(is_neg)
+                strcat(errstr,"-");
+            if(k) {
+                sprintf(temp,"%d",k);
+                strcat(errstr,temp);
+            }
+            switch(n) {
+            case(2):
+                if(m)   strcat(errstr,".5");
+                break;  
+            case(4):
+                switch(m) {
+                case(1): strcat(errstr,".25");  break;
+                case(2): strcat(errstr,".5");   break;
+                case(3): strcat(errstr,".75");  break;
+                }
+            }
+            return(FINISHED);
+        }
+    }
+    sprintf(temp,"%lf",val);
+    strcat(errstr,temp);
+    return(FINISHED);
+}
+
+/******************************** RATIO_TO_TIME ********************************/ 
+
+int ratio_to_time(double ratio)
+{
+    if(ratio <= 0.0) {
+        sprintf(errstr,"Freq ratio <= 0.0 : impossible.\n");
+        return(GOAL_FAILED);
+    }
+    sprintf(errstr,"Timestretch is %lf\n",1.0/ratio);
+    return(FINISHED);
+}
+
+/******************************** TIME_TO_RATIO ********************************/ 
+
+int time_to_ratio(double timestr)
+{
+    if(timestr <= 0.0) {
+        sprintf(errstr,"timestretch <= 0.0 : impossible.\n");
+        return(GOAL_FAILED);
+    }
+    sprintf(errstr,"Timestretch is %lf\n",1.0/timestr);
+    return(FINISHED);
+}
+
+/******************************** SEMITONES_TO_TIME ********************************/ 
+
+void semitones_to_time(double semitone_cnt)
+{
+    double ratio;
+    ratio = pow((double)SEMITONE_INTERVAL,semitone_cnt);
+    sprintf(errstr,"Timestretch is %lf\n",1.0/ratio);
+}
+
+/******************************** OCT_TO_TIME ********************************/ 
+
+void oct_to_time(double oct)
+{
+    double ratio;
+    ratio = my_ANTILOG2(oct);
+    sprintf(errstr,"Timestretch is %lf\n",1.0/ratio);
+}
+
+/******************************** TIME_TO_SEMITONES ********************************/ 
+
+int time_to_semitones(double timestr)
+{
+    double semitone_cnt;
+    double ratio;
+    if(timestr <= 0.0) {
+        sprintf(errstr,"timestretch <= 0.0 : impossible.\n");
+        return(GOAL_FAILED);
+    }
+    ratio = 1.0/timestr;
+    semitone_cnt = log10(ratio)/(double)LOG_SEMITONE_INTERVAL;
+    sprintf(errstr,"%lf semitones\n",semitone_cnt);
+    return(FINISHED);
+}
+
+
+/******************************** TIME_TO_INTERVALS ********************************/ 
+
+int time_to_intervals(double timestr)
+{
+    int exit_status;
+    double ratio;
+    char *p;
+    if(timestr <= 0.0) {
+        sprintf(errstr,"timestretch <= 0.0 : impossible.\n");
+        return(GOAL_FAILED);
+    }
+    ratio = 1.0/timestr;
+    if((exit_status = r_to_i(ratio))<0)
+        return(exit_status);
+    if(ratio<1.0) { 
+        p = errstr;
+        while(*p != ENDOFSTR) {
+            if(*p == NEWLINE) {
+                *p = ENDOFSTR;
+                break;
+            }
+            p++;
+        }
+        strcat(errstr," Downwards.\n");
+    }
+    return(FINISHED);
+}
+
+/******************************** TIME_TO_OCT ********************************/ 
+
+int time_to_oct(double timestr)
+{
+    int exit_status;
+    double oct;
+    if(timestr <= 0.0) {
+        sprintf(errstr,"timestretch <= 0.0 : impossible.\n");
+        return(GOAL_FAILED);
+    }
+//TW UPDATE
+    if(flteq((oct = my_LOG2(1.0/timestr)),0.0)) {
+        sprintf(errstr,"Octave distance is 0\n");
+        return(FINISHED);
+    }
+    sprintf(errstr,"Octave distance is ");
+    if((exit_status = do_fraction(oct))<0)
+        return(exit_status);
+    strcat(errstr,"\n");
+    return(FINISHED);
+}
+
+/********************** SEMITONES_TO_INTERVAL **********************/
+
+int semitones_to_interval(double sc)
+{
+    int ocnt = 0, qcnt, scnt, neg = 0;
+    char temp[200];
+    errstr[0] = ENDOFSTR;
+    if(sc < 0.0)
+        neg = 1;
+    sc   = fabs(sc);
+    ocnt = round(floor(sc/SEMITONES_PER_OCTAVE));
+    sc   = fmod(sc,SEMITONES_PER_OCTAVE);
+    qcnt = round(sc * 2.0);
+    scnt = qcnt/2;
+    if(scnt*2 != qcnt)
+        qcnt = 1;
+    else
+        qcnt = 0;
+    switch(scnt) {
+    case(0):                                break;
+    case(1):  sprintf(errstr,"minor 2nd");  break;  
+    case(2):  sprintf(errstr,"2ns");        break; 
+    case(3):  sprintf(errstr,"minor 3rd");  break;
+    case(4):  sprintf(errstr,"3rd");        break;
+    case(5):  sprintf(errstr,"4th");        break;
+    case(6):  sprintf(errstr,"#4th");       break;
+    case(7):  sprintf(errstr,"5th");        break;
+    case(8):  sprintf(errstr,"minor 6th");  break;
+    case(9):  sprintf(errstr,"6th");        break;
+    case(10): sprintf(errstr,"minor 7th");  break;
+    case(11): sprintf(errstr,"7th");        break;
+    default:
+        sprintf(errstr,"Unknown interval.\n");
+        exit(PROGRAM_ERROR);
+    }
+    if(qcnt) {
+        if(scnt==0)
+            strcat(errstr,"1 quartertone ");
+        else
+            strcat(errstr," + quartertone");
+    }
+    if(ocnt) {
+        if(scnt > 0 || qcnt > 0) {
+            sprintf(temp," plus %d octave",ocnt);
+            strcat(errstr,temp);
+        } else {
+            sprintf(temp,"%d octave",ocnt);
+            strcat(errstr,temp);
+        }
+        if(ocnt > 1) {
+            sprintf(temp,"s");
+            strcat(errstr,temp);
+        }
+    }
+    if(strlen(errstr) <= 0)
+        sprintf(errstr,"Less than a quarter-tone");
+    if(neg)
+        strcat(errstr," down");
+    strcat(errstr,"\n");
+    return(FINISHED);
+}
+
+/********************** GAIN_TO_DB **********************/
+
+void gain_to_db(double gain)
+{
+    double dbgain = log10(gain) * 20.0;
+    if(dbgain <= MIN_DB_ON_16_BIT)
+        sprintf(errstr,"-96dB:  i.e. zero level\n");
+    else
+        sprintf(errstr,"%.3lfdB\n",dbgain);
+}
+
+/********************** DB_TO_GAIN **********************/
+
+void db_to_gain(double dbgain)
+{
+    double gain = dbtogain(dbgain);
+    sprintf(errstr,"Gain = %lf\n",gain);
+}
+
+/************************ MIDI_TO_NOTE *************************/
+
+int midi_to_note(double val,dataptr dz)
+{
+    int oct, imidi, midinote, is_qtone = FALSE, is_approx = FALSE;
+    char temp[6];
+    double midival;
+
+    if(dz->mode==MU_FRQ_TO_NOTE) {
+        if(val<MINPITCH || val >(double)FRQMAX) {
+            sprintf(errstr,"Frq value out of range %ld - %d\n",round(MINPITCH),FRQMAX);
+            return(GOAL_FAILED);
+        }
+        midival  = val;
+        midival /= LOW_A;
+        midival  = my_LOG2(midival);
+        midival *= SEMITONES_PER_OCTAVE;
+        midival -= 3.0;
+    } else
+        midival = val;
+
+    midival *= 2.0;
+    imidi = round(midival); 
+    if(!flteq((double)imidi,midival))
+        is_approx = TRUE;
+    if(ODD(imidi))
+        is_qtone = TRUE;    
+    imidi /= 2;
+
+    midinote = imidi%12;
+    oct = imidi/12;
+    oct -= 5;
+    sprintf(errstr,"Note is ");     
+    if(is_approx)
+        strcat(errstr,"(approx) ");     
+    switch(midinote) {
+    case(0):    strcat(errstr,"C");     break;
+    case(1):    strcat(errstr,"C#");    break;
+    case(2):    strcat(errstr,"D");     break;
+    case(3):    strcat(errstr,"Eb");    break;
+    case(4):    strcat(errstr,"E");     break;
+    case(5):    strcat(errstr,"F");     break;
+    case(6):    strcat(errstr,"F#");    break;
+    case(7):    strcat(errstr,"G");     break;
+    case(8):    strcat(errstr,"Ab");    break;
+    case(9):    strcat(errstr,"A");     break;
+    case(10):   strcat(errstr,"Bb");    break;
+    case(11):   strcat(errstr,"B");     break;
+    }
+    if(is_qtone)
+        strcat(errstr,"u");
+    sprintf(temp,"%d",oct);
+    strcat(errstr,temp);
+    strcat(errstr,"\n");
+    return(FINISHED);
+}
+
+void delay_to_frq(double val) {
+    sprintf(errstr,"Frequency is %.5lf Hz\n",SECS_TO_MS/val);
+}
+
+int delay_to_midi(double val) {
+    int exit_status = FINISHED;
+    val = SECS_TO_MS/val;
+    exit_status = frq_to_midi(val);
+    return(exit_status);
+}
+
+void frq_to_delay(double frq) {
+    sprintf(errstr,"Delay is %.5lf milliseconds\n",SECS_TO_MS/frq);
+}
+
+int midi_to_delay(double midi) {
+    double frq, del;
+    if(midi<(double)MIDIMIN || midi >(double)MIDIMAX) {
+        sprintf(errstr,"MIDI value out of range %d - %d\n",MIDIMIN,MIDIMAX);
+        return(GOAL_FAILED);
+    }
+    frq  = midi;
+    frq += 3.0;
+    frq /= SEMITONES_PER_OCTAVE;
+    frq  = pow((double)2,frq);
+    frq *= LOW_A;
+    del = SECS_TO_MS/frq;
+    sprintf(errstr,"Delay is %lf milliseconds\n",del);
+
+    return(FINISHED);
+}
+
+int tempo_to_delay(double tempo) {
+    double del = (60 * SECS_TO_MS)/(double)tempo;
+    sprintf(errstr,"Delay is %lf milliseconds\n",del);
+    return(FINISHED);
+}
+
+int delay_to_tempo(double del) {
+    double tempo = (60 * SECS_TO_MS)/(double)del;
+    sprintf(errstr,"Tempo : crotchet =  %lf\n",tempo);
+    return(FINISHED);
+}
+

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

+ 578 - 0
dev/spec/ap_simple.c

@@ -0,0 +1,578 @@
+/*
+ * Copyright (c) 1983-2013 Trevor Wishart and Composers Desktop Project Ltd
+ * http://www.trevorwishart.co.uk
+ * http://www.composersdesktop.com
+ *
+ This file is part of the CDP System.
+
+    The CDP System is free software; you can redistribute it
+    and/or modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    The CDP System is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with the CDP System; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+    02111-1307 USA
+ *
+ */
+
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <structures.h>
+#include <cdpmain.h>
+#include <tkglobals.h>
+#include <pnames.h>
+#include <simple.h>
+#include <processno.h>
+#include <modeno.h>
+#include <globcon.h>
+#include <logic.h>
+#include <filetype.h>
+#include <mixxcon.h>
+#include <flags.h>
+#include <speccon.h>
+#include <arrays.h>
+#include <special.h>
+#include <formants.h>
+#include <sfsys.h>
+#include <osbind.h>
+#include <string.h>
+#include <math.h>
+#include <srates.h>
+
+/********************************************************************************************/
+/********************************** FORMERLY IN pconsistency.c ******************************/
+/********************************************************************************************/
+
+static int 	check_compatibility_of_cut_params(dataptr dz);
+
+/********************************************************************************************/
+/********************************** FORMERLY IN preprocess.c ********************************/
+/********************************************************************************************/
+
+#define SKIPWDWS 	(4)
+static int  setup_internal_params_for_clean(dataptr dz);
+
+/********************************************************************************************/
+/************************************ FORMERLY IN aplinit.c *********************************/
+/********************************************************************************************/
+
+/***************************** ESTABLISH_BUFPTRS_AND_EXTRA_BUFFERS **************************/
+
+int establish_bufptrs_and_extra_buffers(dataptr dz)
+{
+	int exit_status;
+	int is_spec = FALSE;
+	dz->extra_bufcnt = -1;	/* ENSURE EVERY CASE HAS A PAIR OF ENTRIES !! */
+	dz->bptrcnt = 0;
+	dz->bufcnt  = 0;
+	switch(dz->process) {
+
+	case(GAIN):       		dz->extra_bufcnt =  0; dz->bptrcnt = 1; 	is_spec = TRUE;		break;
+	case(LIMIT):	  		dz->extra_bufcnt =  0; dz->bptrcnt = 1; 	is_spec = TRUE;		break;
+	case(BARE):       		dz->extra_bufcnt =  0; dz->bptrcnt = 1; 	is_spec = TRUE;		break;
+	case(CLEAN):      		dz->extra_bufcnt =  0; dz->bptrcnt = 1; 	is_spec = TRUE;		break;
+	case(CUT): 	      		dz->extra_bufcnt =  0; dz->bptrcnt = 4; 	is_spec = TRUE;		break;	
+	case(GRAB):       		dz->extra_bufcnt =  0; dz->bptrcnt = 1; 	is_spec = TRUE;		break;	
+	case(MAGNIFY):    		dz->extra_bufcnt =  1; dz->bptrcnt = 1; 	is_spec = TRUE;		break;	
+
+	default:
+		sprintf(errstr,"Unknown program type [%d] in establish_bufptrs_and_extra_buffers()\n",dz->process);
+		return(PROGRAM_ERROR);
+	}
+
+	if(dz->extra_bufcnt < 0) {
+		sprintf(errstr,"bufcnts have not been set: establish_bufptrs_and_extra_buffers()\n");
+		return(PROGRAM_ERROR);
+	}
+	if(is_spec)
+		return establish_spec_bufptrs_and_extra_buffers(dz);
+	else if((dz->process==HOUSE_SPEC && dz->mode==HOUSE_CONVERT) || dz->process==INFO_DIFF) {
+		if((exit_status = establish_spec_bufptrs_and_extra_buffers(dz))<0)
+			return(exit_status);
+	}
+	return establish_groucho_bufptrs_and_extra_buffers(dz);
+}
+
+/***************************** SETUP_INTERNAL_ARRAYS_AND_ARRAY_POINTERS **************************/
+
+int setup_internal_arrays_and_array_pointers(dataptr dz)
+{
+	int n;		 
+	dz->ptr_cnt    = -1;		/* base constructor...process */
+	dz->array_cnt  = -1;
+	dz->iarray_cnt = -1;
+	dz->larray_cnt = -1;
+	switch(dz->process) {
+
+	case(GAIN):   	dz->array_cnt = 0; dz->iarray_cnt = 0; dz->larray_cnt = 0; dz->ptr_cnt = 0; dz->fptr_cnt = 0;	break;
+	case(LIMIT):	dz->array_cnt = 0; dz->iarray_cnt = 0; dz->larray_cnt = 0; dz->ptr_cnt = 0; dz->fptr_cnt = 0;	break;
+	case(BARE):   	dz->array_cnt = 0; dz->iarray_cnt = 0; dz->larray_cnt = 0; dz->ptr_cnt = 0; dz->fptr_cnt = 0;	break;
+	case(CLEAN):  	dz->array_cnt = 0; dz->iarray_cnt =1;  dz->larray_cnt = 0; dz->ptr_cnt = 0; dz->fptr_cnt = 0;	break;
+	case(CUT):  	dz->array_cnt = 0; dz->iarray_cnt = 0; dz->larray_cnt = 0; dz->ptr_cnt = 0; dz->fptr_cnt = 0;	break;
+	case(GRAB):  	dz->array_cnt = 0; dz->iarray_cnt = 0; dz->larray_cnt = 0; dz->ptr_cnt = 0; dz->fptr_cnt = 0;	break;
+	case(MAGNIFY):  dz->array_cnt = 0; dz->iarray_cnt = 0; dz->larray_cnt = 0; dz->ptr_cnt = 0; dz->fptr_cnt = 0;	break;
+
+	}
+
+/*** WARNING ***
+ANY APPLICATION DEALING WITH A NUMLIST INPUT: MUST establish AT LEAST 1 double array: i.e. dz->array_cnt = at least 1
+**** WARNING ***/
+
+
+	if(dz->array_cnt < 0 || dz->iarray_cnt < 0 || dz->larray_cnt < 0 || dz->ptr_cnt < 0 || dz->fptr_cnt < 0) {
+		sprintf(errstr,"array_cnt not set in setup_internal_arrays_and_array_pointers()\n");	   
+		return(PROGRAM_ERROR);
+	}
+
+	if(dz->array_cnt > 0) {  
+		if((dz->parray  = (double **)malloc(dz->array_cnt * sizeof(double *)))==NULL) {
+			sprintf(errstr,"INSUFFICIENT MEMORY for internal double arrays.\n");
+			return(MEMORY_ERROR);
+		}
+		for(n=0;n<dz->array_cnt;n++)
+			dz->parray[n] = NULL;
+	}
+	if(dz->iarray_cnt > 0) {
+		if((dz->iparray = (int     **)malloc(dz->iarray_cnt * sizeof(int *)))==NULL) {
+			sprintf(errstr,"INSUFFICIENT MEMORY for internal int arrays.\n");
+			return(MEMORY_ERROR);
+		}
+		for(n=0;n<dz->iarray_cnt;n++)
+			dz->iparray[n] = NULL;
+	}
+	if(dz->larray_cnt > 0) {	  
+		if((dz->lparray = (int    **)malloc(dz->larray_cnt * sizeof(int *)))==NULL) {
+			sprintf(errstr,"INSUFFICIENT MEMORY for internal long arrays.\n");
+			return(MEMORY_ERROR);
+		}
+		for(n=0;n<dz->larray_cnt;n++)
+			dz->lparray[n] = NULL;
+	}
+	if(dz->ptr_cnt > 0)   {  	  
+		if((dz->ptr    	= (double  **)malloc(dz->ptr_cnt  * sizeof(double *)))==NULL) {
+			sprintf(errstr,"INSUFFICIENT MEMORY for internal pointer arrays.\n");
+			return(MEMORY_ERROR);
+		}
+		for(n=0;n<dz->ptr_cnt;n++)
+			dz->ptr[n] = NULL;
+	}
+	if(dz->fptr_cnt > 0)   {  	  
+		if((dz->fptr = (float  **)malloc(dz->fptr_cnt * sizeof(float *)))==NULL) {
+			sprintf(errstr,"INSUFFICIENT MEMORY for internal float-pointer arrays.\n");
+			return(MEMORY_ERROR);
+		}
+		for(n=0;n<dz->fptr_cnt;n++)
+			dz->fptr[n] = NULL;
+	}
+	return(FINISHED);
+}
+
+/****************************** ASSIGN_PROCESS_LOGIC *********************************/
+
+int assign_process_logic(dataptr dz)
+{						 
+	switch(dz->process) {
+						 					/* INPUT TYPE			PROCESS TYPE		OUTPUT TYPE */
+	case(GAIN):			setup_process_logic(ANALFILE_ONLY,		  	EQUAL_ANALFILE,		ANALFILE_OUT,	dz);	break;
+	case(LIMIT):		setup_process_logic(ANALFILE_ONLY,		  	EQUAL_ANALFILE,		ANALFILE_OUT,	dz);	break;
+	case(BARE):		 	setup_process_logic(ANAL_WITH_PITCHDATA,  	EQUAL_ANALFILE,		ANALFILE_OUT,	dz);	break;
+	case(CLEAN):
+		switch(dz->mode) {
+		case(COMPARING):setup_process_logic(THREE_ANALFILES,	  	EQUAL_ANALFILE,		ANALFILE_OUT,	dz);	break;
+		default:		setup_process_logic(TWO_ANALFILES,		  	EQUAL_ANALFILE,		ANALFILE_OUT,	dz);	break;
+		}
+		break;
+	case(CUT):			setup_process_logic(ANALFILE_ONLY,		  	BIG_ANALFILE,		ANALFILE_OUT,	dz);	break;
+	case(GRAB):			setup_process_logic(ANALFILE_ONLY,		  	BIG_ANALFILE,		ANALFILE_OUT,	dz);	break;
+	case(MAGNIFY):		setup_process_logic(ANALFILE_ONLY,		  	BIG_ANALFILE,		ANALFILE_OUT,	dz);	break;
+
+	default:
+		sprintf(errstr,"Unknown process: assign_process_logic()\n");
+		return(PROGRAM_ERROR);
+		break;
+	}
+	if(dz->has_otherfile) {
+		switch(dz->input_data_type) {
+		case(ALL_FILES):
+		case(TWO_SNDFILES):
+		case(SNDFILE_AND_ENVFILE):
+		case(SNDFILE_AND_BRKFILE):
+		case(SNDFILE_AND_UNRANGED_BRKFILE):
+		case(SNDFILE_AND_DB_BRKFILE):
+			break;
+		case(MANY_SNDFILES):
+			if(dz->process==INFO_TIMELIST)
+				break;
+			/* fall thro */
+		default:
+			sprintf(errstr,"Most processes accepting files with different properties\n"
+						   "can only take 2 sound infiles.\n");
+			return(PROGRAM_ERROR);
+		}
+	}
+	return(FINISHED);
+}
+
+/***************************** SET_LEGAL_INFILE_STRUCTURE **************************
+ *
+ * Allows 2nd infile to have different props to first infile.
+ */
+
+void set_legal_infile_structure(dataptr dz)
+{
+	switch(dz->process) {
+	default:
+		dz->has_otherfile = FALSE;
+		break;
+	}
+}
+
+/********************************************************************************************/
+/********************************* FORMERLY IN internal.c **********************************/
+/********************************************************************************************/
+
+/****************************** SET_LEGAL_INTERNALPARAM_STRUCTURE *********************************/
+
+int set_legal_internalparam_structure(int process,int mode,aplptr ap)
+{
+	int exit_status = FINISHED;
+	switch(process) {
+	case(GAIN):		  	return(FINISHED);
+	case(LIMIT):      	return(FINISHED);
+	case(BARE):		  	return(FINISHED);
+	case(CLEAN):	  	exit_status = set_internalparam_data("i",ap);					break;
+	case(CUT):		  	return(FINISHED);
+	case(GRAB):	      	return(FINISHED);
+	case(MAGNIFY):    	return(FINISHED);
+	default:
+		sprintf(errstr,"Unknown process in set_legal_internalparam_structure()\n");
+		return(PROGRAM_ERROR);
+	}
+	return(exit_status);		
+}
+
+/********************************************************************************************/
+/********************************** FORMERLY IN specialin.c *********************************/
+/********************************************************************************************/
+
+
+/********************** READ_SPECIAL_DATA ************************/
+
+int read_special_data(char *str,dataptr dz)	   
+{
+	aplptr ap = dz->application;
+	switch(ap->special_data) {
+	default:
+		sprintf(errstr,"Unknown special_data type: read_special_data()\n");
+		return(PROGRAM_ERROR);
+	}
+	return(FINISHED);	/* NOTREACHED */
+}
+
+/********************************************************************************************/
+/********************************** FORMERLY IN preprocess.c ********************************/
+/********************************************************************************************/
+
+/****************************** PARAM_PREPROCESS *********************************/
+
+int param_preprocess(dataptr dz)	
+{
+	switch(dz->process) {
+	case(CLEAN):		return setup_internal_params_for_clean(dz);
+
+	case(GAIN):	case(LIMIT): case(BARE): case(CUT):	case(GRAB):	case(MAGNIFY):			
+		return(FINISHED);
+	default:
+		sprintf(errstr,"PROGRAMMING PROBLEM: Unknown process in param_preprocess()\n");
+		return(PROGRAM_ERROR);
+	}
+	return(FINISHED);	/* NOTREACHED */
+}
+
+/************ SETUP_INTERNAL_PARAMS_FOR_CLEAN *************/
+
+int setup_internal_params_for_clean(dataptr dz)
+{
+	int cc;
+	for(cc=0;cc < dz->clength;cc++)
+		dz->amp[cc]   = 0.0F;
+	switch(dz->mode) {
+	case(FROMTIME):  case(ANYWHERE):
+		if((dz->iparam[CL_SKIPW] = round(dz->param[CL_SKIPT]/dz->frametime))<SKIPWDWS)
+			dz->iparam[CL_SKIPW] = SKIPWDWS;
+		break;
+	case(COMPARING):
+		if((dz->iparray[CL_MARK] = (int *)malloc(dz->clength * sizeof(int)))==NULL) {
+			sprintf(errstr,"INSUFFICIENT MEMORY for clean marker store.\n");
+			return(MEMORY_ERROR);
+		}
+		for(cc=0;cc < dz->clength;cc++)
+			dz->iparray[CL_MARK][cc] = 1;
+		break;
+	case(FILTERING):
+		break;
+	default:
+		sprintf(errstr,"Unknown case in setup_internal_params_for_clean()\n");
+		return(PROGRAM_ERROR);
+	}
+	return(FINISHED);
+}
+
+/********************************************************************************************/
+/********************************** FORMERLY IN procspec.c **********************************/
+/********************************************************************************************/
+
+/**************************** SPEC_PROCESS_FILE ****************************/
+
+int spec_process_file(dataptr dz)
+{	
+	dz->total_windows = 0;
+
+	display_virtual_time(0L,dz);
+
+	switch(dz->process) {
+	case(GAIN):		return outer_loop(dz);
+	case(LIMIT):	return outer_loop(dz);
+	case(BARE):		return outer_loop(dz);
+
+	case(CLEAN):	return specclean(dz);
+	case(CUT):	 	return speccut(dz);									
+	case(GRAB):		return specgrab_or_magnify(GRAB_FRZTIME,dz);		
+	case(MAGNIFY):	return specgrab_or_magnify(MAG_FRZTIME,dz);			
+	default:
+		sprintf(errstr,"Unknown process in procspec()\n");
+		return(PROGRAM_ERROR);
+	}
+	return(FINISHED);	/* NOTREACHED */
+}
+
+/**************************** INNER_LOOP ****************************/
+
+int inner_loop
+(int *peakscore,int *descnt,int *in_start_portion,int *least,int *pitchcnt,int windows_in_buf,dataptr dz)
+{
+	int exit_status;
+	int local_zero_set = FALSE;
+	int wc;
+   	for(wc=0; wc<windows_in_buf; wc++) {
+		if(dz->total_windows==0) {
+			if((exit_status = skip_or_special_operation_on_window_zero(dz))<0)
+				return(exit_status);
+			if(exit_status==TRUE) {
+				dz->flbufptr[0] += dz->wanted;
+				dz->total_windows++;
+				dz->time = (float)(dz->time + dz->frametime);
+				continue;
+			}
+		}
+		if((exit_status = read_values_from_all_existing_brktables((double)dz->time,dz))<0)
+			return(exit_status);
+
+		switch(dz->process) {
+		case(BARE):		exit_status = specbare(pitchcnt,dz);	  			break;
+		case(GAIN):		exit_status = specgain(dz);	  						break;
+		case(LIMIT):	exit_status = speclimit(dz);  						break;
+		default:
+			sprintf(errstr,"unknown process in inner_loop()\n");
+			return(PROGRAM_ERROR);
+		}
+		if(exit_status<0)
+			return(exit_status);
+		dz->flbufptr[0] += dz->wanted;
+		dz->total_windows++;
+		dz->time = (float)(dz->time + dz->frametime);
+	}
+	if(!dz->zeroset && local_zero_set==TRUE) {
+		fprintf(stdout,"WARNING: Zero-amp spectral window(s) encountered: orig window(s) substituted.\n"); 
+		fflush(stdout);
+		dz->zeroset = TRUE;
+	}
+	return(FINISHED);
+}
+
+/***************** SKIP_OR_SPECIAL_OPERATION_ON_WINDOW_ZERO ************/
+
+int skip_or_special_operation_on_window_zero(dataptr dz)
+{
+	switch(dz->process) {
+	case(BARE):  
+		return(TRUE);
+	}
+	return(FALSE);
+}
+
+/********************************************************************************************/
+/********************************** FORMERLY IN pconsistency.c ******************************/
+/********************************************************************************************/
+
+/****************************** CHECK_PARAM_VALIDITY_AND_CONSISTENCY *********************************/
+
+int check_param_validity_and_consistency(dataptr dz)
+{
+	handle_pitch_zeros(dz);
+	switch(dz->process) {
+	case(CUT):	   	   return check_compatibility_of_cut_params(dz);
+	}
+	return(FINISHED);
+}
+
+/********************* CHECK_COMPATIBILITY_OF_CUT_PARAMS **********************/
+
+int check_compatibility_of_cut_params(dataptr dz)
+{
+	int startwindow = (int)(dz->param[CUT_STIME]/dz->frametime);
+	int endwindow   = (int)(dz->param[CUT_ETIME]/dz->frametime);
+	if(endwindow <= startwindow) {
+		sprintf(errstr,"Incompatible start and end times for cut.\n");
+		return(USER_ERROR);
+	}
+	return(FINISHED);
+}
+
+/********************************************************************************************/
+/********************************** FORMERLY IN buffers.c ***********************************/
+/********************************************************************************************/
+
+/**************************** ALLOCATE_LARGE_BUFFERS ******************************/
+
+int allocate_large_buffers(dataptr dz)
+{
+	switch(dz->process) {
+	case(GAIN):		case(LIMIT):	case(BARE):		
+	case(CLEAN):	case(GRAB):		case(MAGNIFY):	
+		return allocate_single_buffer(dz);
+
+	case(CUT): 		
+		return allocate_double_buffer(dz);
+	default:
+		sprintf(errstr,"Unknown program no. in allocate_large_buffers()\n");
+		return(PROGRAM_ERROR);
+	}
+	return(FINISHED);	/* NOTREACHED */
+}
+
+/********************************************************************************************/
+/********************************** FORMERLY IN cmdline.c ***********************************/
+/********************************************************************************************/
+
+int get_process_no(char *prog_identifier_from_cmdline,dataptr dz)
+{
+	if     (!strcmp(prog_identifier_from_cmdline,"gain"))	   		dz->process = GAIN;
+	else if(!strcmp(prog_identifier_from_cmdline,"gate"))	   		dz->process = LIMIT;
+	else if(!strcmp(prog_identifier_from_cmdline,"bare"))	   		dz->process = BARE;
+	else if(!strcmp(prog_identifier_from_cmdline,"clean"))     		dz->process = CLEAN;
+	else if(!strcmp(prog_identifier_from_cmdline,"cut"))	   		dz->process = CUT;
+	else if(!strcmp(prog_identifier_from_cmdline,"grab"))	   		dz->process = GRAB;
+	else if(!strcmp(prog_identifier_from_cmdline,"magnify"))   		dz->process = MAGNIFY;
+	else {
+		sprintf(errstr,"Unknown program identification string '%s'\n",prog_identifier_from_cmdline);
+		return(USAGE_ONLY);
+	}
+	return FINISHED;
+}
+
+/********************************************************************************************/
+/********************************** FORMERLY IN usage.c *************************************/
+/********************************************************************************************/
+
+/******************************** USAGE1 ********************************/
+
+int usage1(void)
+{
+	sprintf(errstr,
+	"\nSIMPLE OPERATIONS ON A SPECTRAL FILE\n\n"
+	"USAGE: spec NAME (mode) infile(s) outfile parameters: \n"
+	"\n"
+	"where NAME can be any one of\n"
+	"\n"
+	"gain   gate    bare    clean    cut    grab    magnify\n\n"
+	"Type 'spec gain' for more info on spec gain.. ETC.\n");
+	return(USAGE_ONLY);
+}
+
+/******************************** USAGE2 ********************************/
+
+int usage2(char *str)
+{
+	if(!strcmp(str,"gain")) {
+		sprintf(errstr,
+		"spec gain infile outfile gain\n"
+		"\n"
+		"AMPLIFY OR ATTENUATE THE SPECTRUM\n"
+		"\n"
+		"gain may vary over time.\n"
+		"\n");
+	} else if(!strcmp(str,"gate")) {
+		sprintf(errstr,
+		"spec gate infile outfile threshold\n\n"
+		"ELIMINATE CHANNEL DATA BELOW A THRESHOLD AMP\n\n"
+		"Threshold may vary over time. Range 0 to 1\n");
+	} else if(!strcmp(str,"bare")) {
+		sprintf(errstr,
+		"spec bare infile pitchfile outfile [-x]\n"
+		"\n"
+		"ZERO THE DATA IN CHANNELS WHICH DO NOT CONTAIN HARMONICS\n"
+		"\n"
+		"PITCHFILE must be extracted from your analysis file.\n"
+		"          (normally using -z flag to mark any unpitched material).\n"
+		"\n"
+		"-x        less body in resulting spectrum.\n");
+	} else if(!strcmp(str,"clean")) {
+		fprintf(stdout,
+		"spec clean 1-2 infile nfile       outfile skiptime [-gnoisgain]\n"
+		"spec clean 3   infile nfile       outfile freq     [-gnoisgain]\n"
+		"spec clean 4   infile nfile gfile outfile          [-gnoisgain]\n\n"
+		"REMOVE NOISE FROM PVOC ANALYSIS FILE.\n\n"
+		"INFILE,NFILE and GFILE are all pvoc analysis files.\n"
+		"NFILE and GFILE should be cut (spec cut) from INFILE\n"
+		"to show typical noise (NFILE) and good signal (GFILE).\n"
+		"SKIPTIME     (seconds) may be set to time at which\n"
+		"             good src. signal level has been established.\n"
+		"NOISGAIN     multiplies noiselevels found in NFILE before they are used\n"
+		"             for comparison with infile signal: (Default 2).\n"
+		"MODES\n"
+		"(1) deletes a channel (after skiptime) FROM THE TIME its level falls below\n"
+		"    the (noisgain adjusted) maximum level seen for that channel in NFILE.\n"
+		"(2) deletes channel (after skiptime) ANYWHERE its level falls below\n"
+		"    the (noisgain adjusted) maximum level seen for that channel in NFILE.\n"
+		"(3) Deletes channel as in MODE 2 but ONLY for channels of frq > FREQ.\n"
+		"(4) deletes channel EVERYWHERE, whose level in GFILE is ALWAYS below\n"
+		"    the (noisgain adjusted) maximum level seen for that channel in NFILE.\n");
+	} else if(!strcmp(str,"cut")) {
+		sprintf(errstr,
+		"spec cut infile outfile starttime endtime\n\n"
+		"CUT SECTION OUT OF ANALYSIS FILE, BETWEEN STARTTIME & ENDTIME (SECS)\n"
+		"\n");
+	} else if(!strcmp(str,"grab")) {
+		sprintf(errstr,
+		"spec grab infile outfile time\n\n"
+		"GRAB A SINGLE ANALYSIS WINDOW AT 'TIME'\n\n"
+		"A time beyond end of file will grab last window in file.\n"
+		"\n");
+	} else if(!strcmp(str,"magnify")) {
+		sprintf(errstr,
+		"spec magnify infile outfile time dur\n\n"
+		"MAGNIFY A SINGLE ANALYSIS WINDOW, AT TIME 'TIME', TO DURATION 'DUR'.\n"
+		"\n");
+	} else
+		sprintf(errstr,"Unknown option '%s'\n",str);
+	return(USAGE_ONLY);
+}
+
+/******************************** USAGE3 ********************************/
+
+int usage3(char *str1,char *str2)
+{
+	sprintf(errstr,"Insufficient parameters on command line.\n");
+	return(USAGE_ONLY);
+}
+

+ 234 - 0
dev/spec/main.c

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

+ 459 - 0
dev/spec/simple.c

@@ -0,0 +1,459 @@
+/*
+ * Copyright (c) 1983-2013 Trevor Wishart and Composers Desktop Project Ltd
+ * http://www.trevorwishart.co.uk
+ * http://www.composersdesktop.com
+ *
+ This file is part of the CDP System.
+
+    The CDP System is free software; you can redistribute it
+    and/or modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    The CDP System is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with the CDP System; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+    02111-1307 USA
+ *
+ */
+
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <structures.h>
+#include <tkglobals.h>
+#include <pnames.h>
+#include <globcon.h>
+#include <processno.h>
+#include <modeno.h>
+#include <arrays.h>
+#include <simple.h>
+#include <cdpmain.h>
+#include <formants.h>
+#include <speccon.h>
+#include <sfsys.h>
+#include <string.h>
+#include <simple.h>
+
+#define VERYBIG  		(10000.0)
+#define SRCFILE			(0)
+#define NOISEFILE		(1)
+#define COMPAREFILE		(2)
+
+static int  copy_cut_samps(int startwindow,int *endwindow,int windows_per_buf,int endchunksize,dataptr dz);
+static int  outer_clean_loop(int whichfile,int no_of_marked_channels,dataptr dz);
+static int  adjust_noise_level(dataptr dz);
+static int  setup_cleaning_filter(dataptr dz);
+static int  reorganise_marks(int *no_of_marked_channels,dataptr dz);
+static int  read_noise_data(int windows_in_buffer,dataptr dz);
+static int  read_comparison_data(int windows_in_buffer,dataptr dz);
+static int  do_cleaning(int windows_in_buffer,int no_of_marked_channels,dataptr dz);
+static int  skip_skipwindows(int *wc,int windows_in_buffer,dataptr dz);
+static int  generate_magnified_outfile(dataptr dz);
+static int  read_cut_samps(dataptr dz);
+
+/*********************** SPECGAIN ***************************/
+
+int specgain(dataptr dz)
+{
+	int vc;
+	for( vc = 0; vc < dz->wanted; vc += 2)
+		dz->flbufptr[0][AMPP] = (float)(dz->flbufptr[0][AMPP] * dz->param[GAIN_GAIN]);
+	return(FINISHED);
+}
+
+/*********************** SPECLIMIT ***************************/
+
+int speclimit(dataptr dz)
+{
+	int vc;
+	for( vc = 0; vc < dz->wanted; vc += 2) {
+		if(dz->flbufptr[0][AMPP] < dz->param[LIMIT_THRESH])
+			dz->flbufptr[0][AMPP] = 0.0f;
+	}
+	return(FINISHED);
+}
+
+/**************************** SPECCLEAN ***************************/
+
+int specclean(dataptr dz)
+{
+	int exit_status;
+	int no_of_marked_channels = 0;
+	if((exit_status = outer_clean_loop(NOISEFILE,no_of_marked_channels,dz))<0)
+		return(exit_status);
+	if((exit_status = adjust_noise_level(dz))<0)
+		return(exit_status);
+	switch(dz->mode) {
+	case(FILTERING):
+		if((exit_status = setup_cleaning_filter(dz))<0)
+			return(exit_status);
+		break;
+	case(COMPARING):
+		if((exit_status = outer_clean_loop(COMPAREFILE,no_of_marked_channels,dz))<0)
+			return(exit_status);
+		if((exit_status = reorganise_marks(&no_of_marked_channels,dz))<0)
+			return(exit_status);
+		break;
+	}
+	return outer_clean_loop(SRCFILE,no_of_marked_channels,dz);
+}
+
+/**************************** OUTER_CLEAN_LOOP ****************************/
+
+int outer_clean_loop(int whichfile,int no_of_marked_channels,dataptr dz)
+{
+	int exit_status;
+	int samps_read, windows_in_buffer;
+    while((samps_read = fgetfbufEx(dz->bigfbuf, dz->big_fsize,dz->ifd[whichfile],0)) > 0) {
+    	dz->flbufptr[0]    = dz->bigfbuf;
+	   	windows_in_buffer = samps_read/dz->wanted;
+		switch(whichfile) {
+		case(NOISEFILE):	
+			if((exit_status = read_noise_data(windows_in_buffer,dz))<0)
+				return(exit_status);
+			break;
+		case(COMPAREFILE):	
+			if((exit_status = read_comparison_data(windows_in_buffer,dz))<0)
+				return(exit_status);
+			break;
+		case(SRCFILE):		
+			if((exit_status = do_cleaning(windows_in_buffer,no_of_marked_channels,dz))<0)
+				return(exit_status);
+			break;
+    	default:
+    		sprintf(errstr,"Unknown option in outer_clean_loop()\n");
+			return(PROGRAM_ERROR);
+		}
+		if(whichfile==SRCFILE && (samps_read > 0)) {
+			if((exit_status = write_exact_samps(dz->bigfbuf,samps_read,dz))<0)
+				return(exit_status);
+		}
+	}  
+	if(samps_read<0) {
+		sprintf(errstr,"Sound read error.\n");
+		return(SYSTEM_ERROR);
+	}
+	if(whichfile!=SRCFILE)
+		dz->time = 0.0f;
+	return(FINISHED);
+}
+
+/************************ ADJUST_NOISE_LEVEL **********************/
+
+int adjust_noise_level(dataptr dz)
+{
+	int cc;
+	for( cc = 0; cc < dz->clength; cc++)
+		dz->amp[cc] = (float)(dz->amp[cc] * dz->param[CL_GAIN]);
+	return(FINISHED);
+}
+
+/************************* SETUP_CLEANING_FILTER ***************************/
+
+int setup_cleaning_filter(dataptr dz)
+{
+	int cc, vc;
+	double chtop   = dz->chwidth/2.0;
+	if(chtop < dz->param[CL_FRQ])
+		dz->amp[0] = 0.0f;
+	for( cc = 1, vc = 2; cc < dz->clength; cc++, vc +=2) {
+		chtop += dz->chwidth;
+		if(chtop < dz->param[CL_FRQ])
+			dz->amp[cc] = 0.0f;
+	}
+	return(FINISHED);
+}
+
+/************************ REORGANISE_MARKS **********************
+ *
+ * Instead of keeping 1024 marks, keep the locations of all SET marks!!
+ * Convert locations fron channel no (cc) to buffer location (vc)
+ */
+
+int reorganise_marks(int *no_of_marked_channels,dataptr dz)
+{
+	int n;
+	*no_of_marked_channels = 0;
+	for(n=0;n < dz->clength;n++) {
+		if(dz->iparray[CL_MARK][n]) {
+			dz->iparray[CL_MARK][*no_of_marked_channels] = n;
+			(*no_of_marked_channels)++;
+		}
+	}
+	if(*no_of_marked_channels==0) {
+		sprintf(errstr,"Comparison file is already clean, relative to noisefile.\n");
+		return(GOAL_FAILED);
+	}
+	for(n=0;n < *no_of_marked_channels; n++)		/* change marks from cc to vc */
+		dz->iparray[CL_MARK][n] *= 2;
+	return(FINISHED);
+}
+
+/************************* READ_NOISE_DATA ***************************/
+
+int read_noise_data(int windows_in_buffer,dataptr dz)
+{
+	int wc;
+	int cc, vc;
+	for(wc=0; wc<windows_in_buffer; wc++) {
+		for( cc = 0 ,vc = 0; cc < dz->clength; cc++, vc += 2) {
+			if(dz->flbufptr[0][AMPP] > dz->amp[cc]) 
+				dz->amp[cc] = dz->flbufptr[0][AMPP];
+		}
+		dz->flbufptr[0] += dz->wanted;
+	}
+	return(FINISHED);
+}
+
+/************************* READ_COMPARISON_DATA ***************************/
+
+int read_comparison_data(int windows_in_buffer,dataptr dz)
+{
+	int wc;
+	int cc, vc;
+	for(wc=0; wc<windows_in_buffer; wc++) {
+		for( cc = 0 ,vc = 0; cc < dz->clength; cc++, vc += 2) {
+			if(dz->flbufptr[0][AMPP] > dz->amp[cc])
+				dz->iparray[CL_MARK][cc] = 0;
+		}
+		dz->flbufptr[0] += dz->wanted;
+	}
+	return(FINISHED);
+}
+	
+/************************* DO_CLEANING ***************************/
+
+int do_cleaning(int windows_in_buffer,int no_of_marked_channels,dataptr dz)
+{
+	int exit_status;
+	int wc = 0;
+	int n, cc, vc;
+	switch(dz->mode) {
+	case(COMPARING):
+		for(wc=0; wc<windows_in_buffer; wc++) {
+			for(n=0;n<no_of_marked_channels;n++)
+				dz->flbufptr[0][dz->iparray[CL_MARK][n]] = 0.0F;
+			dz->flbufptr[0] += dz->wanted;
+		}
+		break;
+	case(FROMTIME):
+	case(ANYWHERE):
+		wc = 0;
+		if(!dz->finished) {
+			if((exit_status = skip_skipwindows(&wc,windows_in_buffer,dz))<0)
+				return(exit_status);
+			if(exit_status==FINISHED)
+				break;
+		}
+		/* fall thro */
+	case(FILTERING):
+		for(; wc<windows_in_buffer; wc++) {
+			for(cc=0, vc = 0;cc < dz->clength; cc++, vc += 2) {
+				if(dz->flbufptr[0][AMPP] < dz->amp[cc]) {
+					dz->flbufptr[0][AMPP] = 0.0F;
+					if(dz->mode==FROMTIME)
+						dz->amp[cc] = (float)VERYBIG;
+				}
+			}
+			dz->flbufptr[0] += dz->wanted;
+		}
+		break;
+	default:
+		sprintf(errstr,"unknown case in do_cleaning()\n");
+		return(PROGRAM_ERROR);
+	}
+	return(FINISHED);
+}
+
+/************************ SKIP_SKIPWINDOWS **********************/
+
+int skip_skipwindows(int *wc,int windows_in_buffer,dataptr dz)
+{
+	int step;
+	if((step = dz->iparam[CL_SKIPW] - dz->total_windows) >= windows_in_buffer) {
+		dz->total_windows += windows_in_buffer;
+		dz->time += dz->frametime * windows_in_buffer;
+		return(FINISHED);
+	} else {
+		dz->total_windows += step;
+		*wc = step;
+		dz->time += dz->frametime * step;
+		dz->flbufptr[0] += step * dz->wanted;
+		dz->finished = TRUE;		
+	}
+	return(CONTINUE);
+}
+
+/************************* SPECCUT ***************************/
+
+int speccut(dataptr dz)
+{
+	int exit_status;
+	int samps_remain, bufs_to_skip, endchunksize;
+	int startwindow = (int)(dz->param[CUT_STIME]/dz->frametime);
+	int endwindow   = (int)(dz->param[CUT_ETIME]/dz->frametime);
+	int windows_per_buf = dz->big_fsize/dz->wanted;
+	int w_to_skip = 0;
+	endwindow   = min(endwindow,dz->wlength);
+	if((bufs_to_skip = startwindow/windows_per_buf) > 0) { /* TRUNCATE */
+		w_to_skip = bufs_to_skip * windows_per_buf;
+		if((sndseekEx(dz->ifd[0],w_to_skip * dz->wanted,0))<0) {
+			sprintf(errstr,"Window seek failed: speccut().\n");
+			return(SYSTEM_ERROR);
+		}
+	}
+	startwindow -= w_to_skip;
+	endwindow   -= w_to_skip;
+	if((exit_status = read_cut_samps(dz))<0)
+		return(exit_status);
+	dz->flbufptr[0] = dz->bigfbuf + (startwindow * dz->wanted);
+	endchunksize  = windows_per_buf - startwindow;
+	dz->flbufptr[1] = dz->flbufptr[2];
+	if(endwindow > 0) {
+		do {
+			if((exit_status = copy_cut_samps(startwindow,&endwindow,windows_per_buf,endchunksize,dz))<0)
+				return(exit_status);
+		} while(exit_status==CONTINUE);
+	}
+	if((samps_remain = dz->flbufptr[1] - dz->flbufptr[2]) > 0) {
+		if((exit_status = write_samps(dz->flbufptr[2],samps_remain,dz))<0)
+			return(exit_status);
+	}
+	return(FINISHED);
+}
+
+
+/************************* COPY_CUT_SAMPS ***************************/
+
+int copy_cut_samps(int startwindow,int *endwindow,int windows_per_buf,int endchunksize,dataptr dz)
+{
+	int exit_status;
+	if(*endwindow >= windows_per_buf) {
+		memmove((char *)dz->flbufptr[1],(char *)dz->flbufptr[0],(size_t)(endchunksize * dz->wanted * sizeof(float)));
+		dz->flbufptr[1] += endchunksize * dz->wanted;
+		dz->flbufptr[0]  = dz->bigfbuf;
+		if((exit_status = read_cut_samps(dz))<0)
+			return(exit_status);
+		*endwindow -= windows_per_buf;
+	} else {
+		memmove((char *)dz->flbufptr[1],(char *)dz->flbufptr[0],(size_t)((*endwindow - startwindow) * dz->wanted * sizeof(float)));
+		dz->flbufptr[1] += (*endwindow - startwindow) * dz->wanted;
+		return(FINISHED);
+	}
+	if(*endwindow >= startwindow) {
+		if(startwindow > 0)
+			memmove((char *)dz->flbufptr[1],(char *)dz->flbufptr[0],(size_t)(startwindow * dz->wanted * sizeof(float)));
+		if((exit_status = write_exact_samps(dz->flbufptr[2],dz->big_fsize,dz))<0)
+			return(exit_status);
+		dz->flbufptr[1]  = dz->flbufptr[2];
+		dz->flbufptr[0] += startwindow * dz->wanted;
+	} else {
+		memmove((char *)dz->flbufptr[1],(char *)dz->flbufptr[0],(size_t)(*endwindow * dz->wanted * sizeof(float)));
+		dz->flbufptr[1] += *endwindow * dz->wanted;
+		return(FINISHED);
+	}
+	return(CONTINUE);
+}
+
+/****************************** SPECGRAB_OR_MAGNIFY ***************************/
+
+int specgrab_or_magnify(int frztime_paramno,dataptr dz)
+{
+	int exit_status;
+	int frzwindow, bufs_to_seek, samps_read;
+	int big_wsize = dz->big_fsize/dz->wanted;
+	frzwindow = (int)(dz->param[frztime_paramno]/dz->frametime); 		/* truncate */
+	frzwindow = min(frzwindow,dz->wlength-1); /* if time > filelen, get last window */
+	bufs_to_seek = (frzwindow * dz->wanted)/dz->big_fsize;				/* truncate */
+	if(sndseekEx(dz->ifd[0],bufs_to_seek * dz->big_fsize,0)<0) {
+		sprintf(errstr,"seek failed in specgrab_or_magnify().\n");
+		return(SYSTEM_ERROR);
+	}
+	if((samps_read = fgetfbufEx(dz->bigfbuf,dz->big_fsize,dz->ifd[0],0)) < dz->wanted) {
+		if(samps_read<0) {
+			sprintf(errstr,"Sound read error.\n");
+			return(SYSTEM_ERROR);
+		} else {
+			sprintf(errstr,"Problem reading infile data in specgrab_or_magnify().\n");
+			return(PROGRAM_ERROR);
+		}
+	}
+	frzwindow -= bufs_to_seek * big_wsize;
+	dz->flbufptr[0] = dz->bigfbuf + (frzwindow * dz->wanted);
+	switch(dz->process) {
+	case(GRAB):
+		if((exit_status = write_samps(dz->flbufptr[0],dz->wanted,dz))<0)
+			return(exit_status);
+		break;
+	case(MAGNIFY):
+    	dz->total_windows = round(dz->param[MAG_DUR]/dz->frametime);
+		return generate_magnified_outfile(dz);
+		break;
+	default:
+		sprintf(errstr,"unknown application in specgrab_or_magnify()\n");
+		return(PROGRAM_ERROR);
+	}
+	return(FINISHED);
+}
+
+/******************************** GENERATE_MAGNIFIED_OUTFILE **********************************/
+
+
+int generate_magnified_outfile(dataptr dz)
+{
+    int exit_status;
+    int wc, windows_left;
+    int vc, cc, written_whole_buffer = 0;
+    int w_to_buf = dz->big_fsize/dz->wanted;
+    float *bigbufend = dz->bigfbuf + dz->big_fsize;
+
+	memmove((char *)dz->windowbuf[0],(char *)dz->flbufptr[0],(size_t)(dz->wanted * sizeof(float)));
+    dz->flbufptr[0]  = dz->bigfbuf;
+    for(wc=0; wc<dz->total_windows; wc++) {
+		memmove((char *)dz->flbufptr[0],(char *)dz->windowbuf[0],(size_t)(dz->wanted * sizeof(float)));
+        if((dz->flbufptr[0] += dz->wanted) >= bigbufend) {
+            if(!written_whole_buffer) {
+                for( cc = 0 ,vc = 0; cc < dz->clength; cc++, vc += 2)
+                    dz->bigfbuf[vc] = 0.0F;                                 /* ZERO AMPS IN WINDOW ONE */
+            }
+			if((exit_status = write_exact_samps(dz->bigfbuf,dz->big_fsize,dz))<0)
+                return(exit_status);
+            if(!written_whole_buffer)                                       /* RESTORE DATA IN WINDOW ONE */
+				memmove((char *)dz->bigfbuf,(char *)dz->windowbuf[0],(size_t)(dz->wanted * sizeof(float)));
+            written_whole_buffer = 1;
+            dz->flbufptr[0] = dz->bigfbuf;
+		}
+    }
+    if(!written_whole_buffer) {
+		for( cc = 0 ,vc = 0; cc < dz->clength; cc++, vc += 2)
+            dz->bigfbuf[vc] = 0.0F;                         /* ZERO AMPS IN WINDOW ONE */
+		if(dz->flbufptr[0] -  dz->bigfbuf > 0) {
+			if((exit_status = write_samps(dz->bigfbuf,dz->flbufptr[0] -  dz->bigfbuf,dz))<0)
+				return(exit_status);
+		}
+    } else {
+        if((windows_left  = dz->total_windows % w_to_buf)> 0) {
+            if((exit_status = write_samps(dz->bigfbuf,windows_left * dz->wanted,dz))<0)
+                return(exit_status);
+        }
+    }
+    return(FINISHED);
+}
+
+/************************* READ_CUT_SAMPS ***************************/
+
+int read_cut_samps(dataptr dz)
+{
+	if(fgetfbufEx(dz->bigfbuf,dz->big_fsize,dz->ifd[0],0) < 0) {
+		sprintf(errstr,"Window read failed: read_cut_samps().\n");
+		return(SYSTEM_ERROR);
+	}
+	return(FINISHED);
+}