tomwalters@0
|
1 /*
|
tomwalters@0
|
2 Copyright (c) Applied Psychology Unit, Medical Research Council. 1994
|
tomwalters@0
|
3 ===========================================================================
|
tomwalters@0
|
4
|
tomwalters@0
|
5 Permission to use, copy, modify, and distribute this software without fee
|
tomwalters@0
|
6 is hereby granted for research purposes, provided that this copyright
|
tomwalters@0
|
7 notice appears in all copies and in all supporting documentation, and that
|
tomwalters@0
|
8 the software is not redistributed for any fee (except for a nominal shipping
|
tomwalters@0
|
9 charge). Anyone wanting to incorporate all or part of this software in a
|
tomwalters@0
|
10 commercial product must obtain a license from the Medical Research Council.
|
tomwalters@0
|
11
|
tomwalters@0
|
12 The MRC makes no representations about the suitability of this
|
tomwalters@0
|
13 software for any purpose. It is provided "as is" without express or implied
|
tomwalters@0
|
14 warranty.
|
tomwalters@0
|
15
|
tomwalters@0
|
16 THE MRC DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
|
tomwalters@0
|
17 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL THE
|
tomwalters@0
|
18 A.P.U. BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
|
tomwalters@0
|
19 DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
|
tomwalters@0
|
20 AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
tomwalters@0
|
21 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
tomwalters@0
|
22 */
|
tomwalters@0
|
23
|
tomwalters@0
|
24 /*
|
tomwalters@0
|
25 Acknowledgment:
|
tomwalters@0
|
26 ==============
|
tomwalters@0
|
27
|
tomwalters@0
|
28 The source code provided in this file was originally developed by
|
tomwalters@0
|
29 Christian Giguere as part of a Ph.D degree at the Department of
|
tomwalters@0
|
30 Engineering of the University of Cambridge from April 1990 to
|
tomwalters@0
|
31 November 1993. The code was subsequently adapted under a grant
|
tomwalters@0
|
32 from the Hearing Research Trust for full compatibility with
|
tomwalters@0
|
33 AIM Release 6.15.
|
tomwalters@0
|
34
|
tomwalters@0
|
35 Christian Giguere 25/03/94
|
tomwalters@0
|
36
|
tomwalters@0
|
37 */
|
tomwalters@0
|
38
|
tomwalters@0
|
39 /*
|
tomwalters@0
|
40 ===========================================================
|
tomwalters@0
|
41 bank_tl.c
|
tomwalters@0
|
42 ===========================================================
|
tomwalters@0
|
43
|
tomwalters@0
|
44 Design of cochlear transmission line filterbank (TLF) with
|
tomwalters@0
|
45 coupled outer ear and middle ear (EAR) filter.
|
tomwalters@0
|
46
|
tomwalters@0
|
47 Author : Christian Giguere
|
tomwalters@0
|
48 First written : 01st April, 1991
|
tomwalters@0
|
49 Last edited : 07th March, 1994
|
tomwalters@0
|
50
|
tomwalters@0
|
51 Reference:
|
tomwalters@0
|
52 (1) C.Giguere and P.C.Woodland (1994). JASA 95(1): 331-342.
|
tomwalters@0
|
53 ===========================================================
|
tomwalters@0
|
54 */
|
tomwalters@0
|
55
|
tomwalters@0
|
56 /***** includes *****/
|
tomwalters@0
|
57
|
tomwalters@0
|
58 #include <math.h>
|
tomwalters@0
|
59 #include <stdio.h>
|
tomwalters@0
|
60 #include "stitch.h"
|
tomwalters@0
|
61 #include "source.h"
|
tomwalters@0
|
62 #include "calc.h"
|
tomwalters@0
|
63 #include "calc_tl.h"
|
tomwalters@0
|
64 #include "wdf_tl.h"
|
tomwalters@0
|
65 #include "formulae.h"
|
tomwalters@0
|
66 #include "formulae_tl.h"
|
tomwalters@0
|
67 #include "scales.h"
|
tomwalters@0
|
68 #include "scales_tl.h"
|
tomwalters@0
|
69 #include "bank.h"
|
tomwalters@0
|
70 #include "bank_tl.h"
|
tomwalters@0
|
71 #include "ear.h"
|
tomwalters@0
|
72 #include "wdf_ear.h"
|
tomwalters@0
|
73
|
tomwalters@0
|
74 /***** defines *****/
|
tomwalters@0
|
75
|
tomwalters@0
|
76 #if 0
|
tomwalters@0
|
77 #define _DEBUG_
|
tomwalters@0
|
78 #endif
|
tomwalters@0
|
79
|
tomwalters@0
|
80 #define MIN_CF ( 16.0 ) /* Minimum BM segment CF allowed (Hz) */
|
tomwalters@0
|
81 #define MAX_CF ( 15000.0 ) /* Maximum BM segment CF allowed (Hz) */
|
tomwalters@0
|
82 #define REF_CF ( 1000.0 ) /* Reference CF (Hz) for scaling BM output and Q factor */
|
tomwalters@0
|
83 #define L ( 3.5 ) /* Length of BM (cm) */
|
tomwalters@0
|
84 #define MinLength ( 1.0E-6 ) /* Mininum length of each BM segment (cm) */
|
tomwalters@0
|
85 #define B0 ( 0.015 ) /* BM width at basal end (cm) */
|
tomwalters@0
|
86 #define B_exp ( 0.30 ) /* Exponential constant for BM width (1/cm) */
|
tomwalters@0
|
87 #define A0 ( 0.03 ) /* Cross-sectional area of each scala at basal end (cm2) */
|
tomwalters@0
|
88 #define A_exp ( -0.60 ) /* Exponential constant for scalea cross-sectional area (1/cm) */
|
tomwalters@0
|
89 #define RHO_fluid ( 1.0 ) /* Density of cochlear fluids [g/cm3] */
|
tomwalters@0
|
90 #define MASS_PER_AREA ( 0.015 ) /* Transerval mass per area of basilar membrane (g/cm2) */
|
tomwalters@0
|
91 #define Q_CHANNEL ( 0 ) /* Introduce channel-dependent Q factor */
|
tomwalters@0
|
92 #define RATIO ( 30.0 ) /* Transformer ratio between oval window and eardrum */
|
tomwalters@0
|
93 #define WARPING ( 0 ) /* Compensate frequency warping of bilinear transform */
|
tomwalters@0
|
94
|
tomwalters@0
|
95
|
tomwalters@0
|
96 /***** externals */
|
tomwalters@0
|
97
|
tomwalters@0
|
98 extern Source InterpSource() ;
|
tomwalters@0
|
99
|
tomwalters@0
|
100 /***** functions *****/
|
tomwalters@0
|
101
|
tomwalters@0
|
102 /**************************************************************************
|
tomwalters@0
|
103 * name: function:
|
tomwalters@0
|
104 *
|
tomwalters@0
|
105 * tlf_bank_callback() Callable procedure returning pointer to filtered
|
tomwalters@0
|
106 * data (BM velocity or displacement).
|
tomwalters@0
|
107 *
|
tomwalters@0
|
108 * TLF_GenBank() Set-up and initialization function for the design
|
tomwalters@0
|
109 * of the cochlear filterbank. Returns pointer to
|
tomwalters@0
|
110 * a new source.
|
tomwalters@0
|
111 ***************************************************************************/
|
tomwalters@0
|
112
|
tomwalters@0
|
113 typedef struct _bank_segment BankSegment ;
|
tomwalters@0
|
114
|
tomwalters@0
|
115 struct _bank_segment {
|
tomwalters@0
|
116 double center_frequency ;
|
tomwalters@0
|
117 double seglength, position ;
|
tomwalters@0
|
118 int active ;
|
tomwalters@0
|
119 } ;
|
tomwalters@0
|
120
|
tomwalters@0
|
121 struct _tlf_bank_state {
|
tomwalters@0
|
122 struct _fillable_source parent ;
|
tomwalters@0
|
123 Source source ;
|
tomwalters@0
|
124 Pointer input ;
|
tomwalters@0
|
125 int inout_size ;
|
tomwalters@0
|
126 void (*proc)(), (*closeEar)(), (*closeTLF)() ;
|
tomwalters@0
|
127 int total_chans, display_chans ;
|
tomwalters@0
|
128 TLF_BankInfo *bank ;
|
tomwalters@0
|
129 WDFilterState **states ;
|
tomwalters@0
|
130 int Ntube ;
|
tomwalters@0
|
131 WaveWDFstate *wave_states ;
|
tomwalters@0
|
132 EartubeWDFstate **eartube_states ;
|
tomwalters@0
|
133 EarmiddleWDFstate *earmiddle_states ;
|
tomwalters@0
|
134 } ;
|
tomwalters@0
|
135
|
tomwalters@0
|
136
|
tomwalters@0
|
137 /************************* tlf_bank_callback() ****************************/
|
tomwalters@0
|
138
|
tomwalters@0
|
139 static Pointer tlf_bank_callback( state, bytes, buffer )
|
tomwalters@0
|
140 struct _tlf_bank_state *state ;
|
tomwalters@0
|
141 ByteCount *bytes ;
|
tomwalters@0
|
142 Pointer buffer ;
|
tomwalters@0
|
143 {
|
tomwalters@0
|
144 register TLF_BankInfo *bankInfo = state->bank ;
|
tomwalters@0
|
145 register int last = *bytes == 0 ;
|
tomwalters@0
|
146 register int points ;
|
tomwalters@0
|
147 register ByteCount bytecount ;
|
tomwalters@0
|
148
|
tomwalters@0
|
149 /***** process *****/
|
tomwalters@0
|
150 if( !last ) {
|
tomwalters@0
|
151
|
tomwalters@0
|
152 points = *bytes * bankInfo->decimate_factor /
|
tomwalters@0
|
153 ( state->display_chans * state->inout_size ) ;
|
tomwalters@0
|
154
|
tomwalters@0
|
155 state->input = Pull( state->source, points * state->inout_size ) ;
|
tomwalters@0
|
156
|
tomwalters@0
|
157 state->proc( bankInfo, state->states, state->input, buffer, points,
|
tomwalters@0
|
158 state->total_chans, state->wave_states, state->eartube_states,
|
tomwalters@0
|
159 state->earmiddle_states, state->Ntube ) ;
|
tomwalters@0
|
160
|
tomwalters@0
|
161 return ( buffer ) ;
|
tomwalters@0
|
162 }
|
tomwalters@0
|
163
|
tomwalters@0
|
164 /***** close *****/
|
tomwalters@0
|
165 else {
|
tomwalters@0
|
166
|
tomwalters@0
|
167 Pull( state->source, 0 ) ;
|
tomwalters@0
|
168 state->closeEar( state->wave_states, state->eartube_states, state->earmiddle_states, state->Ntube ) ;
|
tomwalters@0
|
169 state->closeTLF( state->states, state->total_chans, state->bank ) ;
|
tomwalters@0
|
170
|
tomwalters@0
|
171 return ( DeleteFillableSource( state ) ) ;
|
tomwalters@0
|
172 }
|
tomwalters@0
|
173 }
|
tomwalters@0
|
174
|
tomwalters@0
|
175
|
tomwalters@0
|
176 /************************** TLF_GenBank() *****************************/
|
tomwalters@0
|
177
|
tomwalters@0
|
178 Source TLF_GenBank( source, interps, info, chans, decimate_factor, samplerate, center_frequencies,
|
tomwalters@0
|
179 output_gain, outdens, qbase, OHC_gain, OHC_sat, motionstr, concha, canal )
|
tomwalters@0
|
180 Source source ;
|
tomwalters@0
|
181 int interps, info, *chans, *decimate_factor ;
|
tomwalters@0
|
182 double samplerate, *center_frequencies, output_gain, outdens ;
|
tomwalters@0
|
183 double qbase, OHC_gain, OHC_sat ;
|
tomwalters@0
|
184 char *motionstr ;
|
tomwalters@0
|
185 TubeInfo *concha, *canal ;
|
tomwalters@0
|
186 {
|
tomwalters@0
|
187 DeclareNew( struct _tlf_bank_state *, state ) ;
|
tomwalters@0
|
188 BankSegment **bankSeg, *segmentPointer, **GenerateBankSegments() ;
|
tomwalters@0
|
189 double density, freq, scale_disp, scale_vel ;
|
tomwalters@0
|
190 double qfactor, bn, xn, delta_xn, an, Lt, zov ;
|
tomwalters@0
|
191 double length, diam, attn ;
|
tomwalters@0
|
192 Source outputSource ;
|
tomwalters@0
|
193 int chan, total_chans, segment, counter = 0 ;
|
tomwalters@0
|
194
|
tomwalters@0
|
195 /***** initialise input-related parameters *****/
|
tomwalters@0
|
196 state->inout_size = sizeof ( DataType ) ;
|
tomwalters@0
|
197 state->input = ( char * ) 0 ;
|
tomwalters@0
|
198 state->source = source ;
|
tomwalters@0
|
199
|
tomwalters@0
|
200 /***** set WDF-TLF filterbank parameters *****/
|
tomwalters@0
|
201 density = DensityOnScale( ErbScale( center_frequencies[ 0 ]), ErbScale( center_frequencies[ *chans - 1]),
|
tomwalters@0
|
202 *chans ) ;
|
tomwalters@0
|
203 if( density == 0. ) {
|
tomwalters@0
|
204 if( outdens <= 0. )
|
tomwalters@0
|
205 density = 1. ; /* arbitrary */
|
tomwalters@0
|
206 else
|
tomwalters@0
|
207 density = outdens ;
|
tomwalters@0
|
208 }
|
tomwalters@0
|
209
|
tomwalters@0
|
210 if( interps > 0 )
|
tomwalters@0
|
211 interps = MIN( interps, ( int ) floor( log( ( double ) *chans ) / log( 2. ) ) ) ;
|
tomwalters@0
|
212
|
tomwalters@0
|
213 bankSeg = GenerateBankSegments( interps, samplerate, center_frequencies, &density, &outdens,
|
tomwalters@0
|
214 chans, &total_chans ) ;
|
tomwalters@0
|
215 state->display_chans = *chans ;
|
tomwalters@0
|
216 state->total_chans = total_chans ;
|
tomwalters@0
|
217 state->states = NewArray( WDFilterState *, state->total_chans, "bank_tl.c for states" ) ;
|
tomwalters@0
|
218
|
tomwalters@0
|
219 if( info )
|
tomwalters@0
|
220 fprintf( stderr, "\nTLF filterbank information:\n" ) ;
|
tomwalters@0
|
221
|
tomwalters@0
|
222 xn = bankSeg[0]->position ;
|
tomwalters@0
|
223 delta_xn = bankSeg[0]->seglength ;
|
tomwalters@0
|
224 Lt = -2. * RHO_fluid / ( A0 * A_exp ) * ( exp( -A_exp * L ) - exp( -A_exp * ( xn + delta_xn ) ) ) ;
|
tomwalters@0
|
225
|
tomwalters@0
|
226 for( chan = 0 ; chan < state->total_chans ; chan++ ) {
|
tomwalters@0
|
227 segmentPointer = bankSeg[ chan ] ;
|
tomwalters@0
|
228 freq = segmentPointer->center_frequency ;
|
tomwalters@0
|
229 xn = segmentPointer->position ;
|
tomwalters@0
|
230 delta_xn = MAX( segmentPointer->seglength, MinLength ) ;
|
tomwalters@0
|
231
|
tomwalters@0
|
232 /*** channel-dependent scalea cross-sectional area ***/
|
tomwalters@0
|
233 an = A0 * exp( A_exp * xn ) ;
|
tomwalters@0
|
234
|
tomwalters@0
|
235 /*** channel-dependent BM width ***/
|
tomwalters@0
|
236 bn = B0 * exp( B_exp * xn ) ;
|
tomwalters@0
|
237
|
tomwalters@0
|
238 /*** channel-dependent Q-factor ***/
|
tomwalters@0
|
239 if ( Q_CHANNEL != 0 )
|
tomwalters@0
|
240 qfactor = qbase * ( freq / REF_CF ) * ( Erb( REF_CF ) / Erb(freq) ) ;
|
tomwalters@0
|
241 else
|
tomwalters@0
|
242 qfactor = qbase ;
|
tomwalters@0
|
243
|
tomwalters@0
|
244 /*** print filterbank configuration ***/
|
tomwalters@0
|
245 if( info ) {
|
tomwalters@0
|
246 counter += 1 * segmentPointer->active ;
|
tomwalters@0
|
247 fprintf( stderr, "%3d -- active=%3d -- cf:%7.1f Hz =%6.2f ERBs -- x=%.3fcm delta=%.3fcm b=%.3fcm A=%.3fcm2\n",
|
tomwalters@0
|
248 state->total_chans - chan, counter * segmentPointer->active, freq, ErbScale( freq ), xn, delta_xn, bn, an ) ;
|
tomwalters@0
|
249 }
|
tomwalters@0
|
250
|
tomwalters@0
|
251 /*** scale output ***/
|
tomwalters@0
|
252 scale_vel = output_gain * FILTERBANK_SCALE ;
|
tomwalters@0
|
253 scale_disp = TwoPi * REF_CF * scale_vel ;
|
tomwalters@0
|
254
|
tomwalters@0
|
255 /*** get filter states ***/
|
tomwalters@0
|
256 state->states[ chan ] = WDFilter( samplerate, freq, scale_vel, scale_disp, RHO_fluid, an, bn,
|
tomwalters@0
|
257 qfactor, MASS_PER_AREA, delta_xn, Lt, WARPING,
|
tomwalters@0
|
258 segmentPointer->active, &zov, OHC_gain, OHC_sat ) ;
|
tomwalters@0
|
259
|
tomwalters@0
|
260 Delete( segmentPointer ) ;
|
tomwalters@0
|
261 }
|
tomwalters@0
|
262
|
tomwalters@0
|
263 Delete( bankSeg ) ;
|
tomwalters@0
|
264
|
tomwalters@0
|
265
|
tomwalters@0
|
266 /*** set parameters common to all channels ***/
|
tomwalters@0
|
267
|
tomwalters@0
|
268 state->bank = New( TLF_BankInfo * ) ;
|
tomwalters@0
|
269 state->bank->output_chans = state->display_chans ;
|
tomwalters@0
|
270
|
tomwalters@0
|
271 /* set decimation parameters */
|
tomwalters@0
|
272 state->bank->decimateCount = 0 ;
|
tomwalters@0
|
273 *decimate_factor = MAX( 1, *decimate_factor ) ;
|
tomwalters@0
|
274 state->bank->decimate_factor = *decimate_factor ;
|
tomwalters@0
|
275
|
tomwalters@0
|
276
|
tomwalters@0
|
277 /***** set output and nonlinearity variables, and filter procedure *****/
|
tomwalters@0
|
278
|
tomwalters@0
|
279 if( strncmp( motionstr, "velocity", 3 ) == 0 ) {
|
tomwalters@0
|
280 state->proc = DoWDFdataArray ;
|
tomwalters@0
|
281 state->bank->output_var = VELOCITY ;
|
tomwalters@0
|
282 state->bank->nl_var = DISPLACEMENT ;
|
tomwalters@0
|
283 }
|
tomwalters@0
|
284 else {
|
tomwalters@0
|
285 state->proc = DoWDFdataArray ;
|
tomwalters@0
|
286 state->bank->output_var = DISPLACEMENT ;
|
tomwalters@0
|
287 state->bank->nl_var = DISPLACEMENT ;
|
tomwalters@0
|
288 }
|
tomwalters@0
|
289
|
tomwalters@0
|
290
|
tomwalters@0
|
291 /***** Set WDF-EAR filter design parameters *****/
|
tomwalters@0
|
292 state->wave_states = FreefieldWDF( samplerate, RHO_air, C, As, concha->diameter/2. ) ;
|
tomwalters@0
|
293
|
tomwalters@0
|
294 state->Ntube = concha->Nsegments + canal->Nsegments ;
|
tomwalters@0
|
295 state->eartube_states = NewArray( EartubeWDFstate *, state->Ntube, "ear.c for eartube states" ) ;
|
tomwalters@0
|
296
|
tomwalters@0
|
297 length = concha->length / concha->Nsegments ;
|
tomwalters@0
|
298 diam = concha->diameter ;
|
tomwalters@0
|
299 attn = concha->att_factor ;
|
tomwalters@0
|
300 for( segment = 0 ; segment < concha->Nsegments ; segment++ )
|
tomwalters@0
|
301 state->eartube_states[ segment ] = EartubeWDF( samplerate, RHO_air, C, diam, length, attn ) ;
|
tomwalters@0
|
302
|
tomwalters@0
|
303 length = canal->length / canal->Nsegments ;
|
tomwalters@0
|
304 diam = canal->diameter ;
|
tomwalters@0
|
305 attn = canal->att_factor ;
|
tomwalters@0
|
306 for( ; segment < state->Ntube ; segment++ )
|
tomwalters@0
|
307 state->eartube_states[ segment ] = EartubeWDF( samplerate, RHO_air, C, diam, length, attn ) ;
|
tomwalters@0
|
308
|
tomwalters@0
|
309 state->earmiddle_states = EarmiddleWDF( samplerate, zov, 1.0, RATIO ) ;
|
tomwalters@0
|
310
|
tomwalters@0
|
311
|
tomwalters@0
|
312 /***** specify procedures upon closing *****/
|
tomwalters@0
|
313 state->closeEar = CloseEarWDF ;
|
tomwalters@0
|
314 state->closeTLF = CloseWDF ;
|
tomwalters@0
|
315
|
tomwalters@0
|
316 /***** initialise output-related parameters and return *****/
|
tomwalters@0
|
317 outputSource = SetFillableSource( state, tlf_bank_callback, "bank_tl.c filter" ) ;
|
tomwalters@0
|
318
|
tomwalters@0
|
319 for( *chans = state->display_chans ; interps-- > 0 ; *chans = *chans * 2 - 1, density = density * 2. )
|
tomwalters@0
|
320 outputSource = InterpSource( outputSource, *chans ) ;
|
tomwalters@0
|
321
|
tomwalters@0
|
322 return ( outputSource ) ;
|
tomwalters@0
|
323 }
|
tomwalters@0
|
324
|
tomwalters@0
|
325
|
tomwalters@0
|
326 /************************** lower level functions *************************/
|
tomwalters@0
|
327
|
tomwalters@0
|
328 BankSegment **GenerateBankSegments( interps, samplerate, display_frequencies, display_dens,
|
tomwalters@0
|
329 out_dens, display_chans, total_chans )
|
tomwalters@0
|
330 int interps ;
|
tomwalters@0
|
331 double samplerate ;
|
tomwalters@0
|
332 double *display_frequencies ;
|
tomwalters@0
|
333 double *display_dens, *out_dens ;
|
tomwalters@0
|
334 int *display_chans, *total_chans ;
|
tomwalters@0
|
335 {
|
tomwalters@0
|
336 BankSegment **bankSeg, *segmentPointer ;
|
tomwalters@0
|
337 double min_cf, max_cf ;
|
tomwalters@0
|
338 double apical_cf, basal_cf ;
|
tomwalters@0
|
339 double *apical_frequencies, *basal_frequencies ;
|
tomwalters@0
|
340 double apical_dens, basal_dens, central_dens ;
|
tomwalters@0
|
341 int apical_chans, basal_chans, central_chans ;
|
tomwalters@0
|
342 int ichan, chan ;
|
tomwalters@0
|
343 int remainder ;
|
tomwalters@0
|
344 double cm_per_CB = GetERBscaling ( ) / 10. ;
|
tomwalters@0
|
345
|
tomwalters@0
|
346
|
tomwalters@0
|
347 /***** set number and density of central channels *****/
|
tomwalters@0
|
348 if( interps >= 0 ) {
|
tomwalters@0
|
349
|
tomwalters@0
|
350 central_chans = *display_chans = *display_chans >> interps ;
|
tomwalters@0
|
351 central_dens = *display_dens = ldexp( *display_dens, -interps ) ;
|
tomwalters@0
|
352 min_cf = FofErbScale( ErbScale( display_frequencies[0] ) - 1. / central_dens ) ;
|
tomwalters@0
|
353 max_cf = display_frequencies[ ( central_chans - 1 ) << interps ] ;
|
tomwalters@0
|
354 }
|
tomwalters@0
|
355
|
tomwalters@0
|
356 else {
|
tomwalters@0
|
357 central_chans = *display_chans << -interps ;
|
tomwalters@0
|
358 central_dens = ldexp( *display_dens, -interps ) ;
|
tomwalters@0
|
359 min_cf = FofErbScale( ErbScale( display_frequencies[0] )
|
tomwalters@0
|
360 - ( 1 << -interps ) / central_dens ) ;
|
tomwalters@0
|
361 max_cf = display_frequencies[*display_chans - 1] ;
|
tomwalters@0
|
362 }
|
tomwalters@0
|
363
|
tomwalters@0
|
364
|
tomwalters@0
|
365 /***** set number and density of apical and basal channels outside display range *****/
|
tomwalters@0
|
366
|
tomwalters@0
|
367 if( *out_dens <= 0. ) {
|
tomwalters@0
|
368
|
tomwalters@0
|
369 apical_cf = min_cf ;
|
tomwalters@0
|
370 apical_dens = 0. ;
|
tomwalters@0
|
371 basal_cf = max_cf ;
|
tomwalters@0
|
372 basal_dens = 0. ;
|
tomwalters@0
|
373 }
|
tomwalters@0
|
374 else {
|
tomwalters@0
|
375 apical_cf = adjustCF( MIN_CF, samplerate ) ;
|
tomwalters@0
|
376 apical_dens = *out_dens ;
|
tomwalters@0
|
377 basal_cf = adjustCF( MAX_CF, samplerate ) ;
|
tomwalters@0
|
378 basal_dens = *out_dens ;
|
tomwalters@0
|
379 }
|
tomwalters@0
|
380
|
tomwalters@0
|
381 apical_chans = 0 ;
|
tomwalters@0
|
382 basal_chans = 0 ;
|
tomwalters@0
|
383
|
tomwalters@0
|
384
|
tomwalters@0
|
385 /***** generate apical and basal center frequencies outside display range *****/
|
tomwalters@0
|
386
|
tomwalters@0
|
387 apical_frequencies = GenerateFrequencies( apical_cf, min_cf, min_cf, &apical_dens, &apical_chans ) ;
|
tomwalters@0
|
388 basal_frequencies = GenerateFrequencies( max_cf, basal_cf, max_cf, &basal_dens, &basal_chans ) ;
|
tomwalters@0
|
389
|
tomwalters@0
|
390 /***** fill in array of BanKSegment structures with BM segment info *****/
|
tomwalters@0
|
391 *total_chans = apical_chans + central_chans + basal_chans - 2 ;
|
tomwalters@0
|
392 bankSeg = NewArray( BankSegment *, *total_chans + 1, "tl_bank.c for segments" ) ;
|
tomwalters@0
|
393
|
tomwalters@0
|
394 ichan = 0 ;
|
tomwalters@0
|
395 for( chan = 1 ; chan < apical_chans ; chan++ ) {
|
tomwalters@0
|
396
|
tomwalters@0
|
397 bankSeg[ ichan++ ] = segmentPointer = New( BankSegment * ) ;
|
tomwalters@0
|
398 segmentPointer->center_frequency = apical_frequencies[ chan ] ;
|
tomwalters@0
|
399 segmentPointer->seglength = cm_per_CB / apical_dens ;
|
tomwalters@0
|
400 segmentPointer->position = L - cm_per_CB * ErbScale( segmentPointer->center_frequency ) ;
|
tomwalters@0
|
401 segmentPointer->active = 0 ;
|
tomwalters@0
|
402 }
|
tomwalters@0
|
403
|
tomwalters@0
|
404 for( chan = 0 ; chan < central_chans ; chan++ ) {
|
tomwalters@0
|
405
|
tomwalters@0
|
406 bankSeg[ ichan++ ] = segmentPointer = New( BankSegment * ) ;
|
tomwalters@0
|
407
|
tomwalters@0
|
408 if( interps >= 0 ) {
|
tomwalters@0
|
409 segmentPointer->center_frequency = display_frequencies[ chan << interps ] ;
|
tomwalters@0
|
410 segmentPointer->active = 1 ;
|
tomwalters@0
|
411 }
|
tomwalters@0
|
412 else {
|
tomwalters@0
|
413 remainder = chan % ( 1 << -interps ) ;
|
tomwalters@0
|
414 segmentPointer->center_frequency = FofErbScale( ErbScale( display_frequencies[ chan >> -interps ] )
|
tomwalters@0
|
415 + ( remainder - ( 1 << -interps ) + 1 ) / central_dens ) ;
|
tomwalters@0
|
416 segmentPointer->active = ( remainder == ( ( 1 << -interps ) - 1 ) ) ;
|
tomwalters@0
|
417 }
|
tomwalters@0
|
418
|
tomwalters@0
|
419 segmentPointer->seglength = cm_per_CB / central_dens ;
|
tomwalters@0
|
420 segmentPointer->position = L - cm_per_CB * ErbScale( segmentPointer->center_frequency ) ;
|
tomwalters@0
|
421 }
|
tomwalters@0
|
422
|
tomwalters@0
|
423
|
tomwalters@0
|
424 for( chan = 1 ; chan < basal_chans ; chan++ ) {
|
tomwalters@0
|
425
|
tomwalters@0
|
426 bankSeg[ ichan++ ] = segmentPointer = New( BankSegment * ) ;
|
tomwalters@0
|
427 segmentPointer->center_frequency = basal_frequencies[ chan ] ;
|
tomwalters@0
|
428 segmentPointer->seglength = cm_per_CB / basal_dens ;
|
tomwalters@0
|
429 segmentPointer->position = L - cm_per_CB * ErbScale( segmentPointer->center_frequency ) ;
|
tomwalters@0
|
430 segmentPointer->active = 0 ;
|
tomwalters@0
|
431 }
|
tomwalters@0
|
432
|
tomwalters@0
|
433 segmentPointer = bankSeg[ 0 ] ;
|
tomwalters@0
|
434 if( ( segmentPointer->position + segmentPointer->seglength ) > L )
|
tomwalters@0
|
435 segmentPointer->seglength = L - MIN( L, segmentPointer->position ) ;
|
tomwalters@0
|
436
|
tomwalters@0
|
437 /***** return and deallocate dynamic memory *****/
|
tomwalters@0
|
438 Delete( apical_frequencies ) ;
|
tomwalters@0
|
439 Delete( basal_frequencies ) ;
|
tomwalters@0
|
440
|
tomwalters@0
|
441 return( bankSeg ) ;
|
tomwalters@0
|
442 }
|
tomwalters@0
|
443
|
tomwalters@0
|
444
|
tomwalters@0
|
445 double *GenerateFrequencies( min_cf, max_cf, base_cf, density, channels )
|
tomwalters@0
|
446 double min_cf, max_cf, base_cf ;
|
tomwalters@0
|
447 double *density ;
|
tomwalters@0
|
448 int *channels ;
|
tomwalters@0
|
449 {
|
tomwalters@0
|
450 double freq, *frequencies ;
|
tomwalters@0
|
451
|
tomwalters@0
|
452 /*** map characteristic frequencies onto specified scale ***/
|
tomwalters@0
|
453 min_cf = ErbScale( min_cf ) ;
|
tomwalters@0
|
454 max_cf = ErbScale( max_cf ) ;
|
tomwalters@0
|
455 max_cf = MAX( min_cf, max_cf ) ; /* max_cf cannot be smaller than min_cf */
|
tomwalters@0
|
456 base_cf = ErbScale( base_cf ) ;
|
tomwalters@0
|
457
|
tomwalters@0
|
458
|
tomwalters@0
|
459 /*** call appropriate generating functions ***/
|
tomwalters@0
|
460 if( *channels <= 0 ) {
|
tomwalters@0
|
461
|
tomwalters@0
|
462 if( *density <= 0. ) {
|
tomwalters@0
|
463 *channels = 1 ; /* there must be at least one channel */
|
tomwalters@0
|
464 freq = FofErbScale( min_cf ) ; /* arbitrary */
|
tomwalters@0
|
465 frequencies = &freq ;
|
tomwalters@0
|
466 *density = 1. ; /* arbitrary */
|
tomwalters@0
|
467
|
tomwalters@0
|
468 }
|
tomwalters@0
|
469 else {
|
tomwalters@0
|
470 frequencies = GenerateScale( min_cf, max_cf, *density, base_cf, FofErbScale ) ;
|
tomwalters@0
|
471 *channels = NumberOnScale( min_cf, max_cf, *density, base_cf ) ;
|
tomwalters@0
|
472 }
|
tomwalters@0
|
473 }
|
tomwalters@0
|
474
|
tomwalters@0
|
475 else {
|
tomwalters@0
|
476 frequencies = NumberedScale( min_cf, max_cf, *channels, FofErbScale ) ;
|
tomwalters@0
|
477 *density = DensityOnScale( min_cf, max_cf, *channels ) ;
|
tomwalters@0
|
478 if( *density == 0. )
|
tomwalters@0
|
479 *density = 1. ; /* arbitrary */
|
tomwalters@0
|
480 }
|
tomwalters@0
|
481
|
tomwalters@0
|
482 /*** return pointer to array of center frequencies ***/
|
tomwalters@0
|
483 return ( frequencies ) ;
|
tomwalters@0
|
484 }
|
tomwalters@0
|
485
|
tomwalters@0
|
486
|
tomwalters@0
|
487 double adjustCF( cf, samplerate )
|
tomwalters@0
|
488 double cf, samplerate ;
|
tomwalters@0
|
489 {
|
tomwalters@0
|
490 cf = MAX( cf, MIN_CF ) ;
|
tomwalters@0
|
491 cf = MAX( cf, FofErbScale( 0. ) ) ;
|
tomwalters@0
|
492
|
tomwalters@0
|
493 cf = MIN( cf, samplerate / 2. ) ;
|
tomwalters@0
|
494 cf = MIN( cf, MAX_CF ) ;
|
tomwalters@0
|
495 cf = MIN( cf, FofErbScale( 10. * L / GetERBscaling() ) );
|
tomwalters@0
|
496
|
tomwalters@0
|
497 return ( cf ) ;
|
tomwalters@0
|
498 }
|
tomwalters@0
|
499
|