1 // ---------------------------------------------------------------------------
2 // This file is part of reSID, a MOS6581 SID emulator engine.
3 // Copyright (C) 2004 Dag Lem <resid@nimrod.no>
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.
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 // ---------------------------------------------------------------------------
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
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.
61 // -----------------------------------------------
65 // | ------------<A]-----R1--------- |
67 // | | ---C---| ---C---|
69 // | --R1-- ---R1-- |---Rs--| |---Rs--|
71 // ----R1--|-----[A>--|--R-----[A>--|--R-----[A>--|
79 // vhp - highpass output
80 // vbp - bandpass output
81 // vlp - lowpass output
83 // R1 - summer resistor
84 // Rq - resistor array controlling resonance (4 resistors)
85 // R - NMOS FET voltage controlled resistor controlling cutoff frequency
104 // |---Rs-----------|---- vo
107 // vi ---- -----|------------||
120 // ----------------------------------------------------------------------------
126 void enable_filter(bool enable
);
127 void set_chip_model(chip_model model
);
130 void clock(sound_sample voice1
, sound_sample voice2
, sound_sample voice3
,
131 sound_sample ext_in
);
133 void clock(cycle_count delta_t
,
134 sound_sample voice1
, sound_sample voice2
, sound_sample voice3
,
135 sound_sample ext_in
);
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();
148 void fc_default(const fc_point
*& points
, int& count
);
149 PointPlotter
<sound_sample
> fc_plotter();
158 // Filter cutoff frequency.
164 // Selects which inputs to route through filter.
167 // Switch voice 3 off.
170 // Highpass, bandpass, and lowpass filter modes.
173 // Output master volume.
177 sound_sample mixer_DC
;
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];
194 static fc_point f0_points_6581
[];
195 static fc_point f0_points_8580
[];
203 // ----------------------------------------------------------------------------
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 // ----------------------------------------------------------------------------
215 void Filter::clock(sound_sample voice1
,
220 // Scale each voice down from 20 to 13 bits.
224 // NB! Voice 3 is not silenced by voice3off if it is routed through
226 if (voice3off
&& !(filt
& 0x04)) {
235 // This is handy for testing.
237 Vnf
= voice1
+ voice2
+ voice3
+ ext_in
;
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;
254 Vnf
= voice1
+ voice2
+ voice3
+ ext_in
;
258 Vnf
= voice2
+ voice3
+ ext_in
;
262 Vnf
= voice1
+ voice3
+ ext_in
;
265 Vi
= voice1
+ voice2
;
266 Vnf
= voice3
+ ext_in
;
270 Vnf
= voice1
+ voice2
+ ext_in
;
273 Vi
= voice1
+ voice3
;
274 Vnf
= voice2
+ ext_in
;
277 Vi
= voice2
+ voice3
;
278 Vnf
= voice1
+ ext_in
;
281 Vi
= voice1
+ voice2
+ voice3
;
286 Vnf
= voice1
+ voice2
+ voice3
;
289 Vi
= voice1
+ ext_in
;
290 Vnf
= voice2
+ voice3
;
293 Vi
= voice2
+ ext_in
;
294 Vnf
= voice1
+ voice3
;
297 Vi
= voice1
+ voice2
+ ext_in
;
301 Vi
= voice3
+ ext_in
;
302 Vnf
= voice1
+ voice2
;
305 Vi
= voice1
+ voice3
+ ext_in
;
309 Vi
= voice2
+ voice3
+ ext_in
;
313 Vi
= voice1
+ voice2
+ voice3
+ ext_in
;
318 // delta_t = 1 is converted to seconds given a 1MHz clock by dividing
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);
330 Vhp
= (Vbp
*_1024_div_Q
>> 10) - Vlp
- Vi
;
333 // ----------------------------------------------------------------------------
334 // SID clocking - delta_t cycles.
335 // ----------------------------------------------------------------------------
337 void Filter::clock(cycle_count delta_t
,
343 // Scale each voice down from 20 to 13 bits.
347 // NB! Voice 3 is not silenced by voice3off if it is routed through
349 if (voice3off
&& !(filt
& 0x04)) {
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
363 Vnf
= voice1
+ voice2
+ voice3
+ ext_in
;
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;
380 Vnf
= voice1
+ voice2
+ voice3
+ ext_in
;
384 Vnf
= voice2
+ voice3
+ ext_in
;
388 Vnf
= voice1
+ voice3
+ ext_in
;
391 Vi
= voice1
+ voice2
;
392 Vnf
= voice3
+ ext_in
;
396 Vnf
= voice1
+ voice2
+ ext_in
;
399 Vi
= voice1
+ voice3
;
400 Vnf
= voice2
+ ext_in
;
403 Vi
= voice2
+ voice3
;
404 Vnf
= voice1
+ ext_in
;
407 Vi
= voice1
+ voice2
+ voice3
;
412 Vnf
= voice1
+ voice2
+ voice3
;
415 Vi
= voice1
+ ext_in
;
416 Vnf
= voice2
+ voice3
;
419 Vi
= voice2
+ ext_in
;
420 Vnf
= voice1
+ voice3
;
423 Vi
= voice1
+ voice2
+ ext_in
;
427 Vi
= voice3
+ ext_in
;
428 Vnf
= voice1
+ voice2
;
431 Vi
= voice1
+ voice3
+ ext_in
;
435 Vi
= voice2
+ voice3
+ ext_in
;
439 Vi
= voice1
+ voice2
+ voice3
+ ext_in
;
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;
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);
467 Vhp
= (Vbp
*_1024_div_Q
>> 10) - Vlp
- Vi
;
469 delta_t
-= delta_t_flt
;
474 // ----------------------------------------------------------------------------
475 // SID audio output (20 bits).
476 // ----------------------------------------------------------------------------
478 sound_sample
Filter::output()
480 // This is handy for testing.
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;
520 Vf
= Vlp
+ Vbp
+ Vhp
;
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__