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.
14 //
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 //  ---------------------------------------------------------------------------
19 //  Filter distortion code written by Antti S. Lankila 2007 - 2009.
20 
21 #include "filterfp.h"
22 #include "sidfp.h"
23 
24 // ----------------------------------------------------------------------------
25 // Constructor.
26 // ----------------------------------------------------------------------------
FilterFP()27 FilterFP::FilterFP()
28 {
29   model = (chip_model) 0; // neither 6581/8580; init time only
30   enable_filter(true);
31   /* approximate; sid.cc calls us when set_sampling_parameters() occurs. */
32   set_clock_frequency(1e6f);
33   /* these parameters are a work-in-progress. */
34   set_distortion_properties(0.5f, 3.3e6f, 3.0e-4f);
35   /* sound similar to alankila6581r4ar3789 */
36   set_type3_properties(1299501.5675945764f, 284015710.29875594f, 1.0065089724604026f, 18741.324073610594f);
37   /* sound similar to trurl8580r5_3691 */
38   set_type4_properties(6.55f, 20.f);
39   reset();
40   set_chip_model(MOS6581);
41 }
42 
43 
44 // ----------------------------------------------------------------------------
45 // Enable filter.
46 // ----------------------------------------------------------------------------
enable_filter(bool enable)47 void FilterFP::enable_filter(bool enable)
48 {
49   enabled = enable;
50   if (! enabled)
51     filt = 0; // XXX should also restore this...
52 }
53 
54 // ----------------------------------------------------------------------------
55 // Set chip model.
56 // ----------------------------------------------------------------------------
set_chip_model(chip_model model)57 void FilterFP::set_chip_model(chip_model model)
58 {
59     this->model = model;
60     set_Q();
61     set_w0();
62 }
63 
set_nonlinearity(float nl)64 void FilterFP::set_nonlinearity(float nl)
65 {
66     nonlinearity = nl;
67     set_w0();
68 }
69 
70 /* dist_CT eliminates 1/x at hot spot */
set_clock_frequency(float clock)71 void FilterFP::set_clock_frequency(float clock) {
72     clock_frequency = clock;
73     distortion_CT = 1.f / (sidcaps_6581 * clock_frequency);
74     set_w0();
75 }
76 
set_distortion_properties(float a,float nl,float il)77 void FilterFP::set_distortion_properties(float a, float nl, float il)
78 {
79     attenuation = a;
80     distortion_nonlinearity = nl;
81     intermixing_leaks = il;
82     set_w0();
83 }
84 
set_type4_properties(float k,float b)85 void FilterFP::set_type4_properties(float k, float b)
86 {
87     type4_k = k;
88     type4_b = b;
89     set_w0();
90 }
91 
set_type3_properties(float br,float o,float s,float mfr)92 void FilterFP::set_type3_properties(float br, float o, float s, float mfr)
93 {
94     type3_baseresistance = br;
95     type3_offset = o;
96     type3_steepness = -logf(s) / FC_TO_OSC; /* s^x to e^(x*ln(s)), 1/e^x == e^-x. */
97     type3_minimumfetresistance = mfr;
98     set_w0();
99 }
100 
101 // ----------------------------------------------------------------------------
102 // SID reset.
103 // ----------------------------------------------------------------------------
reset()104 void FilterFP::reset()
105 {
106   fc = 0;
107   res = filt = voice3off = hp_bp_lp = 0;
108   vol = 0;
109   volf = Vhp = Vbp = Vlp = 0;
110   type3_fc_kink_exp = 0;
111   type4_w0_cache = 0;
112   set_w0();
113   set_Q();
114 }
115 
116 // ----------------------------------------------------------------------------
117 // Register functions.
118 // ----------------------------------------------------------------------------
writeFC_LO(reg8 fc_lo)119 void FilterFP::writeFC_LO(reg8 fc_lo)
120 {
121   fc = (fc & 0x7f8) | (fc_lo & 0x007);
122   set_w0();
123 }
124 
writeFC_HI(reg8 fc_hi)125 void FilterFP::writeFC_HI(reg8 fc_hi)
126 {
127   fc = ((fc_hi << 3) & 0x7f8) | (fc & 0x007);
128   set_w0();
129 }
130 
writeRES_FILT(reg8 res_filt)131 void FilterFP::writeRES_FILT(reg8 res_filt)
132 {
133   res = (res_filt >> 4) & 0x0f;
134   set_Q();
135   filt = enabled ? res_filt & 0x0f : 0;
136 }
137 
writeMODE_VOL(reg8 mode_vol)138 void FilterFP::writeMODE_VOL(reg8 mode_vol)
139 {
140   voice3off = mode_vol & 0x80;
141 
142   hp_bp_lp = mode_vol >> 4;
143 
144   vol = mode_vol & 0x0f;
145   volf = static_cast<float>(vol) / 15.f;
146 }
147 
148 // Set filter cutoff frequency.
set_w0()149 void FilterFP::set_w0()
150 {
151   if (model == MOS6581) {
152     float type3_fc_kink = SIDFP::kinked_dac(fc, nonlinearity, 11);
153     type3_fc_kink_exp = type3_offset * expf(type3_fc_kink * type3_steepness * FC_TO_OSC);
154   }
155   if (model == MOS8580) {
156     type4_w0_cache = type4_w0();
157   }
158 }
159 
160 // Set filter resonance.
set_Q()161 void FilterFP::set_Q()
162 {
163   if (model == MOS6581) {
164     _1_div_Q = 1.f / (0.5f + res / 20.f);
165   } else {
166     _1_div_Q = 1.f / (0.707f + res / 15.f);
167   }
168 }
169