libresidfp 0.9.1
FilterModelConfig.h
1/*
2 * This file is part of libsidplayfp, a SID player engine.
3 *
4 * Copyright 2011-2024 Leandro Nini <drfiemost@users.sourceforge.net>
5 * Copyright 2007-2010 Antti Lankila
6 * Copyright 2004,2010 Dag Lem
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21 */
22
23#ifndef FILTERMODELCONFIG_H
24#define FILTERMODELCONFIG_H
25
26#include <algorithm>
27#include <random>
28#include <cassert>
29#include <climits>
30
31#include "OpAmp.h"
32#include "Spline.h"
33
34#include "siddefs-fp.h"
35
36namespace reSIDfp
37{
38
40{
41public:
42 // The highpass summer has 2 - 6 inputs (bandpass, lowpass, and 0 - 4 voices).
43 template<int i>
45 {
46 static constexpr int value = summer_offset<i - 1>::value + ((2 + i - 1) << 16);
47 };
48
49 // The mixer has 0 - 7 inputs (0 - 4 voices and 0 - 3 filter outputs).
50 template<int i>
52 {
53 static constexpr int value = mixer_offset<i - 1>::value + ((i - 1) << 16);
54 };
55
56protected:
57 static inline unsigned short to_ushort_dither(double x, double d_noise)
58 {
59 const int tmp = static_cast<int>(x + d_noise);
60 assert((tmp >= 0) && (tmp <= USHRT_MAX));
61 return static_cast<unsigned short>(tmp);
62 }
63
64 static inline unsigned short to_ushort(double x)
65 {
66 return to_ushort_dither(x, 0.5);
67 }
68
69private:
70 /*
71 * Hack to add quick dither when converting values from float to int
72 * and avoid quantization noise.
73 * Hopefully this can be removed the day we move all the analog part
74 * processing to floats.
75 *
76 * Not sure about the effect of using such small buffer of numbers
77 * since the random sequence repeats every 1024 values but for
78 * now it seems to do the job.
79 */
80 class Randomnoise
81 {
82 private:
83 double buffer[1024];
84 mutable int index = 0;
85 public:
86 Randomnoise()
87 {
88 std::uniform_real_distribution<double> unif(0., 1.);
89 std::default_random_engine re;
90 for (int i=0; i<1024; i++)
91 buffer[i] = unif(re);
92 }
93 double getNoise() const { index = (index + 1) & 0x3ff; return buffer[index]; }
94 };
95
96protected:
98 const double C;
99
101
102
103 static constexpr double k = 1.380649e-23; // Boltzmann Constant
104 static constexpr double q = 1.602176634e-19; // charge of an electron
105 static constexpr double temp = 27; // temperature in °C
106 static constexpr double Ut = (k * (temp + 273.15)) / q;
107
108 const double Vdd;
109 const double Vth;
110 const double Vddt;
111 double uCox;
113
114 // Derived stuff
115 const double vmin, vmax;
116 const double denorm, norm;
117
119 const double N16;
120
121 const double voice_voltage_range;
122
125
127
128 unsigned short* mixer; //-V730_NOINIT this is initialized in the derived class constructor
129 unsigned short* summer; //-V730_NOINIT this is initialized in the derived class constructor
130 unsigned short* volume; //-V730_NOINIT this is initialized in the derived class constructor
131 unsigned short* resonance; //-V730_NOINIT this is initialized in the derived class constructor
133
135 unsigned short opamp_rev[1 << 16]; //-V730_NOINIT this is initialized in the derived class constructor
136
137private:
138 Randomnoise rnd;
139
140private:
141 FilterModelConfig(const FilterModelConfig&) = delete;
142 FilterModelConfig& operator= (const FilterModelConfig&) = delete;
143
144 inline double getVoiceVoltage(float value, unsigned int env) const
145 {
146 return value * voice_voltage_range + getVoiceDC(env);
147 }
148
149protected:
160 double vvr,
161 double c,
162 double vdd,
163 double vth,
164 double ucox,
165 const Spline::Point *opamp_voltage,
166 int opamp_size
167 );
168
170
171 void setUCox(double new_uCox);
172
173 virtual double getVoiceDC(unsigned int env) const = 0;
174
184 inline void buildSummerTable(const OpAmp& opampModel)
185 {
186 const double r_N16 = 1. / N16;
187
188 int idx = 0;
189 for (int i = 0; i < 5; i++)
190 {
191 const int idiv = 2 + i; // 2 - 6 input "resistors".
192 const int size = idiv << 16;
193 const double n = idiv;
194 const double r_idiv = 1. / idiv;
195 opampModel.reset();
196
197 for (int vi = 0; vi < size; vi++)
198 {
199 const double vin = vmin + vi * r_N16 * r_idiv; /* vmin .. vmax */
200 summer[idx++] = getNormalizedValue(opampModel.solve(n, vin));
201 }
202 }
203 }
204
213 inline void buildMixerTable(const OpAmp& opampModel, double nRatio)
214 {
215 const double r_N16 = 1. / N16;
216
217 int idx = 0;
218 for (int i = 0; i < 8; i++)
219 {
220 const int idiv = (i == 0) ? 1 : i;
221 const int size = (i == 0) ? 1 : i << 16;
222 const double n = i * nRatio;
223 const double r_idiv = 1. / idiv;
224 opampModel.reset();
225
226 for (int vi = 0; vi < size; vi++)
227 {
228 const double vin = vmin + vi * r_N16 * r_idiv; /* vmin .. vmax */
229 mixer[idx++] = getNormalizedValue(opampModel.solve(n, vin));
230 }
231 }
232 }
233
241 inline void buildVolumeTable(const OpAmp& opampModel, double nDivisor)
242 {
243 const double r_N16 = 1. / N16;
244
245 int idx = 0;
246 for (int n8 = 0; n8 < 16; n8++)
247 {
248 constexpr int size = 1 << 16;
249 const double n = n8 / nDivisor;
250 opampModel.reset();
251
252 for (int vi = 0; vi < size; vi++)
253 {
254 const double vin = vmin + vi * r_N16; /* vmin .. vmax */
255 volume[idx++] = getNormalizedValue(opampModel.solve(n, vin));
256 }
257 }
258 }
259
267 inline void buildResonanceTable(const OpAmp& opampModel, const double resonance_n[16])
268 {
269 const double r_N16 = 1. / N16;
270
271 int idx = 0;
272 for (int n8 = 0; n8 < 16; n8++)
273 {
274 constexpr int size = 1 << 16;
275 opampModel.reset();
276
277 for (int vi = 0; vi < size; vi++)
278 {
279 const double vin = vmin + vi * r_N16; /* vmin .. vmax */
280 resonance[idx++] = getNormalizedValue(opampModel.solve(resonance_n[n8], vin));
281 }
282 }
283 }
284
285public:
286 unsigned short* getVolume() { return volume; }
287 unsigned short* getResonance() { return resonance; }
288 unsigned short* getSummer() { return summer; }
289 unsigned short* getMixer() { return mixer; }
290
291 inline unsigned short getOpampRev(int i) const { return opamp_rev[i]; }
292 inline double getVddt() const { return Vddt; }
293 inline double getVth() const { return Vth; }
294
295 // helper functions
296
297 inline unsigned short getNormalizedValue(double value) const
298 {
299 return to_ushort_dither(N16 * (value - vmin), rnd.getNoise());
300 }
301
302 template<int N>
303 inline unsigned short getNormalizedCurrentFactor(double wl) const
304 {
305 return to_ushort((1 << N) * currFactorCoeff * wl);
306 }
307
308 inline unsigned short getNVmin() const
309 {
310 return to_ushort(N16 * vmin);
311 }
312
313 inline int getNormalizedVoice(float value, unsigned int env) const
314 {
315 return static_cast<int>(getNormalizedValue(getVoiceVoltage(value, env)));
316 }
317};
318
319template<>
321{
322 static constexpr int value = 0;
323};
324
325template<>
327{
328 static constexpr int value = 1;
329};
330
331template<>
333{
334 static constexpr int value = 0;
335};
336
337} // namespace reSIDfp
338
339#endif
Definition FilterModelConfig.h:40
void buildVolumeTable(const OpAmp &opampModel, double nDivisor)
Definition FilterModelConfig.h:241
const double Vdd
Positive supply voltage.
Definition FilterModelConfig.h:108
void buildResonanceTable(const OpAmp &opampModel, const double resonance_n[16])
Definition FilterModelConfig.h:267
unsigned short * mixer
Lookup tables for gain and summer op-amps in output stage / filter.
Definition FilterModelConfig.h:128
double uCox
Transconductance coefficient: u*Cox.
Definition FilterModelConfig.h:111
const double Vddt
Vdd - Vth.
Definition FilterModelConfig.h:110
static constexpr double k
Transistor parameters.
Definition FilterModelConfig.h:103
double currFactorCoeff
Current factor coefficient for op-amp integrators.
Definition FilterModelConfig.h:124
const double C
Capacitor value.
Definition FilterModelConfig.h:98
unsigned short opamp_rev[1<< 16]
Reverse op-amp transfer function.
Definition FilterModelConfig.h:135
const double Vth
Threshold voltage.
Definition FilterModelConfig.h:109
void buildMixerTable(const OpAmp &opampModel, double nRatio)
Definition FilterModelConfig.h:213
const double N16
Fixed point scaling for 16 bit op-amp output.
Definition FilterModelConfig.h:119
void buildSummerTable(const OpAmp &opampModel)
Definition FilterModelConfig.h:184
Definition OpAmp.h:71
double solve(double n, double vi) const
Definition OpAmp.cpp:33
void reset() const
Definition OpAmp.h:102
Definition FilterModelConfig.h:52
Definition FilterModelConfig.h:45