diff options
Diffstat (limited to 'audio')
-rw-r--r-- | audio/fmopl.cpp | 21 | ||||
-rw-r--r-- | audio/module.mk | 5 | ||||
-rw-r--r-- | audio/opl2lpt.cpp | 154 |
3 files changed, 179 insertions, 1 deletions
diff --git a/audio/fmopl.cpp b/audio/fmopl.cpp index 3756d98123..3a003c80d9 100644 --- a/audio/fmopl.cpp +++ b/audio/fmopl.cpp @@ -43,6 +43,12 @@ namespace ALSA { } // End of namespace ALSA #endif // USE_ALSA +#ifdef ENABLE_OPL2LPT +namespace OPL2LPT { + OPL *create(); +} // End of namespace OPL2LPT +#endif // ENABLE_OPL2LPT + // Config implementation enum OplEmulator { @@ -50,7 +56,8 @@ enum OplEmulator { kMame = 1, kDOSBox = 2, kALSA = 3, - kNuked = 4 + kNuked = 4, + kOPL2LPT = 5 }; OPL::OPL() { @@ -71,6 +78,9 @@ const Config::EmulatorDescription Config::_drivers[] = { #ifdef USE_ALSA { "alsa", _s("ALSA Direct FM"), kALSA, kFlagOpl2 | kFlagDualOpl2 | kFlagOpl3 }, #endif +#ifdef ENABLE_OPL2LPT + { "opl2lpt", _s("OPL2LPT"), kOPL2LPT, kFlagOpl2 }, +#endif { 0, 0, 0, 0 } }; @@ -193,6 +203,15 @@ OPL *Config::create(DriverId driver, OplType type) { return ALSA::create(type); #endif +#ifdef ENABLE_OPL2LPT + case kOPL2LPT: + if (type == kOpl2) + return OPL2LPT::create(); + else + warning("OPL2LPT only supports OPL2"); + return 0; +#endif + default: warning("Unsupported OPL emulator %d", driver); // TODO: Maybe we should add some dummy emulator too, which just outputs diff --git a/audio/module.mk b/audio/module.mk index 4f296ba0e1..49584aba90 100644 --- a/audio/module.mk +++ b/audio/module.mk @@ -72,6 +72,11 @@ MODULE_OBJS += \ alsa_opl.o endif +ifdef ENABLE_OPL2LPT +MODULE_OBJS += \ + opl2lpt.o +endif + ifndef USE_ARM_SOUND_ASM MODULE_OBJS += \ rate.o diff --git a/audio/opl2lpt.cpp b/audio/opl2lpt.cpp new file mode 100644 index 0000000000..fc5a4ef465 --- /dev/null +++ b/audio/opl2lpt.cpp @@ -0,0 +1,154 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +/* OPL implementation for OPL2LPT through libieee1284. + */ + +#define FORBIDDEN_SYMBOL_ALLOW_ALL +#include "common/scummsys.h" + +#include "common/config-manager.h" +#include "common/debug.h" +#include "common/str.h" +#include "common/textconsole.h" +#include "audio/fmopl.h" + +#include <unistd.h> +#include <ieee1284.h> + +namespace OPL { +namespace OPL2LPT { + +class OPL : public ::OPL::RealOPL { +private: + struct parport *_pport; + int index; + static const uint8 ctrlBytes[]; + +public: + OPL(); + ~OPL(); + + bool init(); + void reset(); + + void write(int a, int v); + byte read(int a); + + 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() { + if (_pport) { + stop(); + reset(); + ieee1284_close(_pport); + } +} + +bool OPL::init() { + struct parport_list parports = {}; + const Common::String parportName = ConfMan.get("opl2lpt_parport"); + + // Look for available parallel ports + if (ieee1284_find_ports(&parports, 0) != E1284_OK) { + return false; + } + for (int i = 0; i < parports.portc; i++) { + if (parportName == "null" || + parportName == parports.portv[i]->name) { + int caps = CAP1284_RAW; + _pport = parports.portv[i]; + if (ieee1284_open(_pport, F1284_EXCL, &caps) != E1284_OK) { + warning("cannot open parallel port %s", _pport->name); + } + if (ieee1284_claim(_pport) != E1284_OK) { + warning("cannot claim parallel port %s", _pport->name); + ieee1284_close(_pport); + continue; + } + reset(); + // Safe to free ports here, opened ports are refcounted. + ieee1284_free_ports(&parports); + return true; + } + } + _pport = nullptr; + ieee1284_free_ports(&parports); + return false; +} + +void OPL::reset() { + for(int i = 0; i < 256; i ++) { + writeReg(i, 0); + } + index = 0; +} + +void OPL::write(int port, int val) { + if (port & 1) { + writeReg(index, val); + } else { + index = val; + } +} + +byte OPL::read(int port) { + // No read support for the OPL2LPT + return 0; +} + +void OPL::writeReg(int r, int v) { + 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]); + 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]); + usleep(23); +} + +OPL *create() { + return new OPL(); +} + +} // End of namespace OPL2LPT +} // End of namespace OPL |