libsidplayfp  2.15.0
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 "sidcxx11.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 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 
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 Ut = 26.0e-3;
104 
105  const double Vdd;
106  const double Vth;
107  const double Vddt;
108  double uCox;
110 
111  // Derived stuff
112  const double vmin, vmax;
113  const double denorm, norm;
114 
116  const double N16;
117 
118  const double voice_voltage_range;
119 
122 
124 
125  unsigned short* mixer; //-V730_NOINIT this is initialized in the derived class constructor
126  unsigned short* summer; //-V730_NOINIT this is initialized in the derived class constructor
127  unsigned short* volume; //-V730_NOINIT this is initialized in the derived class constructor
128  unsigned short* resonance; //-V730_NOINIT this is initialized in the derived class constructor
130 
132  unsigned short opamp_rev[1 << 16]; //-V730_NOINIT this is initialized in the derived class constructor
133 
134 private:
135  Randomnoise rnd;
136 
137 private:
138  FilterModelConfig(const FilterModelConfig&) = delete;
139  FilterModelConfig& operator= (const FilterModelConfig&) = delete;
140 
141  inline double getVoiceVoltage(float value, unsigned int env) const
142  {
143  return value * voice_voltage_range + getVoiceDC(env);
144  }
145 
146 protected:
157  double vvr,
158  double c,
159  double vdd,
160  double vth,
161  double ucox,
162  const Spline::Point *opamp_voltage,
163  int opamp_size
164  );
165 
167 
168  void setUCox(double new_uCox);
169 
170  virtual double getVoiceDC(unsigned int env) const = 0;
171 
181  inline void buildSummerTable(const OpAmp& opampModel)
182  {
183  const double r_N16 = 1. / N16;
184 
185  int idx = 0;
186  for (int i = 0; i < 5; i++)
187  {
188  const int idiv = 2 + i; // 2 - 6 input "resistors".
189  const int size = idiv << 16;
190  const double n = idiv;
191  const double r_idiv = 1. / idiv;
192  opampModel.reset();
193 
194  for (int vi = 0; vi < size; vi++)
195  {
196  const double vin = vmin + vi * r_N16 * r_idiv; /* vmin .. vmax */
197  summer[idx++] = getNormalizedValue(opampModel.solve(n, vin));
198  }
199  }
200  }
201 
210  inline void buildMixerTable(const OpAmp& opampModel, double nRatio)
211  {
212  const double r_N16 = 1. / N16;
213 
214  int idx = 0;
215  for (int i = 0; i < 8; i++)
216  {
217  const int idiv = (i == 0) ? 1 : i;
218  const int size = (i == 0) ? 1 : i << 16;
219  const double n = i * nRatio;
220  const double r_idiv = 1. / idiv;
221  opampModel.reset();
222 
223  for (int vi = 0; vi < size; vi++)
224  {
225  const double vin = vmin + vi * r_N16 * r_idiv; /* vmin .. vmax */
226  mixer[idx++] = getNormalizedValue(opampModel.solve(n, vin));
227  }
228  }
229  }
230 
238  inline void buildVolumeTable(const OpAmp& opampModel, double nDivisor)
239  {
240  const double r_N16 = 1. / N16;
241 
242  int idx = 0;
243  for (int n8 = 0; n8 < 16; n8++)
244  {
245  constexpr int size = 1 << 16;
246  const double n = n8 / nDivisor;
247  opampModel.reset();
248 
249  for (int vi = 0; vi < size; vi++)
250  {
251  const double vin = vmin + vi * r_N16; /* vmin .. vmax */
252  volume[idx++] = getNormalizedValue(opampModel.solve(n, vin));
253  }
254  }
255  }
256 
264  inline void buildResonanceTable(const OpAmp& opampModel, const double resonance_n[16])
265  {
266  const double r_N16 = 1. / N16;
267 
268  int idx = 0;
269  for (int n8 = 0; n8 < 16; n8++)
270  {
271  constexpr int size = 1 << 16;
272  opampModel.reset();
273 
274  for (int vi = 0; vi < size; vi++)
275  {
276  const double vin = vmin + vi * r_N16; /* vmin .. vmax */
277  resonance[idx++] = getNormalizedValue(opampModel.solve(resonance_n[n8], vin));
278  }
279  }
280  }
281 
282 public:
283  unsigned short* getVolume() { return volume; }
284  unsigned short* getResonance() { return resonance; }
285  unsigned short* getSummer() { return summer; }
286  unsigned short* getMixer() { return mixer; }
287 
288  inline unsigned short getOpampRev(int i) const { return opamp_rev[i]; }
289  inline double getVddt() const { return Vddt; }
290  inline double getVth() const { return Vth; }
291 
292  // helper functions
293 
294  inline unsigned short getNormalizedValue(double value) const
295  {
296  return to_ushort_dither(N16 * (value - vmin), rnd.getNoise());
297  }
298 
299  template<int N>
300  inline unsigned short getNormalizedCurrentFactor(double wl) const
301  {
302  return to_ushort((1 << N) * currFactorCoeff * wl);
303  }
304 
305  inline unsigned short getNVmin() const
306  {
307  return to_ushort(N16 * vmin);
308  }
309 
310  inline int getNormalizedVoice(float value, unsigned int env) const
311  {
312  return static_cast<int>(getNormalizedValue(getVoiceVoltage(value, env)));
313  }
314 };
315 
316 template<>
318 {
319  static constexpr int value = 0;
320 };
321 
322 template<>
324 {
325  static constexpr int value = 1;
326 };
327 
328 template<>
330 {
331  static constexpr int value = 0;
332 };
333 
334 } // namespace reSIDfp
335 
336 #endif
Definition: FilterModelConfig.h:40
void buildVolumeTable(const OpAmp &opampModel, double nDivisor)
Definition: FilterModelConfig.h:238
const double Vdd
Positive supply voltage.
Definition: FilterModelConfig.h:105
void buildResonanceTable(const OpAmp &opampModel, const double resonance_n[16])
Definition: FilterModelConfig.h:264
unsigned short * mixer
Lookup tables for gain and summer op-amps in output stage / filter.
Definition: FilterModelConfig.h:125
double uCox
Transconductance coefficient: u*Cox.
Definition: FilterModelConfig.h:108
const double Vddt
Vdd - Vth.
Definition: FilterModelConfig.h:107
double currFactorCoeff
Current factor coefficient for op-amp integrators.
Definition: FilterModelConfig.h:121
const double C
Capacitor value.
Definition: FilterModelConfig.h:98
unsigned short opamp_rev[1<< 16]
Reverse op-amp transfer function.
Definition: FilterModelConfig.h:132
static constexpr double Ut
Transistor parameters.
Definition: FilterModelConfig.h:103
const double Vth
Threshold voltage.
Definition: FilterModelConfig.h:106
void buildMixerTable(const OpAmp &opampModel, double nRatio)
Definition: FilterModelConfig.h:210
const double N16
Fixed point scaling for 16 bit op-amp output.
Definition: FilterModelConfig.h:116
void buildSummerTable(const OpAmp &opampModel)
Definition: FilterModelConfig.h:181
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