diff options
author | athrxx | 2018-12-04 17:49:15 +0100 |
---|---|---|
committer | athrxx | 2019-03-07 19:43:44 +0100 |
commit | 20b378a41a194bd0869bfc2bb16b9a6897bd8bd2 (patch) | |
tree | 78cd4b25468e7aa1103e7ae0c81d91398c38e085 /audio/softsynth/fmtowns_pc98/pc98_audio.cpp | |
parent | 82a821bf7f25716a124b2d14b26c9c8a28b74e6e (diff) | |
download | scummvm-rg350-20b378a41a194bd0869bfc2bb16b9a6897bd8bd2.tar.gz scummvm-rg350-20b378a41a194bd0869bfc2bb16b9a6897bd8bd2.tar.bz2 scummvm-rg350-20b378a41a194bd0869bfc2bb16b9a6897bd8bd2.zip |
AUDIO: (FM-TOWNS/PC-98) - cleanup
Apart from some basic cleanup this commit reverts a somewhat unfortunate design decision I made. The Kyra/Hof/Lol PC-98 sound drivers shouldn't inherit from the emulator. This commit separates the driver from the emulator putting some common interface in between. This should allow easier implementation of other PC-98 sound drivers.
Diffstat (limited to 'audio/softsynth/fmtowns_pc98/pc98_audio.cpp')
-rw-r--r-- | audio/softsynth/fmtowns_pc98/pc98_audio.cpp | 290 |
1 files changed, 290 insertions, 0 deletions
diff --git a/audio/softsynth/fmtowns_pc98/pc98_audio.cpp b/audio/softsynth/fmtowns_pc98/pc98_audio.cpp new file mode 100644 index 0000000000..d6c6fc94e3 --- /dev/null +++ b/audio/softsynth/fmtowns_pc98/pc98_audio.cpp @@ -0,0 +1,290 @@ +/* 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. + * + */ + +#include "audio/softsynth/fmtowns_pc98/pc98_audio.h" +#include "audio/softsynth/fmtowns_pc98/towns_pc98_fmsynth.h" +#include "common/mutex.h" + +class PC98AudioCoreInternal : public TownsPC98_FmSynth { +private: + PC98AudioCoreInternal(Audio::Mixer *mixer, PC98AudioCore *owner, PC98AudioPluginDriver *driver, PC98AudioPluginDriver::EmuType type, bool externalMutexHandling = false); +public: + ~PC98AudioCoreInternal(); + + static PC98AudioCoreInternal *addNewRef(Audio::Mixer *mixer, PC98AudioCore *owner, PC98AudioPluginDriver *driver, PC98AudioPluginDriver::EmuType type, bool externalMutexHandling = false); + static void releaseRef(PC98AudioCore *owner); + + bool init(); + + void writePort(uint16 port, uint8 value); + uint8 readPort(uint16 port); + + void setMusicVolume(int volume); + void setSoundEffectVolume(int volume); + // Defines the channels used as sound effect channels for the purpose of ScummVM GUI volume control. + // The first 6 bits are 6 fm channels. The next 3 bits are ssg channels. The next bit is the rhythm channel. + void setSoundEffectChanMask(int mask); + + void ssgSetVolume(int volume); + + Common::Mutex &mutex(); + +private: + bool assignPluginDriver(PC98AudioCore *owner, PC98AudioPluginDriver *driver, bool externalMutexHandling = false); + void removePluginDriver(PC98AudioCore *owner); + + void timerCallbackA(); + void timerCallbackB(); + + uint16 _musicVolume; + uint16 _sfxVolume; + + const uint16 _port1, _port2, _port3, _port4; + uint8 _address[2]; + + uint16 _frequency; + + PC98AudioPluginDriver *_drv; + void *_drvOwner; + bool _ready; + + static PC98AudioCoreInternal *_refInstance; + static int _refCount; +}; + +PC98AudioCoreInternal::PC98AudioCoreInternal(Audio::Mixer *mixer, PC98AudioCore *owner, PC98AudioPluginDriver *driver, PC98AudioPluginDriver::EmuType type, bool externalMutexHandling) : + TownsPC98_FmSynth(mixer, (TownsPC98_FmSynth::EmuType)type, externalMutexHandling), + _drv(driver), _drvOwner(owner), + _musicVolume(Audio::Mixer::kMaxMixerVolume), _sfxVolume(Audio::Mixer::kMaxMixerVolume), + _port1(type == PC98AudioPluginDriver::kTypeTowns ? 0x4D8 : 0x188), _port2(type == PC98AudioPluginDriver::kTypeTowns ? 0x4DA : 0x18A), + _port3(type == PC98AudioPluginDriver::kTypeTowns ? 0x4DC : 0x18C), _port4(type == PC98AudioPluginDriver::kTypeTowns ? 0x4DE : 0x18E), + _frequency(0), _ready(false) { + _address[0] = _address[1] = 0xFF; +} + +PC98AudioCoreInternal::~PC98AudioCoreInternal() { + _ready = false; + deinit(); + + Common::StackLock lock(_mutex); + /* + + */ +} + +PC98AudioCoreInternal *PC98AudioCoreInternal::addNewRef(Audio::Mixer *mixer, PC98AudioCore *owner, PC98AudioPluginDriver *driver, PC98AudioPluginDriver::EmuType type, bool externalMutexHandling) { + _refCount++; + if (_refCount == 1 && _refInstance == 0) + _refInstance = new PC98AudioCoreInternal(mixer, owner, driver, type, externalMutexHandling); + else if (_refCount < 2 || _refInstance == 0) + error("PC98AudioCoreInternal::addNewRef(): Internal reference management failure"); + else if (!_refInstance->assignPluginDriver(owner, driver, externalMutexHandling)) + error("PC98AudioCoreInternal::addNewRef(): Plugin driver conflict"); + + return _refInstance; +} + +void PC98AudioCoreInternal::releaseRef(PC98AudioCore *owner) { + if (!_refCount) + return; + + _refCount--; + + if (_refCount) { + if (_refInstance) + _refInstance->removePluginDriver(owner); + } else { + delete _refInstance; + _refInstance = 0; + } +} + +bool PC98AudioCoreInternal::init() { + if (_ready) + return true; + + if (!TownsPC98_FmSynth::init()) + return false; + + reset(); + + writeReg(0, 0x26, 0xDD); + writeReg(0, 0x25, 0x01); + writeReg(0, 0x24, 0x00); + writeReg(0, 0x27, 0x30); + + setVolumeChannelMasks(-1, 0); + ssgSetVolume(0x60); + + _ready = true; + + return true; +} + +void PC98AudioCoreInternal::writePort(uint16 port, uint8 value) { + if (port == _port1) + _address[0] = value; + else if (port == _port2 && _address[0] < 0xc0) { + writeReg(0, _address[0], value); + _address[0] = 0xFF; + } else if (port == _port3) + _address[1] = value; + else if (port == _port4 && _address[1] < 0xc0) { + writeReg(1, _address[1], value); + _address[1] = 0xFF; + } +} + +uint8 PC98AudioCoreInternal::readPort(uint16 port) { + uint8 val = 0; + if (port == _port2 && _address[0] < 0xc0) { + val = readReg(0, _address[0]); + _address[0] = 0xFF; + } else if (port == _port4 && _address[1] < 0xc0) { + val = readReg(1, _address[1]); + _address[1] = 0xFF; + } + return val; +} + +void PC98AudioCoreInternal::setMusicVolume(int volume) { + _musicVolume = CLIP<uint16>(volume, 0, Audio::Mixer::kMaxMixerVolume); + setVolumeIntern(_musicVolume, _sfxVolume); +} + +void PC98AudioCoreInternal::setSoundEffectVolume(int volume) { + _sfxVolume = CLIP<uint16>(volume, 0, Audio::Mixer::kMaxMixerVolume); + setVolumeIntern(_musicVolume, _sfxVolume); +} + +void PC98AudioCoreInternal::setSoundEffectChanMask(int mask) { + setVolumeChannelMasks(~mask, mask); +} + +void PC98AudioCoreInternal::ssgSetVolume(int volume) { + setLevelSSG(volume); +} + +Common::Mutex &PC98AudioCoreInternal::mutex() { + return _mutex; +} + +bool PC98AudioCoreInternal::assignPluginDriver(PC98AudioCore *owner, PC98AudioPluginDriver *driver, bool externalMutexHandling) { + if (_refCount <= 1) + return true; + + if (_drv) { + if (driver && driver != _drv) + return false; + } else { + Common::StackLock lock(_mutex); + _drv = driver; + _drvOwner = owner; + _externalMutex = externalMutexHandling; + } + + return true; +} + +void PC98AudioCoreInternal::removePluginDriver(PC98AudioCore *owner) { + if (_drvOwner == owner) { + Common::StackLock lock(_mutex); + _drv = 0; + } +} + +void PC98AudioCoreInternal::timerCallbackA() { + if (_drv && _ready) + _drv->timerCallbackA(); +} + +void PC98AudioCoreInternal::timerCallbackB() { + if (_drv && _ready) + _drv->timerCallbackB(); +} + +PC98AudioCoreInternal *PC98AudioCoreInternal::_refInstance = 0; + +int PC98AudioCoreInternal::_refCount = 0; + +PC98AudioCore::PC98AudioCore(Audio::Mixer *mixer, PC98AudioPluginDriver *driver, PC98AudioPluginDriver::EmuType type, bool externalMutexHandling) { + _internal = PC98AudioCoreInternal::addNewRef(mixer, this, driver, type, externalMutexHandling); +} + +PC98AudioCore::~PC98AudioCore() { + PC98AudioCoreInternal::releaseRef(this); + _internal = 0; +} + +bool PC98AudioCore::init() { + return _internal->init(); +} + +void PC98AudioCore::reset() { + _internal->reset(); +} + +void PC98AudioCore::writeReg(uint8 part, uint8 regAddress, uint8 value) { + _internal->writeReg(part, regAddress, value); +} + +uint8 PC98AudioCore::readReg(uint8 part, uint8 regAddress) { + return _internal->readReg(part, regAddress); +} + +void PC98AudioCore::writePort(uint16 port, uint8 value) { + _internal->writePort(port, value); +} + +uint8 PC98AudioCore::readPort(uint16 port) { + return _internal->readPort(port); +} + +void PC98AudioCore::setMusicVolume(int volume) { + _internal->setMusicVolume(volume); +} + +void PC98AudioCore::setSoundEffectVolume(int volume) { + _internal->setSoundEffectVolume(volume); +} + +void PC98AudioCore::setSoundEffectChanMask(int mask) { + _internal->setSoundEffectChanMask(mask); +} + +void PC98AudioCore::ssgSetVolume(int volume) { + _internal->ssgSetVolume(volume); +} + +PC98AudioCore::MutexLock PC98AudioCore::stackLockMutex() { + return MutexLock(_internal); +} + +PC98AudioCore::MutexLock::MutexLock(PC98AudioCoreInternal *pc98int) : _pc98int(pc98int) { + if (_pc98int) + _pc98int->mutex().lock(); +} + +PC98AudioCore::MutexLock::~MutexLock() { + if (_pc98int) + _pc98int->mutex().unlock(); +}
\ No newline at end of file |