diff model/model.c @ 0:5242703e91d3 tip

Initial checkin for AIM92 aimR8.2 (last updated May 1997).
author tomwalters
date Fri, 20 May 2011 15:19:45 +0100
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/model/model.c	Fri May 20 15:19:45 2011 +0100
@@ -0,0 +1,2426 @@
+/*
+    Copyright (c) Applied Psychology Unit, Medical Research Council. 1988, 1989
+    ===========================================================================
+
+    Permission to use, copy, modify, and distribute this software without fee 
+    is hereby granted for research purposes, provided that this copyright 
+    notice appears in all copies and in all supporting documentation, and that 
+    the software is not redistributed for any fee (except for a nominal shipping 
+    charge). Anyone wanting to incorporate all or part of this software in a
+    commercial product must obtain a license from the Medical Research Council.
+
+    The MRC makes no representations about the suitability of this 
+    software for any purpose.  It is provided "as is" without express or implied 
+    warranty.
+*/
+
+/*
+	model.c
+	=====
+
+    APU, ASP model demonstration program.
+
+
+    Copyright (c), 1989  The Medical Research Council, Applied Psychology Unit.
+
+
+    Author  : John Holdsworth
+    Written : 22th March, 1989.
+
+    Edited  : Mike Allerhand, 1990.
+
+    Edited  : Roy Patterson, 1992. Changed default values from time to time.
+
+    Edited  : MAA 10th June 1993
+	      Allowed pwidth=0
+
+    Edited  : Christian Giguere, March 1994. 
+	      - Added tools for manipulating sampling rate and scaling data
+	      - Added in an Entry Point for the outer/middle ear function
+	      - Added in an Entry Point for the transmission line filterbank
+	      - Implemented a completely new version of Meddis(). 
+                Files "haircell.h, haircell.c "                             
+	      - Changed option "scale_at" into "gain_at".
+	          That option is now passed to newCorti() as a double instead of an integer
+	          In Corti(), this meant multiplying *optr by state->scale
+              - Provided facilities to print filterbank information to stderr via
+                option info_afb. This supersedes option erbscale_afb.
+	      - Changed some default values
+              - To locate changes, search for "CG"
+
+    Edited  : Jay Datta, November 1994.
+              Added the stcrit options.
+
+            : Jay Datta, March 1995.
+              Added a function Nwidth() which returns the number
+              of sample points of the nwidth section of a SAI. 
+            : Silenced ulim_sas and llim_sas.  
+            : Changed trise_at default to 1000 from 10000. May, 1995.
+            : Changed trise_at default to 10000 from 1000. May, 1995.
+            : Separated nwidth and strobe lag by creating a new
+              option called stlag_ai.   May, 1995.
+
+*/
+
+/***************************************************************************
+* This module contains:
+*   Routines to access or modify string values.
+*   Unit conversion routines.
+*   Model entry-point functions.
+****************************************************************************/
+
+#include <string.h>
+#include  <stdio.h>
+#include   <math.h>
+
+#ifdef THINK_C
+#include <stdlib.h>
+#endif
+
+/* interfaces to stitch system */
+
+#include "options.h"
+
+#include "stitch.h"
+#include "source.h"
+#include  "funcs.h"
+#include  "units.h"
+#include   "calc.h"
+#if defined( DSP32 ) || defined( PC )
+#include   "oops.h"
+#else
+#include    "ops.h"
+#endif
+#include     "io.h"
+
+/* interface to model modules */
+
+#include "gamma_tone.h"
+#include  "integrate.h"
+#include   "formulae.h"              /* CG: removed haircell.h */
+#include    "recurse.h"
+#include     "scales.h"
+#include     "spiral.h"
+#include      "model.h"
+#include      "corti.h"
+#include      "image.h"
+#include       "bank.h"
+
+/* interface to WDF module */        /* CG */
+
+#include "formulae_tl.h"
+#include    "upsample.h"
+#include     "bank_tl.h"
+#include     "calc_tl.h"
+#include      "meddis.h"
+#include         "ear.h"
+
+/********************* Model option parameter strings ***********************
+* The strings are defined, allocated static array space, and initialized to
+* default values.
+****************************************************************************/
+
+#ifndef  lint
+static char *sccs_id = "@(#)model.c	1.49 John Holdsworth, Mike Allerhand, Roy Patterson, Paul Manson (MRC-APU) 12/23/92" ;
+#endif
+
+/* which model to use */
+
+char  whichdflt[] = "none"     ,        *whichstr = whichdflt  ;
+char sampledflt[] = "20000."   ,       *samplestr = sampledflt ;
+
+/* input properties */
+
+static char     dBdflt[] = "60."      ,           *dBstr = dBdflt     ;  /* CG */
+static char   bitsdflt[] = "12"       ,          *bitstr = bitsdflt   ;
+static char   swapdflt[] = "off"      ,         *swapstr = swapdflt   ;
+
+
+/************************ File-format strings ******************************
+* The strings are defined, allocated static array space, and initialized to
+* default values.
+****************************************************************************/
+
+#define RETURN_SIZE 50l
+
+static char      framesbuff[RETURN_SIZE] = "0",       *framesstr = framesbuff ;
+static char       bytesbuff[RETURN_SIZE] = "1",   *framebytesstr = bytesbuff  ;
+static char       widthbuff[RETURN_SIZE] = "1",   *framewidthstr = widthbuff  ;
+static char      heightbuff[RETURN_SIZE] = "1",  *frameheightstr = heightbuff ;
+static char        stepbuff[RETURN_SIZE] = "1",    *framestepstr = stepbuff   ;
+static char nwidthdflt[] = "-5ms"     ,       *nwidthstr = nwidthdflt ; /* roy 23-12-92 */
+static char stlagdflt[]   = "5ms"     ,       *stlagstr   = stlagdflt ; /* jay 16-05-95 */
+static char   susldflt[] = "5"      ,       *suslevelstr = susldflt   ; /* jay 30-08-95 */
+/************************ File-format strings *******************************
+*
+* The data which flows through the model is called a "file".
+* This is in an array which is structured or formatted according to the way
+* data is interpreted as it is pulled from each particular source.
+* The array is formatted into "frames", described by the file-format strings.
+* The format may be as successive points, (in which case each frame is a
+* single point with unit width and height), or the format may be as successive
+* 2-dimensional arrays, (in which case each frame is an array divided into
+* rows and columns).
+*
+* The strings are defined, allocated static array space, and initialized in
+* gen.c. A set of convenience routines (see below) are given to access or to
+* reset the value of a string. This enables the file format to be set up on
+* the fly, depending upon the format of the data passing through the source.
+*
+*  string:        access:     reset:          comment:
+* framesstr      Frames      setFrames       num frames in file
+* framebytesstr  Framebytes  setFramebytes   num bytes in frame
+* framewidthstr  Framewidth  setFramewidth   num points along frame width
+* frameheightst  Frameheight setFrameheight  num points along frame height
+* framestepstr   Framestep   setFramestep    num points between successive frames
+*
+* Access routines for file-format strings:
+*    Frames      returns value of "framesstr",      (initially 0)
+*    Framebytes  returns value of "framebytesstr",  (initially 1)
+*    Framewidth  returns value of "framewidthstr",  (initially 1)
+*    Frameheight returns value of "frameheightstr", (initially 1)
+*    Framestep   returns value of "framestepstr",   (initially 1)
+*
+****************************************************************************/
+
+long Frames()
+{
+    return ( atoi( framesstr      ) ) ;
+}
+
+int Framebytes()
+{
+    return ( atoi( framebytesstr  ) ) ;
+}
+
+int Framewidth()
+{
+    return ( atoi( framewidthstr  ) ) ;
+}
+
+int Frameheight()
+{
+    return ( atoi( frameheightstr ) ) ;
+}
+
+int Framestep()
+{
+    return ( atoi( framestepstr  ) ) ;
+}
+
+int  Nwidth()
+{     
+      int abc = (Samples(stlagstr, Samplerate()));
+      if ( (int)atoi(suslevelstr)>=4)
+      /* fprintf(stderr, "Nwidth is %d\n", -abc); */
+      return (-abc);
+      else
+      return 0;  
+}
+
+
+/******************* Value-to-string conversion routines. ******************/
+char *ltoa( val, buffer )
+long val ;
+char *buffer ;
+{
+    (void) sprintf( buffer, "%ld", val ) ;
+
+    return ( buffer ) ;
+}
+
+char *itoa( val, buffer )
+int val ;
+char *buffer ;
+{
+    (void) sprintf( buffer, "%d", val ) ;
+
+    return ( buffer ) ;
+}
+
+/******************* Reset routines for file-format strings ****************
+*  Convert argument (newval) to a string, and copy into the specific
+*  file-format string.
+*    setFrames      resets  "framesstr",      (initially 0)
+*    setFramebytes  resets  "framebytesstr",  (initially 1)
+*    setFramewidth  resets  "framewidthstr",  (initially 1)
+*    setFrameheight resets  "frameheightstr", (initially 1)
+*    setFramestep   resets  "framestepstr",   (initially 1)
+*
+*    updateFramebytes sets  "framebytesstr" to the total number of bytes in
+*                                     the frame, (ie current width * height).
+*
+*    Note: updateFramebytes is automatically done at the end of each call to
+*          setFramewidth or setFrameheight, to reset the "framebytesstr" to
+*          account for the new frame size.
+****************************************************************************/
+
+void setFrames( newval )
+long newval ;
+{
+    framesstr = ltoa( newval, framesbuff ) ;
+    return ;
+}
+
+void setFramebytes( newval )
+int newval ;
+{
+    framebytesstr  = itoa( newval, bytesbuff ) ;
+    return ;
+}
+
+void updateFramebytes()
+{
+    setFramebytes( Framewidth() * Frameheight() * sizeof ( short ) ) ;
+    return ;
+}
+
+void setFramewidth( newval )
+int newval ;
+{
+    framewidthstr  = itoa( newval, widthbuff ) ;
+    updateFramebytes() ;
+    return ;
+}
+
+void setFrameheight( newval )
+int newval ;
+{
+    frameheightstr = itoa( newval, heightbuff ) ;
+    updateFramebytes() ;
+    return ;
+}
+
+void setFramestep( newval )
+int newval ;
+{
+    framestepstr   = itoa( newval, stepbuff ) ;
+    return ;
+}
+
+
+static Option wavopts[] = {
+
+ { "framebytes",   bytesbuff, &framebytesstr,   "framebytes - internal",                 SilentOption},
+ { "framebytes",   bytesbuff, &framebytesstr,   "framebytes - internal",                 OutputOption},
+ { "frameheight", heightbuff, &frameheightstr,  "frameheight - internal",                SilentOption},
+ { "frameheight", heightbuff, &frameheightstr,  "frameheight - internal",                OutputOption},
+ { "framewidth",   widthbuff, &framewidthstr,   "framewidth - internal",                 SilentOption},
+ { "framewidth",   widthbuff, &framewidthstr,   "framewidth - internal",                 OutputOption},
+ { "frameshift",    stepbuff, &framestepstr,    "framestep - internal",                  SilentOption},
+ { "frameshift",    stepbuff, &framestepstr,    "framestep - internal",                  OutputOption},
+ { "frames",      framesbuff, &framesstr,       "frames - internal",                     SilentOption},
+ { "frames",      framesbuff, &framesstr,       "frames - internal",                     OutputOption},
+
+ { "samplerate",  sampledflt, &samplestr,       "Input wave sample rate (Hz)",            InOutOption},
+ { "swap_wave",     swapdflt, &swapstr,         "Swap bytes in input wave",               InOutOption},
+ { "bits_wave",     bitsdflt, &bitstr,          "Significant bits in input wave",         SilentOption},
+ { "dB_wave",        dBdflt,  &dBstr,           "Rel. input level (_tlf & _med only)\n",  InOutOption},  /* CG */
+ { "what",         whichdflt, &whichstr,        "Type of model to use required",         SilentOption},
+
+ (char *) 0 } ;
+
+
+/***************** Tools for manipulating sampling rate *********************    * CG *
+* This set of two routines allows to change and keep track of the sampling
+* rate of the data which flows through the model. It is the responsability
+* of each entry-point function to update the sampling rate as necessary.
+*
+*  routine:-       comment:-
+*  Samplerate      returns the current value of the sampling rate
+*  SetSamplerate   resets the sampling rate
+****************************************************************************/
+
+static double rateCache = 0.0 ;
+
+void setSamplerate( newval )
+double newval ;
+{
+    rateCache = newval ;
+    return ;
+}
+
+double Samplerate()
+{
+    if( rateCache == 0 )
+	rateCache = Freq( samplestr ) ;
+
+    return( rateCache ) ;
+}
+
+/******************* Tools for checking for special strings ****************
+*  OptionInt( str )
+*  OptionDouble( str )
+*  OptionStringsEqual( str1, str2 )     -(defined in options.c).
+****************************************************************************/
+
+double OptionDouble( str )
+char *str ;
+{
+    if( strcmp( str, "on" ) == 0 )
+	return( 1. ) ;
+    else if( strcmp( str, "Not_used" ) == 0 )
+	return( 0. ) ;
+    else
+	return( atof( str ) ) ;
+}
+
+int OptionInt( str )
+char *str ;
+{
+    if( strcmp( str, "on" ) == 0 )
+	return( 1 ) ;
+    else if( strcmp( str, "Not_used" ) == 0 )
+	return( 0 ) ;
+    else
+	return( atoi( str ) ) ;
+}
+
+int OptionLog ( str )
+char *str ;
+{
+   if ( strcmp( str, "off" ) == 0 )
+	return( 0 ) ;
+    else
+        return( 1 ) ;
+}
+
+
+
+
+/************************* Tools for scaling data **************************     * CG *
+* This set of two routines allows to keep track of the scaling factor needed 
+* to convert the data which flows through the model into absolute units in
+* the cgs system ( 0.0002 dyne/cm2 ==> 0 dB SPL). It is the responsability of
+* each entry-point function to update the correct scaling factor as necessary.
+* The user must initially specify the scaling of the input wave using the
+* "dB_wave" option. The default is "dB_wave=60.".
+*
+*  routine:-     comment:-
+*  Scaling       returns a scalar to convert data to cgs units
+*  SetScaling    resets the scaling factor
+****************************************************************************/
+
+static double scalingCache = 0.0 ;
+
+void setScaling( from_rms, from_dB, to_rms, to_dB )
+double from_rms, from_dB, to_rms, to_dB ;
+{
+    scalingCache = pow( 10., ( from_dB - to_dB ) / 20. ) * to_rms / from_rms ;
+}
+
+double Scaling()
+{
+    double rms = 200. ;      /* the default: 200 rms ==> 60 dB */
+    double dB  =  60. ;
+
+    if( scalingCache == 0 ) {
+    
+	if( strcmp( dBstr, "off" ) != 0 )
+	   dB = Scalar( dBstr ) ;
+	setScaling( rms, dB, 0.0002, 0. ) ;
+    }
+
+   return( scalingCache ) ;
+}
+
+/************************  entry-point functions ***************************
+* Each entry-point function creates and initializes a "source object", and
+* returns a pointer to this object. Each source set up by one of the routines
+* below is designed to be the entry point for a specialized auditory-modelling
+* process. (See also io.c for sources which read from disk).
+* Source set-up functions always return a Source. They may take one or more
+* sources as arguments, as a specification of the input to the process
+* the source performs. The set up routine intializes the source structure with
+* a pointer to a callback function, which performs the data processing when
+* the source is used.
+*
+* Pointers to the entry-point functions are defined in the stage table,
+* (see FindStage() below). The functions are called, using these pointers,
+* from routine ModeledSource() (see below). The purpose of this is to call the
+* functions, in the order set by the stage table, so as to initialize a chain
+* of objects which can ultimately be used to execute the program.
+*
+* The source set-up routines are analogous to fopen(), (see stitch/source.c).
+* The processing phase, (analogous to fread()), uses pull/fill/roll functions,
+* and this execution is started from gen.c:main() by a call to SinkSource().
+*
+*   routine:-                   special subroutines:-
+*   EarEntry()                  Ear()                                           * CG *
+*   GenericEntry()              GenericFilterBank()
+*   FilterEntry()               GenericEntry()
+*   TLF_FilterEntry()           TLF_GenBank()                                   * CG *
+*   FineEntry()                 EarEntry() FilterEntry() TLF_FilterEntry()      * CG *
+*   EnvelopeEntry()             GenericEntry()
+*   ComplexEntry()              GenericEntry()
+*   PolarEntry()
+*   RectifyEntry()
+*   LogEntry()
+*   UncompressEntry()
+*   SaturateEntry()             Saturate()
+*   LowpassEntry()              LowpassDataTypeSource()
+*   ThresholdEntry()            Meddis()  Mfsai()
+*   AdaptEntry()
+*   HardEntry()                 Saturate()
+*   IntegralEntry()             LowpassDataTypeSource()
+*   DownSampleEntry()           DownSampleSource() BlockSampleSource()
+*   SaiEntry()                  Sai()
+*   SummaryEntry()              Summary()
+*   NullEntry()
+****************************************************************************/
+
+/* As a means of introducing "cgm" as an alias for "fed", this NullEntry point does
+   absolutely nothing to the data, but it DOES enable us to enter the queue just above
+   the entry point for "fed". */
+
+static Source NullEntry( source )
+Source source ;
+{
+    return ( source ) ;
+}
+
+
+/***** upsampling parameters *****/                                     /* CG */
+
+static char    upfdflt[] = "auto"     ,          *upfstr = upfdflt    ; /* CG */
+static char cutoffdflt[] = "1.0"      ,       *cutoffstr = cutoffdflt ; /* CG */
+static char  downfdflt[] = "auto"     ,        *downfstr = downfdflt  ; /* CG */
+
+/***** ear parameters *****/                                            /* CG */
+ 
+static char middledflt[] = "on"       ,       *middlestr = middledflt ; /* CG */
+static char  lconcdflt[] = "0.90"     ,        *lconcstr =  lconcdflt ; /* CG */
+static char  rconcdflt[] = "1.00"     ,        *rconcstr =  rconcdflt ; /* CG */
+static char  kconcdflt[] = "0.01"     ,        *kconcstr =  kconcdflt ; /* CG */
+static char  nconcdflt[] = "2"        ,        *nconcstr =  nconcdflt ; /* CG */
+static char lcanaldflt[] = "2.85"     ,       *lcanalstr = lcanaldflt ; /* CG */
+static char rcanaldflt[] = "0.35"     ,       *rcanalstr = rcanaldflt ; /* CG */
+static char kcanaldflt[] = "0.04"     ,       *kcanalstr = kcanaldflt ; /* CG */
+static char ncanaldflt[] = "4"        ,       *ncanalstr = ncanaldflt ; /* CG */
+
+static Source EarEntry( source )                                  /* CG: new entry */
+Source source ;
+{
+    int     upfactor, downfactor ;
+    double  cutoff, gain = OptionDouble( middlestr ) ;
+    DeclareNew( struct _tube_info *, concha ) ;
+    DeclareNew( struct _tube_info *, canal ) ;
+
+    if( gain ) {
+
+      /*** set up/downsampling parameters ***/
+       if( strncmp( upfstr, "auto", 4 ) == 0 ) {
+	   if( strncmp( downfstr, "auto", 4 ) == 0 )
+	      upfactor = MIN( AUTO, ( int ) ( ( MAXSIGNALFREQ * AUTO * 2 ) / Samplerate() + 1.0 ) ) ;
+	   else 
+	      upfactor = ABS( OptionInt( downfstr ) ) ;
+	      downfactor = upfactor ;
+       }
+       else {
+	   upfactor = ABS( OptionInt( upfstr ) ) ;
+	   if( strncmp( downfstr, "auto", 4 ) == 0 )
+	      downfactor = upfactor ; 
+	   else
+	      downfactor = ABS( OptionInt( downfstr ) ) ;
+       }
+	   
+      /*** set cutoff frequency of FIR upsampling filter ***/
+       cutoff = 0.5 * Samplerate() * Scalar( cutoffstr ) ;
+       if( downfactor > upfactor ) {
+	   upfactor = MAX( 1, upfactor ) ;
+	   cutoff = cutoff * ( double ) upfactor / ( double ) downfactor ;
+       }    
+   
+      /*** upsample input wave ***/
+       if( upfactor >= 1 ) {
+	   source = UpSample( source, Samplerate(), cutoff, upfactor ) ;
+	   ( void ) setSamplerate( Samplerate() * upfactor ) ;
+	   ( void ) setFrames( Frames() * upfactor ) ;
+       }
+
+      /*** outer/middle ear filter ***/
+       concha->Nsegments = atoi( nconcstr ) ;
+       concha->length = atof( lconcstr ) ;
+       concha->diameter = atof( rconcstr ) * 2. ;
+       concha->att_factor = atof( kconcstr ) ;
+       canal->Nsegments = atoi( ncanalstr ) ;
+       canal->length = atof( lcanalstr ) ;
+       canal->diameter = atof( rcanalstr ) * 2. ;
+       canal->att_factor = atof( kcanalstr ) ;
+
+       source = Ear( source, Samplerate(), gain, concha, canal ) ;
+
+       Delete( concha ) ;
+       Delete( canal ) ;
+
+      /*** downsample output data ***/
+       if( downfactor >= 1 ) {
+	   source = DownSampleSource( source, downfactor, 1 ) ;
+	   ( void ) setSamplerate( Samplerate() / downfactor ) ;
+	   ( void ) setFrames( Frames() / downfactor ) ;
+       }
+
+    }
+    return ( source ) ;
+}
+
+
+/***** frequency scale parameters*****/
+
+static char   qualdflt[] = "9.265"    ,         *qualstr = qualdflt   ;
+static char  limitdflt[] = "24.7Hz"   ,        *limitstr = limitdflt  ;
+static char     mmdflt[] = "0.89"     ,           *mmstr = mmdflt     ; /* CG */
+
+static char interpdflt[] = "off"      ,       *interpstr = interpdflt ;
+
+/***** filterbank parameters ****/
+
+static char    maxdflt[] = "6000Hz"   ,          *maxstr = maxdflt    ; /* roy 23-12-92 */
+static char    mindflt[] = "100Hz"    ,          *minstr = mindflt    ; /* roy 23-12-92 */
+#ifdef PC
+static char    dendflt[] = "off"      ,          *denstr = dendflt    ; /* roy 23-12-92 */
+#else
+static char    dendflt[] = "off"      ,          *denstr = dendflt    ; /* roy 23-12-92 */
+#endif
+static char  chansdflt[] = "75"       ,        *chansstr = chansdflt  ; /* roy 23-12-92 */
+static char  audiodflt[] = "off"      ,        *audiostr = audiodflt  ; /* CG */
+static char   infodflt[] = "off"      ,         *infostr = infodflt   ; /* CG */
+
+static char filterdflt[] = "gtf"      ,       *filterstr = filterdflt ; /* CG */
+
+
+/****************************************************************************
+* updateFrequencies()
+* Routine called from ModeledSource(), below.
+* It sets the frameheight (number of filter-bank channels), and initializes
+* the array of channel centre-frequencies, (called "frequencies").
+* These are derived from three basic parameters:
+* option-name:  string-value: default:  comment:
+*  mincf_afb      minstr       220Hz    Minimum center frequency (Hz)
+*  maxcf_afb      maxstr       4400Hz   Maximum center frequency (Hz)
+*  dencf_afb      denstr       4.       Filter density (filters/critical band)
+*
+* The frameheight is calculated in the routine "NumberCenterFrequencies",
+* and the result is copied into the "frameheightstr" by a call to the routine
+* "setFrameheight".
+* The "frequencies" are calculated in the routine "GenerateCenterFrequencies".
+* (Both CenterFrequency routines are in gamma_tone.c).
+*
+* The frequencies are stored in a global array of center frequencies (below).
+****************************************************************************/
+
+double *frequencies ;    /* global array of centre frequencies */
+
+static void reverseFrequencies( freqs, channels )
+double *freqs ;
+int channels ;
+{
+    int i ;
+    double d ;
+
+    for( i=0 ; i<channels/2 ; i++ ) {
+	d = freqs[i] ;
+	freqs[i] = freqs[channels-i] ;
+	freqs[channels-i] = d ;
+    }
+}
+
+
+static void updateFrequencies()                                     /* CG: modified */
+{
+    int    chans = OptionInt( chansstr ) ;
+    double min, max, density = atof( denstr ) ;
+
+    if( frequencies != (double *) 0 )
+	Delete( frequencies ) ;
+
+    SetErbParameters( Freq( limitstr ), atof( qualstr ) ) ;
+
+    if( strncmp( filterstr, "tlf", 3 ) == 0 ) {
+
+	if( chans == 0 && density == 0. )
+	    chans = 1 ;
+
+	min  = adjustCF( Freq( minstr ), Samplerate() ) ;
+	max  = adjustCF( MAX( Freq( maxstr ), min ), Samplerate() ) ;
+    }
+
+    else {
+	min  = Freq( minstr ) ;
+	max  = Freq( maxstr ) ;
+    }
+
+    if( chans == 0 ) {
+	frequencies = GenerateCenterFrequencies( min, max, density )   ;
+	setFrameheight( NumberCenterFrequencies( min, max, density ) ) ;
+    }
+    else {
+	frequencies = NumberedCenterFrequencies( min, max, chans )   ;
+	setFrameheight( chans ) ;
+    }
+
+/*
+    reverseFrequencies( Frequencies, Frameheight() ) ;
+*/
+
+    return ;
+}
+
+
+ChannelAxis( min, max, label )
+double *min, *max ;
+char **label ;
+{
+    *min = (int) ( ErbScale( Freq( minstr ) ) * 10. ) / 10. ;
+    *max = (int) ( ErbScale( Freq( maxstr ) ) * 10. ) / 10. ;
+
+    *label = "Center Frequency [ERBs]" ;
+}
+
+/***** GTF auditory filter parameters *****/                             /* CG */
+
+static char  orderdflt[] = "4"        ,        *orderstr = orderdflt  ;
+static char  phasedflt[] = "0"        ,        *phasestr = phasedflt  ;
+static char   gaindflt[] = "4."       ,         *gainstr = gaindflt   ;
+static char  floatdflt[] = "off"      ,        *floatstr = floatdflt  ;
+
+static Source GenericEntry( source, proc )                               /* CG */
+Source source ;
+int (*proc)() ;
+{
+    int chans ;
+    Source ret ;
+
+    updateFrequencies() ;
+
+    chans  = Frameheight() ;
+    ret = GenericFilterBank( source, OptionInt( interpstr ), &chans, Samplerate(), 
+                      frequencies, Erb, ErbScale, Scalar( gainstr ), OptionDouble( audiostr ),
+                      atoi( orderstr ), atoi( phasestr ), atoi( bitstr ), Frames(), proc, 
+                      sizeof ( DataType ), OptionInt( infostr ) ) ;      /* CG */
+
+    setFrameheight( chans ) ;
+
+    return ( ret ) ;
+}
+
+static Source FilterEntry( source )
+Source source ;
+{
+    switch( OptionInt( floatstr ) ) {
+#ifdef FLOAT
+	case 0 :
+	case 1 :
+	    return ( GenericEntry( source, DoRealFilterFloatDataArray ) ) ;
+#else
+	case 0 :
+	    return ( GenericEntry( source,     DoFilterShortDataArray ) ) ;
+	case 1 :
+	    return ( GenericEntry( source, DoRealFilterShortDataArray ) ) ;
+#endif 
+	case 2 :
+	    return ( GenericEntry( source,       DoNewFilterDataArray ) ) ;
+    }
+
+    return ( source ) ;
+}
+
+/***** TLF auditory filter parameters *****/                             /* CG */
+
+static char  tgaindflt[] = "4."       ,        *tgainstr = tgaindflt  ;  /* CG */
+static char   dsatdflt[] = "5.75e-6"  ,         *dsatstr = dsatdflt   ;  /* CG */
+static char   feeddflt[] = "0.99"     ,         *feedstr = feeddflt   ;  /* CG */
+static char   qrefdflt[] = "2."       ,         *qrefstr = qrefdflt   ;  /* CG */ 
+static char outdendflt[] = "4."       ,       *outdenstr = outdendflt ;  /* CG */
+static char motiondflt[] = "vel"      ,       *motionstr = motiondflt ;  /* CG */
+
+static Source TLF_FilterEntry( source )                                  /* CG: new entry */
+Source source ;
+{
+    int chans ;
+    int upfactor, downfactor ;
+    double cutoff, dsat ;
+    DeclareNew( struct _tube_info *, concha ) ;
+    DeclareNew( struct _tube_info *, canal ) ;
+
+   /*** set up/downsampling parameters ***/
+    if( strncmp( upfstr, "auto", 4 ) == 0 ) {
+	if( strncmp( downfstr, "auto", 4 ) == 0 )
+	   upfactor = MIN( AUTO, ( int ) ( ( MAXSIGNALFREQ * AUTO * 2 ) / Samplerate() +1.0 ) ) ;
+	else 
+	   upfactor = ABS( OptionInt( downfstr ) ) ;
+	downfactor = upfactor ;
+    }
+    else {
+	upfactor = ABS( OptionInt( upfstr ) ) ;
+	if( strncmp( downfstr, "auto", 4 ) == 0 )
+	   downfactor = upfactor ; 
+	else
+	   downfactor = ABS( OptionInt( downfstr ) ) ;
+    }
+	   
+   /*** set cutoff frequency of FIR upsampling filter ***/
+    cutoff = 0.5 * Samplerate() * Scalar( cutoffstr ) ;
+    if( downfactor > upfactor ) {
+	upfactor = MAX( 1, upfactor ) ;
+	cutoff = cutoff * ( double ) upfactor / ( double ) downfactor ;
+    }    
+  
+   /*** upsample input wave ***/
+    if( upfactor >= 1 ) {
+	source = UpSample( source, Samplerate(), cutoff, upfactor ) ;
+	( void ) setSamplerate( Samplerate() * upfactor ) ;
+	( void ) setFrames( Frames() * upfactor ) ;
+    }
+
+   /*** set outer/middle ear parameters ***/
+    concha->Nsegments = atoi( nconcstr ) ;
+    concha->length = atof( lconcstr ) ;
+    concha->diameter = atof( rconcstr ) * 2. ;
+    concha->att_factor = atof( kconcstr ) ;
+    canal->Nsegments = atoi( ncanalstr ) ;
+    canal->length = atof( lcanalstr ) ;
+    canal->diameter = atof( rcanalstr ) * 2. ;
+    canal->att_factor = atof( kcanalstr ) ;
+
+   /*** set bank parameters ***/
+    updateFrequencies() ;
+    SetERBscaling( atof( mmstr ) ) ;
+    chans = Frameheight() ;
+
+   /*** OHC normalization: converts from cgs units (0 dB SPL=>0.0002 dynes/cm2) to input wave units ***/
+    dsat = atof( dsatstr ) / Scaling() ;
+
+   /*** process data and downsample output ***/
+    source = TLF_GenBank( source, OptionInt( interpstr ), OptionInt( infostr ), &chans, &downfactor, 
+                          Samplerate(), frequencies, Scalar( tgainstr ), atof( outdenstr ),
+			  atof( qrefstr ), atof( feedstr ), dsat, motionstr, concha, canal ) ;
+
+   /*** reset sampling rate and file-format strings ***/
+    ( void ) setFrameheight( chans ) ;
+    ( void ) setSamplerate ( Samplerate() / downfactor ) ;  
+    ( void ) setFrames( Frames() / downfactor ) ;
+
+    Delete( concha ) ;
+    Delete( canal ) ;
+
+    return ( source ) ;
+}
+
+static Source FineEntry(source )                                 /* CG: new Entry */
+Source source ;
+{
+    if( strncmp( filterstr, "off", 3 ) == 0 )
+	source = EarEntry( source ) ;
+
+    else {
+
+	if( strncmp( filterstr, "tlf", 3 ) == 0 )
+	    source = TLF_FilterEntry( source ) ;
+
+	else {
+       	    source = EarEntry( source ) ;
+	    source = FilterEntry( source ) ;
+	}
+    }
+
+    return( source ) ;
+}
+
+static Source EnvelopeEntry( source )
+Source source ;
+{
+#ifdef FLOAT
+    return ( GenericEntry( source, DoRealEnvelopeFloatDataArray ) ) ;
+#else
+    if( OptionInt( floatstr ) != 0 )
+	return ( GenericEntry( source, DoRealEnvelopeShortDataArray ) ) ;
+    else
+	return ( GenericEntry( source,     DoEnvelopeShortDataArray ) ) ;
+#endif
+}
+
+static Source ComplexEntry( source )
+Source source ;
+{
+    Source ret ;
+
+#ifdef FLOAT
+    ret = GenericEntry( source, DoComplexFilterFloatDataArray ) ;
+#else
+    ret = GenericEntry( source, DoComplexFilterShortDataArray ) ;
+#endif
+    setFrameheight( Frameheight() * 2 ) ;
+
+    return ( ret ) ;
+}
+
+/******* [fbm] [bmm] [fcp,fcr] stage: "auditory filter output" ************/
+
+static  Option fbmopts[] = {
+
+ {     "upfactor",    upfdflt,    &upfstr, "Upsampling factor (off, auto, int)",        SilentOption},  /* CG */
+ {       "cutoff", cutoffdflt, &cutoffstr, "LP cutoff as a fraction of Nyquist freq.",  SilentOption},  /* CG */
+ {   "downfactor",  downfdflt,  &downfstr, "Downsampling factor (off, auto, int)\n",    SilentOption},  /* CG */
+
+ {   "middle_ear", middledflt, &middlestr, "Enable outer/middle ear function\n",         InOutOption},  /* CG */
+ {  "nconcha_ear",  nconcdflt,  &nconcstr, "Number of segments in concha",              SilentOption},  /* CG */
+ {  "lconcha_ear",  lconcdflt,  &lconcstr, "Total length of concha (cm)",               SilentOption},  /* CG */
+ {  "rconcha_ear",  rconcdflt,  &rconcstr, "Radius of concha (cm)",                     SilentOption},  /* CG */
+ {  "kconcha_ear",  kconcdflt,  &kconcstr, "Attn. constant of concha (1/cm)",           SilentOption},  /* CG */
+ {   "ncanal_ear", ncanaldflt, &ncanalstr, "Number of segments in ear canal",           SilentOption},  /* CG */
+ {   "lcanal_ear", lcanaldflt, &lcanalstr, "Length of ear canal (cm)",                  SilentOption},  /* CG */
+ {   "rcanal_ear", rcanaldflt, &rcanalstr, "Radius of ear canal (cm)",                  SilentOption},  /* CG */
+ {   "kcanal_ear", kcanaldflt, &kcanalstr, "Attn. constant of ear canal (1/cm)\n",      SilentOption},  /* CG */
+
+ { "channels_afb",  chansdflt,  &chansstr, "Number of channels in filter",               InOutOption},
+ {    "mincf_afb",    mindflt,    &minstr, "Minimum center frequency (Hz)",              InOutOption},
+ {    "maxcf_afb",    maxdflt,    &maxstr, "Maximum center frequency (Hz)",              InOutOption},
+ {    "dencf_afb",    dendflt,    &denstr, "Filter density (filters/critical band)",     InOutOption},
+ {     "info_afb",  infodflt,    &infostr, "Prints filterbank information (to stderr).", InputOption},  /* CG */
+ {   "interp_afb", interpdflt, &interpstr, "Levels of interpolation to apply",          OutputOption},
+ {   "interp_afb", interpdflt, &interpstr, "Levels of interpolation to apply",          SilentOption},
+ {"audiogram_afb",  audiodflt,  &audiostr, "Audiogram equalisation parameter",          SilentOption},  /* CG */ 
+ {    "bwmin_afb",  limitdflt,  &limitstr, "Minimum filter bandwith",                    InOutOption},
+ {  "quality_afb",   qualdflt,   &qualstr, "Ultimate qualtity factor of filters",        InOutOption},
+ {    "mmerb_afb",     mmdflt,     &mmstr, "Length of 1 erb-rate unit along BM (mm)\n",  InOutOption},  /* CG */
+
+ {       "filter", filterdflt, &filterstr, "Select auditory filter (gtf, tlf, off)\n",   InOutOption},  /* CG */
+
+ {    "float_gtf",  floatdflt,  &floatstr, "Floating point filter calculations",        OutputOption},
+ {    "float_gtf",  floatdflt,  &floatstr, "Floating point filter calculations",        SilentOption},
+ {    "phase_gtf",  phasedflt,  &phasestr, "Phase compensation option",                  InOutOption},
+ {    "order_gtf",  orderdflt,  &orderstr, "Filter order",                               InOutOption},
+ {     "gain_gtf",   gaindflt,   &gainstr, "Filter output amplification\n",              InOutOption},  /* CG */
+
+ {   "motion_tlf", motiondflt, &motionstr, "BM output motion (disp, vel)",               InOutOption},  /* CG */
+ { "outdencf_tlf", outdendflt, &outdenstr, "Filter density outside display range",       InOutOption},  /* CG */
+ {     "qref_tlf",   qrefdflt,   &qrefstr, "Local Q-factor of BM segment",               InOutOption},  /* CG */
+ { "feedback_tlf",   feeddflt,   &feedstr, "Feedback gain of OHCs (0 to 0.999)",         InOutOption},  /* CG */
+ {     "dsat_tlf",   dsatdflt,   &dsatstr, "Half-saturation displacement (cm)",          InOutOption},  /* CG */
+ {     "gain_tlf",  tgaindflt,  &tgainstr, "Filter output amplification\n",              InOutOption},  /* CG */
+
+ ( char * ) 0 } ;
+
+static void polar_callback( state, bytes, output, end, input )
+Source state ;
+ByteCount *bytes ;
+scomplex *output, *end, *input ;
+{
+    register scomplex *iptr = input ;
+    register scomplex *optr = output ;
+    register scomplex *eptr = end ;
+
+    while( optr < eptr ) {
+	optr->real = imB( (long) iptr->real * iptr->real + (long) iptr->imag * iptr->imag ) >> 1 ;
+	optr->imag = iatan2( iptr->imag, iptr->real ) ;
+	iptr++ ;
+	optr++ ;
+    }
+
+    return ;
+}
+
+static Source PolarEntry( source )
+Source source ;
+{
+    return ( NewSimpleProcessingSource( polar_callback, source, "model.c polar conversion" ) ) ;
+}
+
+static void fullwave_callback( state, bytes, buffer, end, input )
+Source state ;
+ByteCount *bytes ;
+DataType *buffer, *end, *input ;
+{
+    register DataType *iptr = input ;
+    register DataType *optr = buffer ;
+    register DataType *eptr = end ;
+
+    if( optr < eptr )
+	do
+	    if( *iptr > 0 )
+		*optr++ =  *iptr++ ;
+	    else
+		*optr++ = -*iptr++ ;
+
+	while( optr < eptr ) ;
+
+    return ;
+}
+
+
+/* rectification */
+
+static char   rectdflt[] =     "off",   *rectstr =   rectdflt ;
+
+/************** [fbr] stage: "rectified filter output" ******************/
+
+static  Option fbropts[] = {
+
+ {      "rectify",   rectdflt,   &rectstr, "Rectify filter output",                      InOutOption},
+
+ ( char * ) 0 } ;
+
+
+static void halfwave_callback( state, bytes, buffer, end, input )
+Source state ;
+ByteCount *bytes ;
+DataType *buffer, *end, *input ;
+{
+    register DataType *iptr = input ;
+    register DataType *optr = buffer ;
+    register DataType *eptr = end ;
+
+    if( optr < eptr )
+	do
+	    if( *iptr > 0 )
+		*optr++ =  *iptr++ ;
+	    else
+		*optr++ =0,*iptr++ ;
+
+	while( optr < eptr ) ;
+
+    return ;
+}
+
+static Source RectifyEntry( source )
+Source source ;
+{
+    switch( OptionInt( rectstr ) ) {
+
+	case 1 :
+	    return ( SharingSource( NewSimpleProcessingSource( halfwave_callback, source, "model.c recification" ), source ) ) ;
+
+	case 2:
+	    return ( SharingSource( NewSimpleProcessingSource( fullwave_callback, source, "model.c recification" ), source ) ) ;
+
+	default :
+	    return ( source ) ;
+    }
+}
+
+
+/*********** [fbc] [fec] stage: "compressed filter output" **************/
+
+/* logaritmic compression function */
+
+static char    logdflt[] =      "log",    *logstr =    logdflt ;
+static char    powdflt[] =      "off",    *powstr =    powdflt ;
+
+static  Option fbcopts[] = {
+
+ {     "compress",    logdflt,    &logstr, "Compression (log, power value [0-1], off)",   InOutOption},
+ ( char * ) 0 } ;
+
+
+#ifdef FLOAT
+static void mB_callback( state, bytes, buffer, end, input )
+Pointer state ;
+ByteCount *bytes ;
+DataType *buffer, *end, *input ;
+{
+    register DataType *iptr = input  ;
+    register DataType *optr = buffer ;
+    register DataType *eptr = end ;
+    double pw;
+
+    if (!strcmp(logstr, "log") || !strcmp(logstr, "on"))
+      ;
+    else 
+      {
+	pw=(double)atof(logstr);
+        strcpy(powstr, "on");
+	if (pw > 1.0) {
+          fprintf(stderr, "The value of power compression cannot be more than 1.0\n");
+	  exit(-125);}
+      }
+    
+    if( optr < eptr )
+      do{
+	if( *iptr  >= 1. ){
+	  if (!(strcmp(powstr, "off"))){
+	    *optr = log10( *iptr ) * 2000. ;} 
+	  else{ 
+	    *optr = (float) pow((double)*iptr, (double) pw) * 100./(pw); } 
+	}
+	else
+	     *optr =   0. ;   /* -10.    Changed from -10,  AJD 29th August, 1995.  */
+	     iptr++; optr++;  }
+      while( optr < eptr ) ;
+
+    return ;
+
+}
+#endif
+
+static Source LogEntry( source )
+Source source ;
+{
+    if( OptionLog( logstr ) != 0 )
+#ifdef FLOAT
+	return ( SharingSource( NewSimpleProcessingSource( mB_callback, source, "model.c compression" ), source ) ) ;
+#else
+	return ( SharingSource( milliBellShortSource( source ), source ) ) ;
+#endif
+    else
+	return ( source ) ;
+}
+
+/*********** [fbu] [feu] stage: "uncompressed filter output" **************/
+
+/***** uncompress data by raising to a power *****/
+
+static char  powerdflt[] =     "off",  *powerstr =  powerdflt ;
+
+static  Option fbuopts[] = {
+
+ {        "power",  powerdflt,  &powerstr, "Power of Compression",                      SilentOption},
+
+ ( char * ) 0 } ;
+
+
+struct _uncompress_state { double power ; } ;
+
+static void uncompress_callback( state, bytes, buffer, end, input )
+struct _uncompress_state *state ;
+ByteCount *bytes ;
+DataType *buffer, *end, *input ;
+{
+    register DataType *iptr = input  ;
+    register DataType *optr = buffer ;
+    register DataType *eptr = end ;
+    register double power = state->power ;
+
+    if( optr < eptr )
+	do
+	    *optr++ = pow( 10., *iptr++ * power ) ;
+	while( optr < eptr ) ;
+
+    return ;
+}
+static Source UncompressEntry( source )
+Source source ;
+{
+    DeclareNew( struct _uncompress_state *, state ) ;
+
+    if( OptionDouble( powerstr ) != 0.0 ) {
+
+	state->power  = OptionDouble( powerstr ) / 2000. ;
+
+	return ( SharingSource (NewProcessingSource( state, uncompress_callback, stitch_free, source, "model.c compression" ), source ) ) ;
+    }
+    else
+	return ( source ) ;
+}
+
+/*********** [fbs] [fes] stage: "saturated filter output" **************/
+
+/***** provide for possible saturation at this point *****/
+
+static char    satdflt[] =     "off",    *satstr =    satdflt ;
+
+static  Option fbsopts[] = {
+
+ {     "saturate",    satdflt,    &satstr, "Introduce Saturation of non-linearity\n",   SilentOption},
+
+ ( char * ) 0 } ;
+
+
+struct _sat_state { int saturation ; } ;
+
+static void sat_callback( state, bytes, buffer, end, input )
+struct _sat_state *state ;
+ByteCount *bytes ;
+DataType *buffer, *end, *input ;
+{
+    register DataType *iptr = input ;
+    register DataType *optr = buffer ;
+    register DataType *eptr = end ;
+
+    if( optr < eptr )
+	do {
+
+	     if( *iptr > 0 )
+		 *optr++ = SCALE( *iptr ) / ( SCALE( 1 ) + SCALE( *iptr ) / state->saturation ) ;
+	     else
+		 *optr++ = SCALE( *iptr ) / ( SCALE( 1 ) - SCALE( *iptr ) / state->saturation ) ;
+	     iptr++ ;
+
+	} while( optr < eptr ) ;
+
+    return ;
+}
+
+static Source Saturate( source, str )
+Source source ;
+char *str ;
+{
+    DeclareNew( struct _sat_state *, state ) ;
+
+    if( OptionInt( str ) != 0 ) {
+
+	state->saturation = OptionInt( str ) ;
+
+	return ( SharingSource( NewProcessingSource( (Pointer) state, sat_callback, stitch_free, source, "model.c stauration"  ), source ) ) ;
+    }
+    else
+	return ( source ) ;
+}
+
+static Source SaturateEntry( source )
+Source source ;
+{
+    return( Saturate( source, satstr ) ) ;
+}
+
+#if 00
+/***** new processing entry *****/
+
+static char zongdflt[] =     "off", *zongstr = zongdflt ; /* parameter default for table.c */
+
+static Source ZongEntry( source )
+Source source ;
+{
+    int i, chans = Frameheight() ;
+    DeclareNewArray( WuState *, states, chans, "model.c for states" ) ;
+
+    /* for all of the channels create a new wu cels object */
+
+    for( i=0 ; i<chans ; i++ )
+	states[ i ] = NewWu( zongstr ) ; /* call constructor of new wu cell */
+
+    /* use general purpose source for processing multiplexed files with these cells */
+
+return (source ) ;
+    return ( NewMultiplexedSource( states, WuMultiplexedDataArray, DeleteWu, chans, source, "model.c wu" ) ) ;
+}
+#endif
+
+/*********** [fbl] [fel] stage: "low-pass filtered filter output ***********/
+
+/* low pass filtering */
+
+static char lstagedflt[] =     "off", *lstagestr = lstagedflt ;
+static char    lupdflt[] =   "0.5ms",    *lupstr =    lupdflt ;
+static char  ldowndflt[] =       "1",  *ldownstr =  ldowndflt ;
+static char  llossdflt[] =       "1",  *llossstr =  llossdflt ;
+static char lvlossdflt[] =       "0", *lvlossstr = lvlossdflt ;
+static char ligaindflt[] =       "1", *ligainstr = ligaindflt ;
+
+static  Option fblopts[] = {
+
+ {   "ligain_lpf", ligaindflt, &ligainstr, "Gain of integration stage\n",               OutputOption},
+ {   "ligain_lpf", ligaindflt, &ligainstr, "Gain of integration stage\n",               SilentOption},
+ {   "lvloss_lpf", lvlossdflt, &lvlossstr, "Rest level for loss",                       OutputOption},
+ {   "lvloss_lpf", lvlossdflt, &lvlossstr, "Rest level for loss",                       SilentOption},
+ {    "lloss_lpf",  llossdflt,  &llossstr, "Loss time constant",                        OutputOption},
+ {    "lloss_lpf",  llossdflt,  &llossstr, "Loss time constant",                        SilentOption},
+ {   "ltdown_lpf",  ldowndflt,  &ldownstr, "Downward time constant in ms",              OutputOption},
+ {   "ltdown_lpf",  ldowndflt,  &ldownstr, "Downward time constant in ms",              SilentOption},
+ {     "ltup_lpf",    lupdflt,    &lupstr, "Upward time constant in ms",                SilentOption},
+ {  "lstages_lpf", lstagedflt, &lstagestr, "Stages of integration\n",                   SilentOption},
+
+ ( char * ) 0 } ;
+
+static Source LowpassEntry( source )
+Source source ;
+{
+    return ( LowpassDataTypeSource( source, OptionInt( lstagestr ), Frameheight(), Samples( lupstr, Samplerate() ), Samples( ldownstr, Samplerate() ), Scalar( ligainstr ) ) ) ;
+}
+
+
+/*********** [nap,fbt] [fet] stage: "neural activity pattern" **************/
+
+/***** transduction switch *****/                              /* CG */
+
+static char  transdflt[] =    "at", *transstr = transdflt ;    /* CG */
+
+
+/***** meddis inner haircell model *****/                      /* CG */
+
+static char meddisdflt[] =    "1.", *meddisstr = meddisdflt ;
+static char  fibredflt[] ="medium",  *fibrestr = fibredflt ;   /* CG */
+static char thresdflt[] =     "0.",  *thresstr = thresdflt ;   /* CG */
+
+Source Meddis( input, chans, samplerate, scalar )              /* CG: modified */
+Source input ;
+int chans ;
+double samplerate, scalar ;
+{
+    char *state ;
+    double coupling = 100. / pow( 10., atof( thresstr ) / 20. ) ;
+
+   /*** convert from filterbank units to meddis units (30 dB => 1 rms ) ***/
+
+      /* first convert from filterbank output units to cgs units (0 dB SPL => 0.0002 dynes/cm2) ***/
+       ( void ) setScaling( 0.0002 / Scaling() * FILTERBANK_SCALE * 4.0, 0., 0.0002, 0. ) ;
+
+      /* second convert from cgs units to meddis units (30 dB => 1 rms) ***/
+       ( void ) setScaling( 0.0002 / Scaling(), 0., MEDDIS_RMS, MEDDIS_dB ) ;
+
+   /*** start array of Meddis hair cells ***/
+    coupling = coupling * Scaling() ;
+    state = NewHaircells( chans, samplerate, scalar, coupling, fibrestr ) ;
+    return ( NewProcessingSource( state, DoHaircells, CloseHaircells, input, "model.c meddis" ) ) ;
+}
+
+/***** adaptive thresholding *****/
+
+static char    stxdflt[] =      "1.",    *stxstr =    stxdflt ; /* CG 23-03-94 */
+static char   risedflt[] =  "10000.",   *risestr =   risedflt ;
+static char  rapiddflt[] =     "0.6",  *rapidstr =  rapiddflt ;
+static char   fastdflt[] =     "0.2",   *faststr =   fastdflt ;
+static char   propdflt[] =     "0.5",   *propstr =   propdflt ;
+static char    latdflt[] =     "20.",    *latstr =    latdflt ; /* roy 23-12-92 */
+static char vdraindflt[] =       "5", *vdrainstr = vdraindflt ;
+static char  timesdflt[] =       "2",  *timesstr =  timesdflt ;
+
+static char   compdflt[] =     "on",    *compstr =   compdflt ; /* mha 22/1/93 */
+
+
+static  Option fbtopts[] = {
+
+ { "transduction",  transdflt,  &transstr, "Select transduction function (at, meddis, off)\n",InOutOption},  /* CG */
+ 
+ {     "trise_at",   risedflt,   &risestr, "Threshold adaptation rate (upwards)",        InOutOption},
+ {"t1recovery_at",  rapiddflt,  &rapidstr, "Initial recovery rate relative to filter",   InOutOption},
+ {"t2recovery_at",   fastdflt,   &faststr, "Secondary recovery rate relative to filter", InOutOption},
+ {  "propt2t1_at",   propdflt,   &propstr, "Relative height of secondary adaptation",    InOutOption},
+ { "frecovery_at",    latdflt,    &latstr, "Recovery rate across frequency",             InOutOption},
+ {  "reclimit_at", vdraindflt, &vdrainstr, "Limitation on recovery level",               InOutOption},
+ {     "times_at",  timesdflt,  &timesstr, "Oversampling of calculation of threshold",  OutputOption},
+ {     "times_at",  timesdflt,  &timesstr, "Oversampling of calculation of threshold",  SilentOption},
+ {"compensate_at",   compdflt,   &compstr, "Cochlea output compensation",               SilentOption},
+ {      "gain_at",    stxdflt,    &stxstr, "Adaptive thresholding output gain\n",        InOutOption},  /* CG */ 
+
+ {    "fibre_med",  fibredflt,  &fibrestr, "Spont-rate fibre type (medium, high)",       InOutOption},  /* CG */
+ {   "thresh_med", thresdflt,   &thresstr, "Haircell threshold shift (dB)",              InOutOption},  /* CG */
+ {     "gain_med", meddisdflt, &meddisstr, "Meddis haircell model output gain\n",        InOutOption},  /* CG */
+
+ ( char * ) 0 } ;
+
+static Source ThresholdEntry( source )                           /* CG: modified */
+Source source ;
+{
+    double density ;
+
+    if( OptionInt( chansstr ) == 0 )
+	density = OptionDouble( denstr ) ;
+    else 
+	density = OptionInt( chansstr ) / ( ErbScale( Freq( maxstr ) ) - ErbScale( Freq( minstr ) ) ) ;
+
+    if( strncmp( transstr, "off", 3 ) == 0 ) 
+        source = source ;
+
+    else {
+
+        if( strncmp( transstr, "med", 3 ) == 0 )
+            source = Meddis(  source, Frameheight(), Samplerate(), OptionDouble( meddisstr ) ) ;
+
+        else {
+	   compensate = OptionDouble( compstr ) ;
+
+	   source = NewProcessingSource(
+		         newCorti(
+		             Frameheight(), Samplerate(), frequencies, Erb,
+			     atof(  risestr ), atof(  latstr ) * density,
+			     atof( rapidstr ), atof( faststr ), atof( propstr ),
+			     log10( Scalar( vdrainstr ) ) * 2000.,
+			     (int) ( density * atof( latstr ) / Samplerate() + 1. ) * atoi( timesstr ),
+			     OptionDouble( stxstr )
+			 ), (void ( * )()) Corti, closeCorti,
+			 source,
+			 "model.c thresholding"
+		   ) ;
+
+         }
+    }
+    return ( source ) ;
+}
+
+/* modulation frequency image */
+
+static char stepmfdflt[] =   "250Hz", *stepmfstr = stepmfdflt ;
+static char  maxmfdflt[] =   "250Hz",  *maxmfstr =  maxmfdflt ;
+static char  minmfdflt[] =    "50Hz",  *minmfstr =  minmfdflt ;
+static char  denmfdflt[] =     "off",  *denmfstr =  denmfdflt ;
+
+#ifndef DSP32
+
+Source Mfsai( source, segment )                               /* CG */
+Source source ;
+int segment ;
+{
+    extern char *filestr ;
+    Source mfsource = FileNameSource( filestr ) ;
+    int frameheight = Frameheight() ;
+    int i ;
+
+    frequencies = GenerateCenterFrequencies( Freq( minmfstr ), Freq( maxmfstr ), OptionDouble( denmfstr ) ) ;
+    setFrameheight( NumberCenterFrequencies( Freq( minmfstr ), Freq( maxmfstr ), OptionDouble( denmfstr ) ) ) ;
+
+    mfsource = GenericEntry( mfsource, DoFilterShortDataArray ) ;
+   /*  mfsource = GenericEntry( mfsource, DoNewFilterDataArray ) ; */
+    mfsource = NewProcessingSource(
+		newCorti(
+		    Frameheight(), Samplerate(), frequencies, Erb,
+		    atof( risestr ), atof( latstr ) * OptionDouble( denmfstr ),
+		    atof( rapidstr ), atof( faststr ), atof( propstr ),
+		    log10( Scalar( vdrainstr ) ) * 2000., /* convert to millibells */
+		    (int) ( OptionDouble( denmfstr ) * atof( latstr ) / Samplerate() + 1. ) * atoi( timesstr ),
+		    0
+		), (void ( * )()) Corti, closeCorti,
+		mfsource,
+		"model.c thresholding"
+	    ) ;
+
+    return ( mfsource ) ;
+}
+
+#endif
+/***** long term adaptation  - not implemented - used to sneak in modulation frequency thing *****/
+
+static char   adapdflt[] =       "0",   *adapstr =   adapdflt ;
+
+static Source AdaptEntry( source )
+Source source ;
+{
+#ifndef DSP32
+    if( OptionDouble( denmfstr ) > 0 )
+	source = Mfsai( source ) ;
+#endif
+    return( source ) ;
+}
+
+/*********** [fba] [fea] stage: "adapted transduced filter output" *********/
+
+static  Option fbaopts[] = {
+
+ {   "mmincf_mfb",  minmfdflt,  &minmfstr, "Minimum modulation frequency (Hz)",         SilentOption},
+ {   "mmaxcf_mfb",  maxmfdflt,  &maxmfstr, "Maximum modulation frequency (Hz)",         SilentOption},
+ {   "mdencf_mfb",  denmfdflt,  &denmfstr, "Modulation filter density ",                SilentOption},
+ {   "stepcf_mfb", stepmfdflt, &stepmfstr, "Step between images\n",                     SilentOption},
+
+ {  "tadaptation",   adapdflt,   &adapstr, "Time constant of long term adaptation\n",   SilentOption},
+
+ ( char * ) 0 } ;
+
+
+
+/***** hard limiting *****/
+
+static char   harddflt[] =     "off",   *hardstr =   harddflt ;
+
+static Source HardEntry( source )
+Source source ;
+{
+    return( Saturate( source, hardstr ) ) ;
+}
+
+/*********** [fbh] [feh] stage: "hard limited filter output" **************/
+
+static  Option fbhopts[] = {
+
+ {   "hard_limit",   harddflt,   &hardstr, "Hardlimit firing rate before integration\n",OutputOption},
+ {   "hard_limit",   harddflt,   &hardstr, "Hardlimit firing rate before integration\n",SilentOption},
+
+ ( char * ) 0 } ;
+
+
+/***** [sgm,cgm,fbd,fbi] [fed,fei] stage: "integrated filter output" *******/
+
+/***** temporal integration *****/
+
+static char  stagedflt[] =     "off",  *stagestr =  stagedflt ;
+static char     updflt[] =     "8ms",     *upstr =     updflt ;
+static char   downdflt[] =       "1",   *downstr =   downdflt ;
+static char   lossdflt[] =       "1",   *lossstr =   lossdflt ;
+static char  vlossdflt[] =       "0",  *vlossstr =  vlossdflt ;
+static char  igaindflt[] =       "1",  *igainstr =  igaindflt ;
+
+static  Option fbiopts[] = {
+
+ {   "stages_idt",  stagedflt,  &stagestr, "Stages of integration",                      InOutOption},
+ {    "igain_idt",  igaindflt,  &igainstr, "Gain of integration stage\n",               OutputOption},
+ {    "igain_idt",  igaindflt,  &igainstr, "Gain of integration stage\n",               SilentOption},
+
+ {    "vloss_idt",  vlossdflt,  &vlossstr, "Rest level for loss",                       OutputOption},
+ {    "vloss_idt",  vlossdflt,  &vlossstr, "Rest level for loss",                       SilentOption},
+ {     "loss_idt",   lossdflt,   &lossstr, "Loss time constant",                        OutputOption},
+ {     "loss_idt",   lossdflt,   &lossstr, "Loss time constant",                        SilentOption},
+ {    "tdown_idt",   downdflt,   &downstr, "Downward time constant in ms",              OutputOption},
+ {    "tdown_idt",   downdflt,   &downstr, "Downward time constant in ms",              SilentOption},
+ {      "tup_idt",     updflt,     &upstr, "Low-pass filter time constant",              InOutOption},
+
+ ( char * ) 0 } ;
+
+static Source IntegralEntry( source )
+Source source ;
+{
+    return ( LowpassDataTypeSource( source, OptionInt( stagestr ), Frameheight(), Samples( upstr, Samplerate() ), Samples( downstr, Samplerate() ), Scalar( igainstr ) ) ) ;
+}
+
+
+/* downsampling */
+
+static char  downsdflt[] =     "off",  *downsstr =  downsdflt ;
+
+static Option dwnopts[] = {
+
+ { "downsample",   downsdflt, &downsstr,  "Downsampling over time",                    InOutOption},
+ { "frstep_epn",   downsdflt, &downsstr,  "Downsampling over time\n",                  InOutOption},
+
+ (char *) 0 } ;
+
+static Source DownSampleEntry( source )
+Source source ;
+{
+    int spacing = Samples( downsstr, Samplerate() ) ;
+    int channels = Frameheight() * Framewidth() ;
+
+    if( spacing != 0 ) {
+
+#if defined( PC ) || defined( DSP32 )
+	source = NewSegmentingSource( source, Frameheight() * Framewidth() * sizeof ( DataType ) * 4 ) ;
+#endif
+
+	if( spacing > 0 )
+	    source  = DownSampleSource( source, spacing, channels ) ;
+	else {
+	    spacing = -spacing ;
+	    source = BlockSampleSource( source, spacing, channels ) ;
+	}
+
+	setFramestep( spacing ) ;
+
+	setFrames( Frames() / spacing ) ;
+    }
+
+    return( source ) ;
+}
+
+
+/* stabilised image defaults */
+
+static char   llimdflt[] = "1.5c"     ,         *llimstr = llimdflt   ;
+static char   ulimdflt[] = "24ms"     ,         *ulimstr = ulimdflt   ;
+
+static char    saidflt[] = "1"        ,          *saistr = saidflt    ;
+#ifdef PC
+static char pwidthdflt[] = "20ms"     ,       *pwidthstr = pwidthdflt ;
+#else
+static char pwidthdflt[] = "35ms"     ,       *pwidthstr = pwidthdflt ; /* roy 23-12-92 */
+#endif
+/* static char nwidthdflt[] = "-5ms"     ,       *nwidthstr = nwidthdflt ; roy 23-12-92 */
+
+static char  ltlimdflt[] = "150Hz"    ,        *ltlimstr = ltlimdflt  ;
+static char  utlimdflt[] = "20Hz"      ,        *utlimstr = utlimdflt ;
+static char  decaydflt[] = "30ms"     ,        *decaystr = decaydflt  ;
+static char    cgmdflt[] = "2.5"     ,          *cgmstr = cgmdflt    ; /* 30ms > 1.25 roy 23-12-92 */
+static char     ttdflt[] = "5"       ,           *ttstr = ttdflt     ; /* 8ms > 10 roy 23-12-92 */
+
+static char   sustdflt[] = "0"      ,     *susthreshstr  = sustdflt   ;
+
+static char     swdflt[] = "off"    ,            *swstr  = swdflt     ;
+
+#ifdef PC
+static char   stepdflt[] = "15.25ms"  ,         *stepstr = stepdflt    ;
+#else
+static char   stepdflt[] = "16ms"  ,         *stepstr = stepdflt    ;
+#endif
+
+/* spiral parameters */
+
+static char   zerodflt[] = "off"      ,         *zerostr = zerodflt    ;
+static char   formdflt[] = "arch"     ,         *formstr = formdflt    ;
+static char   origdflt[] = "3.072"    ,         *origstr = origdflt    ;
+
+static char       ArchStr[] =              "arch" ;
+static char        LogStr[] =               "log" ;
+
+static char   expodflt[] =  "off"     ,         *expostr = expodflt ;
+
+/*********** [spl,sai] [sie] stage: "stabilized auditory image" ************/
+
+static  Option saiopts[] = {
+
+ {   "frstep_aid",   stepdflt,   &stepstr,  "Step between frames of the auditory image (ms)",InOutOption},
+ {   "pwidth_aid", pwidthdflt, &pwidthstr,  "Positive width of auditory image  (ms)",    InOutOption},
+ {   "nwidth_aid", nwidthdflt, &nwidthstr,  "Negative width of auditory image (ms)",   InOutOption},
+
+ {     "form_spd",   formdflt,   &formstr,  "Form of spiral: Archemedian or log",        InputOption},
+ { "zeroline_spd",   zerodflt,   &zerostr,  "Draw zero axis of spiral",                  InOutOption},
+ {     "orig_spd",   origdflt,   &origstr,  "Spiral rotation and circuit removal\n",     InOutOption},
+
+ {  "napdecay_ai",    cgmdflt,    &cgmstr,  "Neural activity decay rate in %/ms",        InOutOption},
+ {   "stdecay_ai",     ttdflt,     &ttstr,  "Strobe-threshold decay rate in %/ms",       InOutOption},
+ {"stcrit_ai",   susldflt, &suslevelstr,"Strobe criterion (1 to 5) ",  InOutOption},
+ {"stlag_ai" ,  stlagdflt, &stlagstr,   "Auditory image strobe lag time (in ms)",      InOutOption},
+ {   "stthresh_ai",   sustdflt, &susthreshstr, "Strobe threshold set to all points above this", SilentOption},
+ {     "decay_ai",  decaydflt,  &decaystr,  "Auditory image decay time constant",      InOutOption},
+ {      "stinfo_ai",     swdflt,     &swstr,  "Strobe information (off, on, filename)\n",  InOutOption},   
+
+ {    "utrate_ai",  utlimdflt,  &utlimstr,  "Disconnected in R5.6",                      SilentOption},
+ {    "ltrate_ai",  ltlimdflt,  &ltlimstr,  "Disconnected in R5.6",                      SilentOption}, 
+ {     "ulim_sas",   ulimdflt,   &ulimstr,  "Upper integration limit for auditory image",   SilentOption},
+ {     "llim_sas",   llimdflt,   &llimstr,  "Lower integration limit for auditory image\n", SilentOption},
+ 
+ { "exponential_decay"  ,   expodflt,     &expostr , "Exponential trigger Decay", SilentOption},   
+
+ ( char * ) 0 } ;
+
+/* generate Stabilised image in image.c */
+
+static Source SaiEntry( source )                                   /* CG */
+Source source ;
+{
+    int framestep   = Samples( stepstr,   Samplerate() ) / Framestep() ;
+    int pwidth      = Samples( pwidthstr, Samplerate() ) / Framestep() ;
+    int nwidth      = Samples( nwidthstr, Samplerate() ) / Framestep() ;
+    int stlag       = Samples( stlagstr,  Samplerate() ) / Framestep() ;
+
+
+    /* Convert arguments for spiral drawing. See spiral.ch */
+
+#ifndef DSP32
+    if      (strncmp(formstr, ArchStr, strlen( formstr) ) == 0)    form_spl = 'A';
+    else if (strncmp(formstr,  LogStr, strlen( formstr) ) == 0)    form_spl = 'L';
+    else stitch_error("gensai: unknown form_spl\n");
+
+    axis_spl      = OptionInt(    zerostr ) ;
+    zero_spl      = OptionDouble( origstr ) ;
+#endif
+
+    /* Hack so that spirals never include transient info.  */ 
+     if (strncmp(whichstr,"spl", strlen("spl")) == 0) 
+       { nwidth=0; 
+         if ( (int)atoi(suslevelstr)>=4)
+            suslevelstr="3";
+/*         if ( (int)atoi(suslevelstr)>=4) 
+            pwidth+=stlag; 
+          else
+            stlag=0; */
+       }
+    /* Hack so that sas and sep have pwidth=max(ulim) and nwidth=min(llim) */
+
+    if ( strcmp(whichstr, "sas") == 0 || strcmp(whichstr, "sep") == 0 ) {
+	pwidth = Cycles( ulimstr, frequencies[0], Samplerate() ) ;
+	nwidth = Cycles( llimstr, frequencies[0], Samplerate() ) ;
+	if (nwidth > 0) nwidth=0;
+    }
+
+    /* Check ranges of pwidth and nwidth, and quit if invalid */
+    if (pwidth < 0)
+	stitch_error("Warning: gensai  pwidth_aid  should be positive\n");
+    if (nwidth > 0)
+	stitch_error("Warning: gensai  nwidth_aid  should be zero or negative\n");
+
+    /* nwidth is given as a -ve value, but is used internally as +ve */
+    nwidth = -(nwidth);
+
+    source = Sai( source,  Frameheight(),  framestep,  pwidth,  nwidth,
+		  (int)Samples(decaystr, Samplerate())/Framestep(),
+		  (int)Samplerate(),  frequencies,
+		  (double)atof(ttstr),
+		  Samples(cgmstr,Samplerate())/Framestep(),
+		  (int)Freq(utlimstr),  (int)Freq(ltlimstr), (int)atoi(suslevelstr),
+                  susthreshstr, swstr, expostr, stlag);
+
+    setFramewidth( pwidth+nwidth ) ;
+    setFramestep( framestep ) ;
+    setFrames( Frames()/framestep ) ;
+
+    return( source ) ;
+}
+
+DelayAxis( min, max, label )
+double *min, *max ;
+char **label ;
+{
+    *min = -Samples( pwidthstr, Samplerate() ) / Samplerate() * 1000. ;
+    *max = -Samples( nwidthstr, Samplerate() ) / Samplerate() * 1000. ;
+
+    *label = "Integration Interval [ms]" ;
+}
+
+
+
+#if 0 /* where did this come from? */
+/* table of default model options */
+
+static char   llimdflt[] =    "3.5",    *llimstr =   llimdflt ;
+static char   ulimdflt[] = "imagedurn", *ulimstr =   ulimdflt ;
+static char    saidflt[] =    "0.25",    *saistr =    saidflt ;
+/* static char   susldflt[] = "1",     *suslevelstr =    susldflt ;  AJD 13-3-95
+   static char   sustdflt[] = "0",    *susthreshstr =    sustdflt; */
+#endif
+
+
+
+/*********** [sas] [sse] stage: "stabilized auditory spectrogram" **********/
+
+/* summarise spectrogram by adding across rows */
+
+static  Option sasopts[] = {
+
+ ( char * ) 0 } ;
+
+static Source SummaryEntry( source )                             /* CG */
+Source source ;
+{
+    source = Summary( source, Frameheight(), Scalar( saistr ), frequencies, Samplerate(), llimstr, ulimstr ) ;
+
+    setFramewidth( 1 ) ;
+
+    return( source ) ;
+}
+
+#if defined(DSP32) || defined( THINK_C )
+static void swab( in, out, bytes )
+char *in, *out ;
+int bytes ;
+{
+    register int i ;
+
+    for( i=0 ; i<bytes ; i+=2 ) {
+	out[i+1] = in[i] ;
+	out[i] = in[i+1] ;
+    }
+
+    return ;
+}
+#endif
+
+static void swab_callback( state, bytes, buffer, end, input )
+Source state ;
+ByteCount *bytes ;
+DataType *buffer, *end, *input ;
+{
+    extern void swab() ;
+
+    swab( (char *) input, (char *) buffer, *bytes ) ;
+
+    return ;
+}
+
+static Source SwabEntry( source )
+Source source ;
+{
+    return ( NewSimpleProcessingSource( swab_callback, source, "model.c byte swapping" ) ) ;
+}
+
+struct _test_state { struct _fillable_source parent ; Source source ; unsigned chans ; } ;
+
+static Pointer test_callback( state, bytes, buffer )
+struct _test_state *state ;
+ByteCount *bytes ;
+DataType *buffer ;
+{
+    register DataType input ;
+    register DataType *optr = buffer ;
+    register Pointer eptr = (Pointer) buffer + *bytes ;
+    register int last = *bytes == 0 ;
+    register int chan ;
+
+    while( (Pointer) optr < eptr ) {
+
+	input = *PullItems( state->source, 1, DataType ) ;
+
+	for( chan=0 ; chan<state->chans ; chan++ )
+		*optr++ = input ;
+    }
+
+    if( !last )
+	return ( (Pointer) buffer ) ;
+    else
+	return ( DeleteFillableSource( state ) ) ;
+}
+
+static Source TestEntry( source )
+Source source ;
+{
+    DeclareNew( struct _test_state *, state ) ;
+
+    state->source = source ;
+    state->chans  = Frameheight() ;
+
+    return( SetFillableSource( state, test_callback, "test model.c" ) ) ;
+}
+
+/********************* Option defaults (application specific) ***************
+* Each application may have its own set of option defaults.
+* These override the generic defaults defined for each option, when the
+* options table is constructed, (see constructOptions()).
+* Note that options must have their full names. Abbreviations won't do here.
+****************************************************************************/
+
+/* Wave and excitation pattern modules */
+
+#ifndef DSP32
+static char zerobotstr[]   = "bottom=0" ;
+static char excitestr[]    = "view=excitation" ;
+static char nohiding[]     = "hiddenline=off" ;
+static char downsample[]   = "downsample=10ms" ;
+static char turn_on_idt[]  = "stages_idt=2" ;
+static char mincfdflt[]    = "mincf_afb=50" ;
+static char maxcfdflt[]    = "maxcf_afb=5000" ;
+static char chandflt[]     = "channels_afb=128" ;
+static char lengthdflt[]   = "length=32ms"  ;
+static char greyscalestr[] = "view=greyscale" ;
+#endif
+
+char *wavdflts[] = {
+#ifndef DSP32
+		     "view=wave",
+#endif
+		      (char *)0 } ;
+
+char *stpdflts[] = {                                             /* CG */
+#ifndef DSP32
+		     "view=wave",
+                     "filter=off",
+#endif
+		      (char *)0 } ;
+
+char *asadflts[] = {
+#ifndef DSP32
+		     excitestr,
+		     "top=2500",               zerobotstr,
+		     nohiding,
+		     chandflt,                                   /* CG */
+		     "transduction=off",                         /* CG */
+		     turn_on_idt,                                /* CG */
+		     downsample,                                 /* CG */
+#endif
+		      (char *)0 } ;
+
+char *epndflts[] = {
+#ifndef DSP32
+		     excitestr,
+		     "top=1000",                zerobotstr,      /* CG */
+		     nohiding,
+		     chandflt,                                   /* CG */
+		     turn_on_idt,
+		     downsample,
+#endif
+		      (char *)0 } ;
+
+char *sepdflts[] = {
+#ifndef DSP32
+		     excitestr,
+		     "top=200",                zerobotstr,
+		     nohiding,
+		     chandflt,                                   /* CG */
+		     "ulim_sas=16ms",          "llim_sas=-4ms",
+#endif
+		      (char *)0 } ;
+
+/* Auditory (ie landscape) modules */
+
+char *bmmdflts[] = {
+#ifndef DSP32
+		     lengthdflt,
+		     "top=100",                "bottom=-100",
+#endif
+		      (char *)0 } ;
+
+char *napdflts[] = {
+#ifndef DSP32
+		     lengthdflt,
+		     "top=2000",                zerobotstr,      /* CG */
+		     chandflt,                                   /* CG */
+		     "stages_idt=2",
+		     "tup_idt=0.133ms",
+		     "downsample=1p",
+#endif
+		      (char *)0 } ;
+
+
+char *saidflts[] = {
+#ifndef DSP32
+		     "top=500",                zerobotstr,       /* CG */
+		     "stages_idt=2",
+		     "tup_idt=0.133ms",
+		     "downsample=1p",
+		     "frstep_epn=1p",
+#endif
+		      (char *)0 } ;
+
+char *spldflts[] = {
+#ifndef DSP32
+		     "view=spiral",
+#ifdef PC
+		     "width_win=300",          "height_win=300",
+#else
+		     "width_win=500",          "height_win=500",
+#endif
+                     "box_ps=off",                 /* MAA 6/9/1995 */
+                     "figurelinewidth_ps=0.25",    /* MAA 6/9/1995 */
+		     "top=26",                 "bottom=25",
+		     "dencf=1",                 "pen=2", 
+		     "nwidth_aid=0ms",           "pwidth_aid=35ms",
+                     "stlag=5ms",                "stcrit=5",  /* AJD */
+#endif
+		      (char *)0 } ;
+
+/* Speech (ie greyscale) modules */
+
+char *sgmdflts[] = {
+#ifndef DSP32
+		     greyscalestr,
+		     "top=2500",               zerobotstr,
+		     chandflt,                                   /* CG */
+		     "transduction=off",                         /* CG */
+		     turn_on_idt,
+		     downsample,
+#endif
+		      (char *)0 } ;
+
+char *cgmdflts[] = {
+#ifndef DSP32
+		     greyscalestr,
+		     "top=1000",                zerobotstr,      /* CG */
+		     chandflt,                                   /* CG */
+		     turn_on_idt,
+		     downsample,
+#endif
+		      (char *)0 } ;
+
+char *sasdflts[] = {
+#ifndef DSP32
+		     greyscalestr,
+		     "top=300",                zerobotstr,       /* CG */
+		     chandflt,                                   /* CG */
+		     "stages_idt=off",
+		     "frstep_epn=off",
+		     "downsample=off",
+		     "ulim_sas=16ms",          "llim_sas=-4ms",
+#endif
+		      (char *)0 } ;
+
+
+
+/******************************* stage table ********************************
+*
+* The "stages" are application names.
+* A stage identifier name is the last three chars of the program name.
+*    (Eg "sai" is the stage identifier for the stabilized auditory image
+*     application, which is a program called "gensai". This is an alias for
+*     the "gen" program, provided by one of the set of symbolic links).
+* The stages are grouped into "models" (each an array of structs below):
+*     envelope: calculation of the envelope of the underlying function.
+*     fine:     calculation of the whole ("fine structure") of the function.
+*     complex
+*     nonmult
+*     noncalc
+*
+* FindStage( which )  - find a place in the stage table for the program goal.
+* Take a stage identifier, (contained in the "which" string), and return a ptr
+* to the corresponding stage structure, (one line of one of the arrays below).
+*
+* The returned goal stage is the final processing stage of the sequence of
+* stages which make up the program.
+* The sequential order of processing is dictated by the stage table.
+* The sequence of stages is from the first stage (texually at the bottom of
+* each "model" group in the stage table), through each stage back up the table
+* to the goal stage.
+*
+* The stage structure (defined below) is as follows:
+*     struct _stage {
+*         char    *ident    ;       Stage identifier name
+*         Source (*entry)() ;       Pointer to function for entry to stage
+*         Option  *options  ;       Model options for stage (see table.c)
+*         char   **defaults ;       Option defaults for stage (see gen.c)
+*         char    *help     ;       Description of stage
+*     };
+*
+* For example, the sai stage (found when gensai is asked for) is:
+*     "sai",  SaiEntry,  saiopts,  saidflts,  "stabilized auditory image",
+*
+* The stage struct fields are:
+*
+*  *ident
+* Stage identifier name used by FindStage() to match a stage struct to the
+* application. The stage is found by matching the ident string against those
+* stored in the model arrays of stages. The default stage is "wav".
+*
+*  (*entry)()
+* The name of the entry-point function for the stage. Most entry-point
+* functions are defned in model.c. The entry-point function name is only
+* accessed by a call to FindStage() from ModeledSource() in gen.c.
+*
+*  *options
+* The options field of a stage is used by the constructOptions() routine
+* to include the model options for that stage in the complete options table
+* which it constructs. This is composed of the display options, (which are
+* common to all applications, and are listed in array displayopts[] in gen.c),
+* the model options for the stage, (which are listed in table.c), AND all the
+* model options given for each of the stages back to the start stage, (at the
+* bottom of the stage table, within a model group of stages).
+*
+*  **defaults
+* The defaults field is used by the constructOptions() routine to override the
+* defaults defined for the options which have been included in the complete
+* options table. The reason for this is so that each application can have its
+* own set of option defaults, if necessary. (If defaults are not given
+* or the set is not complete, then the original defaults still apply).
+* The defaults fields contain option defaults which override the generic
+* defaults defined for each option.
+* After the complete options table has been constructed, (constructOptions()),
+* all options in the table will be:
+* a) initialized to their default values (in getnopts()).
+* b) re-initialized by any corresponding options in "rc" files.
+* c) displayed as a help menu (if asked for).
+*
+*  *help
+* This message is printed at the top of the help menu. The help field is only
+* accessed by modelHelp(which), called from gen.c, which takes a stage
+* identifier and returns the "help" string of the stage struct which has a
+* matching ident field, to assign it to "helpstring".
+*
+*
+* Its important to note that the options field refers to model options, and
+* these are cumulative over the sequential stages of processing.
+* The defaults field refers to the defaults to be used for the goal stage
+* only, (ie the application), and these are not cumulative.
+* The complete options table (constructed at run time) consists of the display
+* options, and the accumulated model options (one group per processing stage).
+*
+* The NullEntry routine is a dummy which does no processing, and is used to
+* introduce aliases into the stage sequence.
+*
+* Routines which call FindStage(), and access the stage table:
+*
+*                               main()
+*                                 |
+*          +----------------------+-----------------+
+*          |                      |                 |
+*          |                      |                 |
+*  constructOptions()       ModeledSource()     modelHelp()
+*          |                      |                 |
+*          |                      |                 |
+*          +----------------------+-----------------+
+*                                 |
+*                             FindStage()
+*
+****************************************************************************/
+
+
+#define NO_OPTS     (Option *) 0
+#define NO_DFLTS    (char **)  0
+
+struct _stage *FindStage( which )
+char *which ;
+{
+    static struct _stage envelope[] = {
+	"sse",    SummaryEntry, sasopts,    sasdflts,   "stabilized auditory spectrogram",
+	"sie",        SaiEntry, saiopts,    saidflts,   "stabilized auditory image",
+	"sem",       NullEntry, NO_OPTS,    NO_DFLTS,   "spectrogram",
+	"fed", DownSampleEntry, dwnopts,    NO_DFLTS,   "downsampled filter envelope",
+	"fei",   IntegralEntry, fbiopts,    NO_DFLTS,   "integrated filter envelope",
+	"feh",       HardEntry, fbhopts,    NO_DFLTS,   "hard limited filter envelope",
+	"fea",      AdaptEntry, fbaopts,    NO_DFLTS,   "adapted filter envelope",
+	"fet",  ThresholdEntry, fbtopts,    NO_DFLTS,   "thresholded filter envelope",
+	"fel",    LowpassEntry, fblopts,    NO_DFLTS,   "low-pass filtered filter envelope",
+	"fes",   SaturateEntry, fbsopts,    NO_DFLTS,   "saturated filter envelope",
+	"feu", UncompressEntry, fbuopts,    NO_DFLTS,   "uncompressed filter envelope",
+	"fec",   EnvelopeEntry, fbcopts,    NO_DFLTS,   "compressed filter envelope",
+	"fem",       NullEntry, fbmopts,    NO_DFLTS,   "dummy entry to get options through",
+	"wav",       NullEntry, wavopts,    wavdflts,   "picture of wave",
+	( char * ) 0 } ;
+
+    static struct _stage fine[] = {
+	"sep",       NullEntry, NO_OPTS,    sepdflts,   "stabilized excitation pattern",
+	"sas",    SummaryEntry, sasopts,    sasdflts,   "stabilized auditory spectrogram",
+	"spl",       NullEntry, NO_OPTS,    spldflts,   "spiral stabilized auditory image",
+	"sai",        SaiEntry, saiopts,    saidflts,   "stabilized auditory image",
+	"sgm",       NullEntry, NO_OPTS,    sgmdflts,   "spectrogram",
+	"cgm",       NullEntry, NO_OPTS,    cgmdflts,   "cochleogram",
+	"nap",       NullEntry, NO_OPTS,    napdflts,   "neural activity pattern",
+	"asa",       NullEntry, NO_OPTS,    asadflts,   "auditory spectral analysis",
+	"epn",       NullEntry, NO_OPTS,    epndflts,   "excitation pattern",
+	"fbd", DownSampleEntry, dwnopts,    NO_DFLTS,   "downsampled filter output",
+	"fbi",   IntegralEntry, fbiopts,    NO_DFLTS,   "integrated filter output",
+	"fbh",       HardEntry, fbhopts,    NO_DFLTS,   "hard limited filter output",
+	"fba",      AdaptEntry, fbaopts,    NO_DFLTS,   "adapted transduced filter output",
+	"fbt",  ThresholdEntry, fbtopts,    NO_DFLTS,   "thresholded filter output",
+	"fbl",    LowpassEntry, fblopts,    NO_DFLTS,   "low-pass filtered filter output",
+	"fbs",   SaturateEntry, fbsopts,    NO_DFLTS,   "saturated filter output",
+	"fbu", UncompressEntry, fbuopts,    NO_DFLTS,   "uncompressed filter output",
+	"fbc",        LogEntry, fbcopts,    NO_DFLTS,   "compressed filter output",
+	"fbr",    RectifyEntry, fbropts,    NO_DFLTS,   "rectified filter output",
+	"fbm",       NullEntry, NO_OPTS,    NO_DFLTS,   "auditory filter output",           /* CG */
+        "stp",       FineEntry, fbmopts,    stpdflts,   "stapes vibration output",          /* CG */
+	"wav",       NullEntry, wavopts,    wavdflts,   "picture of wave",
+	( char * ) 0 } ;
+
+    static struct _stage complex[] = {
+	"fcp",      PolarEntry, NO_OPTS,    NO_DFLTS,   "polar co-ordinate complex output",
+	"fcr",    ComplexEntry, fbmopts,    NO_DFLTS,   "rectangular co-ordinate complex output",
+	"wav",       NullEntry, wavopts,    wavdflts,   "picture of wave",
+	( char * ) 0 } ;
+
+    static struct _stage nonmult[] = {
+	"bmm",       NullEntry, NO_OPTS,    bmmdflts,   "basilar membrane motion",          /* CG */
+        "stp",       FineEntry, fbmopts,    stpdflts,   "stapes vibration output",          /* CG */
+	"wav",       NullEntry, wavopts,    wavdflts,   "draw wave",
+	( char * ) 0 } ;
+
+    static struct _stage noncalc[] = {
+	"tst",       TestEntry, NO_OPTS,    NO_DFLTS,   "Test system",
+	"wav",       NullEntry, wavopts,    wavdflts,   "draw wave",
+	( char * ) 0 } ;
+
+    static struct _stage *models[] = { envelope, fine, complex, nonmult, noncalc, ( struct _stage * ) 0 } ;
+
+    struct _stage *stage ;
+    int model ;
+
+    /* for each type of model */
+    for( model=0 ; models[ model ] != ( struct _stage * ) 0 ; model++ )
+	/* for each stage in the model */
+	for( stage=models[ model ] ; stage->ident != ( char * ) 0 ; stage++ )
+	    if( strncmp( which, stage->ident, strlen( stage->ident ) ) == 0 ) {
+
+		/* kludge to fix bug (see fixchans routine below) */
+		if ( strcmp( which, "nap" ) == 0 )
+		    fixchans( stage->defaults ) ;
+
+		return ( stage ) ;
+	    }
+
+    return ( FindStage( "wav" ) ) ;
+}
+
+/* Return the "help" string for the given stage identifier */
+/* This routine is called once from gen.c:main()           */
+char *modelHelp( which )
+char *which ;
+{
+    return( FindStage( which )->help ) ;
+}
+
+
+/*
+This routine is a hack to fix a bug we caused earlier!
+We changed the order of entry points in Findstage, so that nap was able
+to use the lp filter. But this caused nap to inherit the defaults of all
+the other entry points which use that filter. In particular, the number of
+channels for nap was changed as a result of this. This hack is designed to
+restore the number chans, in the case of gennap only, to their default
+value.
+*/
+
+fixchans( str )
+char **str ;
+{
+    while ( *str != (char *)0 ) {
+	if ( strncmp( *str, "channels_afb", 12 ) == 0 ) {
+	    strcpy( (*str)+13, chansdflt ) ;
+	/*    fprintf(stderr, "fixchans: %s\n", *str ) ;        */
+	    break ;
+	}
+	*str++ ;
+    }
+}
+
+
+/*********************** Strings for use in DSP version ********************/
+
+#if defined(DSPHOST) || defined(DSP32)
+#if 00
+char **shared[] = { &llimstr,       &ulimstr,        &saistr,       &pwidthstr,
+		    &nwidthstr,     &ltlimstr,       &utlimstr,     &ttstr,
+		    &cgmstr,        &decaystr,       &stepstr,      &downsstr,
+		    &stagestr,      &upstr,          &downstr,      &lossstr,
+		    &vlossstr,      &igainstr,       &hardstr,      &adapstr,
+		    &timesstr,      &vdrainstr,      &propstr,      &faststr,
+		    &latstr,        &rapidstr,       &risestr,      &stxstr,
+		    &lstagestr,     &lupstr,         &ldownstr,     &llossstr,
+		    &lvlossstr,     &ligainstr,      &meddisstr,    &satstr,
+		    &logstr,        &rectstr,        &qualstr,      &limitstr,
+		    &interpstr,     &minstr,         &maxstr,       &denstr,
+		    &chansstr,      &orderstr,       &phasestr,     &gainstr,
+		    &audiostr,      &floatstr,       &samplestr,    &bitstr,
+		    &envstr,        &whichstr,       &framesstr,    &framebytesstr,
+		    &framewidthstr, &frameheightstr, &framestepstr,
+		    ( char ** ) 0 } ;
+#endif
+char **returned[] = { &framesstr,      &framebytesstr,  &framewidthstr,
+		      &frameheightstr, &framestepstr,
+		      ( char ** ) 0 } ;
+
+#endif
+
+
+/******* support for DSP32 C ******************/
+
+#ifdef DSP32
+void receiveParameters( parameters, psize )
+char *parameters ;
+short psize ;
+{
+    struct _stage *stage = FindStage( "sas" ), *sptr ;
+    char *bptr ;
+    int c ;
+
+    for( sptr = stage ; sptr->ident != (char *) 0 ; sptr++ )
+	;
+
+    sptr-- ;
+
+    for( bptr = parameters ; bptr < parameters + psize ; sptr-- )
+	if( sptr->options != (Option *) 0 )
+	    for( c=0 ; sptr->options[c].name != (char *) 0 ; c++ ) {
+		*(sptr->options[c].value) = bptr ;
+		bptr += strlen( bptr ) + 1 ;
+	    }
+
+    return ;
+}
+#endif
+
+#ifdef DSPHOST
+#include "utils.h"
+#define  DSP_BIN_VAR     "DSPBIN"
+#define  DEFAULT_DSP_BIN "c:\\bin\\dspmain"
+extern char *getenv() ;
+
+void sendParameters( which )
+char *which ;
+{
+    register struct _stage *stage = FindStage( which ), *sptr ;
+    unsigned c, bytes = 0 ;
+    char *buffer, *bptr ;
+    long paddr, baddr ;
+
+    for( sptr = stage ; sptr->ident != (char *) 0 ; sptr++ )
+	if( sptr->options != (Option *) 0 )
+	    for( c=0 ; sptr->options[c].name != (char *) 0 ; c++ )
+		bytes += strlen( *(sptr->options[c].value) ) + 1 ;
+
+    sptr-- ;
+
+    buffer = Allocate( bytes, "argument array model.c" ) ;
+
+    for( bptr = buffer ; sptr >= stage ; sptr-- )
+	if( sptr->options != (Option *) 0 )
+	    for( c=0 ; sptr->options[c].name != (char *) 0 ; c++ ) {
+		(void) strcpy( bptr, *(sptr->options[c].value) ) ;
+		bptr += strlen( bptr ) + 1 ;
+	    }
+
+
+    paddr = find_label_name( "psize" ) ;
+
+    dsp_dl_int( paddr, (int) ( bptr - buffer ) ) ;
+
+    baddr = find_label_name( "params" ) ;
+
+    while( dsp_up_long( baddr ) == 0 )
+	;
+
+    dsp_dl_bytes( deref( baddr ), (long) ( bptr - buffer ), buffer ) ;
+
+    dsp_dl_int( paddr, 0 ) ;
+
+    return ;
+}
+
+
+struct _dsp_state { unsigned long needed_addr, output_addr, errno_addr ; } ;
+
+static void dsp_callback( state, bytes, buffer )
+struct _dsp_state *state ;
+ByteCount bytes ;
+Pointer buffer ;
+{	
+    char errbuff[200] ;
+	
+    /* tell dsp how much you want */
+
+    dsp_dl_int( state->needed_addr, bytes ) ;
+
+    /* wait for it to provide it */
+
+    while( dsp_up_int( state->needed_addr ) != 0 )
+	if( dsp_up_int( state->errno_addr ) != 0 ) {
+/*
+	    if( dispw != ( WindowObject ) 0 ) Close( dispw ) ;
+*/
+	    dsp_up_bytes( find_label_name( "errstr" ), (long) sizeof ( errbuff ), errbuff ) ;
+	    printf( "freemem %ld stackmax %lx\n",
+		dsp_up_long( find_label_name( "freemem"  ) ),
+		dsp_up_long( find_label_name( "stackmax" ) ) ) ;
+	    stitch_error( errbuff, dsp_up_int( find_label_name( "errno" ) ) ) ;
+     	}
+    
+    /* upload it into PC buffer */
+
+    dsp_up_bytes( deref( state->output_addr ), (long) bytes, buffer ) ;
+
+    return ;
+}
+
+Source DspSource( source )
+Source source ;
+{
+    DeclareNew( struct _dsp_state *, state ) ;
+    unsigned long addr ;
+    char errbuff[200] ;
+    char ***param ;
+    char *binary_path = getenv( DSP_BIN_VAR ) ;
+
+    if( binary_path == ( char * ) 0 )
+	binary_path =  DEFAULT_DSP_BIN ;
+
+    /* load dsp */
+
+    (void) fprintf( stderr, "Downloading %s to DSP32 at i/o addres 0x%x\n", binary_path, default_addr() ) ;
+
+    if( dsp_dl_exec( binary_path ) == 0 )
+	stitch_error( "\nDSP load failed\n" ) ;
+
+    /* start dsp */
+
+    dsp_run() ;
+
+    /* send parameters down to model */
+
+    sendParameters( whichstr ) ;
+
+    /* send down input if required */
+
+    if( whichstr[0] != 'i' ) {
+    	
+	addr = find_label_name( "input" ) ;
+
+	while( dsp_up_long( addr ) == 0 )
+	    ;
+
+	(void) fprintf( stderr, "Downloading input file of %ld points to dsp addres 0x%lx\n", Frames(), deref( addr ) ) ;
+
+	dsp_dl_array( deref( addr ), Frames(), PullInts( source, Frames() ) ) ;
+    }
+
+    /* wait for model setup */
+
+    state->needed_addr = find_label_name( "needed" ) ;
+    state->output_addr = find_label_name( "output" ) ;
+    state->errno_addr  = find_label_name( "errno"  ) ;
+
+    addr = find_label_name( "source" ) ;
+
+    while( dsp_up_long( addr ) == 0l && dsp_up_int( state->errno_addr ) == 0 )
+	(void) fprintf( stderr, "Waiting for dsp (status:%d)\r", dsp_up_long( addr ) ) ;
+      
+    if( dsp_up_int( state->errno_addr ) != 0 ) {
+	dsp_up_bytes( find_label_name( "errstr" ), (long) sizeof ( errbuff ), errbuff ) ;
+	(void) fprintf( stderr, "dsp error: %s\n", errbuff ) ;
+	stitch_error( "so there" ) ;
+    }
+
+    (void) fprintf( stderr, "DSP setup (source=0x%lx)\n", dsp_up_long( addr ) ) ;
+
+    addr = find_label_name( "returned" ) ;
+
+    for( param=returned ; *param != ( char ** ) 0 ; param++ ) {
+
+	dsp_up_bytes( deref( deref( addr ) ), RETURN_SIZE, **param ) ;
+	addr += 4 ;
+    }
+#if 0
+    fprintf( stderr, "Frames %ld - %d %d %d\n\nType Return\n", Frames(), Frameheight(), Framewidth(), Framebytes() ) ;
+    getchar() ;
+#endif
+    return ( stdAutoSource( ( Pointer ) state, dsp_callback ) ) ;
+}
+
+#endif
+
+/***************************************************************************
+* ModeledSource()
+* Called from main() in gen.c to initialize a chain of objects which will
+* ultimately execute the program, (see also SinkSource() in gen.c:main).
+*
+* The routine ModeledSource() first uses Findstage() to find the appropriate
+* place in the stage table, called for by the program, (and indicated by
+* "whichstr", the last three chars of the program's name).
+* Then it finds the end of the table, and works back up to the stage called
+* for by the program.
+* At each stage, call the corresponding entry-point function, (provided it's
+* not a null pointer), to create and initialize a source object.
+* (Each stage in the table is a process on the way to the program as a whole.
+* The order of the stage table sets the order of processing).
+*
+* The "check" argument is used when the "useprevious" option is on,
+* (see main() and checkForFile() in gen.c), otherwise it will be a null ptr.
+***************************************************************************/
+
+Source ModeledSource( source, check )
+Source source ;
+Source (*check)() ;
+{
+    /* Find the place in the stage table called for by the program */
+    register struct _stage *sptr, *stage = FindStage( whichstr ) ;
+    Source stmp ;
+
+#if !defined( DSP32 ) && !defined( THINK_C )
+    if( OptionInt( swapstr ) != 0 )
+	source = SwabEntry( source ) ;
+#endif
+
+#ifdef DSPHOST
+    if( getenv( "DSP32" ) != ( char * ) 0 )
+	return ( DspSource( source ) ) ;
+    else
+	(void) fprintf( stderr, "Not using DSP card\n" ) ;
+#endif
+
+    if( stage->entry == ( Source ( * )() ) 0 )
+	return ( source ) ;
+#if 00
+    /* Set frameheight (channels) and centre-frequencies array */
+    updateFrequencies() ;
+#endif
+
+#ifdef FLOAT
+    source = ShortFloatSource( source ) ;
+#endif
+
+    /* Find the end of the stage table */
+    for( sptr = stage ; sptr->ident != ( char * ) 0 ; sptr++ )
+	;
+
+    /* Work back up the stage table to the stage called for by the program */
+    /* At each stage, call the entry-point function (if it's not null)     */
+    while( sptr-- > stage ) {
+
+	if( sptr->entry != (Source ( * )()) 0 )
+	    source = sptr->entry( source ) ;
+
+	if( check != ( Source ( * )() ) 0 ) {
+	    stmp = check( sptr->ident ) ;
+	    if( _SPTR( stmp ) != (struct _source *) 0 ) {
+
+#ifdef FLOAT
+		source = ShortFloatSource( stmp ) ;
+#else
+		source = stmp ;
+#endif
+		/* Set frameheight (channels) and centre-frequencies array */
+		updateFrequencies() ;
+	    }
+	}
+    }
+
+#ifdef FLOAT
+    source = FloatShortSource( source ) ;
+#endif
+
+    setFrames( Frames() ) ;
+
+    return ( source ) ;
+}
+
+