DOSBox-X
|
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