diff --git a/include/hardware.h b/include/hardware.h index 5f5e4c74..26d3fde8 100644 --- a/include/hardware.h +++ b/include/hardware.h @@ -24,7 +24,7 @@ class Section; enum OPL_Mode { - OPL_none,OPL_cms,OPL_opl2,OPL_dualopl2,OPL_opl3 + OPL_none,OPL_cms,OPL_opl2,OPL_dualopl2,OPL_opl3,OPL_opl3gold }; #define CAPTURE_WAVE 0x01 #define CAPTURE_OPL 0x02 diff --git a/src/dosbox.cpp b/src/dosbox.cpp index 83e6f434..1462fae3 100644 --- a/src/dosbox.cpp +++ b/src/dosbox.cpp @@ -537,7 +537,7 @@ void DOSBOX_Init(void) { Pbool = secprop->Add_bool("sbmixer",Property::Changeable::WhenIdle,true); Pbool->Set_help("Allow the soundblaster mixer to modify the DOSBox mixer."); - const char* oplmodes[]={ "auto", "cms", "opl2", "dualopl2", "opl3", "none", 0}; + const char* oplmodes[]={ "auto", "cms", "opl2", "dualopl2", "opl3", "opl3gold", "none", 0}; Pstring = secprop->Add_string("oplmode",Property::Changeable::WhenIdle,"auto"); Pstring->Set_values(oplmodes); Pstring->Set_help("Type of OPL emulation. On 'auto' the mode is determined by sblaster type. All OPL modes are Adlib-compatible, except for 'cms'."); diff --git a/src/hardware/adlib.cpp b/src/hardware/adlib.cpp index 89e512bf..6c4b3983 100644 --- a/src/hardware/adlib.cpp +++ b/src/hardware/adlib.cpp @@ -440,6 +440,36 @@ void Module::DualWrite( Bit8u index, Bit8u reg, Bit8u val ) { CacheWrite( fullReg, val ); } +void Module::CtrlWrite( Bit8u val ) { + switch ( ctrl.index ) { + case 0x09: /* Left FM Volume */ + ctrl.lvol = val; + goto setvol; + case 0x0a: /* Right FM Volume */ + ctrl.rvol = val; +setvol: + if ( ctrl.mixer ) { + //Dune cdrom uses 32 volume steps in an apparent mistake, should be 128 + mixerChan->SetVolume( (float)(ctrl.lvol&0x1f)/31.0f, (float)(ctrl.rvol&0x1f)/31.0f ); + } + break; + } +} + +Bitu Module::CtrlRead( void ) { + switch ( ctrl.index ) { + case 0x00: /* Board Options */ + return 0x70; //No options installed + case 0x09: /* Left FM Volume */ + return ctrl.lvol; + case 0x0a: /* Right FM Volume */ + return ctrl.rvol; + case 0x15: /* Audio Relocation */ + return 0x388 >> 3; //Cryo installer detection + } + return 0xff; +} + void Module::PortWrite( Bitu port, Bitu val, Bitu iolen ) { //Keep track of last write time @@ -450,6 +480,14 @@ void Module::PortWrite( Bitu port, Bitu val, Bitu iolen ) { } if ( port&1 ) { switch ( mode ) { + case MODE_OPL3GOLD: + if ( port == 0x38b ) { + if ( ctrl.active ) { + CtrlWrite( val ); + break; + } + } + //Fall-through if not handled by control chip case MODE_OPL2: case MODE_OPL3: if ( !chip[0].Write( reg.normal, val ) ) { @@ -476,6 +514,20 @@ void Module::PortWrite( Bitu port, Bitu val, Bitu iolen ) { case MODE_OPL2: reg.normal = handler->WriteAddr( port, val ) & 0xff; break; + case MODE_OPL3GOLD: + if ( port == 0x38a ) { + if ( val == 0xff ) { + ctrl.active = true; + break; + } else if ( val == 0xfe ) { + ctrl.active = false; + break; + } else if ( ctrl.active ) { + ctrl.index = val & 0xff; + break; + } + } + //Fall-through if not handled by control chip case MODE_OPL3: reg.normal = handler->WriteAddr( port, val ) & 0x1ff; break; @@ -504,6 +556,15 @@ Bitu Module::PortRead( Bitu port, Bitu iolen ) { } else { return 0xff; } + case MODE_OPL3GOLD: + if ( ctrl.active ) { + if ( port == 0x38a ) { + return 0; //Control status, not busy + } else if ( port == 0x38b ) { + return CtrlRead(); + } + } + //Fall-through if not handled by control chip case MODE_OPL3: //We allocated 4 ports, so just return -1 for the higher ones if ( !(port & 3 ) ) { @@ -527,6 +588,7 @@ void Module::Init( Mode m ) { mode = m; switch ( mode ) { case MODE_OPL3: + case MODE_OPL3GOLD: case MODE_OPL2: break; case MODE_DUALOPL2: @@ -627,6 +689,10 @@ Module::Module( Section* configuration ) : Module_base(configuration) { reg.dual[0] = 0; reg.dual[1] = 0; reg.normal = 0; + ctrl.active = false; + ctrl.index = 0; + ctrl.lvol = 0xff; + ctrl.rvol = 0xff; handler = 0; capture = 0; @@ -637,6 +703,7 @@ Module::Module( Section* configuration ) : Module_base(configuration) { if ( rate < 8000 ) rate = 8000; std::string oplemu( section->Get_string( "oplemu" ) ); + ctrl.mixer = section->Get_bool("sbmixer"); mixerChan = mixerObject.Install(OPL_CallBack,rate,"FM"); mixerChan->SetScale( 2.0 ); @@ -664,6 +731,9 @@ Module::Module( Section* configuration ) : Module_base(configuration) { case OPL_opl3: Init( Adlib::MODE_OPL3 ); break; + case OPL_opl3gold: + Init( Adlib::MODE_OPL3GOLD ); + break; } //0x388 range WriteHandler[0].Install(0x388,OPL_Write,IO_MB, 4 ); diff --git a/src/hardware/adlib.h b/src/hardware/adlib.h index 681fd491..26114c2c 100644 --- a/src/hardware/adlib.h +++ b/src/hardware/adlib.h @@ -90,7 +90,8 @@ struct Chip { typedef enum { MODE_OPL2, MODE_DUALOPL2, - MODE_OPL3 + MODE_OPL3, + MODE_OPL3GOLD } Mode; class Handler { @@ -125,8 +126,17 @@ class Module: public Module_base { Bit32u normal; Bit8u dual[2]; } reg; + struct { + bool active; + Bit8u index; + Bit8u lvol; + Bit8u rvol; + bool mixer; + } ctrl; void CacheWrite( Bit32u reg, Bit8u val ); void DualWrite( Bit8u index, Bit8u reg, Bit8u val ); + void CtrlWrite( Bit8u val ); + Bitu CtrlRead( void ); public: static OPL_Mode oplmode; MixerChannel* mixerChan; diff --git a/src/hardware/sblaster.cpp b/src/hardware/sblaster.cpp index d72066bb..80376a67 100644 --- a/src/hardware/sblaster.cpp +++ b/src/hardware/sblaster.cpp @@ -1533,6 +1533,7 @@ private: else if (!strcasecmp(omode,"opl2")) opl_mode=OPL_opl2; else if (!strcasecmp(omode,"dualopl2")) opl_mode=OPL_dualopl2; else if (!strcasecmp(omode,"opl3")) opl_mode=OPL_opl3; + else if (!strcasecmp(omode,"opl3gold")) opl_mode=OPL_opl3gold; /* Else assume auto */ else { switch (type) { @@ -1588,6 +1589,7 @@ public: // fall-through case OPL_dualopl2: case OPL_opl3: + case OPL_opl3gold: OPL_Init(section,oplmode); break; } @@ -1645,6 +1647,7 @@ public: // fall-through case OPL_dualopl2: case OPL_opl3: + case OPL_opl3gold: OPL_ShutDown(m_configuration); break; }