Mercurial > hg > aim92
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, ×str, "Oversampling of calculation of threshold", OutputOption}, + { "times_at", timesdflt, ×str, "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, <limstr, "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, <limstr, &utlimstr, &ttstr, + &cgmstr, &decaystr, &stepstr, &downsstr, + &stagestr, &upstr, &downstr, &lossstr, + &vlossstr, &igainstr, &hardstr, &adapstr, + ×str, &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 ) ; +} + +