home *** CD-ROM | disk | FTP | other *** search
/ Large Pack of OldSkool DOS MOD Trackers / goattracker_2.73.zip / src / resid / filter.h < prev    next >
Encoding:
C/C++ Source or Header  |  2014-07-23  |  14.3 KB  |  532 lines

  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.  
  20. #ifndef __FILTER_H__
  21. #define __FILTER_H__
  22.  
  23. #include "siddefs.h"
  24. #include "spline.h"
  25.  
  26. // ----------------------------------------------------------------------------
  27. // The SID filter is modeled with a two-integrator-loop biquadratic filter,
  28. // which has been confirmed by Bob Yannes to be the actual circuit used in
  29. // the SID chip.
  30. //
  31. // Measurements show that excellent emulation of the SID filter is achieved,
  32. // except when high resonance is combined with high sustain levels.
  33. // In this case the SID op-amps are performing less than ideally and are
  34. // causing some peculiar behavior of the SID filter. This however seems to
  35. // have more effect on the overall amplitude than on the color of the sound.
  36. //
  37. // The theory for the filter circuit can be found in "Microelectric Circuits"
  38. // by Adel S. Sedra and Kenneth C. Smith.
  39. // The circuit is modeled based on the explanation found there except that
  40. // an additional inverter is used in the feedback from the bandpass output,
  41. // allowing the summer op-amp to operate in single-ended mode. This yields
  42. // inverted filter outputs with levels independent of Q, which corresponds with
  43. // the results obtained from a real SID.
  44. //
  45. // We have been able to model the summer and the two integrators of the circuit
  46. // to form components of an IIR filter.
  47. // Vhp is the output of the summer, Vbp is the output of the first integrator,
  48. // and Vlp is the output of the second integrator in the filter circuit.
  49. //
  50. // According to Bob Yannes, the active stages of the SID filter are not really
  51. // op-amps. Rather, simple NMOS inverters are used. By biasing an inverter
  52. // into its region of quasi-linear operation using a feedback resistor from
  53. // input to output, a MOS inverter can be made to act like an op-amp for
  54. // small signals centered around the switching threshold.
  55. //
  56. // Qualified guesses at SID filter schematics are depicted below.
  57. //
  58. // SID filter
  59. // ----------
  60. // 
  61. //     -----------------------------------------------
  62. //    |                                               |
  63. //    |            ---Rq--                            |
  64. //    |           |       |                           |
  65. //    |  ------------<A]-----R1---------              |
  66. //    | |                               |             |
  67. //    | |                        ---C---|      ---C---|
  68. //    | |                       |       |     |       |
  69. //    |  --R1--    ---R1--      |---Rs--|     |---Rs--| 
  70. //    |        |  |       |     |       |     |       |
  71. //     ----R1--|-----[A>--|--R-----[A>--|--R-----[A>--|
  72. //             |          |             |             |
  73. // vi -----R1--           |             |             |
  74. // 
  75. //                       vhp           vbp           vlp
  76. // 
  77. // 
  78. // vi  - input voltage
  79. // vhp - highpass output
  80. // vbp - bandpass output
  81. // vlp - lowpass output
  82. // [A> - op-amp
  83. // R1  - summer resistor
  84. // Rq  - resistor array controlling resonance (4 resistors)
  85. // R   - NMOS FET voltage controlled resistor controlling cutoff frequency
  86. // Rs  - shunt resitor
  87. // C   - capacitor
  88. // 
  89. // 
  90. // 
  91. // SID integrator
  92. // --------------
  93. // 
  94. //                                   V+
  95. // 
  96. //                                   |
  97. //                                   |
  98. //                              -----|
  99. //                             |     |
  100. //                             | ||--
  101. //                              -||
  102. //                   ---C---     ||->
  103. //                  |       |        |
  104. //                  |---Rs-----------|---- vo
  105. //                  |                |
  106. //                  |            ||--
  107. // vi ----     -----|------------||
  108. //        |   ^     |            ||->
  109. //        |___|     |                |
  110. //        -----     |                |
  111. //          |       |                |
  112. //          |---R2--                 |
  113. //          |
  114. //          R1                       V-
  115. //          |
  116. //          |
  117. // 
  118. //          Vw
  119. //
  120. // ----------------------------------------------------------------------------
  121. class Filter
  122. {
  123. public:
  124.   Filter();
  125.  
  126.   void enable_filter(bool enable);
  127.   void set_chip_model(chip_model model);
  128.  
  129.   RESID_INLINE
  130.   void clock(sound_sample voice1, sound_sample voice2, sound_sample voice3,
  131.        sound_sample ext_in);
  132.   RESID_INLINE
  133.   void clock(cycle_count delta_t,
  134.          sound_sample voice1, sound_sample voice2, sound_sample voice3,
  135.        sound_sample ext_in);
  136.   void reset();
  137.  
  138.   // Write registers.
  139.   void writeFC_LO(reg8);
  140.   void writeFC_HI(reg8);
  141.   void writeRES_FILT(reg8);
  142.   void writeMODE_VOL(reg8);
  143.  
  144.   // SID audio output (16 bits).
  145.   sound_sample output();
  146.  
  147.   // Spline functions.
  148.   void fc_default(const fc_point*& points, int& count);
  149.   PointPlotter<sound_sample> fc_plotter();
  150.  
  151. protected:
  152.   void set_w0();
  153.   void set_Q();
  154.  
  155.   // Filter enabled.
  156.   bool enabled;
  157.  
  158.   // Filter cutoff frequency.
  159.   reg12 fc;
  160.  
  161.   // Filter resonance.
  162.   reg8 res;
  163.  
  164.   // Selects which inputs to route through filter.
  165.   reg8 filt;
  166.  
  167.   // Switch voice 3 off.
  168.   reg8 voice3off;
  169.  
  170.   // Highpass, bandpass, and lowpass filter modes.
  171.   reg8 hp_bp_lp;
  172.  
  173.   // Output master volume.
  174.   reg4 vol;
  175.  
  176.   // Mixer DC offset.
  177.   sound_sample mixer_DC;
  178.  
  179.   // State of filter.
  180.   sound_sample Vhp; // highpass
  181.   sound_sample Vbp; // bandpass
  182.   sound_sample Vlp; // lowpass
  183.   sound_sample Vnf; // not filtered
  184.  
  185.   // Cutoff frequency, resonance.
  186.   sound_sample w0, w0_ceil_1, w0_ceil_dt;
  187.   sound_sample _1024_div_Q;
  188.  
  189.   // Cutoff frequency tables.
  190.   // FC is an 11 bit register.
  191.   sound_sample f0_6581[2048];
  192.   sound_sample f0_8580[2048];
  193.   sound_sample* f0;
  194.   static fc_point f0_points_6581[];
  195.   static fc_point f0_points_8580[];
  196.   fc_point* f0_points;
  197.   int f0_count;
  198.  
  199. friend class SID;
  200. };
  201.  
  202.  
  203. // ----------------------------------------------------------------------------
  204. // Inline functions.
  205. // The following functions are defined inline because they are called every
  206. // time a sample is calculated.
  207. // ----------------------------------------------------------------------------
  208.  
  209. #if RESID_INLINING || defined(__FILTER_CC__)
  210.  
  211. // ----------------------------------------------------------------------------
  212. // SID clocking - 1 cycle.
  213. // ----------------------------------------------------------------------------
  214. RESID_INLINE
  215. void Filter::clock(sound_sample voice1,
  216.        sound_sample voice2,
  217.        sound_sample voice3,
  218.        sound_sample ext_in)
  219. {
  220.   // Scale each voice down from 20 to 13 bits.
  221.   voice1 >>= 7;
  222.   voice2 >>= 7;
  223.  
  224.   // NB! Voice 3 is not silenced by voice3off if it is routed through
  225.   // the filter.
  226.   if (voice3off && !(filt & 0x04)) {
  227.     voice3 = 0;
  228.   }
  229.   else {
  230.     voice3 >>= 7;
  231.   }
  232.  
  233.   ext_in >>= 7;
  234.  
  235.   // This is handy for testing.
  236.   if (!enabled) {
  237.     Vnf = voice1 + voice2 + voice3 + ext_in;
  238.     Vhp = Vbp = Vlp = 0;
  239.     return;
  240.   }
  241.  
  242.   // Route voices into or around filter.
  243.   // The code below is expanded to a switch for faster execution.
  244.   // (filt1 ? Vi : Vnf) += voice1;
  245.   // (filt2 ? Vi : Vnf) += voice2;
  246.   // (filt3 ? Vi : Vnf) += voice3;
  247.  
  248.   sound_sample Vi;
  249.  
  250.   switch (filt) {
  251.   default:
  252.   case 0x0:
  253.     Vi = 0;
  254.     Vnf = voice1 + voice2 + voice3 + ext_in;
  255.     break;
  256.   case 0x1:
  257.     Vi = voice1;
  258.     Vnf = voice2 + voice3 + ext_in;
  259.     break;
  260.   case 0x2:
  261.     Vi = voice2;
  262.     Vnf = voice1 + voice3 + ext_in;
  263.     break;
  264.   case 0x3:
  265.     Vi = voice1 + voice2;
  266.     Vnf = voice3 + ext_in;
  267.     break;
  268.   case 0x4:
  269.     Vi = voice3;
  270.     Vnf = voice1 + voice2 + ext_in;
  271.     break;
  272.   case 0x5:
  273.     Vi = voice1 + voice3;
  274.     Vnf = voice2 + ext_in;
  275.     break;
  276.   case 0x6:
  277.     Vi = voice2 + voice3;
  278.     Vnf = voice1 + ext_in;
  279.     break;
  280.   case 0x7:
  281.     Vi = voice1 + voice2 + voice3;
  282.     Vnf = ext_in;
  283.     break;
  284.   case 0x8:
  285.     Vi = ext_in;
  286.     Vnf = voice1 + voice2 + voice3;
  287.     break;
  288.   case 0x9:
  289.     Vi = voice1 + ext_in;
  290.     Vnf = voice2 + voice3;
  291.     break;
  292.   case 0xa:
  293.     Vi = voice2 + ext_in;
  294.     Vnf = voice1 + voice3;
  295.     break;
  296.   case 0xb:
  297.     Vi = voice1 + voice2 + ext_in;
  298.     Vnf = voice3;
  299.     break;
  300.   case 0xc:
  301.     Vi = voice3 + ext_in;
  302.     Vnf = voice1 + voice2;
  303.     break;
  304.   case 0xd:
  305.     Vi = voice1 + voice3 + ext_in;
  306.     Vnf = voice2;
  307.     break;
  308.   case 0xe:
  309.     Vi = voice2 + voice3 + ext_in;
  310.     Vnf = voice1;
  311.     break;
  312.   case 0xf:
  313.     Vi = voice1 + voice2 + voice3 + ext_in;
  314.     Vnf = 0;
  315.     break;
  316.   }
  317.     
  318.   // delta_t = 1 is converted to seconds given a 1MHz clock by dividing
  319.   // with 1 000 000.
  320.  
  321.   // Calculate filter outputs.
  322.   // Vhp = Vbp/Q - Vlp - Vi;
  323.   // dVbp = -w0*Vhp*dt;
  324.   // dVlp = -w0*Vbp*dt;
  325.  
  326.   sound_sample dVbp = (w0_ceil_1*Vhp >> 20);
  327.   sound_sample dVlp = (w0_ceil_1*Vbp >> 20);
  328.   Vbp -= dVbp;
  329.   Vlp -= dVlp;
  330.   Vhp = (Vbp*_1024_div_Q >> 10) - Vlp - Vi;
  331. }
  332.  
  333. // ----------------------------------------------------------------------------
  334. // SID clocking - delta_t cycles.
  335. // ----------------------------------------------------------------------------
  336. RESID_INLINE
  337. void Filter::clock(cycle_count delta_t,
  338.        sound_sample voice1,
  339.        sound_sample voice2,
  340.        sound_sample voice3,
  341.        sound_sample ext_in)
  342. {
  343.   // Scale each voice down from 20 to 13 bits.
  344.   voice1 >>= 7;
  345.   voice2 >>= 7;
  346.  
  347.   // NB! Voice 3 is not silenced by voice3off if it is routed through
  348.   // the filter.
  349.   if (voice3off && !(filt & 0x04)) {
  350.     voice3 = 0;
  351.   }
  352.   else {
  353.     voice3 >>= 7;
  354.   }
  355.  
  356.   ext_in >>= 7;
  357.  
  358.   // Enable filter on/off.
  359.   // This is not really part of SID, but is useful for testing.
  360.   // On slow CPUs it may be necessary to bypass the filter to lower the CPU
  361.   // load.
  362.   if (!enabled) {
  363.     Vnf = voice1 + voice2 + voice3 + ext_in;
  364.     Vhp = Vbp = Vlp = 0;
  365.     return;
  366.   }
  367.  
  368.   // Route voices into or around filter.
  369.   // The code below is expanded to a switch for faster execution.
  370.   // (filt1 ? Vi : Vnf) += voice1;
  371.   // (filt2 ? Vi : Vnf) += voice2;
  372.   // (filt3 ? Vi : Vnf) += voice3;
  373.  
  374.   sound_sample Vi;
  375.  
  376.   switch (filt) {
  377.   default:
  378.   case 0x0:
  379.     Vi = 0;
  380.     Vnf = voice1 + voice2 + voice3 + ext_in;
  381.     break;
  382.   case 0x1:
  383.     Vi = voice1;
  384.     Vnf = voice2 + voice3 + ext_in;
  385.     break;
  386.   case 0x2:
  387.     Vi = voice2;
  388.     Vnf = voice1 + voice3 + ext_in;
  389.     break;
  390.   case 0x3:
  391.     Vi = voice1 + voice2;
  392.     Vnf = voice3 + ext_in;
  393.     break;
  394.   case 0x4:
  395.     Vi = voice3;
  396.     Vnf = voice1 + voice2 + ext_in;
  397.     break;
  398.   case 0x5:
  399.     Vi = voice1 + voice3;
  400.     Vnf = voice2 + ext_in;
  401.     break;
  402.   case 0x6:
  403.     Vi = voice2 + voice3;
  404.     Vnf = voice1 + ext_in;
  405.     break;
  406.   case 0x7:
  407.     Vi = voice1 + voice2 + voice3;
  408.     Vnf = ext_in;
  409.     break;
  410.   case 0x8:
  411.     Vi = ext_in;
  412.     Vnf = voice1 + voice2 + voice3;
  413.     break;
  414.   case 0x9:
  415.     Vi = voice1 + ext_in;
  416.     Vnf = voice2 + voice3;
  417.     break;
  418.   case 0xa:
  419.     Vi = voice2 + ext_in;
  420.     Vnf = voice1 + voice3;
  421.     break;
  422.   case 0xb:
  423.     Vi = voice1 + voice2 + ext_in;
  424.     Vnf = voice3;
  425.     break;
  426.   case 0xc:
  427.     Vi = voice3 + ext_in;
  428.     Vnf = voice1 + voice2;
  429.     break;
  430.   case 0xd:
  431.     Vi = voice1 + voice3 + ext_in;
  432.     Vnf = voice2;
  433.     break;
  434.   case 0xe:
  435.     Vi = voice2 + voice3 + ext_in;
  436.     Vnf = voice1;
  437.     break;
  438.   case 0xf:
  439.     Vi = voice1 + voice2 + voice3 + ext_in;
  440.     Vnf = 0;
  441.     break;
  442.   }
  443.  
  444.   // Maximum delta cycles for the filter to work satisfactorily under current
  445.   // cutoff frequency and resonance constraints is approximately 8.
  446.   cycle_count delta_t_flt = 8;
  447.  
  448.   while (delta_t) {
  449.     if (delta_t < delta_t_flt) {
  450.       delta_t_flt = delta_t;
  451.     }
  452.  
  453.     // delta_t is converted to seconds given a 1MHz clock by dividing
  454.     // with 1 000 000. This is done in two operations to avoid integer
  455.     // multiplication overflow.
  456.  
  457.     // Calculate filter outputs.
  458.     // Vhp = Vbp/Q - Vlp - Vi;
  459.     // dVbp = -w0*Vhp*dt;
  460.     // dVlp = -w0*Vbp*dt;
  461.     sound_sample w0_delta_t = w0_ceil_dt*delta_t_flt >> 6;
  462.  
  463.     sound_sample dVbp = (w0_delta_t*Vhp >> 14);
  464.     sound_sample dVlp = (w0_delta_t*Vbp >> 14);
  465.     Vbp -= dVbp;
  466.     Vlp -= dVlp;
  467.     Vhp = (Vbp*_1024_div_Q >> 10) - Vlp - Vi;
  468.  
  469.     delta_t -= delta_t_flt;
  470.   }
  471. }
  472.  
  473.  
  474. // ----------------------------------------------------------------------------
  475. // SID audio output (20 bits).
  476. // ----------------------------------------------------------------------------
  477. RESID_INLINE
  478. sound_sample Filter::output()
  479. {
  480.   // This is handy for testing.
  481.   if (!enabled) {
  482.     return (Vnf + mixer_DC)*static_cast<sound_sample>(vol);
  483.   }
  484.  
  485.   // Mix highpass, bandpass, and lowpass outputs. The sum is not
  486.   // weighted, this can be confirmed by sampling sound output for
  487.   // e.g. bandpass, lowpass, and bandpass+lowpass from a SID chip.
  488.  
  489.   // The code below is expanded to a switch for faster execution.
  490.   // if (hp) Vf += Vhp;
  491.   // if (bp) Vf += Vbp;
  492.   // if (lp) Vf += Vlp;
  493.  
  494.   sound_sample Vf;
  495.  
  496.   switch (hp_bp_lp) {
  497.   default:
  498.   case 0x0:
  499.     Vf = 0;
  500.     break;
  501.   case 0x1:
  502.     Vf = Vlp;
  503.     break;
  504.   case 0x2:
  505.     Vf = Vbp;
  506.     break;
  507.   case 0x3:
  508.     Vf = Vlp + Vbp;
  509.     break;
  510.   case 0x4:
  511.     Vf = Vhp;
  512.     break;
  513.   case 0x5:
  514.     Vf = Vlp + Vhp;
  515.     break;
  516.   case 0x6:
  517.     Vf = Vbp + Vhp;
  518.     break;
  519.   case 0x7:
  520.     Vf = Vlp + Vbp + Vhp;
  521.     break;
  522.   }
  523.  
  524.   // Sum non-filtered and filtered output.
  525.   // Multiply the sum with volume.
  526.   return (Vnf + Vf + mixer_DC)*static_cast<sound_sample>(vol);
  527. }
  528.  
  529. #endif // RESID_INLINING || defined(__FILTER_CC__)
  530.  
  531. #endif // not __FILTER_H__
  532.