filter.h 14 KB

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