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