libresidfp  1.2.3
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 
36 namespace reSIDfp
37 {
38 
40 {
41 public:
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>
51  struct mixer_offset
52  {
53  static constexpr int value = mixer_offset<i - 1>::value + ((i - 1) << 16);
54  };
55 
56 protected:
57  static inline uint16_t to_uint16_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<uint16_t>(tmp);
62  }
63 
64  static inline uint16_t to_uint16(double x)
65  {
66  return to_uint16_dither(x, 0.5);
67  }
68 
69 private:
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 
96 protected:
98  const double C;
99 
101 
102  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;
112 
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  uint16_t* mixer; //-V730_NOINIT this is initialized in the derived class constructor
129  uint16_t* summer; //-V730_NOINIT this is initialized in the derived class constructor
130  uint16_t* volume; //-V730_NOINIT this is initialized in the derived class constructor
131  uint16_t* resonance; //-V730_NOINIT this is initialized in the derived class constructor
133 
135  uint16_t opamp_rev[1 << 16]; //-V730_NOINIT this is initialized in the derived class constructor
136 
137 private:
138  Randomnoise rnd;
139 
140 private:
141  FilterModelConfig(const FilterModelConfig&) = delete;
142  FilterModelConfig& operator= (const FilterModelConfig&) = delete;
143 
144  inline double getVoiceVoltage(float value, uint8_t env) const
145  {
146  return value * voice_voltage_range + getVoiceDC(env);
147  }
148 
149 protected:
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 calcCurrFactorCoeff();
172 
173  virtual double getVoiceDC(uint8_t 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 
285 public:
286  uint16_t* getVolume() const { return volume; }
287  uint16_t* getResonance() const { return resonance; }
288  uint16_t* getSummer() const { return summer; }
289  uint16_t* getMixer() const { return mixer; }
290 
291  inline uint16_t 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 uint16_t getNormalizedValue(double value) const
298  {
299  return to_uint16_dither(N16 * (value - vmin), rnd.getNoise());
300  }
301 
302  template<int N>
303  inline uint16_t getNormalizedCurrentFactor(double wl) const
304  {
305  return to_uint16((1 << N) * currFactorCoeff * wl);
306  }
307 
308  inline uint16_t getNVmin() const
309  {
310  return to_uint16(N16 * vmin);
311  }
312 
313  inline int32_t getNormalizedVoice(float value, uint8_t env) const
314  {
315  return static_cast<int32_t>(getNormalizedValue(getVoiceVoltage(value, env)));
316  }
317 };
318 
319 template<>
321 {
322  static constexpr int value = 0;
323 };
324 
325 template<>
327 {
328  static constexpr int value = 1;
329 };
330 
331 template<>
333 {
334  static constexpr int value = 0;
335 };
336 
337 } // namespace reSIDfp
338 
339 #endif
uint16_t * resonance
Lookup tables for gain and summer op-amps in output stage / filter.
Definition: FilterModelConfig.h:131
uint16_t * volume
Lookup tables for gain and summer op-amps in output stage / filter.
Definition: FilterModelConfig.h:130
static constexpr double k
Transistor parameters.
Definition: FilterModelConfig.h:103
double uCox
Transconductance coefficient: u*Cox.
Definition: FilterModelConfig.h:111
const double N16
Fixed point scaling for 16 bit op-amp output.
Definition: FilterModelConfig.h:119
static constexpr double q
Positive supply voltage.
Definition: FilterModelConfig.h:104
double currFactorCoeff
Current factor coefficient for op-amp integrators.
Definition: FilterModelConfig.h:124
void buildVolumeTable(const OpAmp &opampModel, double nDivisor)
Definition: FilterModelConfig.h:241
Definition: Dac.cpp:27
void reset() const
Definition: OpAmp.h:102
void buildResonanceTable(const OpAmp &opampModel, const double resonance_n[16])
Definition: FilterModelConfig.h:267
void buildMixerTable(const OpAmp &opampModel, double nRatio)
Definition: FilterModelConfig.h:213
Definition: FilterModelConfig.h:51
static constexpr double temp
Positive supply voltage.
Definition: FilterModelConfig.h:105
static constexpr double Ut
Positive supply voltage.
Definition: FilterModelConfig.h:106
uint16_t * summer
Lookup tables for gain and summer op-amps in output stage / filter.
Definition: FilterModelConfig.h:129
Definition: FilterModelConfig.h:39
const double Vdd
Positive supply voltage.
Definition: FilterModelConfig.h:108
Definition: FilterModelConfig.h:44
const double C
Capacitor value.
Definition: FilterModelConfig.h:98
void buildSummerTable(const OpAmp &opampModel)
Definition: FilterModelConfig.h:184
double solve(double n, double vi) const
Definition: OpAmp.cpp:33
Definition: OpAmp.h:70
uint16_t opamp_rev[1<< 16]
Reverse op-amp transfer function.
Definition: FilterModelConfig.h:135
const double Vth
Threshold voltage.
Definition: FilterModelConfig.h:109
const double Vddt
Vdd - Vth.
Definition: FilterModelConfig.h:110
uint16_t * mixer
Lookup tables for gain and summer op-amps in output stage / filter.
Definition: FilterModelConfig.h:128