DOSBox-X
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines
src/hardware/reSID/extfilt.h
00001 //  ---------------------------------------------------------------------------
00002 //  This file is part of reSID, a MOS6581 SID emulator engine.
00003 //  Copyright (C) 2004  Dag Lem <resid@nimrod.no>
00004 //
00005 //  This program is free software; you can redistribute it and/or modify
00006 //  it under the terms of the GNU General Public License as published by
00007 //  the Free Software Foundation; either version 2 of the License, or
00008 //  (at your option) any later version.
00009 //
00010 //  This program is distributed in the hope that it will be useful,
00011 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
00012 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013 //  GNU General Public License for more details.
00014 //
00015 //  You should have received a copy of the GNU General Public License
00016 //  along with this program; if not, write to the Free Software
00017 //  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00018 //  ---------------------------------------------------------------------------
00019 
00020 #ifndef __EXTFILT_H__
00021 #define __EXTFILT_H__
00022 
00023 #include "siddefs.h"
00024 #include <sstream>
00025 
00026 // ----------------------------------------------------------------------------
00027 // The audio output stage in a Commodore 64 consists of two STC networks,
00028 // a low-pass filter with 3-dB frequency 16kHz followed by a high-pass
00029 // filter with 3-dB frequency 16Hz (the latter provided an audio equipment
00030 // input impedance of 1kOhm).
00031 // The STC networks are connected with a BJT supposedly meant to act as
00032 // a unity gain buffer, which is not really how it works. A more elaborate
00033 // model would include the BJT, however DC circuit analysis yields BJT
00034 // base-emitter and emitter-base impedances sufficiently low to produce
00035 // additional low-pass and high-pass 3dB-frequencies in the order of hundreds
00036 // of kHz. This calls for a sampling frequency of several MHz, which is far
00037 // too high for practical use.
00038 // ----------------------------------------------------------------------------
00039 class ExternalFilter
00040 {
00041 public:
00042   ExternalFilter();
00043 
00044   void enable_filter(bool enable);
00045   void set_chip_model(chip_model model);
00046 
00047   RESID_INLINE void clock(sound_sample Vi);
00048   RESID_INLINE void clock(cycle_count delta_t, sound_sample Vi);
00049   void reset();
00050 
00051   // Audio output (20 bits).
00052   RESID_INLINE sound_sample output();
00053 
00054         void SaveState( std::ostream& stream );
00055         void LoadState( std::istream& stream );
00056 
00057 protected:
00058   // Filter enabled.
00059   bool enabled;
00060 
00061   // Maximum mixer DC offset.
00062   sound_sample mixer_DC;
00063 
00064   // State of filters.
00065   sound_sample Vlp; // lowpass
00066   sound_sample Vhp; // highpass
00067   sound_sample Vo;
00068 
00069   // Cutoff frequencies.
00070   sound_sample w0lp;
00071   sound_sample w0hp;
00072 
00073 friend class SID2;
00074 };
00075 
00076 
00077 // ----------------------------------------------------------------------------
00078 // Inline functions.
00079 // The following functions are defined inline because they are called every
00080 // time a sample is calculated.
00081 // ----------------------------------------------------------------------------
00082 
00083 #if RESID_INLINING || defined(__EXTFILT_CC__)
00084 
00085 // ----------------------------------------------------------------------------
00086 // SID clocking - 1 cycle.
00087 // ----------------------------------------------------------------------------
00088 RESID_INLINE
00089 void ExternalFilter::clock(sound_sample Vi)
00090 {
00091   // This is handy for testing.
00092   if (!enabled) {
00093     // Remove maximum DC level since there is no filter to do it.
00094     Vlp = Vhp = 0;
00095     Vo = Vi - mixer_DC;
00096     return;
00097   }
00098 
00099   // delta_t is converted to seconds given a 1MHz clock by dividing
00100   // with 1 000 000.
00101 
00102   // Calculate filter outputs.
00103   // Vo  = Vlp - Vhp;
00104   // Vlp = Vlp + w0lp*(Vi - Vlp)*delta_t;
00105   // Vhp = Vhp + w0hp*(Vlp - Vhp)*delta_t;
00106 
00107   sound_sample dVlp = (w0lp >> 8)*(Vi - Vlp) >> 12;
00108   sound_sample dVhp = w0hp*(Vlp - Vhp) >> 20;
00109   Vo = Vlp - Vhp;
00110   Vlp += dVlp;
00111   Vhp += dVhp;
00112 }
00113 
00114 // ----------------------------------------------------------------------------
00115 // SID clocking - delta_t cycles.
00116 // ----------------------------------------------------------------------------
00117 RESID_INLINE
00118 void ExternalFilter::clock(cycle_count delta_t,
00119                            sound_sample Vi)
00120 {
00121   // This is handy for testing.
00122   if (!enabled) {
00123     // Remove maximum DC level since there is no filter to do it.
00124     Vlp = Vhp = 0;
00125     Vo = Vi - mixer_DC;
00126     return;
00127   }
00128 
00129   // Maximum delta cycles for the external filter to work satisfactorily
00130   // is approximately 8.
00131   cycle_count delta_t_flt = 8;
00132 
00133   while (delta_t) {
00134     if (delta_t < delta_t_flt) {
00135       delta_t_flt = delta_t;
00136     }
00137 
00138     // delta_t is converted to seconds given a 1MHz clock by dividing
00139     // with 1 000 000.
00140 
00141     // Calculate filter outputs.
00142     // Vo  = Vlp - Vhp;
00143     // Vlp = Vlp + w0lp*(Vi - Vlp)*delta_t;
00144     // Vhp = Vhp + w0hp*(Vlp - Vhp)*delta_t;
00145 
00146     sound_sample dVlp = (w0lp*delta_t_flt >> 8)*(Vi - Vlp) >> 12;
00147     sound_sample dVhp = w0hp*delta_t_flt*(Vlp - Vhp) >> 20;
00148     Vo = Vlp - Vhp;
00149     Vlp += dVlp;
00150     Vhp += dVhp;
00151 
00152     delta_t -= delta_t_flt;
00153   }
00154 }
00155 
00156 
00157 // ----------------------------------------------------------------------------
00158 // Audio output (19.5 bits).
00159 // ----------------------------------------------------------------------------
00160 RESID_INLINE
00161 sound_sample ExternalFilter::output()
00162 {
00163   return Vo;
00164 }
00165 
00166 #endif // RESID_INLINING || defined(__EXTFILT_CC__)
00167 
00168 #endif // not __EXTFILT_H__