AudioJack: do not use QVector in processCallback()
[lmms.git] / plugins / sid / filter.h
blob8d8aece3dbe61c4c47ef06ce54d60ef05d82277b
1 // ---------------------------------------------------------------------------
2 // This file is part of reSID, a MOS6581 SID emulator engine.
3 // Copyright (C) 2004 Dag Lem <resid@nimrod.no>
4 //
5 // This program is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation; either version 2 of the License, or
8 // (at your option) any later version.
9 //
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software
17 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 // ---------------------------------------------------------------------------
20 #ifndef __FILTER_H__
21 #define __FILTER_H__
23 #include "siddefs.h"
24 #include "spline.h"
26 // ----------------------------------------------------------------------------
27 // The SID filter is modeled with a two-integrator-loop biquadratic filter,
28 // which has been confirmed by Bob Yannes to be the actual circuit used in
29 // the SID chip.
31 // Measurements show that excellent emulation of the SID filter is achieved,
32 // except when high resonance is combined with high sustain levels.
33 // In this case the SID op-amps are performing less than ideally and are
34 // causing some peculiar behavior of the SID filter. This however seems to
35 // have more effect on the overall amplitude than on the color of the sound.
37 // The theory for the filter circuit can be found in "Microelectric Circuits"
38 // by Adel S. Sedra and Kenneth C. Smith.
39 // The circuit is modeled based on the explanation found there except that
40 // an additional inverter is used in the feedback from the bandpass output,
41 // allowing the summer op-amp to operate in single-ended mode. This yields
42 // inverted filter outputs with levels independent of Q, which corresponds with
43 // the results obtained from a real SID.
45 // We have been able to model the summer and the two integrators of the circuit
46 // to form components of an IIR filter.
47 // Vhp is the output of the summer, Vbp is the output of the first integrator,
48 // and Vlp is the output of the second integrator in the filter circuit.
50 // According to Bob Yannes, the active stages of the SID filter are not really
51 // op-amps. Rather, simple NMOS inverters are used. By biasing an inverter
52 // into its region of quasi-linear operation using a feedback resistor from
53 // input to output, a MOS inverter can be made to act like an op-amp for
54 // small signals centered around the switching threshold.
56 // Qualified guesses at SID filter schematics are depicted below.
58 // SID filter
59 // ----------
60 //
61 // -----------------------------------------------
62 // | |
63 // | ---Rq-- |
64 // | | | |
65 // | ------------<A]-----R1--------- |
66 // | | | |
67 // | | ---C---| ---C---|
68 // | | | | | |
69 // | --R1-- ---R1-- |---Rs--| |---Rs--|
70 // | | | | | | | |
71 // ----R1--|-----[A>--|--R-----[A>--|--R-----[A>--|
72 // | | | |
73 // vi -----R1-- | | |
74 //
75 // vhp vbp vlp
76 //
77 //
78 // vi - input voltage
79 // vhp - highpass output
80 // vbp - bandpass output
81 // vlp - lowpass output
82 // [A> - op-amp
83 // R1 - summer resistor
84 // Rq - resistor array controlling resonance (4 resistors)
85 // R - NMOS FET voltage controlled resistor controlling cutoff frequency
86 // Rs - shunt resitor
87 // C - capacitor
88 //
89 //
90 //
91 // SID integrator
92 // --------------
93 //
94 // V+
95 //
96 // |
97 // |
98 // -----|
99 // | |
100 // | ||--
101 // -||
102 // ---C--- ||->
103 // | | |
104 // |---Rs-----------|---- vo
105 // | |
106 // | ||--
107 // vi ---- -----|------------||
108 // | ^ | ||->
109 // |___| | |
110 // ----- | |
111 // | | |
112 // |---R2-- |
113 // |
114 // R1 V-
115 // |
116 // |
118 // Vw
120 // ----------------------------------------------------------------------------
121 class Filter
123 public:
124 Filter();
126 void enable_filter(bool enable);
127 void set_chip_model(chip_model model);
129 RESID_INLINE
130 void clock(sound_sample voice1, sound_sample voice2, sound_sample voice3,
131 sound_sample ext_in);
132 RESID_INLINE
133 void clock(cycle_count delta_t,
134 sound_sample voice1, sound_sample voice2, sound_sample voice3,
135 sound_sample ext_in);
136 void reset();
138 // Write registers.
139 void writeFC_LO(reg8);
140 void writeFC_HI(reg8);
141 void writeRES_FILT(reg8);
142 void writeMODE_VOL(reg8);
144 // SID audio output (16 bits).
145 sound_sample output();
147 // Spline functions.
148 void fc_default(const fc_point*& points, int& count);
149 PointPlotter<sound_sample> fc_plotter();
151 protected:
152 void set_w0();
153 void set_Q();
155 // Filter enabled.
156 bool enabled;
158 // Filter cutoff frequency.
159 reg12 fc;
161 // Filter resonance.
162 reg8 res;
164 // Selects which inputs to route through filter.
165 reg8 filt;
167 // Switch voice 3 off.
168 reg8 voice3off;
170 // Highpass, bandpass, and lowpass filter modes.
171 reg8 hp_bp_lp;
173 // Output master volume.
174 reg4 vol;
176 // Mixer DC offset.
177 sound_sample mixer_DC;
179 // State of filter.
180 sound_sample Vhp; // highpass
181 sound_sample Vbp; // bandpass
182 sound_sample Vlp; // lowpass
183 sound_sample Vnf; // not filtered
185 // Cutoff frequency, resonance.
186 sound_sample w0, w0_ceil_1, w0_ceil_dt;
187 sound_sample _1024_div_Q;
189 // Cutoff frequency tables.
190 // FC is an 11 bit register.
191 sound_sample f0_6581[2048];
192 sound_sample f0_8580[2048];
193 sound_sample* f0;
194 static fc_point f0_points_6581[];
195 static fc_point f0_points_8580[];
196 fc_point* f0_points;
197 int f0_count;
199 friend class cSID;
203 // ----------------------------------------------------------------------------
204 // Inline functions.
205 // The following functions are defined inline because they are called every
206 // time a sample is calculated.
207 // ----------------------------------------------------------------------------
209 #if RESID_INLINING || defined(__FILTER_CC__)
211 // ----------------------------------------------------------------------------
212 // SID clocking - 1 cycle.
213 // ----------------------------------------------------------------------------
214 RESID_INLINE
215 void Filter::clock(sound_sample voice1,
216 sound_sample voice2,
217 sound_sample voice3,
218 sound_sample ext_in)
220 // Scale each voice down from 20 to 13 bits.
221 voice1 >>= 7;
222 voice2 >>= 7;
224 // NB! Voice 3 is not silenced by voice3off if it is routed through
225 // the filter.
226 if (voice3off && !(filt & 0x04)) {
227 voice3 = 0;
229 else {
230 voice3 >>= 7;
233 ext_in >>= 7;
235 // This is handy for testing.
236 if (!enabled) {
237 Vnf = voice1 + voice2 + voice3 + ext_in;
238 Vhp = Vbp = Vlp = 0;
239 return;
242 // Route voices into or around filter.
243 // The code below is expanded to a switch for faster execution.
244 // (filt1 ? Vi : Vnf) += voice1;
245 // (filt2 ? Vi : Vnf) += voice2;
246 // (filt3 ? Vi : Vnf) += voice3;
248 sound_sample Vi;
250 switch (filt) {
251 default:
252 case 0x0:
253 Vi = 0;
254 Vnf = voice1 + voice2 + voice3 + ext_in;
255 break;
256 case 0x1:
257 Vi = voice1;
258 Vnf = voice2 + voice3 + ext_in;
259 break;
260 case 0x2:
261 Vi = voice2;
262 Vnf = voice1 + voice3 + ext_in;
263 break;
264 case 0x3:
265 Vi = voice1 + voice2;
266 Vnf = voice3 + ext_in;
267 break;
268 case 0x4:
269 Vi = voice3;
270 Vnf = voice1 + voice2 + ext_in;
271 break;
272 case 0x5:
273 Vi = voice1 + voice3;
274 Vnf = voice2 + ext_in;
275 break;
276 case 0x6:
277 Vi = voice2 + voice3;
278 Vnf = voice1 + ext_in;
279 break;
280 case 0x7:
281 Vi = voice1 + voice2 + voice3;
282 Vnf = ext_in;
283 break;
284 case 0x8:
285 Vi = ext_in;
286 Vnf = voice1 + voice2 + voice3;
287 break;
288 case 0x9:
289 Vi = voice1 + ext_in;
290 Vnf = voice2 + voice3;
291 break;
292 case 0xa:
293 Vi = voice2 + ext_in;
294 Vnf = voice1 + voice3;
295 break;
296 case 0xb:
297 Vi = voice1 + voice2 + ext_in;
298 Vnf = voice3;
299 break;
300 case 0xc:
301 Vi = voice3 + ext_in;
302 Vnf = voice1 + voice2;
303 break;
304 case 0xd:
305 Vi = voice1 + voice3 + ext_in;
306 Vnf = voice2;
307 break;
308 case 0xe:
309 Vi = voice2 + voice3 + ext_in;
310 Vnf = voice1;
311 break;
312 case 0xf:
313 Vi = voice1 + voice2 + voice3 + ext_in;
314 Vnf = 0;
315 break;
318 // delta_t = 1 is converted to seconds given a 1MHz clock by dividing
319 // with 1 000 000.
321 // Calculate filter outputs.
322 // Vhp = Vbp/Q - Vlp - Vi;
323 // dVbp = -w0*Vhp*dt;
324 // dVlp = -w0*Vbp*dt;
326 sound_sample dVbp = (w0_ceil_1*Vhp >> 20);
327 sound_sample dVlp = (w0_ceil_1*Vbp >> 20);
328 Vbp -= dVbp;
329 Vlp -= dVlp;
330 Vhp = (Vbp*_1024_div_Q >> 10) - Vlp - Vi;
333 // ----------------------------------------------------------------------------
334 // SID clocking - delta_t cycles.
335 // ----------------------------------------------------------------------------
336 RESID_INLINE
337 void Filter::clock(cycle_count delta_t,
338 sound_sample voice1,
339 sound_sample voice2,
340 sound_sample voice3,
341 sound_sample ext_in)
343 // Scale each voice down from 20 to 13 bits.
344 voice1 >>= 7;
345 voice2 >>= 7;
347 // NB! Voice 3 is not silenced by voice3off if it is routed through
348 // the filter.
349 if (voice3off && !(filt & 0x04)) {
350 voice3 = 0;
352 else {
353 voice3 >>= 7;
356 ext_in >>= 7;
358 // Enable filter on/off.
359 // This is not really part of SID, but is useful for testing.
360 // On slow CPUs it may be necessary to bypass the filter to lower the CPU
361 // load.
362 if (!enabled) {
363 Vnf = voice1 + voice2 + voice3 + ext_in;
364 Vhp = Vbp = Vlp = 0;
365 return;
368 // Route voices into or around filter.
369 // The code below is expanded to a switch for faster execution.
370 // (filt1 ? Vi : Vnf) += voice1;
371 // (filt2 ? Vi : Vnf) += voice2;
372 // (filt3 ? Vi : Vnf) += voice3;
374 sound_sample Vi;
376 switch (filt) {
377 default:
378 case 0x0:
379 Vi = 0;
380 Vnf = voice1 + voice2 + voice3 + ext_in;
381 break;
382 case 0x1:
383 Vi = voice1;
384 Vnf = voice2 + voice3 + ext_in;
385 break;
386 case 0x2:
387 Vi = voice2;
388 Vnf = voice1 + voice3 + ext_in;
389 break;
390 case 0x3:
391 Vi = voice1 + voice2;
392 Vnf = voice3 + ext_in;
393 break;
394 case 0x4:
395 Vi = voice3;
396 Vnf = voice1 + voice2 + ext_in;
397 break;
398 case 0x5:
399 Vi = voice1 + voice3;
400 Vnf = voice2 + ext_in;
401 break;
402 case 0x6:
403 Vi = voice2 + voice3;
404 Vnf = voice1 + ext_in;
405 break;
406 case 0x7:
407 Vi = voice1 + voice2 + voice3;
408 Vnf = ext_in;
409 break;
410 case 0x8:
411 Vi = ext_in;
412 Vnf = voice1 + voice2 + voice3;
413 break;
414 case 0x9:
415 Vi = voice1 + ext_in;
416 Vnf = voice2 + voice3;
417 break;
418 case 0xa:
419 Vi = voice2 + ext_in;
420 Vnf = voice1 + voice3;
421 break;
422 case 0xb:
423 Vi = voice1 + voice2 + ext_in;
424 Vnf = voice3;
425 break;
426 case 0xc:
427 Vi = voice3 + ext_in;
428 Vnf = voice1 + voice2;
429 break;
430 case 0xd:
431 Vi = voice1 + voice3 + ext_in;
432 Vnf = voice2;
433 break;
434 case 0xe:
435 Vi = voice2 + voice3 + ext_in;
436 Vnf = voice1;
437 break;
438 case 0xf:
439 Vi = voice1 + voice2 + voice3 + ext_in;
440 Vnf = 0;
441 break;
444 // Maximum delta cycles for the filter to work satisfactorily under current
445 // cutoff frequency and resonance constraints is approximately 8.
446 cycle_count delta_t_flt = 8;
448 while (delta_t) {
449 if (delta_t < delta_t_flt) {
450 delta_t_flt = delta_t;
453 // delta_t is converted to seconds given a 1MHz clock by dividing
454 // with 1 000 000. This is done in two operations to avoid integer
455 // multiplication overflow.
457 // Calculate filter outputs.
458 // Vhp = Vbp/Q - Vlp - Vi;
459 // dVbp = -w0*Vhp*dt;
460 // dVlp = -w0*Vbp*dt;
461 sound_sample w0_delta_t = w0_ceil_dt*delta_t_flt >> 6;
463 sound_sample dVbp = (w0_delta_t*Vhp >> 14);
464 sound_sample dVlp = (w0_delta_t*Vbp >> 14);
465 Vbp -= dVbp;
466 Vlp -= dVlp;
467 Vhp = (Vbp*_1024_div_Q >> 10) - Vlp - Vi;
469 delta_t -= delta_t_flt;
474 // ----------------------------------------------------------------------------
475 // SID audio output (20 bits).
476 // ----------------------------------------------------------------------------
477 RESID_INLINE
478 sound_sample Filter::output()
480 // This is handy for testing.
481 if (!enabled) {
482 return (Vnf + mixer_DC)*static_cast<sound_sample>(vol);
485 // Mix highpass, bandpass, and lowpass outputs. The sum is not
486 // weighted, this can be confirmed by sampling sound output for
487 // e.g. bandpass, lowpass, and bandpass+lowpass from a SID chip.
489 // The code below is expanded to a switch for faster execution.
490 // if (hp) Vf += Vhp;
491 // if (bp) Vf += Vbp;
492 // if (lp) Vf += Vlp;
494 sound_sample Vf;
496 switch (hp_bp_lp) {
497 default:
498 case 0x0:
499 Vf = 0;
500 break;
501 case 0x1:
502 Vf = Vlp;
503 break;
504 case 0x2:
505 Vf = Vbp;
506 break;
507 case 0x3:
508 Vf = Vlp + Vbp;
509 break;
510 case 0x4:
511 Vf = Vhp;
512 break;
513 case 0x5:
514 Vf = Vlp + Vhp;
515 break;
516 case 0x6:
517 Vf = Vbp + Vhp;
518 break;
519 case 0x7:
520 Vf = Vlp + Vbp + Vhp;
521 break;
524 // Sum non-filtered and filtered output.
525 // Multiply the sum with volume.
526 return (Vnf + Vf + mixer_DC)*static_cast<sound_sample>(vol);
529 #endif // RESID_INLINING || defined(__FILTER_CC__)
531 #endif // not __FILTER_H__