From 4f0768b9096aab65961d697ca60d6e939f36eae2 Mon Sep 17 00:00:00 2001 From: Johannes Schickel Date: Tue, 12 May 2009 18:42:44 +0000 Subject: - Add support for selecting the OPL emulator being used (config entry: "opl_driver") - Make MAME FM OPL the default emulator again - Add GUI support for selecting the active OPL emulator - Update themes svn-id: r40496 --- engines/sci/sfx/softseq/adlib.cpp | 2 +- gui/options.cpp | 31 ++++++ gui/options.h | 1 + gui/themes/default.inc | 6 ++ gui/themes/scummclassic.zip | Bin 45619 -> 45730 bytes gui/themes/scummclassic/classic_layout.stx | 3 + gui/themes/scummclassic/classic_layout_lowres.stx | 3 + gui/themes/scummmodern.zip | Bin 148830 -> 148944 bytes gui/themes/scummmodern/scummmodern_layout.stx | 3 + .../scummmodern/scummmodern_layout_lowres.stx | 3 + sound/fmopl.cpp | 104 ++++++++++++++++++--- sound/fmopl.h | 70 ++++++++++++-- sound/softsynth/opl/dosbox.cpp | 36 +++---- sound/softsynth/opl/dosbox.h | 6 +- 14 files changed, 223 insertions(+), 45 deletions(-) diff --git a/engines/sci/sfx/softseq/adlib.cpp b/engines/sci/sfx/softseq/adlib.cpp index 3be0ed86f3..92a04f065e 100644 --- a/engines/sci/sfx/softseq/adlib.cpp +++ b/engines/sci/sfx/softseq/adlib.cpp @@ -82,7 +82,7 @@ int MidiDriver_Adlib::open(bool isSCI0) { debug(3, "ADLIB: Starting driver in %s mode", (isSCI0 ? "SCI0" : "SCI1")); _isSCI0 = isSCI0; - _opl = OPL::OPL::create(isStereo() ? OPL::OPL::kDualOpl2 : OPL::OPL::kOpl2); + _opl = OPL::Config::create(isStereo() ? OPL::Config::kDualOpl2 : OPL::Config::kOpl2); if (!_opl) return -1; diff --git a/gui/options.cpp b/gui/options.cpp index 956c0d8cf6..c152a3a266 100644 --- a/gui/options.cpp +++ b/gui/options.cpp @@ -40,6 +40,7 @@ #include "sound/mididrv.h" #include "sound/mixer.h" +#include "sound/fmopl.h" namespace GUI { @@ -102,6 +103,7 @@ void OptionsDialog::init() { _aspectCheckbox = 0; _enableAudioSettings = false; _midiPopUp = 0; + _oplPopUp = 0; _outputRatePopUp = 0; _enableMIDISettings = false; _multiMidiCheckbox = 0; @@ -181,6 +183,9 @@ void OptionsDialog::open() { _midiPopUp->setSelectedTag(id); } + if (_oplPopUp) + _oplPopUp->setSelectedTag(OPL::Config::parse(ConfMan.get("opl_driver", _domain))); + if (_outputRatePopUp) { _outputRatePopUp->setSelected(1); int value = ConfMan.getInt("output_rate", _domain); @@ -315,6 +320,21 @@ void OptionsDialog::close() { } } + if (_oplPopUp) { + if (_enableAudioSettings) { + const OPL::Config::EmulatorDescription *ed = OPL::Config::getAvailable(); + while (ed->name && ed->id != (int)_oplPopUp->getSelectedTag()) + ++ed; + + if (ed->name) + ConfMan.set("opl_driver", ed->name, _domain); + else + ConfMan.removeKey("opl_driver", _domain); + } else { + ConfMan.removeKey("opl_driver", _domain); + } + } + if (_outputRatePopUp) { if (_enableAudioSettings) { if (_outputRatePopUp->getSelectedTag() != 0) @@ -457,6 +477,7 @@ void OptionsDialog::setAudioSettingsState(bool enabled) { _enableAudioSettings = enabled; _midiPopUp->setEnabled(enabled); + _oplPopUp->setEnabled(enabled); _outputRatePopUp->setEnabled(enabled); } @@ -545,6 +566,16 @@ void OptionsDialog::addAudioControls(GuiObject *boss, const String &prefix) { md++; } + // The OPL emulator popup & a label + _oplPopUp = new PopUpWidget(boss, prefix + "auOPLPopup", "AdLib emulator:"); + + // Populate it + const OPL::Config::EmulatorDescription *ed = OPL::Config::getAvailable(); + while (ed->name) { + _oplPopUp->appendEntry(ed->description, ed->id); + ++ed; + } + // Sample rate settings _outputRatePopUp = new PopUpWidget(boss, prefix + "auSampleRatePopup", "Output rate:"); diff --git a/gui/options.h b/gui/options.h index aca5db83cd..53fc5e2d01 100644 --- a/gui/options.h +++ b/gui/options.h @@ -101,6 +101,7 @@ private: // bool _enableAudioSettings; PopUpWidget *_midiPopUp; + PopUpWidget *_oplPopUp; PopUpWidget *_outputRatePopUp; // diff --git a/gui/themes/default.inc b/gui/themes/default.inc index d5fcd8e6eb..ddb8127d77 100644 --- a/gui/themes/default.inc +++ b/gui/themes/default.inc @@ -475,6 +475,9 @@ " " +" " " " @@ -1115,6 +1118,9 @@ " " +" " " " diff --git a/gui/themes/scummclassic.zip b/gui/themes/scummclassic.zip index ad886efd12..798f4d292f 100644 Binary files a/gui/themes/scummclassic.zip and b/gui/themes/scummclassic.zip differ diff --git a/gui/themes/scummclassic/classic_layout.stx b/gui/themes/scummclassic/classic_layout.stx index 4d7698f306..bb7fdc20a2 100644 --- a/gui/themes/scummclassic/classic_layout.stx +++ b/gui/themes/scummclassic/classic_layout.stx @@ -186,6 +186,9 @@ + diff --git a/gui/themes/scummclassic/classic_layout_lowres.stx b/gui/themes/scummclassic/classic_layout_lowres.stx index 33401966c4..c144f0bad3 100644 --- a/gui/themes/scummclassic/classic_layout_lowres.stx +++ b/gui/themes/scummclassic/classic_layout_lowres.stx @@ -183,6 +183,9 @@ + diff --git a/gui/themes/scummmodern.zip b/gui/themes/scummmodern.zip index eb0f890f15..a67b11f244 100644 Binary files a/gui/themes/scummmodern.zip and b/gui/themes/scummmodern.zip differ diff --git a/gui/themes/scummmodern/scummmodern_layout.stx b/gui/themes/scummmodern/scummmodern_layout.stx index 6377cc48ae..736fce87f2 100644 --- a/gui/themes/scummmodern/scummmodern_layout.stx +++ b/gui/themes/scummmodern/scummmodern_layout.stx @@ -201,6 +201,9 @@ + diff --git a/gui/themes/scummmodern/scummmodern_layout_lowres.stx b/gui/themes/scummmodern/scummmodern_layout_lowres.stx index 36ed3f25fa..bf19b48485 100644 --- a/gui/themes/scummmodern/scummmodern_layout_lowres.stx +++ b/gui/themes/scummmodern/scummmodern_layout_lowres.stx @@ -181,6 +181,9 @@ + diff --git a/sound/fmopl.cpp b/sound/fmopl.cpp index eb84d37366..f0f7327fd4 100644 --- a/sound/fmopl.cpp +++ b/sound/fmopl.cpp @@ -27,27 +27,101 @@ #include "sound/softsynth/opl/dosbox.h" #include "sound/softsynth/opl/mame.h" +#include "common/config-manager.h" + namespace OPL { -bool OPL::_hasInstance = false; +// Config implementation -OPL *OPL::create(kOplType type) { - // Simple hack to assure we only create one instance, - // since the DOSBox OPL emulator does not allow more than - // one instance. - assert(!_hasInstance); - _hasInstance = true; +enum OplEmulator { + kMame = 0, + kDOSBox = 1 +}; -#ifdef DISABLE_DOSBOX_OPL - if (type != kOpl2) - return 0; - else - return new MAME::OPL(); -#else - return new DOSBox::OPL(type); +const Config::EmulatorDescription Config::_drivers[] = { + { "auto", "", 0, kFlagOpl2 | kFlagDualOpl2 | kFlagOpl3 }, + { "mame", "MAME OPL emulator", kMame, kFlagOpl2 }, +#ifndef DISABLE_DOSBOX_OPL + { "db", "DOSBox OPL emulator (experimental)", kDOSBox, kFlagOpl2 | kFlagDualOpl2 | kFlagOpl3 }, #endif + { 0, 0, 0, 0 } +}; + +Config::DriverId Config::parse(const Common::String &name) { + for (int i = 0; _drivers[i].name; ++i) { + if (name.equalsIgnoreCase(_drivers[i].name)) + return _drivers[i].id; + } + + return 0; } +Config::DriverId Config::detect(OplType type) { + uint32 flags = 0; + switch (type) { + case kOpl2: + flags = kFlagOpl2; + break; + + case kDualOpl2: + flags = kFlagDualOpl2; + break; + + case kOpl3: + flags = kFlagOpl3; + break; + } + + DriverId drv = parse(ConfMan.get("opl_driver")); + + // When a valid driver is selected, check whether it supports + // the requested OPL chip. + if (validDriver(drv)) { + // If the chip is supported, just use the driver. + if ((flags & _drivers[drv].flags)) + return drv; + + // When it doesn't support the flags fall back to auto detection + } + + // Detect the first matching emulator + for (int i = 1; _drivers[i].name; ++i) { + if (_drivers[i].flags & flags) { + drv = _drivers[i].id; + break; + } + } + + return drv; +} + +OPL *Config::create(DriverId driver, OplType type) { + if (!validDriver(driver)) + driver = detect(type); + + switch (driver) { + case kMame: + if (type == kOpl2) + return new MAME::OPL(); + else + warning("MAME OPL emulator only supports OPL2 emulation."); + return 0; + +#ifndef DISABLE_DOSBOX_OPL + case kDOSBox: + return new DOSBox::OPL(type); +#endif + + default: + warning("Unsupported OPL emulator %d", driver); + // TODO: Maybe we should add some dummy emulator too, which just outputs + // silence as sound? + return 0; + } +} + +bool OPL::_hasInstance = false; + } // end of namespace OPL void OPLDestroy(FM_OPL *OPL) { @@ -75,7 +149,7 @@ void YM3812UpdateOne(FM_OPL *OPL, int16 *buffer, int length) { } FM_OPL *makeAdlibOPL(int rate) { - FM_OPL *opl = OPL::OPL::create(OPL::OPL::kOpl2); + FM_OPL *opl = OPL::Config::create(OPL::Config::kOpl2); if (opl) { if (!opl->init(rate)) { diff --git a/sound/fmopl.h b/sound/fmopl.h index 7713f76e6a..d84b62f693 100644 --- a/sound/fmopl.h +++ b/sound/fmopl.h @@ -26,25 +26,81 @@ #define SOUND_FMOPL_H #include "common/scummsys.h" +#include "common/str.h" namespace OPL { -class OPL { -private: - // TODO: This is part of a temporary HACK to allow only 1 instance - static bool _hasInstance; +class OPL; + +class Config { public: - virtual ~OPL() { _hasInstance = false; } + enum OplFlags { + kFlagOpl2 = (1 << 0), + kFlagDualOpl2 = (1 << 1), + kFlagOpl3 = (1 << 2) + }; /** * OPL type to emulate. */ - enum kOplType { + enum OplType { kOpl2, kDualOpl2, kOpl3 }; + typedef int8 DriverId; + struct EmulatorDescription { + const char *name; + const char *description; + + DriverId id; // A unique ID for each driver + uint32 flags; // Capabilities of this driver + }; + + /** + * Get a list of all available OPL emulators. + * @return list of all available OPL emulators, terminated by a zero entry + */ + static const EmulatorDescription *getAvailable() { return _drivers; } + + /** + * Returns the driver id of a given name. + */ + static DriverId parse(const Common::String &name); + + /** + * Detects a driver for the specific type. + */ + static DriverId detect(OplType type = kOpl2); + + /** + * Checks whether the driver id is valid. + */ + static bool validDriver(DriverId id) { return (id > 0); } + + /** + * Creates the specific driver with a specific type setup. + */ + static OPL *create(DriverId driver, OplType type); + + /** + * Wrapper to easily init an OPL chip, without specifing an emulator. + */ + static OPL *create(OplType type) { return create(detect(type), type); } + +private: + static const EmulatorDescription _drivers[]; +}; + +class OPL { +private: + // TODO: This is part of a temporary HACK to allow only 1 instance + static bool _hasInstance; +public: + OPL() { _hasInstance = true; } + virtual ~OPL() { _hasInstance = false; } + /** * Initializes the OPL emulator. * @@ -99,8 +155,6 @@ public: * Returns whether the setup OPL mode is stereo or not */ virtual bool isStereo() const = 0; - - static OPL *create(kOplType type); }; } // end of namespace OPL diff --git a/sound/softsynth/opl/dosbox.cpp b/sound/softsynth/opl/dosbox.cpp index db8f8109d7..cbb3090608 100644 --- a/sound/softsynth/opl/dosbox.cpp +++ b/sound/softsynth/opl/dosbox.cpp @@ -190,7 +190,7 @@ struct Handler : public DOSBox::Handler { }; } // end of namespace OPL3 -OPL::OPL(kOplType type) : _type(type), _rate(0), _handler(0) { +OPL::OPL(Config::OplType type) : _type(type), _rate(0), _handler(0) { } OPL::~OPL() { @@ -209,12 +209,12 @@ bool OPL::init(int rate) { memset(_chip, 0, sizeof(_chip)); switch (_type) { - case kOpl2: + case Config::kOpl2: _handler = new OPL2::Handler(); break; - case kDualOpl2: - case kOpl3: + case Config::kDualOpl2: + case Config::kOpl3: _handler = new OPL3::Handler(); break; @@ -224,7 +224,7 @@ bool OPL::init(int rate) { _handler->init(rate); - if (_type == kDualOpl2) { + if (_type == Config::kDualOpl2) { // Setup opl3 mode in the hander _handler->writeReg(0x105, 1); } @@ -240,12 +240,12 @@ void OPL::reset() { void OPL::write(int port, int val) { if (port&1) { switch (_type) { - case kOpl2: - case kOpl3: + case Config::kOpl2: + case Config::kOpl3: if (!_chip[0].write(_reg.normal, val)) _handler->writeReg(_reg.normal, val); break; - case kDualOpl2: + case Config::kDualOpl2: // Not a 0x??8 port, then write to a specific port if (!(port & 0x8)) { byte index = (port & 2) >> 1; @@ -261,13 +261,13 @@ void OPL::write(int port, int val) { // Ask the handler to write the address // Make sure to clip them in the right range switch (_type) { - case kOpl2: + case Config::kOpl2: _reg.normal = _handler->writeAddr(port, val) & 0xff; break; - case kOpl3: + case Config::kOpl3: _reg.normal = _handler->writeAddr(port, val) & 0x1ff; break; - case kDualOpl2: + case Config::kDualOpl2: // Not a 0x?88 port, when write to a specific side if (!(port & 0x8)) { byte index = (port & 2) >> 1; @@ -283,16 +283,16 @@ void OPL::write(int port, int val) { byte OPL::read(int port) { switch (_type) { - case kOpl2: + case Config::kOpl2: if (!(port & 1)) //Make sure the low bits are 6 on opl2 return _chip[0].read() | 0x6; break; - case kOpl3: + case Config::kOpl3: if (!(port & 1)) return _chip[0].read(); break; - case kDualOpl2: + case Config::kDualOpl2: // Only return for the lower ports if (port & 1) return 0xff; @@ -305,9 +305,9 @@ byte OPL::read(int port) { void OPL::writeReg(int r, int v) { byte tempReg = 0; switch (_type) { - case kOpl2: - case kDualOpl2: - case kOpl3: + case Config::kOpl2: + case Config::kDualOpl2: + case Config::kOpl3: // We can't use _handler->writeReg here directly, since it would miss timer changes. // Backup old setup register @@ -350,7 +350,7 @@ void OPL::dualWrite(uint8 index, uint8 reg, uint8 val) { void OPL::readBuffer(int16 *buffer, int length) { // For stereo OPL cards, we divide the sample count by 2, // to match stereo AudioStream behavior. - if (_type != kOpl2) + if (_type != Config::kOpl2) length >>= 1; _handler->generate(buffer, length); diff --git a/sound/softsynth/opl/dosbox.h b/sound/softsynth/opl/dosbox.h index 68a53276f0..488cc3d82a 100644 --- a/sound/softsynth/opl/dosbox.h +++ b/sound/softsynth/opl/dosbox.h @@ -85,7 +85,7 @@ public: class OPL : public ::OPL::OPL { private: - kOplType _type; + Config::OplType _type; uint _rate; Handler *_handler; @@ -98,7 +98,7 @@ private: void free(); void dualWrite(uint8 index, uint8 reg, uint8 val); public: - OPL(kOplType type); + OPL(Config::OplType type); ~OPL(); bool init(int rate); @@ -110,7 +110,7 @@ public: void writeReg(int r, int v); void readBuffer(int16 *buffer, int length); - bool isStereo() const { return _type != kOpl2; } + bool isStereo() const { return _type != Config::kOpl2; } }; } // end of namespace DOSBox -- cgit v1.2.3