aboutsummaryrefslogtreecommitdiff
path: root/audio/softsynth/fmtowns_pc98/pc98_audio.cpp
diff options
context:
space:
mode:
authorathrxx2018-12-04 17:49:15 +0100
committerathrxx2019-03-07 19:43:44 +0100
commit20b378a41a194bd0869bfc2bb16b9a6897bd8bd2 (patch)
tree78cd4b25468e7aa1103e7ae0c81d91398c38e085 /audio/softsynth/fmtowns_pc98/pc98_audio.cpp
parent82a821bf7f25716a124b2d14b26c9c8a28b74e6e (diff)
downloadscummvm-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.cpp290
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