DOSBox-X
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines
src/hardware/adlib.h
00001 /*
00002  *  Copyright (C) 2002-2020  The DOSBox Team
00003  *
00004  *  This program is free software; you can redistribute it and/or modify
00005  *  it under the terms of the GNU General Public License as published by
00006  *  the Free Software Foundation; either version 2 of the License, or
00007  *  (at your option) any later version.
00008  *
00009  *  This program is distributed in the hope that it will be useful,
00010  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  *  GNU General Public License for more details.
00013  *
00014  *  You should have received a copy of the GNU General Public License along
00015  *  with this program; if not, write to the Free Software Foundation, Inc.,
00016  *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00017  */
00018 
00019 
00020 #ifndef DOSBOX_ADLIB_H
00021 #define DOSBOX_ADLIB_H
00022 
00023 #include "dosbox.h"
00024 #include "mixer.h"
00025 #include "inout.h"
00026 #include "setup.h"
00027 #include "pic.h"
00028 #include "hardware.h"
00029 
00030 
00031 namespace Adlib {
00032 
00033 class Timer {
00034         //Rounded down start time
00035         double start;
00036         //Clock interval
00037         double interval;
00038         //Delay before you overflow
00039         double delay;
00040         Bit8u counter;
00041 public:
00042         bool enabled;
00043         bool overflow;
00044 
00045         Timer( Bit16s micros ) {
00046                 overflow = false;
00047                 enabled = false;
00048                 counter = 0;
00049                 start = 0;
00050                 delay = 0;
00051                 //Interval in milliseconds
00052                 interval = micros * 0.001;
00053         }
00054 
00055         //Update returns with true if overflow
00056         bool Update( double time ) {
00057                 if ( !enabled ) 
00058                         return false;
00059                 const double deltaTime = time - start;
00060                 //Only set the overflow flag when not masked
00061                 if (deltaTime >= delay  ) {
00062                         overflow = true;
00063                         return true;
00064                 }
00065                 return false;
00066         }
00067         
00068         //On a reset make sure the start is in sync with the next cycle
00069         void Reset(const double time ) {
00070                 overflow = false;
00071                 if ( !enabled )
00072                         return;
00073                 //Sync start to the last delay interval
00074                 const double deltaTime = time - start;
00075                 const double rem = fmod(deltaTime, delay);
00076                 start = time - rem;
00077         }
00078 
00079         void SetCounter(Bit8u val) {
00080                 counter = val;
00081         }
00082         
00083         //Stopping always clears the overflow as well
00084         void Stop( ) {
00085                 enabled = false;
00086                 overflow = false;
00087         }
00088         
00089         //Starting clears overflow
00090         void Start( const double time ) {
00091                 enabled = true;
00092                 overflow = false;
00093                 //The counter is basically copied on start so calculate delay now
00094                 delay = (256 - counter) * interval;
00095                 //Sync start to the last clock interval
00096                 double rem = fmod(time, interval);
00097                 start = time - rem;
00098         }
00099         
00100         //Does this clock need an update, you could save a pic_fullindex on read?
00101         bool NeedUpdate() const {
00102                 return enabled && !overflow;
00103         }
00104 };
00105 
00106 struct Chip {
00107         //Last selected register
00108         Timer timer0, timer1;
00109         //Check for it being a write to the timer
00110         bool Write( Bit32u reg, Bit8u val );
00111         //Read the current timer state, will use current double
00112         Bit8u Read( );
00113         
00114         Chip();
00115         //poll counter
00116         double last_poll = 0;
00117         unsigned int poll_counter = 0;
00118 };
00119 
00120 //The type of handler this is
00121 typedef enum {
00122         MODE_OPL2,
00123         MODE_DUALOPL2,
00124         MODE_OPL3,
00125         MODE_OPL3GOLD
00126 } Mode;
00127 
00128 class Handler {
00129 public:
00130         //Write an address to a chip, returns the address the chip sets
00131         virtual Bit32u WriteAddr( Bit32u port, Bit8u val ) = 0;
00132         //Write to a specific register in the chip
00133         virtual void WriteReg( Bit32u addr, Bit8u val ) = 0;
00134         //Generate a certain amount of samples
00135         virtual void Generate( MixerChannel* chan, Bitu samples ) = 0;
00136         //Initialize at a specific sample rate and mode
00137         virtual void Init( Bitu rate ) = 0;
00138         virtual void SaveState( std::ostream& stream ) { (void)stream; }
00139         virtual void LoadState( std::istream& stream ) { (void)stream; }
00140 
00141         virtual ~Handler() {
00142         }
00143 };
00144 
00145 //The cache for 2 chips or an opl3
00146 typedef Bit8u RegisterCache[512];
00147 
00148 //Internal class used for dro capturing
00149 class Capture;
00150 
00151 class Module: public Module_base {
00152         IO_ReadHandleObject ReadHandler[12];
00153         IO_WriteHandleObject WriteHandler[12];
00154         MixerObject mixerObject;
00155 
00156         //Mode we're running in
00157         Mode mode;
00158         //Last selected address in the chip for the different modes
00159         union {
00160                 Bit32u normal;
00161                 Bit8u dual[2];
00162         } reg;
00163         struct {
00164                 bool active;
00165                 Bit8u index;
00166                 Bit8u lvol;
00167                 Bit8u rvol;
00168                 bool mixer;
00169     } ctrl = {};
00170         void CacheWrite( Bit32u reg, Bit8u val );
00171         void DualWrite( Bit8u index, Bit8u reg, Bit8u val );
00172         void CtrlWrite( Bit8u val );
00173         Bitu CtrlRead( void );
00174 public:
00175         static OPL_Mode oplmode;
00176         MixerChannel* mixerChan;
00177         Bit32u lastUsed;                                //Ticks when adlib was last used to turn of mixing after a few second
00178 
00179         Handler* handler;                               //Handler that will generate the sound
00180     RegisterCache cache = {};
00181         Capture* capture;
00182         Chip    chip[2];
00183 
00184         //Handle port writes
00185         void PortWrite( Bitu port, Bitu val, Bitu iolen );
00186         Bitu PortRead( Bitu port, Bitu iolen );
00187         void Init( Mode m );
00188 
00189         // savestate support
00190         virtual void SaveState( std::ostream& stream );
00191         virtual void LoadState( std::istream& stream );
00192 
00193         Module( Section* configuration); 
00194         ~Module();
00195 };
00196 
00197 
00198 }               //Adlib namespace
00199 
00200 #endif