tomwalters@0
|
1 /*
|
tomwalters@0
|
2 Copyright (c) Applied Psychology Unit, Medical Research Council. 1988, 1989
|
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 */
|
tomwalters@0
|
17
|
tomwalters@0
|
18 /*
|
tomwalters@0
|
19 bank.c
|
tomwalters@0
|
20 ======
|
tomwalters@0
|
21
|
tomwalters@0
|
22 long awaited proper generic multiplexed filter bank with phase compensation!
|
tomwalters@0
|
23
|
tomwalters@0
|
24
|
tomwalters@0
|
25 Copyright (c), 1989 The Medical Research Council, Applied Psychology Unit.
|
tomwalters@0
|
26
|
tomwalters@0
|
27
|
tomwalters@0
|
28 Author : John Holdsworth
|
tomwalters@0
|
29 Written : 10th March, 1989.
|
tomwalters@0
|
30
|
tomwalters@0
|
31 Edited :
|
tomwalters@0
|
32 Christian Giguere, March 1994
|
tomwalters@0
|
33 - Provided facilities to print filterbank information to stderr
|
tomwalters@0
|
34 - To locate changes, search for "CG"
|
tomwalters@0
|
35
|
tomwalters@0
|
36 */
|
tomwalters@0
|
37
|
tomwalters@0
|
38 #include <math.h>
|
tomwalters@0
|
39 #include <stdio.h> /* CG */
|
tomwalters@0
|
40
|
tomwalters@0
|
41 #include "stitch.h"
|
tomwalters@0
|
42 #include "source.h"
|
tomwalters@0
|
43 #include "recurse.h"
|
tomwalters@0
|
44 #include "formulae.h"
|
tomwalters@0
|
45
|
tomwalters@0
|
46 #include "bank.h"
|
tomwalters@0
|
47
|
tomwalters@0
|
48 #ifndef lint
|
tomwalters@0
|
49 static char *sccs_id = "@(#)bank.c 1.16 John Holdsworth (MRC-APU) 6/6/91" ;
|
tomwalters@0
|
50 #endif
|
tomwalters@0
|
51
|
tomwalters@0
|
52
|
tomwalters@0
|
53 /* interpolation */
|
tomwalters@0
|
54
|
tomwalters@0
|
55 struct _interp_state { struct _fillable_source parent ; Source source ; unsigned ichans ; int (*interp)() ; } ;
|
tomwalters@0
|
56
|
tomwalters@0
|
57 static Pointer interp_callback( state, bytes, buffer )
|
tomwalters@0
|
58 struct _interp_state *state ;
|
tomwalters@0
|
59 ByteCount *bytes ;
|
tomwalters@0
|
60 short *buffer ;
|
tomwalters@0
|
61 {
|
tomwalters@0
|
62 register int last = *bytes == 0 ;
|
tomwalters@0
|
63 register int ipointer, points = ToPoints( short, *bytes ) ;
|
tomwalters@0
|
64 register int ipoints = points / (state->ichans*2-1) * state->ichans ;
|
tomwalters@0
|
65 short *input = PullShorts( state->source, ipoints ) ;
|
tomwalters@0
|
66
|
tomwalters@0
|
67 if( !last ) {
|
tomwalters@0
|
68 for( ipointer=0 ; ipointer < ipoints ; ipointer += state->ichans )
|
tomwalters@0
|
69 state->interp( input+ipointer, buffer+ipointer/state->ichans*(state->ichans*2-1), state->ichans, state->ichans*2-1 ) ;
|
tomwalters@0
|
70
|
tomwalters@0
|
71 return ( (Pointer) buffer ) ;
|
tomwalters@0
|
72 }
|
tomwalters@0
|
73 else
|
tomwalters@0
|
74 return ( DeleteFillableSource( state ) ) ;
|
tomwalters@0
|
75 }
|
tomwalters@0
|
76
|
tomwalters@0
|
77 Source InterpSource( source, ichans )
|
tomwalters@0
|
78 Source source ;
|
tomwalters@0
|
79 int ichans ;
|
tomwalters@0
|
80 {
|
tomwalters@0
|
81 DeclareNew( struct _interp_state *, state ) ;
|
tomwalters@0
|
82 extern int interp() ;
|
tomwalters@0
|
83
|
tomwalters@0
|
84 state->source = source ;
|
tomwalters@0
|
85 state->ichans = ichans ;
|
tomwalters@0
|
86 state->interp = interp ;
|
tomwalters@0
|
87
|
tomwalters@0
|
88 return ( SetFillableSource( state, interp_callback, "bank.c interpolating" ) ) ;
|
tomwalters@0
|
89 }
|
tomwalters@0
|
90
|
tomwalters@0
|
91 Source LinterpSource( source, ichans )
|
tomwalters@0
|
92 Source source ;
|
tomwalters@0
|
93 int ichans ;
|
tomwalters@0
|
94 {
|
tomwalters@0
|
95 DeclareNew( struct _interp_state *, state ) ;
|
tomwalters@0
|
96 extern int linterp() ;
|
tomwalters@0
|
97
|
tomwalters@0
|
98 state->source = source ;
|
tomwalters@0
|
99 state->ichans = ichans ;
|
tomwalters@0
|
100 state->interp = linterp ;
|
tomwalters@0
|
101
|
tomwalters@0
|
102 return ( SetFillableSource( state, interp_callback, "bank.c linterpolating" ) ) ;
|
tomwalters@0
|
103 }
|
tomwalters@0
|
104
|
tomwalters@0
|
105 static int segsize = 50 ;
|
tomwalters@0
|
106
|
tomwalters@0
|
107 #ifdef DSP32
|
tomwalters@0
|
108 #define BUFFSIZE 256
|
tomwalters@0
|
109 #else
|
tomwalters@0
|
110 #define BUFFSIZE 2048
|
tomwalters@0
|
111 #endif
|
tomwalters@0
|
112
|
tomwalters@0
|
113 /* multiplexed filter bank */
|
tomwalters@0
|
114
|
tomwalters@0
|
115 struct _bank_state {
|
tomwalters@0
|
116 struct _fillable_source parent ;
|
tomwalters@0
|
117 Source source ; char *input ; unsigned chans ;
|
tomwalters@0
|
118 int active, pointer, iptr, *delays, (*proc)(), input_size, output_size ;
|
tomwalters@0
|
119 RecursiveFilterState **states ;
|
tomwalters@0
|
120 } ;
|
tomwalters@0
|
121
|
tomwalters@0
|
122 static Pointer bank_callback( state, bytes, buffer )
|
tomwalters@0
|
123 struct _bank_state *state ;
|
tomwalters@0
|
124 ByteCount *bytes ;
|
tomwalters@0
|
125 char *buffer ;
|
tomwalters@0
|
126 {
|
tomwalters@0
|
127 extern char *bstart, *bend ;
|
tomwalters@0
|
128 register int last = *bytes == 0 ;
|
tomwalters@0
|
129 static int segment = BUFFSIZE ;
|
tomwalters@0
|
130 int points, bytecount ;
|
tomwalters@0
|
131
|
tomwalters@0
|
132 if( state->input == ( char * ) 0 ) {
|
tomwalters@0
|
133
|
tomwalters@0
|
134 if( state->delays[0] < 0 )
|
tomwalters@0
|
135 state->pointer = state->delays[0] ;
|
tomwalters@0
|
136 else
|
tomwalters@0
|
137 state->pointer = 0 ;
|
tomwalters@0
|
138
|
tomwalters@0
|
139 if( segment < state->delays[state->chans-1] - state->delays[0] )
|
tomwalters@0
|
140 segment = state->delays[state->chans-1] - state->delays[0] << 1 ;
|
tomwalters@0
|
141
|
tomwalters@0
|
142 state->input = Pull( state->source, segment * state->input_size ) ;
|
tomwalters@0
|
143 state->iptr = state->pointer ;
|
tomwalters@0
|
144 state->active = 0 ;
|
tomwalters@0
|
145
|
tomwalters@0
|
146 bstart = state->input - segment * state->input_size ;
|
tomwalters@0
|
147 bend = state->input + segment * state->input_size ;
|
tomwalters@0
|
148 }
|
tomwalters@0
|
149
|
tomwalters@0
|
150 if( !last ) {
|
tomwalters@0
|
151 for( bytecount=0 ; bytecount<*bytes ; ) {
|
tomwalters@0
|
152
|
tomwalters@0
|
153 if( state->iptr + segsize - state->delays[0] >= segment ) {
|
tomwalters@0
|
154 state->input = Pull( state->source, segment * state->input_size ) ;
|
tomwalters@0
|
155 state->iptr -= segment ;
|
tomwalters@0
|
156
|
tomwalters@0
|
157 bstart = state->input - segment * state->input_size ;
|
tomwalters@0
|
158 bend = state->input + segment * state->input_size ;
|
tomwalters@0
|
159
|
tomwalters@0
|
160 }
|
tomwalters@0
|
161
|
tomwalters@0
|
162 while( state->active < state->chans && state->delays[ state->active ] <= state->pointer )
|
tomwalters@0
|
163 state->active++ ;
|
tomwalters@0
|
164
|
tomwalters@0
|
165 if( state->pointer < 0 || state->active < state->chans || state->output_size == 0 ) {
|
tomwalters@0
|
166
|
tomwalters@0
|
167 points = 1 ;
|
tomwalters@0
|
168
|
tomwalters@0
|
169 state->output_size = state->proc( state->states, state->delays, state->input + state->iptr * state->input_size, buffer+bytecount, points, state->active ) ;
|
tomwalters@0
|
170
|
tomwalters@0
|
171 stitch_bzero( buffer+bytecount+state->active*state->output_size, (int) ( ( state->chans - state->active ) * state->output_size ) ) ;
|
tomwalters@0
|
172 }
|
tomwalters@0
|
173 else {
|
tomwalters@0
|
174 points = ( *bytes - bytecount ) / state->chans / state->output_size ;
|
tomwalters@0
|
175
|
tomwalters@0
|
176 if( points > segsize )
|
tomwalters@0
|
177 points = segsize ;
|
tomwalters@0
|
178
|
tomwalters@0
|
179 state->output_size = state->proc( state->states, state->delays, state->input + state->iptr * state->input_size, buffer+bytecount, points, state->active ) ;
|
tomwalters@0
|
180 }
|
tomwalters@0
|
181
|
tomwalters@0
|
182 state->iptr += points ;
|
tomwalters@0
|
183
|
tomwalters@0
|
184 if( ++state->pointer > 0 )
|
tomwalters@0
|
185 bytecount += points*state->chans*state->output_size ;
|
tomwalters@0
|
186 }
|
tomwalters@0
|
187
|
tomwalters@0
|
188 return ( buffer ) ;
|
tomwalters@0
|
189 }
|
tomwalters@0
|
190 else {
|
tomwalters@0
|
191 Pull( state->source, 0 ) ;
|
tomwalters@0
|
192
|
tomwalters@0
|
193 for( last=0 ; last<state->chans ; last++ )
|
tomwalters@0
|
194 Delete( state->states[last] ) ;
|
tomwalters@0
|
195
|
tomwalters@0
|
196 Delete( state->states ) ;
|
tomwalters@0
|
197 Delete( state->delays ) ;
|
tomwalters@0
|
198
|
tomwalters@0
|
199 return ( DeleteFillableSource( state ) ) ;
|
tomwalters@0
|
200 }
|
tomwalters@0
|
201
|
tomwalters@0
|
202 }
|
tomwalters@0
|
203
|
tomwalters@0
|
204
|
tomwalters@0
|
205 Source GenericFilterBank( source, interps, chans, samplerate, center_frequencies, bandwidth_function, scale_function, output_scale, audio_power, order, phase_compensation, input_bits, frames, proc, input_size, info )
|
tomwalters@0
|
206 Source source ;
|
tomwalters@0
|
207 int interps, *chans ;
|
tomwalters@0
|
208 double samplerate, *center_frequencies, (*bandwidth_function)(), (*scale_function)() ; /* CG: 23-03-94 */
|
tomwalters@0
|
209 double output_scale, audio_power ; /* CG: 23-03-94 */
|
tomwalters@0
|
210 int order, phase_compensation, input_bits ;
|
tomwalters@0
|
211 long frames ;
|
tomwalters@0
|
212 int (*proc)(), input_size, info ; /* CG: 23-03-94 */
|
tomwalters@0
|
213 {
|
tomwalters@0
|
214 DeclareNew( struct _bank_state *, state ) ;
|
tomwalters@0
|
215 double sample_delay, max_delay, freq ;
|
tomwalters@0
|
216 extern Source Interp() ;
|
tomwalters@0
|
217 Source out ;
|
tomwalters@0
|
218 int chan ;
|
tomwalters@0
|
219
|
tomwalters@0
|
220 state->chans = *chans >> interps ;
|
tomwalters@0
|
221
|
tomwalters@0
|
222 state->states = NewArray( RecursiveFilterState *, state->chans, "bank.c for states" ) ;
|
tomwalters@0
|
223 state->delays = NewArray( int, state->chans, "bank.c for delays" ) ;
|
tomwalters@0
|
224
|
tomwalters@0
|
225 state->input_size = input_size ;
|
tomwalters@0
|
226
|
tomwalters@0
|
227 if( info ) /* CG: 23-03-94 */
|
tomwalters@0
|
228 fprintf( stderr, "\nGTF filterbank information:\n" ) ;
|
tomwalters@0
|
229
|
tomwalters@0
|
230 for( chan=0 ; chan < state->chans ; chan++ ) {
|
tomwalters@0
|
231 sample_delay = 0 ;
|
tomwalters@0
|
232
|
tomwalters@0
|
233 freq = center_frequencies[ chan<<interps ] ;
|
tomwalters@0
|
234
|
tomwalters@0
|
235 if( info ) /* CG: 23-03-94 */
|
tomwalters@0
|
236 fprintf( stderr, "%3d -- cf:%7.1f Hz =%6.2f ERBs -- bwidth=%5.1f Hz\n",
|
tomwalters@0
|
237 chan + 1 , freq, scale_function( freq ), bandwidth_function( freq ) ) ;
|
tomwalters@0
|
238
|
tomwalters@0
|
239 state->states[ chan ] = NewRecursiveFilter( samplerate, freq, bandwidth_function( freq ),
|
tomwalters@0
|
240 output_scale * pow( Audiogram( freq ), audio_power ),
|
tomwalters@0
|
241 order, phase_compensation, input_bits, &sample_delay ) ;
|
tomwalters@0
|
242
|
tomwalters@0
|
243 if( chan == 0 )
|
tomwalters@0
|
244 max_delay = sample_delay ;
|
tomwalters@0
|
245
|
tomwalters@0
|
246 if( phase_compensation == FINE_ALIGNMENT || phase_compensation == ENVELOPE_ALIGNMENT )
|
tomwalters@0
|
247 state->delays[ chan ] = sample_delay - max_delay ;
|
tomwalters@0
|
248 else
|
tomwalters@0
|
249 state->delays[ chan ] = sample_delay ;
|
tomwalters@0
|
250 }
|
tomwalters@0
|
251
|
tomwalters@0
|
252 state->output_size = 0 ;
|
tomwalters@0
|
253
|
tomwalters@0
|
254 state->source = NewRetainingSource( source, BUFFSIZE * state->input_size ) ;
|
tomwalters@0
|
255
|
tomwalters@0
|
256 state->input = ( char * ) 0 ;
|
tomwalters@0
|
257 state->proc = proc ;
|
tomwalters@0
|
258
|
tomwalters@0
|
259 out = SetFillableSource( state, bank_callback, "bank.c filter" ) ;
|
tomwalters@0
|
260
|
tomwalters@0
|
261 for( chan = state->chans ; interps-- > 0 ; chan = chan*2-1 )
|
tomwalters@0
|
262 out = InterpSource( out, chan ) ;
|
tomwalters@0
|
263
|
tomwalters@0
|
264 *chans = chan ;
|
tomwalters@0
|
265
|
tomwalters@0
|
266 return ( out ) ;
|
tomwalters@0
|
267 }
|
tomwalters@0
|
268
|