libsidplayfp 1.8.8
extfilt.h
1// ---------------------------------------------------------------------------
2// This file is part of reSID, a MOS6581 SID emulator engine.
3// Copyright (C) 2010 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 RESID_EXTFILT_H
21#define RESID_EXTFILT_H
22
23#include "resid-config.h"
24
25namespace reSID
26{
27
28// ----------------------------------------------------------------------------
29// The audio output stage in a Commodore 64 consists of two STC networks,
30// a low-pass filter with 3-dB frequency 16kHz followed by a high-pass
31// filter with 3-dB frequency 1.6Hz (the latter provided an audio equipment
32// input impedance of 10kOhm).
33// The STC networks are connected with a BJT supposedly meant to act as
34// a unity gain buffer, which is not really how it works. A more elaborate
35// model would include the BJT, however DC circuit analysis yields BJT
36// base-emitter and emitter-base impedances sufficiently low to produce
37// additional low-pass and high-pass 3dB-frequencies in the order of hundreds
38// of kHz. This calls for a sampling frequency of several MHz, which is far
39// too high for practical use.
40// ----------------------------------------------------------------------------
42{
43public:
45
46 void enable_filter(bool enable);
47
48 void clock(short Vi);
49 void clock(cycle_count delta_t, short Vi);
50 void reset();
51
52 // Audio output (16 bits).
53 short output();
54
55protected:
56 // Filter enabled.
57 bool enabled;
58
59 // State of filters (27 bits).
60 int Vlp; // lowpass
61 int Vhp; // highpass
62
63 // Cutoff frequencies.
64 int w0lp_1_s7;
65 int w0hp_1_s17;
66
67friend class SID;
68};
69
70
71// ----------------------------------------------------------------------------
72// Inline functions.
73// The following functions are defined inline because they are called every
74// time a sample is calculated.
75// ----------------------------------------------------------------------------
76
77#if RESID_INLINING || defined(RESID_EXTFILT_CC)
78
79// ----------------------------------------------------------------------------
80// SID clocking - 1 cycle.
81// ----------------------------------------------------------------------------
82RESID_INLINE
83void ExternalFilter::clock(short Vi)
84{
85 // This is handy for testing.
86 if (unlikely(!enabled)) {
87 // Vo = Vlp - Vhp;
88 Vlp = Vi << 11;
89 Vhp = 0;
90 return;
91 }
92
93 // Calculate filter outputs.
94 // Vlp = Vlp + w0lp*(Vi - Vlp)*delta_t;
95 // Vhp = Vhp + w0hp*(Vlp - Vhp)*delta_t;
96 // Vo = Vlp - Vhp;
97
98 int dVlp = w0lp_1_s7*((Vi << 11) - Vlp) >> 7;
99 int dVhp = w0hp_1_s17*(Vlp - Vhp) >> 17;
100 Vlp += dVlp;
101 Vhp += dVhp;
102}
103
104// ----------------------------------------------------------------------------
105// SID clocking - delta_t cycles.
106// ----------------------------------------------------------------------------
107RESID_INLINE
108void ExternalFilter::clock(cycle_count delta_t, short Vi)
109{
110 // This is handy for testing.
111 if (unlikely(!enabled)) {
112 // Vo = Vlp - Vhp;
113 Vlp = Vi << 11;
114 Vhp = 0;
115 return;
116 }
117
118 // Maximum delta cycles for the external filter to work satisfactorily
119 // is approximately 8.
120 cycle_count delta_t_flt = 8;
121
122 while (delta_t) {
123 if (unlikely(delta_t < delta_t_flt)) {
124 delta_t_flt = delta_t;
125 }
126
127 // Calculate filter outputs.
128 // Vlp = Vlp + w0lp*(Vi - Vlp)*delta_t;
129 // Vhp = Vhp + w0hp*(Vlp - Vhp)*delta_t;
130 // Vo = Vlp - Vhp;
131
132 int dVlp = (w0lp_1_s7*delta_t_flt >> 3)*((Vi << 11) - Vlp) >> 4;
133 int dVhp = (w0hp_1_s17*delta_t_flt >> 3)*(Vlp - Vhp) >> 14;
134 Vlp += dVlp;
135 Vhp += dVhp;
136
137 delta_t -= delta_t_flt;
138 }
139}
140
141
142// ----------------------------------------------------------------------------
143// Audio output (16 bits).
144// ----------------------------------------------------------------------------
145RESID_INLINE
146short ExternalFilter::output()
147{
148 // Saturated arithmetics to guard against 16 bit sample overflow.
149 const int half = 1 << 15;
150 int Vo = (Vlp - Vhp) >> 11;
151 if (Vo >= half) {
152 Vo = half - 1;
153 }
154 else if (Vo < -half) {
155 Vo = -half;
156 }
157 return Vo;
158}
159
160#endif // RESID_INLINING || defined(RESID_EXTFILT_CC)
161
162} // namespace reSID
163
164#endif // not RESID_EXTFILT_H
Definition: extfilt.h:42
Definition: sid.h:35