diff options
-rw-r--r-- | audio/fmopl.cpp | 24 | ||||
-rw-r--r-- | audio/opl2lpt.cpp | 84 |
2 files changed, 76 insertions, 32 deletions
diff --git a/audio/fmopl.cpp b/audio/fmopl.cpp index 3a003c80d9..d1389d79e9 100644 --- a/audio/fmopl.cpp +++ b/audio/fmopl.cpp @@ -45,7 +45,7 @@ namespace ALSA { #ifdef ENABLE_OPL2LPT namespace OPL2LPT { - OPL *create(); + OPL *create(Config::OplType type); } // End of namespace OPL2LPT #endif // ENABLE_OPL2LPT @@ -57,7 +57,8 @@ enum OplEmulator { kDOSBox = 2, kALSA = 3, kNuked = 4, - kOPL2LPT = 5 + kOPL2LPT = 5, + kOPL3LPT = 6 }; OPL::OPL() { @@ -79,7 +80,8 @@ const Config::EmulatorDescription Config::_drivers[] = { { "alsa", _s("ALSA Direct FM"), kALSA, kFlagOpl2 | kFlagDualOpl2 | kFlagOpl3 }, #endif #ifdef ENABLE_OPL2LPT - { "opl2lpt", _s("OPL2LPT"), kOPL2LPT, kFlagOpl2 }, + { "opl2lpt", _s("OPL2LPT"), kOPL2LPT, kFlagOpl2}, + { "opl3lpt", _s("OPL3LPT"), kOPL3LPT, kFlagOpl2 | kFlagOpl3 }, #endif { 0, 0, 0, 0 } }; @@ -205,10 +207,18 @@ OPL *Config::create(DriverId driver, OplType type) { #ifdef ENABLE_OPL2LPT case kOPL2LPT: - if (type == kOpl2) - return OPL2LPT::create(); - else - warning("OPL2LPT only supports OPL2"); + if (type == kOpl2) { + return OPL2LPT::create(type); + } + + warning("OPL2LPT only supprts OPL2"); + return 0; + case kOPL3LPT: + if (type == kOpl2 || type == kOpl3) { + return OPL2LPT::create(type); + } + + warning("OPL3LPT does not support dual OPL2"); return 0; #endif diff --git a/audio/opl2lpt.cpp b/audio/opl2lpt.cpp index fc5a4ef465..3b30b60501 100644 --- a/audio/opl2lpt.cpp +++ b/audio/opl2lpt.cpp @@ -20,7 +20,7 @@ * */ -/* OPL implementation for OPL2LPT through libieee1284. +/* OPL implementation for OPL2LPT and OPL3LPT through libieee1284. */ #define FORBIDDEN_SYMBOL_ALLOW_ALL @@ -35,17 +35,35 @@ #include <unistd.h> #include <ieee1284.h> +static const uint8 OPL2LPTRegisterSelect[] = { + (C1284_NSELECTIN | C1284_NSTROBE | C1284_NINIT) ^ C1284_INVERTED, + (C1284_NSELECTIN | C1284_NSTROBE) ^ C1284_INVERTED, + (C1284_NSELECTIN | C1284_NSTROBE | C1284_NINIT) ^ C1284_INVERTED +}; + +static const uint8 OPL3LPTRegisterSelect[] = { + (C1284_NSTROBE | C1284_NINIT) ^ C1284_INVERTED, + C1284_NSTROBE ^ C1284_INVERTED, + (C1284_NSTROBE | C1284_NINIT) ^ C1284_INVERTED +}; + +static const uint8 OPL2LPTRegisterWrite[] = { + (C1284_NSELECTIN | C1284_NINIT) ^ C1284_INVERTED, + C1284_NSELECTIN ^ C1284_INVERTED, + (C1284_NSELECTIN | C1284_NINIT) ^ C1284_INVERTED +}; + namespace OPL { namespace OPL2LPT { class OPL : public ::OPL::RealOPL { private: struct parport *_pport; + Config::OplType _type; int index; - static const uint8 ctrlBytes[]; public: - OPL(); + explicit OPL(Config::OplType type); ~OPL(); bool init(); @@ -57,17 +75,7 @@ public: void writeReg(int r, int v); }; -const uint8 OPL::ctrlBytes[] = { - (C1284_NSELECTIN | C1284_NSTROBE | C1284_NINIT) ^ C1284_INVERTED, - (C1284_NSELECTIN | C1284_NSTROBE) ^ C1284_INVERTED, - (C1284_NSELECTIN | C1284_NSTROBE | C1284_NINIT) ^ C1284_INVERTED, - - (C1284_NSELECTIN | C1284_NINIT) ^ C1284_INVERTED, - C1284_NSELECTIN ^ C1284_INVERTED, - (C1284_NSELECTIN | C1284_NINIT) ^ C1284_INVERTED -}; - -OPL::OPL() : _pport(nullptr) { +OPL::OPL(Config::OplType type) : _pport(nullptr), _type(type), index(0) { } OPL::~OPL() { @@ -114,6 +122,11 @@ void OPL::reset() { for(int i = 0; i < 256; i ++) { writeReg(i, 0); } + if (_type == Config::kOpl3) { + for (int i = 0; i < 256; i++) { + writeReg(i + 256, 0); + } + } index = 0; } @@ -121,7 +134,17 @@ void OPL::write(int port, int val) { if (port & 1) { writeReg(index, val); } else { - index = val; + switch (_type) { + case Config::kOpl2: + index = val & 0xff; + break; + case Config::kOpl3: + index = (val & 0xff) | ((port << 7) & 0x100); + break; + default: + warning("OPL2LPT: unsupported OPL mode %d", _type); + break; + } } } @@ -131,23 +154,34 @@ byte OPL::read(int port) { } void OPL::writeReg(int r, int v) { - r &= 0xff; + if (_type == Config::kOpl3) { + r &= 0x1ff; + } else { + r &= 0xff; + } v &= 0xff; - ieee1284_write_data(_pport, r); - ieee1284_write_control(_pport, ctrlBytes[0]); - ieee1284_write_control(_pport, ctrlBytes[1]); - ieee1284_write_control(_pport, ctrlBytes[2]); + + ieee1284_write_data(_pport, r & 0xff); + if (r < 0x100) { + ieee1284_write_control(_pport, OPL2LPTRegisterSelect[0]); + ieee1284_write_control(_pport, OPL2LPTRegisterSelect[1]); + ieee1284_write_control(_pport, OPL2LPTRegisterSelect[2]); + } else { + ieee1284_write_control(_pport, OPL3LPTRegisterSelect[0]); + ieee1284_write_control(_pport, OPL3LPTRegisterSelect[1]); + ieee1284_write_control(_pport, OPL3LPTRegisterSelect[2]); + } usleep(4); // 3.3 us ieee1284_write_data(_pport, v); - ieee1284_write_control(_pport, ctrlBytes[3]); - ieee1284_write_control(_pport, ctrlBytes[4]); - ieee1284_write_control(_pport, ctrlBytes[5]); + ieee1284_write_control(_pport, OPL2LPTRegisterWrite[0]); + ieee1284_write_control(_pport, OPL2LPTRegisterWrite[1]); + ieee1284_write_control(_pport, OPL2LPTRegisterWrite[2]); usleep(23); } -OPL *create() { - return new OPL(); +OPL *create(Config::OplType type) { + return new OPL(type); } } // End of namespace OPL2LPT |