source: gs3-extensions/web-audio/trunk/js-dsp/component/wf-filter-bank.js@ 28388

Last change on this file since 28388 was 28388, checked in by davidb, 11 years ago

Set of JS, CSS, PNG etc web resources to support a mixture of audio player/document display capabilities

File size: 7.1 KB
Line 
1
2var WFFilterBank = function(frameBufferLength,channels,samplerate,totalNumFrames) {
3
4 this.frameBufferLength = frameBufferLength;
5 this.channels = channels;
6 this.samplerate = samplerate;
7
8 this.totalNumFrames = totalNumFrames; // **** Not currently used
9
10 this.defaults();
11
12 var fftWindowSize = Math.floor(this.frameBufferLength/channels); // check this is a power of 2??
13
14 this.initCQT(fftWindowSize, fftWindowSize/2);
15
16 //this.fft = new FFTCustom(fftWindowSize, this.samplerate);
17
18 this.filterBankOut = new Float32Array(this.cqt_rec.cqtN); // ditto above
19
20 this.filterBankSequence = new Array();
21
22 this.maxval = 0.0;
23
24}
25
26WFFilterBank.inherits(Component);
27
28//----------------------------- OVERVIEW -----------------------------------------------------
29
30WFFilterBank.staticfield('Component', {
31
32 creator: "David Bainbridge",
33 description: "Overview: Computes a frequency filter bank based on frequency spectrum input",
34 name: "filterBank",
35 tags: "signal process, filter-bank",
36 dependency: [ "dsp.js" ]
37});
38
39//------------------------------ INPUTS ------------------------------------------------------
40
41WFFilterBank.staticfield('ComponentInputArray', [
42 {
43 name: "freqSpectrumInputFrames",
44 description: "Frames of (mono) freqency spectrum input"
45 }
46
47]);
48
49
50//------------------------------ PROPERTIES --------------------------------------------------
51
52WFFilterBank.staticfield('ComponentPropertyArray', [
53]);
54
55
56//------------------------------ OUTPUTS -----------------------------------------------------
57
58WFFilterBank.staticfield('ComponentOutputArray', [
59 {
60 name: "filterBankFrames",
61 description: "Per frame filter bank"
62 }
63]);
64
65
66
67WFFilterBank.prototype.reset = function()
68{
69 this.maxval = 0.0;
70}
71
72
73WFFilterBank.prototype.setMaxVal = function(v)
74{
75 this.maxval = v;
76}
77
78
79WFFilterBank.prototype.getMaxVal = function()
80{
81 return this.maxval;
82}
83
84WFFilterBank.prototype.getFilterBankSequence = function() {
85 return this.filterBankSequence;
86}
87
88
89// ******
90// ******
91
92
93
94WFFilterBank.prototype.defaults = function() {
95
96 this.constantQ = 12;
97
98 this.loEdge = 55.0 * Math.pow(2.0, 2.5/12.0); // low C minus quater tone
99 this.hiEdge = 8000.0;
100};
101
102
103WFFilterBank.prototype.initializeCallback = function(ccp) {
104
105}
106
107
108//
109// init Constant Q transform (http://en.wikipedia.org/wiki/Constant_Q_transform)
110//
111WFFilterBank.prototype.initCQT = function(fftN, outN) {
112
113 // Linear to log frequency map for FFT
114
115 // BPO = bands per octave
116
117 var info_mess = "filter-bank: { ";
118 info_mess += "constantQ: " + this.constantQ;
119 info_mess += ", fftN = " + fftN;
120 info_mess += ", outN = " + outN;
121 info_mess += ", sameplerate = " + this.samplerate;
122 info_mess += ", loEdge = " + this.loEdge + " Hz";
123 info_mess += ", hiEdge = " + this.hiEdge + " Hz";
124 info_mess += " }";
125
126 console.info(info_mess);
127
128 var i,j;
129
130 var BPO = this.constantQ;
131 var fratio = Math.pow(2.0,1.0/BPO);// Constant-Q bandwidth
132
133 var cqtN = Math.floor(Math.log(this.hiEdge/this.loEdge)/Math.log(fratio));
134 if(cqtN<1) {
135 console.error("cqtN not positive definite");
136 }
137
138 if (_dspdebug) {
139 console.log("debug: cqtN = " + cqtN);
140 }
141
142 var fftfrqs = new Float32Array(outN); // Actual number of real FFT coefficients
143 var logfrqs = new Float32Array(cqtN); // Number of constant-Q spectral bins
144 var logfbws = new Float32Array(cqtN); // Bandwidths of constant-Q bins
145
146 var CQT = new Float32Array(cqtN*outN); // The transformation matrix
147
148 var mxnorm = new Float32Array(cqtN); // Normalization coefficients
149 var N = fftN; // N used as a (double)
150
151 for(i=0; i < outN; i++) {
152 fftfrqs[i] = i * this.samplerate / N;
153 }
154
155 for(i=0; i<cqtN; i++){
156 logfrqs[i] = this.loEdge * Math.exp(Math.log(2.0)*i/BPO);
157 logfbws[i] = Math.max(logfrqs[i] * (fratio - 1.0), this.samplerate / N);
158 }
159
160 var ovfctr = 0.5475; // Norm constant so CQT'*CQT close to 1.0
161 var tmp,tmp2;
162 var ptr;
163
164 // Build the constant-Q transform (CQT)
165 for(i=0,ptr=0; i<cqtN; i++){
166 mxnorm[i]=0.0;
167 tmp2=1.0/(ovfctr*logfbws[i]);
168 for(j=0 ; j < outN; j++, ptr++){
169 tmp=(logfrqs[i] - fftfrqs[j])*tmp2;
170 tmp=Math.exp(-0.5*tmp*tmp);
171 CQT[ptr]=tmp; // row major transform
172 mxnorm[i]+=tmp*tmp;
173 }
174 mxnorm[i]=2.0*Math.sqrt(mxnorm[i]);
175 }
176
177 // Normalize transform matrix for identity inverse
178 for(i=0,ptr=0; i<cqtN; i++) {
179 tmp = 1.0/mxnorm[i];
180 for(j=0; j<outN; j++,ptr++) {
181 CQT[ptr] *= tmp;
182 }
183 }
184
185 var cqt_rec = { CQT: CQT, cqtN: cqtN, outN: outN };
186
187 if (_dspdebug) {
188 var CQT = cqt_rec.CQT;
189 var cqtN = cqt_rec.cqtN;
190 var outN = cqt_rec.outN;
191
192 //for(i=0,ptr=0; i<cqtN; i++){
193 for(i=0,ptr=0; i<cqtN; i+=10){
194 ptr = i*outN;
195 var line = "";
196 //for(j=0; j<outN; j++,ptr++) {
197 for(j=0; j<outN; j+=20,ptr+=20) {
198 line += CQT[ptr] + " ";
199 }
200 console.log(line);
201 }
202 }
203
204 // store it in object
205 this.cqt_rec = cqt_rec;
206
207};
208
209
210WFFilterBank.prototype.computeFilterBank = function(fftSpectrumIn,cqtOut)
211{
212 var CQT = this.cqt_rec.CQT;
213 var cqtN = this.cqt_rec.cqtN;
214 var outN = this.cqt_rec.outN;
215
216 // matrix product of CQT * fftSpectrumIn
217
218 var a=cqtN;
219 var i=0;
220
221 while (a--) {
222 cqtOut[i] = 0.0;
223
224 var ptr2 = i * outN;
225 var ptr3 = 0;
226
227 var b = outN;
228 while (b--) {
229
230 cqtOut[i] += CQT[ptr2] * fftSpectrumIn[ptr3];
231
232 ptr2++;
233 ptr3++;
234 }
235
236 if (cqtOut[i]>this.maxval) {
237 this.maxval = cqtOut[i];
238 }
239
240 i++;
241 }
242}
243
244/*
245WFFilterBank.prototype.computeTransform = function(signal) {
246
247 // executeCallback
248 // need to get signal from 'cc' rather than passed in directly as param
249
250 this.fft.forward(signal);
251
252 this.computeFilterBank(this.fft.powerSpectrum,this.filterBankOut);
253
254 var filterBankCopy = new Float32Array(this.filterBankOut); // need a copy of the array (not just a reference)
255 this.filterBankSequence.push(filterBankCopy);
256
257 if (_dspdebug) {
258 var line = "";
259 for (i=0; i<this.filterBankOut.length; i+=20) {
260 line += this.filterBankOut[i] + " ";
261 }
262
263 console.log("filter bank: " + line);
264 }
265
266}
267
268*/
269
270
271WFFilterBank.prototype.executeCallBack = function(cc) {
272
273 // typeof(cc) => ComponentContext
274
275 // get the "[D" input
276
277 //console.info("*** WFFilterBank::executeCallBack(): away to request 'inputFrames'");
278
279 var frame = cc.getDataComponentFromInput("freqSpectrumInputFrames");
280
281// this.fft.forward(frame);
282
283// this.computeFilterBank(this.fft.powerSpectrum,this.filterBankOut);
284
285 this.computeFilterBank(frame,this.filterBankOut);
286
287 var filterBankCopy = new Float32Array(this.filterBankOut); // need a copy of the array (not just a reference)
288 this.filterBankSequence.push(filterBankCopy);
289
290 cc.pushDataComponentToOutput("filterBankFrames",this.filterBankOut);
291
292}
293
Note: See TracBrowser for help on using the repository browser.