DOSBox-X
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines
src/hardware/adlib.h
00001 /*
00002  *  Copyright (C) 2002-2019  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
00015  *  along with this program; if not, write to the Free Software
00016  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, 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 struct Timer {
00034         double start;
00035         double delay;
00036         bool enabled, overflow, masked;
00037         Bit8u counter;
00038         Timer() {
00039                 masked = false;
00040                 overflow = false;
00041                 enabled = false;
00042                 counter = 0;
00043                 delay = 0;
00044         start = 0;
00045         }
00046         //Call update before making any further changes
00047         void Update( double time ) {
00048                 if ( !enabled || !delay ) 
00049                         return;
00050                 double deltaStart = time - start;
00051                 //Only set the overflow flag when not masked
00052                 if ( deltaStart >= 0 && !masked ) {
00053                         overflow = 1;
00054                 }
00055         }
00056         //On a reset make sure the start is in sync with the next cycle
00057         void Reset(const double& time ) {
00058                 overflow = false;
00059                 if ( !delay || !enabled )
00060                         return;
00061                 double delta = (time - start);
00062                 double rem = fmod( delta, delay );
00063                 double next = delay - rem;
00064                 start = time + next;            
00065         }
00066         void Stop( ) {
00067                 enabled = false;
00068         }
00069         void Start( const double& time, Bits scale ) {
00070                 //Don't enable again
00071                 if ( enabled ) {
00072                         return;
00073                 }
00074                 enabled = true;
00075                 delay = 0.001 * (256 - counter ) * scale;
00076                 start = time + delay;
00077         }
00078 
00079 };
00080 
00081 struct Chip {
00082         Chip() {
00083                 last_poll = 0;
00084                 poll_counter = 0;
00085         }
00086         //Last selected register
00087         Timer timer[2];
00088         //Check for it being a write to the timer
00089         bool Write( Bit32u addr, Bit8u val );
00090         //Read the current timer state, will use current double
00091         Bit8u Read( );
00092         //poll counter
00093         double last_poll;
00094         unsigned int poll_counter;
00095 };
00096 
00097 //The type of handler this is
00098 typedef enum {
00099         MODE_OPL2,
00100         MODE_DUALOPL2,
00101         MODE_OPL3,
00102         MODE_OPL3GOLD
00103 } Mode;
00104 
00105 class Handler {
00106 public:
00107         //Write an address to a chip, returns the address the chip sets
00108         virtual Bit32u WriteAddr( Bit32u port, Bit8u val ) = 0;
00109         //Write to a specific register in the chip
00110         virtual void WriteReg( Bit32u addr, Bit8u val ) = 0;
00111         //Generate a certain amount of samples
00112         virtual void Generate( MixerChannel* chan, Bitu samples ) = 0;
00113         //Initialize at a specific sample rate and mode
00114         virtual void Init( Bitu rate ) = 0;
00115 
00116         virtual ~Handler() {
00117         }
00118 };
00119 
00120 //The cache for 2 chips or an opl3
00121 typedef Bit8u RegisterCache[512];
00122 
00123 //Internal class used for dro capturing
00124 class Capture;
00125 
00126 class Module: public Module_base {
00127         IO_ReadHandleObject ReadHandler[12];
00128         IO_WriteHandleObject WriteHandler[12];
00129         MixerObject mixerObject;
00130 
00131         //Mode we're running in
00132         Mode mode;
00133         //Last selected address in the chip for the different modes
00134         union {
00135                 Bit32u normal;
00136                 Bit8u dual[2];
00137         } reg;
00138         struct {
00139                 bool active;
00140                 Bit8u index;
00141                 Bit8u lvol;
00142                 Bit8u rvol;
00143                 bool mixer;
00144     } ctrl = {};
00145         void CacheWrite( Bit32u reg, Bit8u val );
00146         void DualWrite( Bit8u index, Bit8u reg, Bit8u val );
00147         void CtrlWrite( Bit8u val );
00148         Bitu CtrlRead( void );
00149 public:
00150         static OPL_Mode oplmode;
00151         MixerChannel* mixerChan;
00152         Bit32u lastUsed;                                //Ticks when adlib was last used to turn of mixing after a few second
00153 
00154         Handler* handler;                               //Handler that will generate the sound
00155     RegisterCache cache = {};
00156         Capture* capture;
00157         Chip    chip[2];
00158 
00159         //Handle port writes
00160         void PortWrite( Bitu port, Bitu val, Bitu iolen );
00161         Bitu PortRead( Bitu port, Bitu iolen );
00162         void Init( Mode m );
00163 
00164         Module( Section* configuration); 
00165         ~Module();
00166 };
00167 
00168 
00169 }               //Adlib namespace
00170 
00171 #endif