[Scummvm-git-logs] scummvm master -> 8d4418fa365511e8d598823e4369cdc10f87f6b8
athrxx
athrxx at scummvm.org
Thu Mar 7 22:32:40 CET 2019
This automated email contains information about 6 new commits which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .
Summary:
20b378a41a AUDIO: (FM-TOWNS/PC-98) - cleanup
4a226aa835 AUDIO: (FM-TOWNS/PC-98) - more cleanup
b789d50a55 AUDIO: (FM-TOWNS/PC-98) - fix valgrind warning
49e85f64cf AUDIO: (FM-TOWNS/PC-98) - allow individual operator frequencies
1237eb496b AUDIO: (FM-TOWNS/PC-98) - initialize some uninitialized vars
8d4418fa36 AUDIO: (FM-TOWNS) - cleanup
Commit: 20b378a41a194bd0869bfc2bb16b9a6897bd8bd2
https://github.com/scummvm/scummvm/commit/20b378a41a194bd0869bfc2bb16b9a6897bd8bd2
Author: athrxx (athrxx at scummvm.org)
Date: 2019-03-07T19:43:44+01:00
Commit Message:
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.
Changed paths:
A audio/softsynth/fmtowns_pc98/pc98_audio.cpp
A audio/softsynth/fmtowns_pc98/pc98_audio.h
audio/module.mk
audio/softsynth/fmtowns_pc98/towns_pc98_driver.cpp
audio/softsynth/fmtowns_pc98/towns_pc98_driver.h
audio/softsynth/fmtowns_pc98/towns_pc98_fmsynth.cpp
audio/softsynth/fmtowns_pc98/towns_pc98_fmsynth.h
diff --git a/audio/module.mk b/audio/module.mk
index 0add7cf..686c70b 100644
--- a/audio/module.mk
+++ b/audio/module.mk
@@ -46,6 +46,7 @@ MODULE_OBJS := \
softsynth/opl/dbopl.o \
softsynth/opl/dosbox.o \
softsynth/opl/mame.o \
+ softsynth/fmtowns_pc98/pc98_audio.o \
softsynth/fmtowns_pc98/towns_audio.o \
softsynth/fmtowns_pc98/towns_euphony.o \
softsynth/fmtowns_pc98/towns_midi.o \
diff --git a/audio/softsynth/fmtowns_pc98/pc98_audio.cpp b/audio/softsynth/fmtowns_pc98/pc98_audio.cpp
new file mode 100644
index 0000000..d6c6fc9
--- /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
diff --git a/audio/softsynth/fmtowns_pc98/pc98_audio.h b/audio/softsynth/fmtowns_pc98/pc98_audio.h
new file mode 100644
index 0000000..b6269f0
--- /dev/null
+++ b/audio/softsynth/fmtowns_pc98/pc98_audio.h
@@ -0,0 +1,84 @@
+/* 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.
+ *
+ */
+
+#ifndef PC98_AUDIO_H
+#define PC98_AUDIO_H
+
+#include "common/scummsys.h"
+
+namespace Audio {
+class Mixer;
+}
+
+class PC98AudioCoreInternal;
+class PC98AudioPluginDriver {
+public:
+ enum EmuType {
+ kTypeTowns,
+ kType26,
+ kType86
+ };
+
+ virtual ~PC98AudioPluginDriver() {}
+ virtual void timerCallbackA() {}
+ virtual void timerCallbackB() {}
+};
+
+class PC98AudioCore {
+public:
+ PC98AudioCore(Audio::Mixer *mixer, PC98AudioPluginDriver *driver, PC98AudioPluginDriver::EmuType type, bool externalMutexHandling = false);
+ ~PC98AudioCore();
+
+ bool init();
+ void reset();
+
+ void writeReg(uint8 part, uint8 regAddress, uint8 value);
+ uint8 readReg(uint8 part, uint8 regAddress);
+
+ 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 the 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);
+
+ class MutexLock {
+ friend class PC98AudioCore;
+ public:
+ ~MutexLock();
+ private:
+ MutexLock(PC98AudioCoreInternal *pc98int);
+ PC98AudioCoreInternal *_pc98int;
+ };
+
+ MutexLock stackLockMutex();
+
+private:
+ PC98AudioCoreInternal *_internal;
+};
+
+#endif
diff --git a/audio/softsynth/fmtowns_pc98/towns_pc98_driver.cpp b/audio/softsynth/fmtowns_pc98/towns_pc98_driver.cpp
index 6a49278..091905b 100644
--- a/audio/softsynth/fmtowns_pc98/towns_pc98_driver.cpp
+++ b/audio/softsynth/fmtowns_pc98/towns_pc98_driver.cpp
@@ -615,7 +615,7 @@ void TownsPC98_MusicChannelSSG::processEvents() {
if (_flags & CHS_EOT)
return;
- _drv->toggleRegProtection(_flags & CHS_PROTECT ? true : false);
+ _drv->preventRegisterWrite(_flags & CHS_PROTECT ? true : false);
if (!_hold && _ticksLeft == _keyOffTime)
nextShape();
@@ -750,7 +750,7 @@ void TownsPC98_MusicChannelSSG::keyOn() {
if (!(_algorithm & 0x80))
_drv->writeReg(_part, 6, _algorithm & 0x7f);
- uint8 e = (_drv->readSSGStatus() & c) | t;
+ uint8 e = (_drv->_pc98a->readReg(0, 7) & c) | t;
_drv->writeReg(_part, 7, e);
}
@@ -768,7 +768,7 @@ void TownsPC98_MusicChannelSSG::restore() {
}
void TownsPC98_MusicChannelSSG::loadData(uint8 *data) {
- _drv->toggleRegProtection(_flags & CHS_PROTECT ? true : false);
+ _drv->preventRegisterWrite(_flags & CHS_PROTECT ? true : false);
TownsPC98_MusicChannel::loadData(data);
setOutputLevel(0);
_algorithm = 0x80;
@@ -1017,7 +1017,7 @@ bool TownsPC98_MusicChannelPCM::control_ff_endOfTrack(uint8 para) {
}
#endif // DISABLE_PC98_RHYTHM_CHANNEL
-TownsPC98_AudioDriver::TownsPC98_AudioDriver(Audio::Mixer *mixer, EmuType type) : TownsPC98_FmSynth(mixer, type),
+TownsPC98_AudioDriver::TownsPC98_AudioDriver(Audio::Mixer *mixer, EmuType type) :
_channels(0), _ssgChannels(0), _sfxChannels(0),
#ifndef DISABLE_PC98_RHYTHM_CHANNEL
_rhythmChannel(0),
@@ -1036,32 +1036,27 @@ TownsPC98_AudioDriver::TownsPC98_AudioDriver(Audio::Mixer *mixer, EmuType type)
#else
0x00
#endif
- : 0x00), _finishedRhythmFlag(0),
- _updateSfxFlag(0), _finishedSfxFlag(0),
-
- _musicTickCounter(0),
-
- _musicVolume(255), _sfxVolume(255),
-
+ : 0x00),
+ _numChanFM(type == kType26 ? 3 : 6), _numChanSSG(type == kTypeTowns ? 0 : 3), _numChanRHY(type == kType86 ? 1 : 0),
+ _finishedRhythmFlag(0), _updateSfxFlag(0), _finishedSfxFlag(0),
+ _musicTickCounter(0), _regWriteProtect(false),
_musicPlaying(false), _sfxPlaying(false), _fading(false), _looping(0), _ready(false) {
-
_sfxOffsets[0] = _sfxOffsets[1] = 0;
+ _pc98a = new PC98AudioCore(mixer, this, type);
}
TownsPC98_AudioDriver::~TownsPC98_AudioDriver() {
_ready = false;
- deinit();
-
- Common::StackLock lock(_mutex);
+ delete _pc98a;
if (_channels) {
- for (int i = 0; i < _numChan; i++)
+ for (int i = 0; i < _numChanFM; i++)
delete _channels[i];
delete[] _channels;
}
if (_ssgChannels) {
- for (int i = 0; i < _numSSG; i++)
+ for (int i = 0; i < _numChanSSG; i++)
delete _ssgChannels[i];
delete[] _ssgChannels;
}
@@ -1084,24 +1079,25 @@ bool TownsPC98_AudioDriver::init() {
return true;
}
- TownsPC98_FmSynth::init();
+ if (!_pc98a->init())
+ return false;
- setVolumeChannelMasks(-1, 0);
+ _pc98a->setSoundEffectChanMask(0);
- _channels = new TownsPC98_MusicChannel *[_numChan];
- for (int i = 0; i < _numChan; i++) {
+ _channels = new TownsPC98_MusicChannel *[_numChanFM];
+ for (int i = 0; i < _numChanFM; i++) {
int ii = i * 6;
_channels[i] = new TownsPC98_MusicChannel(this, _drvTables[ii], _drvTables[ii + 1],
_drvTables[ii + 2], _drvTables[ii + 3], _drvTables[ii + 4], _drvTables[ii + 5]);
_channels[i]->init();
}
- if (_numSSG) {
+ if (_numChanSSG) {
_ssgPatches = new uint8[256];
memcpy(_ssgPatches, _drvTables + 156, 256);
- _ssgChannels = new TownsPC98_MusicChannelSSG *[_numSSG];
- for (int i = 0; i < _numSSG; i++) {
+ _ssgChannels = new TownsPC98_MusicChannelSSG *[_numChanSSG];
+ for (int i = 0; i < _numChanSSG; i++) {
int ii = i * 6;
_ssgChannels[i] = new TownsPC98_MusicChannelSSG(this, _drvTables[ii], _drvTables[ii + 1],
_drvTables[ii + 2], _drvTables[ii + 3], _drvTables[ii + 4], _drvTables[ii + 5]);
@@ -1118,7 +1114,7 @@ bool TownsPC98_AudioDriver::init() {
}
#ifndef DISABLE_PC98_RHYTHM_CHANNEL
- if (_hasPercussion) {
+ if (_numChanRHY) {
_rhythmChannel = new TownsPC98_MusicChannelPCM(this, 0, 0, 0, 0, 0, 1);
_rhythmChannel->init();
}
@@ -1145,7 +1141,7 @@ void TownsPC98_AudioDriver::loadMusicData(uint8 *data, bool loadPaused) {
reset();
- Common::StackLock lock(_mutex);
+ PC98AudioCore::MutexLock lock = _pc98a->stackLockMutex();
uint8 *src_a = _trackPtr = _musicBuffer = data;
for (uint8 i = 0; i < 3; i++) {
@@ -1153,24 +1149,24 @@ void TownsPC98_AudioDriver::loadMusicData(uint8 *data, bool loadPaused) {
src_a += 2;
}
- for (int i = 0; i < _numSSG; i++) {
+ for (int i = 0; i < _numChanSSG; i++) {
_ssgChannels[i]->loadData(data + READ_LE_UINT16(src_a));
src_a += 2;
}
- for (uint8 i = 3; i < _numChan; i++) {
+ for (uint8 i = 3; i < _numChanFM; i++) {
_channels[i]->loadData(data + READ_LE_UINT16(src_a));
src_a += 2;
}
- if (_hasPercussion) {
+ if (_numChanRHY) {
#ifndef DISABLE_PC98_RHYTHM_CHANNEL
_rhythmChannel->loadData(data + READ_LE_UINT16(src_a));
#endif
src_a += 2;
}
- toggleRegProtection(false);
+ preventRegisterWrite(false);
_patches = src_a + 4;
_finishedChannelsFlag = _finishedSSGFlag = _finishedRhythmFlag = 0;
@@ -1194,7 +1190,7 @@ void TownsPC98_AudioDriver::loadSoundEffectData(uint8 *data, uint8 trackNum) {
return;
}
- Common::StackLock lock(_mutex);
+ PC98AudioCore::MutexLock lock = _pc98a->stackLockMutex();
_sfxData = _sfxBuffer = data;
_sfxOffsets[0] = READ_LE_UINT16(&_sfxData[(trackNum << 2)]);
_sfxOffsets[1] = READ_LE_UINT16(&_sfxData[(trackNum << 2) + 2]);
@@ -1203,7 +1199,7 @@ void TownsPC98_AudioDriver::loadSoundEffectData(uint8 *data, uint8 trackNum) {
}
void TownsPC98_AudioDriver::reset() {
- Common::StackLock lock(_mutex);
+ PC98AudioCore::MutexLock lock = _pc98a->stackLockMutex();
_musicPlaying = false;
_sfxPlaying = false;
@@ -1212,14 +1208,14 @@ void TownsPC98_AudioDriver::reset() {
_musicTickCounter = 0;
_sfxData = 0;
- TownsPC98_FmSynth::reset();
+ _pc98a->reset();
- for (int i = 0; i < _numChan; i++)
+ for (int i = 0; i < _numChanFM; i++)
_channels[i]->reset();
- for (int i = 0; i < _numSSG; i++)
+ for (int i = 0; i < _numChanSSG; i++)
_ssgChannels[i]->reset();
- if (_numSSG) {
+ if (_numChanSSG) {
for (int i = 0; i < 2; i++)
_sfxChannels[i]->reset();
@@ -1236,12 +1232,12 @@ void TownsPC98_AudioDriver::fadeStep() {
if (!_musicPlaying)
return;
- for (int j = 0; j < _numChan; j++) {
+ for (int j = 0; j < _numChanFM; j++) {
if (_updateChannelsFlag & _channels[j]->_idFlag)
_channels[j]->fadeStep();
}
- for (int j = 0; j < _numSSG; j++) {
+ for (int j = 0; j < _numChanSSG; j++) {
if (_updateSSGFlag & _ssgChannels[j]->_idFlag)
_ssgChannels[j]->fadeStep();
}
@@ -1249,7 +1245,7 @@ void TownsPC98_AudioDriver::fadeStep() {
if (!_fading) {
_fading = 19;
#ifndef DISABLE_PC98_RHYTHM_CHANNEL
- if (_hasPercussion) {
+ if (_numChanRHY) {
if (_updateRhythmFlag & _rhythmChannel->_idFlag)
_rhythmChannel->reset();
}
@@ -1277,13 +1273,20 @@ bool TownsPC98_AudioDriver::musicPlaying() {
}
void TownsPC98_AudioDriver::setMusicVolume(int volume) {
- _musicVolume = volume;
- setVolumeIntern(_musicVolume, _sfxVolume);
+ _pc98a->setMusicVolume(volume);
}
void TownsPC98_AudioDriver::setSoundEffectVolume(int volume) {
- _sfxVolume = volume;
- setVolumeIntern(_musicVolume, _sfxVolume);
+ _pc98a->setSoundEffectVolume(volume);
+}
+
+void TownsPC98_AudioDriver::writeReg(uint8 part, uint8 reg, uint8 val) {
+ if (!_regWriteProtect)
+ _pc98a->writeReg(part, reg, val);
+}
+
+void TownsPC98_AudioDriver::preventRegisterWrite(bool prevent) {
+ _regWriteProtect = prevent;
}
void TownsPC98_AudioDriver::timerCallbackA() {
@@ -1307,7 +1310,7 @@ void TownsPC98_AudioDriver::timerCallbackA() {
if (_updateSfxFlag && _finishedSfxFlag == _updateSfxFlag) {
_sfxPlaying = false;
_updateSfxFlag = 0;
- setVolumeChannelMasks(-1, 0);
+ _pc98a->setSoundEffectChanMask(0);
}
}
@@ -1317,14 +1320,14 @@ void TownsPC98_AudioDriver::timerCallbackB() {
if (_musicPlaying) {
_musicTickCounter++;
- for (int i = 0; i < _numChan; i++) {
+ for (int i = 0; i < _numChanFM; i++) {
if (_updateChannelsFlag & _channels[i]->_idFlag) {
_channels[i]->processEvents();
_channels[i]->processFrequency();
}
}
- for (int i = 0; i < _numSSG; i++) {
+ for (int i = 0; i < _numChanSSG; i++) {
if (_updateSSGFlag & _ssgChannels[i]->_idFlag) {
_ssgChannels[i]->processEvents();
_ssgChannels[i]->processFrequency();
@@ -1332,13 +1335,13 @@ void TownsPC98_AudioDriver::timerCallbackB() {
}
#ifndef DISABLE_PC98_RHYTHM_CHANNEL
- if (_hasPercussion)
+ if (_numChanRHY)
if (_updateRhythmFlag & _rhythmChannel->_idFlag)
_rhythmChannel->processEvents();
#endif
}
- toggleRegProtection(false);
+ preventRegisterWrite(false);
if (_finishedChannelsFlag == _updateChannelsFlag && _finishedSSGFlag == _updateSSGFlag && _finishedRhythmFlag == _updateRhythmFlag)
_musicPlaying = false;
@@ -1353,14 +1356,14 @@ void TownsPC98_AudioDriver::startSoundEffect() {
_sfxChannels[i]->reset();
_sfxChannels[i]->loadData(_sfxData + _sfxOffsets[i]);
_updateSfxFlag |= _sfxChannels[i]->_idFlag;
- volFlags |= (_sfxChannels[i]->_idFlag << _numChan);
+ volFlags |= (_sfxChannels[i]->_idFlag << _numChanFM);
} else {
_ssgChannels[i + 1]->restore();
_updateSfxFlag &= ~_sfxChannels[i]->_idFlag;
}
}
- setVolumeChannelMasks(~volFlags, volFlags);
+ _pc98a->setSoundEffectChanMask(volFlags);
_sfxData = 0;
}
diff --git a/audio/softsynth/fmtowns_pc98/towns_pc98_driver.h b/audio/softsynth/fmtowns_pc98/towns_pc98_driver.h
index 918446f..0b9edcf 100644
--- a/audio/softsynth/fmtowns_pc98/towns_pc98_driver.h
+++ b/audio/softsynth/fmtowns_pc98/towns_pc98_driver.h
@@ -23,7 +23,7 @@
#ifndef TOWNS_PC98_AUDIODRIVER_H
#define TOWNS_PC98_AUDIODRIVER_H
-#include "audio/softsynth/fmtowns_pc98/towns_pc98_fmsynth.h"
+#include "audio/softsynth/fmtowns_pc98/pc98_audio.h"
class TownsPC98_MusicChannel;
class TownsPC98_MusicChannelSSG;
@@ -32,7 +32,7 @@ class TownsPC98_SfxChannel;
class TownsPC98_MusicChannelPCM;
#endif
-class TownsPC98_AudioDriver : public TownsPC98_FmSynth {
+class TownsPC98_AudioDriver : public PC98AudioPluginDriver {
friend class TownsPC98_MusicChannel;
friend class TownsPC98_MusicChannelSSG;
friend class TownsPC98_SfxChannel;
@@ -60,6 +60,9 @@ public:
void setSoundEffectVolume(int volume);
private:
+ void writeReg(uint8 part, uint8 reg, uint8 val);
+ void preventRegisterWrite(bool prevent);
+
void timerCallbackA();
void timerCallbackB();
@@ -106,8 +109,12 @@ private:
uint8 *_sfxData;
uint16 _sfxOffsets[2];
- uint16 _musicVolume;
- uint16 _sfxVolume;
+ bool _regWriteProtect;
+ PC98AudioCore *_pc98a;
+
+ const int _numChanFM;
+ const int _numChanSSG;
+ const int _numChanRHY;
static const uint8 _drvTables[];
diff --git a/audio/softsynth/fmtowns_pc98/towns_pc98_fmsynth.cpp b/audio/softsynth/fmtowns_pc98/towns_pc98_fmsynth.cpp
index 03c9679..b73030e 100644
--- a/audio/softsynth/fmtowns_pc98/towns_pc98_fmsynth.cpp
+++ b/audio/softsynth/fmtowns_pc98/towns_pc98_fmsynth.cpp
@@ -288,9 +288,9 @@ void TownsPC98_FmSynthOperator::decayRate(uint32 value) {
}
void TownsPC98_FmSynthOperator::sustainRate(uint32 value) {
- _specifiedSustainRate = value;
- recalculateRates();
- }
+ _specifiedSustainRate = value;
+ recalculateRates();
+}
void TownsPC98_FmSynthOperator::sustainLevel(uint32 value) {
_sustainLevel = (value == 0x0f) ? 0x3e0 : value << 5;
@@ -337,6 +337,7 @@ public:
void init(const int *rsTable, const int *rseTable);
void reset();
void writeReg(uint8 address, uint8 value, bool force = false);
+ uint8 readReg(uint8 address) const;
void nextTick(int32 *buffer, uint32 bufferSize);
@@ -348,10 +349,10 @@ public:
_volMaskA = channelMaskA;
_volMaskB = channelMaskB;
}
-
- uint8 chanEnable() const {
- return _chanEnable;
+ void setOutputLevel(int vol) {
+ _volumeT = vol;
}
+
private:
void updateRegs();
@@ -393,6 +394,7 @@ private:
uint16 _volumeA;
uint16 _volumeB;
+ uint16 _volumeT;
int _volMaskA;
int _volMaskB;
@@ -410,6 +412,7 @@ public:
void init(const uint8 *instrData = 0);
void reset();
void writeReg(uint8 address, uint8 value);
+ uint8 readReg(uint8 address) const;
void nextTick(int32 *buffer, uint32 bufferSize);
@@ -470,7 +473,7 @@ private:
TownsPC98_FmSynthSquareSineSource::TownsPC98_FmSynthSquareSineSource(const uint32 timerbase, const uint32 rtt) : _tlTable(0),
_rtt(rtt), _tleTable(0), _updateRequest(-1), _tickLength(timerbase * 27), _ready(0), _reg(0), _rand(1), _outN(1),
_nTick(0), _evpUpdateCnt(0), _evpTimer(0x1f), _pReslt(0x1f), _attack(0), _cont(false), _evpUpdate(true),
- _timer(0), _noiseGenerator(0), _chanEnable(0),
+ _timer(0), _noiseGenerator(0), _chanEnable(0), _volumeT(0x60),
_volMaskA(0), _volMaskB(0), _volumeA(Audio::Mixer::kMaxMixerVolume), _volumeB(Audio::Mixer::kMaxMixerVolume) {
memset(_channels, 0, sizeof(_channels));
@@ -579,6 +582,13 @@ void TownsPC98_FmSynthSquareSineSource::writeReg(uint8 address, uint8 value, boo
*_reg[address] = value;
}
+uint8 TownsPC98_FmSynthSquareSineSource::readReg(uint8 address) const {
+ if (!_ready || address > 10)
+ return 0;
+
+ return *_reg[address];
+}
+
void TownsPC98_FmSynthSquareSineSource::nextTick(int32 *buffer, uint32 bufferSize) {
if (!_ready)
return;
@@ -635,7 +645,7 @@ void TownsPC98_FmSynthSquareSineSource::nextTick(int32 *buffer, uint32 bufferSiz
finOut += finOutTemp;
}
- finOut /= 3;
+ finOut = (finOut * _volumeT) / Audio::Mixer::kMaxMixerVolume;
buffer[i << 1] += finOut;
buffer[(i << 1) + 1] += finOut;
@@ -781,6 +791,13 @@ void TownsPC98_FmSynthPercussionSource::writeReg(uint8 address, uint8 value) {
}
}
+uint8 TownsPC98_FmSynthPercussionSource::readReg(uint8 address) const {
+ if (!_ready || address > 0x0F)
+ return 0;
+
+ return *_reg[address];
+}
+
void TownsPC98_FmSynthPercussionSource::nextTick(int32 *buffer, uint32 bufferSize) {
if (!_ready)
return;
@@ -861,12 +878,14 @@ TownsPC98_FmSynth::TownsPC98_FmSynth(Audio::Mixer *mixer, EmuType type, bool ext
_hasPercussion(type == kType86 ? true : false),
_oprRates(0), _oprRateshift(0), _oprAttackDecay(0), _oprFrq(0), _oprSinTbl(0), _oprLevelOut(0), _oprDetune(0),
_rtt(type == kTypeTowns ? 0x514767 : 0x5B8D80), _baserate(55125.0f / (float)mixer->getOutputRate()),
- _volMaskA(0), _volMaskB(0), _volumeA(255), _volumeB(255),
- _regProtectionFlag(false), _externalMutex(externalMutexHandling), _ready(false) {
+ _volMaskA(0), _volMaskB(0), _volumeA(255), _volumeB(255), _externalMutex(externalMutexHandling), _ready(false) {
memset(&_timers[0], 0, sizeof(ChipTimer));
memset(&_timers[1], 0, sizeof(ChipTimer));
+ memset(_registers[0], 0, 255);
+ memset(_registers[1], 0, 255);
+
_timers[0].cb = _timers[1].cb = &TownsPC98_FmSynth::idleTimerCallback;
_timerbase = (uint32)(_baserate * 1000000.0f);
}
@@ -931,6 +950,9 @@ bool TownsPC98_FmSynth::init() {
}
void TownsPC98_FmSynth::reset() {
+ if (!_ready)
+ return;
+
Common::StackLock lock(_mutex);
for (int i = 0; i < _numChan; i++) {
for (int ii = 0; ii < 4; ii++)
@@ -942,6 +964,9 @@ void TownsPC98_FmSynth::reset() {
_chanInternal[i].updateEnvelopeParameters = false;
}
+ memset(_registers[0], 0, 255);
+ memset(_registers[1], 0, 255);
+
writeReg(0, 0x27, 0x33);
if (_ssg)
@@ -954,13 +979,20 @@ void TownsPC98_FmSynth::reset() {
}
void TownsPC98_FmSynth::writeReg(uint8 part, uint8 regAddress, uint8 value) {
- if (_regProtectionFlag || !_ready)
+ if (!_ready)
return;
+ if (part > 1) {
+ warning("TownsPC98_FmSynth::writeReg(): invalid part argument '%d'", part);
+ part = 1;
+ }
+
Common::StackLock lock(_mutex);
static const uint8 oprOrdr[] = { 0, 2, 1, 3 };
+ _registers[regAddress][part] = value;
+
uint8 h = regAddress & 0xf0;
uint8 l = (regAddress & 0x0f);
@@ -1141,6 +1173,18 @@ void TownsPC98_FmSynth::writeReg(uint8 part, uint8 regAddress, uint8 value) {
}
}
+uint8 TownsPC98_FmSynth::readReg(uint8 part, uint8 regAddress) {
+ if (!_ready || part > 1)
+ return 0;
+
+ if (!(regAddress & 0xF0) && _ssg)
+ return _ssg->readReg(regAddress & 0x0F);
+ else if ((regAddress & 0xF0) == 0x10 && _prc)
+ return _prc->readReg(regAddress & 0x0F);
+
+ return _registers[regAddress][part];
+}
+
int TownsPC98_FmSynth::readBuffer(int16 *buffer, const int numSamples) {
memset(buffer, 0, sizeof(int16) * numSamples);
int32 *tmp = new int32[numSamples];
@@ -1242,14 +1286,6 @@ void TownsPC98_FmSynth::deinit() {
_timers[0].cb = _timers[1].cb = &TownsPC98_FmSynth::idleTimerCallback;
}
-void TownsPC98_FmSynth::toggleRegProtection(bool prot) {
- _regProtectionFlag = prot;
-}
-
-uint8 TownsPC98_FmSynth::readSSGStatus() {
- return _ssg->chanEnable();
-}
-
void TownsPC98_FmSynth::setVolumeIntern(int volA, int volB) {
Common::StackLock lock(_mutex);
_volumeA = CLIP<uint16>(volA, 0, Audio::Mixer::kMaxMixerVolume);
@@ -1274,6 +1310,11 @@ void TownsPC98_FmSynth::setVolumeChannelMasks(int channelMaskA, int channelMaskB
#endif
}
+void TownsPC98_FmSynth::setLevelSSG(int vol) {
+ if (_ssg)
+ _ssg->setOutputLevel(vol);
+}
+
void TownsPC98_FmSynth::generateTables() {
delete[] _oprRates;
_oprRates = new uint8[128];
diff --git a/audio/softsynth/fmtowns_pc98/towns_pc98_fmsynth.h b/audio/softsynth/fmtowns_pc98/towns_pc98_fmsynth.h
index 5af9282..ba484e2 100644
--- a/audio/softsynth/fmtowns_pc98/towns_pc98_fmsynth.h
+++ b/audio/softsynth/fmtowns_pc98/towns_pc98_fmsynth.h
@@ -66,6 +66,7 @@ public:
virtual void reset();
void writeReg(uint8 part, uint8 regAddress, uint8 value);
+ uint8 readReg(uint8 part, uint8 regAddress);
// AudioStream interface
int readBuffer(int16 *buffer, const int numSamples);
@@ -80,9 +81,6 @@ protected:
// additional output that has to be inserted into the buffer.
virtual void nextTickEx(int32 *buffer, uint32 bufferSize) {}
- void toggleRegProtection(bool prot);
- uint8 readSSGStatus();
-
virtual void timerCallbackA() = 0;
virtual void timerCallbackB() = 0;
@@ -94,6 +92,8 @@ protected:
void setVolumeIntern(int volA, int volB);
void setVolumeChannelMasks(int channelMaskA, int channelMaskB);
+ void setLevelSSG(int vol);
+
const int _numChan;
const int _numSSG;
const bool _hasPercussion;
@@ -104,7 +104,6 @@ protected:
private:
void generateTables();
void nextTick(int32 *buffer, uint32 bufferSize);
- void generateOutput(int32 &leftSample, int32 &rightSample, int32 *del, int32 *feed);
struct ChanInternal {
ChanInternal();
@@ -171,6 +170,8 @@ private:
uint32 _timerbase;
uint32 _rtt;
+ uint8 _registers[255][2];
+
Audio::Mixer *_mixer;
Audio::SoundHandle _soundHandle;
Commit: 4a226aa8358108b1a7b861bb0578ba7be84b44b1
https://github.com/scummvm/scummvm/commit/4a226aa8358108b1a7b861bb0578ba7be84b44b1
Author: athrxx (athrxx at scummvm.org)
Date: 2019-03-07T19:43:55+01:00
Commit Message:
AUDIO: (FM-TOWNS/PC-98) - more cleanup
sort and rename some methods and vars and move as much as possible from public to private section
Changed paths:
audio/softsynth/fmtowns_pc98/towns_pc98_driver.cpp
audio/softsynth/fmtowns_pc98/towns_pc98_driver.h
diff --git a/audio/softsynth/fmtowns_pc98/towns_pc98_driver.cpp b/audio/softsynth/fmtowns_pc98/towns_pc98_driver.cpp
index 091905b..b5e8c84 100644
--- a/audio/softsynth/fmtowns_pc98/towns_pc98_driver.cpp
+++ b/audio/softsynth/fmtowns_pc98/towns_pc98_driver.cpp
@@ -23,35 +23,30 @@
#include "audio/softsynth/fmtowns_pc98/towns_pc98_driver.h"
#include "common/endian.h"
#include "common/textconsole.h"
+#include "common/func.h"
+#include "common/array.h"
class TownsPC98_MusicChannel {
public:
- TownsPC98_MusicChannel(TownsPC98_AudioDriver *driver, uint8 regOffs, uint8 flgs, uint8 num,
- uint8 key, uint8 prt, uint8 id);
+ TownsPC98_MusicChannel(TownsPC98_AudioDriver *driver, uint8 regOffs, uint8 flgs, uint8 num, uint8 key, uint8 prt, uint8 id);
virtual ~TownsPC98_MusicChannel();
- virtual void init();
typedef enum channelState {
CHS_RECALCFREQ = 0x01,
- CHS_KEYOFF = 0x02,
- CHS_SSGOFF = 0x04,
- CHS_VBROFF = 0x08,
- CHS_ALLOFF = 0x0f,
- CHS_PROTECT = 0x40,
- CHS_EOT = 0x80
+ CHS_KEYOFF = 0x02,
+ CHS_SSGOFF = 0x04,
+ CHS_VBROFF = 0x08,
+ CHS_ALLOFF = 0x0f,
+ CHS_PROTECT = 0x40,
+ CHS_EOT = 0x80
} ChannelState;
+ virtual void reset();
virtual void loadData(uint8 *data);
virtual void processEvents();
virtual void processFrequency();
- virtual bool processControlEvent(uint8 cmd);
-
- virtual void keyOn();
- void keyOff();
-
- void setOutputLevel();
- virtual void fadeStep();
- virtual void reset();
+
+ virtual void fadeStep();
const uint8 _idFlag;
@@ -59,31 +54,52 @@ protected:
void setupVibrato();
bool processVibrato();
+ uint8 readReg(uint8 part, uint8 reg);
+ void writeReg(uint8 part, uint8 reg, uint8 val);
+
bool control_dummy(uint8 para);
- bool control_f0_setPatch(uint8 para);
- bool control_f1_presetOutputLevel(uint8 para);
- bool control_f2_setKeyOffTime(uint8 para);
- bool control_f3_setFreqLSB(uint8 para);
- bool control_f4_setOutputLevel(uint8 para);
- bool control_f5_setTempo(uint8 para);
+ bool control_f2_duration(uint8 para);
+ bool control_f3_pitchBend(uint8 para);
+ bool control_f5_tempo(uint8 para);
bool control_f6_repeatSection(uint8 para);
bool control_f7_setupVibrato(uint8 para);
bool control_f8_toggleVibrato(uint8 para);
bool control_fa_writeReg(uint8 para);
- virtual bool control_fb_incOutLevel(uint8 para);
- virtual bool control_fc_decOutLevel(uint8 para);
bool control_fd_jump(uint8 para);
- virtual bool control_ff_endOfTrack(uint8 para);
uint8 _ticksLeft;
- uint8 _algorithm;
+ uint8 _duration;
uint8 _instr;
uint8 _totalLevel;
uint8 _frqBlockMSB;
- int8 _frqLSB;
- uint8 _keyOffTime;
- bool _hold;
+ uint16 _frequency;
+ uint8 _block;
+ int8 _pitchBend;
+ uint8 _regOffset;
+ uint8 _flags;
uint8 *_dataPtr;
+ bool _sustain;
+ bool _fading;
+
+ TownsPC98_AudioDriver *_driver;
+ const uint8 _chanNum;
+
+ static const uint8 _controlEventSize[16];
+
+private:
+ void keyOn();
+ void keyOff();
+
+ void setOutputLevel();
+ bool processControlEvent(uint8 cmd);
+
+ bool control_f0_setPatch(uint8 para);
+ bool control_f1_presetOutputLevel(uint8 para);
+ bool control_f4_setOutputLevel(uint8 para);
+ bool control_fb_incOutLevel(uint8 para);
+ bool control_fc_decOutLevel(uint8 para);
+ bool control_ff_endOfTrack(uint8 para);
+
uint8 _vbrInitDelayHi;
uint8 _vbrInitDelayLo;
int16 _vbrModInitVal;
@@ -91,49 +107,36 @@ protected:
uint8 _vbrCurDelay;
int16 _vbrModCurVal;
uint8 _vbrDurLeft;
- uint16 _frequency;
- uint8 _block;
- uint8 _regOffset;
- uint8 _flags;
- uint8 _ssgTl;
- uint8 _ssgStep;
- uint8 _ssgTicksLeft;
- uint8 _ssgTargetLvl;
- uint8 _ssgStartLvl;
-
- const uint8 _chanNum;
+ uint8 _algorithm;
+
const uint8 _keyNum;
const uint8 _part;
- TownsPC98_AudioDriver *_drv;
-
- typedef bool (TownsPC98_MusicChannel::*ControlEventFunc)(uint8 para);
- const ControlEventFunc *controlEvents;
+ typedef Common::Functor1Mem<uint8, bool, TownsPC98_MusicChannel> ControlEvent;
+ Common::Array<const ControlEvent*> _controlEvents;
};
class TownsPC98_MusicChannelSSG : public TownsPC98_MusicChannel {
public:
- TownsPC98_MusicChannelSSG(TownsPC98_AudioDriver *driver, uint8 regOffs,
- uint8 flgs, uint8 num, uint8 key, uint8 prt, uint8 id);
- virtual ~TownsPC98_MusicChannelSSG() {}
- void init();
+ TownsPC98_MusicChannelSSG(TownsPC98_AudioDriver *driver, uint8 regOffs, uint8 flgs, uint8 num, uint8 key, uint8 prt, uint8 id);
+ virtual ~TownsPC98_MusicChannelSSG();
+ virtual void reset();
virtual void loadData(uint8 *data);
void processEvents();
void processFrequency();
- bool processControlEvent(uint8 cmd);
-
- void keyOn();
- void nextShape();
void protect();
void restore();
- virtual void reset();
void fadeStep();
protected:
+ void keyOn();
+ void nextShape();
+
void setOutputLevel(uint8 lvl);
+ bool processControlEvent(uint8 cmd);
bool control_f0_setPatch(uint8 para);
bool control_f1_setTotalLevel(uint8 para);
@@ -143,101 +146,103 @@ protected:
bool control_fc_decOutLevel(uint8 para);
bool control_ff_endOfTrack(uint8 para);
- typedef bool (TownsPC98_MusicChannelSSG::*ControlEventFunc)(uint8 para);
- const ControlEventFunc *controlEvents;
+ uint8 _ssgTl;
+ uint8 _ssgStep;
+ uint8 _ssgTicksLeft;
+ uint8 _ssgTargetLvl;
+ uint8 _ssgStartLvl;
+ uint8 _algorithm;
+
+ static uint8 *_envPatchData;
+ static const uint8 _envData[256];
+
+ typedef Common::Functor1Mem<uint8, bool, TownsPC98_MusicChannelSSG> ControlEvent;
+ Common::Array<const ControlEvent*> _controlEvents;
};
class TownsPC98_SfxChannel : public TownsPC98_MusicChannelSSG {
public:
- TownsPC98_SfxChannel(TownsPC98_AudioDriver *driver, uint8 regOffs,
- uint8 flgs, uint8 num, uint8 key, uint8 prt, uint8 id) :
+ TownsPC98_SfxChannel(TownsPC98_AudioDriver *driver, uint8 regOffs, uint8 flgs, uint8 num, uint8 key, uint8 prt, uint8 id) :
TownsPC98_MusicChannelSSG(driver, regOffs, flgs, num, key, prt, id) {}
- ~TownsPC98_SfxChannel() {}
+ virtual ~TownsPC98_SfxChannel() {}
- void loadData(uint8 *data);
void reset();
+ void loadData(uint8 *data);
};
#ifndef DISABLE_PC98_RHYTHM_CHANNEL
class TownsPC98_MusicChannelPCM : public TownsPC98_MusicChannel {
public:
- TownsPC98_MusicChannelPCM(TownsPC98_AudioDriver *driver, uint8 regOffs,
- uint8 flgs, uint8 num, uint8 key, uint8 prt, uint8 id);
- ~TownsPC98_MusicChannelPCM() {}
- void init();
+ TownsPC98_MusicChannelPCM(TownsPC98_AudioDriver *driver, uint8 regOffs, uint8 flgs, uint8 num, uint8 key, uint8 prt, uint8 id);
+ virtual ~TownsPC98_MusicChannelPCM();
void loadData(uint8 *data);
void processEvents();
- bool processControlEvent(uint8 cmd);
private:
+ bool processControlEvent(uint8 cmd);
bool control_f1_prcStart(uint8 para);
bool control_ff_endOfTrack(uint8 para);
- typedef bool (TownsPC98_MusicChannelPCM::*ControlEventFunc)(uint8 para);
- const ControlEventFunc *controlEvents;
+ uint8 _algorithm;
+
+ typedef Common::Functor1Mem<uint8, bool, TownsPC98_MusicChannelPCM> ControlEvent;
+ Common::Array<const ControlEvent*> _controlEvents;
};
#endif
-TownsPC98_MusicChannel::TownsPC98_MusicChannel(TownsPC98_AudioDriver *driver, uint8 regOffs, uint8 flgs, uint8 num,
- uint8 key, uint8 prt, uint8 id) : _drv(driver), _regOffset(regOffs), _flags(flgs), _chanNum(num), _keyNum(key),
- _part(prt), _idFlag(id), controlEvents(0) {
-
- _ticksLeft = _algorithm = _instr = _totalLevel = _frqBlockMSB = _keyOffTime = 0;
- _ssgStartLvl = _ssgTl = _ssgStep = _ssgTicksLeft = _ssgTargetLvl = _block = 0;
- _vbrInitDelayHi = _vbrInitDelayLo = _vbrDuration = _vbrCurDelay = _vbrDurLeft = 0;
- _frqLSB = 0;
- _hold = false;
- _dataPtr = 0;
- _vbrModInitVal = _vbrModCurVal = 0;
- _frequency = 0;
-}
+#define CONTROL(x) _controlEvents.push_back(new ControlEvent(this, &TownsPC98_MusicChannel::control_##x))
+TownsPC98_MusicChannel::TownsPC98_MusicChannel(TownsPC98_AudioDriver *driver, uint8 regOffs, uint8 flgs, uint8 num, uint8 key, uint8 prt, uint8 id) : _driver(driver),
+_regOffset(regOffs), _flags(flgs), _chanNum(num), _keyNum(key), _part(prt), _idFlag(id), _ticksLeft(0), _algorithm(0), _instr(0), _totalLevel(0),
+_frqBlockMSB(0), _duration(0), _block(0), _vbrInitDelayHi(0), _vbrInitDelayLo(0), _vbrDuration(0), _vbrCurDelay(0), _vbrDurLeft(0), _pitchBend(0),
+_sustain(false), _fading(false), _dataPtr(0), _vbrModInitVal(0), _vbrModCurVal(0), _frequency(0) {
+ CONTROL(f0_setPatch);
+ CONTROL(f1_presetOutputLevel);
+ CONTROL(f2_duration);
+ CONTROL(f3_pitchBend);
+ CONTROL(f4_setOutputLevel);
+ CONTROL(f5_tempo);
+ CONTROL(f6_repeatSection);
+ CONTROL(f7_setupVibrato);
+ CONTROL(f8_toggleVibrato);
+ CONTROL(dummy);
+ CONTROL(fa_writeReg);
+ CONTROL(fb_incOutLevel);
+ CONTROL(fc_decOutLevel);
+ CONTROL(fd_jump);
+ CONTROL(dummy);
+ CONTROL(ff_endOfTrack);
+}
+#undef CONTROL
TownsPC98_MusicChannel::~TownsPC98_MusicChannel() {
+ for (Common::Array<const ControlEvent*>::iterator i = _controlEvents.begin(); i != _controlEvents.end(); ++i)
+ delete *i;
}
-void TownsPC98_MusicChannel::init() {
-#define Control(x) &TownsPC98_MusicChannel::control_##x
- static const ControlEventFunc ctrlEvents[] = {
- Control(f0_setPatch),
- Control(f1_presetOutputLevel),
- Control(f2_setKeyOffTime),
- Control(f3_setFreqLSB),
- Control(f4_setOutputLevel),
- Control(f5_setTempo),
- Control(f6_repeatSection),
- Control(f7_setupVibrato),
- Control(f8_toggleVibrato),
- Control(dummy),
- Control(fa_writeReg),
- Control(fb_incOutLevel),
- Control(fc_decOutLevel),
- Control(fd_jump),
- Control(dummy),
- Control(ff_endOfTrack)
- };
-#undef Control
-
- controlEvents = ctrlEvents;
-}
+void TownsPC98_MusicChannel::reset() {
+ _sustain = false;
+ _duration = 0;
+ _fading = false;
+ _ticksLeft = 1;
-void TownsPC98_MusicChannel::keyOff() {
- // all operators off
- uint8 value = _keyNum & 0x0f;
- if (_part)
- value |= 4;
- uint8 regAddress = 0x28;
- _drv->writeReg(0, regAddress, value);
- _flags |= CHS_KEYOFF;
-}
+ _flags = (_flags & ~CHS_EOT) | CHS_ALLOFF;
-void TownsPC98_MusicChannel::keyOn() {
- // all operators on
- uint8 value = _keyNum | 0xf0;
- if (_part)
- value |= 4;
- uint8 regAddress = 0x28;
- _drv->writeReg(0, regAddress, value);
+ _totalLevel = 0;
+ _algorithm = 0;
+
+ _block = 0;
+ _frequency = 0;
+ _frqBlockMSB = 0;
+ _pitchBend = 0;
+
+ _vbrInitDelayHi = 0;
+ _vbrInitDelayLo = 0;
+ _vbrModInitVal = 0;
+ _vbrDuration = 0;
+ _vbrCurDelay = 0;
+ _vbrModCurVal = 0;
+ _vbrDurLeft = 0;
}
void TownsPC98_MusicChannel::loadData(uint8 *data) {
@@ -253,8 +258,8 @@ void TownsPC98_MusicChannel::loadData(uint8 *data) {
tmp++;
} else if (cmd == 0xff) {
if (READ_LE_UINT16(tmp)) {
- _drv->_looping |= _idFlag;
- tmp += _drv->_opnFxCmdLen[cmd - 240];
+ _driver->_looping |= _idFlag;
+ tmp += _controlEventSize[cmd - 240];
} else
loop = false;
} else if (cmd == 0xf6) {
@@ -262,7 +267,7 @@ void TownsPC98_MusicChannel::loadData(uint8 *data) {
tmp[0] = tmp[1];
tmp += 4;
} else {
- tmp += _drv->_opnFxCmdLen[cmd - 240];
+ tmp += _controlEventSize[cmd - 240];
}
}
}
@@ -271,13 +276,13 @@ void TownsPC98_MusicChannel::processEvents() {
if (_flags & CHS_EOT)
return;
- if (!_hold && _ticksLeft == _keyOffTime)
+ if (!_sustain && _ticksLeft == _duration)
keyOff();
if (--_ticksLeft)
return;
- if (!_hold)
+ if (!_sustain)
keyOff();
uint8 cmd = 0;
@@ -295,14 +300,14 @@ void TownsPC98_MusicChannel::processEvents() {
if (cmd == 0x80) {
keyOff();
- _hold = false;
+ _sustain = false;
} else {
keyOn();
- if (_hold == false || cmd != _frqBlockMSB)
+ if (_sustain == false || cmd != _frqBlockMSB)
_flags |= CHS_RECALCFREQ;
- _hold = (para & 0x80) ? true : false;
+ _sustain = (para & 0x80) ? true : false;
_frqBlockMSB = cmd;
}
@@ -310,12 +315,14 @@ void TownsPC98_MusicChannel::processEvents() {
}
void TownsPC98_MusicChannel::processFrequency() {
+ static const uint16 noteFrequencies[] = { 0x26a, 0x28f, 0x2b6, 0x2df, 0x30b, 0x339, 0x36a, 0x39e, 0x3d5, 0x410, 0x44e, 0x48f };
+
if (_flags & CHS_RECALCFREQ) {
- _frequency = (READ_LE_UINT16(&_drv->_opnFreqTable[(_frqBlockMSB & 0x0f) << 1]) + _frqLSB) | (((_frqBlockMSB & 0x70) >> 1) << 8);
+ _frequency = (noteFrequencies[_frqBlockMSB & 0x0f] + _pitchBend) | (((_frqBlockMSB & 0x70) >> 1) << 8);
- _drv->writeReg(_part, _regOffset + 0xa4, (_frequency >> 8));
- _drv->writeReg(_part, _regOffset + 0xa0, (_frequency & 0xff));
+ writeReg(_part, _regOffset + 0xa4, (_frequency >> 8));
+ writeReg(_part, _regOffset + 0xa0, (_frequency & 0xff));
setupVibrato();
}
@@ -324,11 +331,19 @@ void TownsPC98_MusicChannel::processFrequency() {
if (!processVibrato())
return;
- _drv->writeReg(_part, _regOffset + 0xa4, (_frequency >> 8));
- _drv->writeReg(_part, _regOffset + 0xa0, (_frequency & 0xff));
+ writeReg(_part, _regOffset + 0xa4, (_frequency >> 8));
+ writeReg(_part, _regOffset + 0xa0, (_frequency & 0xff));
}
}
+void TownsPC98_MusicChannel::fadeStep() {
+ _fading = true;
+ _totalLevel += 3;
+ if (_totalLevel > 0x7f)
+ _totalLevel = 0x7f;
+ setOutputLevel();
+}
+
void TownsPC98_MusicChannel::setupVibrato() {
_vbrCurDelay = _vbrInitDelayHi;
if (_flags & CHS_KEYOFF) {
@@ -354,125 +369,31 @@ bool TownsPC98_MusicChannel::processVibrato() {
return true;
}
-bool TownsPC98_MusicChannel::processControlEvent(uint8 cmd) {
- uint8 para = *_dataPtr++;
- return (this->*controlEvents[cmd & 0x0f])(para);
-}
-
-void TownsPC98_MusicChannel::setOutputLevel() {
- uint8 outopr = _drv->_opnCarrier[_algorithm];
- uint8 reg = 0x40 + _regOffset;
-
- for (int i = 0; i < 4; i++) {
- if (outopr & 1)
- _drv->writeReg(_part, reg, _totalLevel);
- outopr >>= 1;
- reg += 4;
- }
-}
-
-void TownsPC98_MusicChannel::fadeStep() {
- _totalLevel += 3;
- if (_totalLevel > 0x7f)
- _totalLevel = 0x7f;
- setOutputLevel();
+uint8 TownsPC98_MusicChannel::readReg(uint8 part, uint8 reg) {
+ return _driver->readReg(part, reg);
}
-void TownsPC98_MusicChannel::reset() {
- _hold = false;
- _keyOffTime = 0;
- _ticksLeft = 1;
-
- _flags = (_flags & ~CHS_EOT) | CHS_ALLOFF;
-
- _totalLevel = 0;
- _algorithm = 0;
-
- _block = 0;
- _frequency = 0;
- _frqBlockMSB = 0;
- _frqLSB = 0;
-
- _ssgTl = 0;
- _ssgStartLvl = 0;
- _ssgTargetLvl = 0;
- _ssgStep = 0;
- _ssgTicksLeft = 0;
-
- _vbrInitDelayHi = 0;
- _vbrInitDelayLo = 0;
- _vbrModInitVal = 0;
- _vbrDuration = 0;
- _vbrCurDelay = 0;
- _vbrModCurVal = 0;
- _vbrDurLeft = 0;
+void TownsPC98_MusicChannel::writeReg(uint8 part, uint8 reg, uint8 val) {
+ _driver->writeReg(part, reg, val);
}
-bool TownsPC98_MusicChannel::control_f0_setPatch(uint8 para) {
- _instr = para;
- uint8 reg = _regOffset + 0x80;
-
- for (int i = 0; i < 4; i++) {
- // set release rate for each operator
- _drv->writeReg(_part, reg, 0x0f);
- reg += 4;
- }
-
- const uint8 *tptr = _drv->_patches + ((uint32)_instr << 5);
- reg = _regOffset + 0x30;
-
- // write registers 0x30 to 0x8f
- for (int i = 0; i < 6; i++) {
- _drv->writeReg(_part, reg, tptr[0]);
- reg += 4;
- _drv->writeReg(_part, reg, tptr[2]);
- reg += 4;
- _drv->writeReg(_part, reg, tptr[1]);
- reg += 4;
- _drv->writeReg(_part, reg, tptr[3]);
- reg += 4;
- tptr += 4;
- }
-
- reg = _regOffset + 0xB0;
- _algorithm = tptr[0] & 7;
- // set feedback and algorithm
- _drv->writeReg(_part, reg, tptr[0]);
-
- setOutputLevel();
- return true;
-}
-
-bool TownsPC98_MusicChannel::control_f1_presetOutputLevel(uint8 para) {
- if (_drv->_fading)
- return true;
-
- _totalLevel = _drv->_opnLvlPresets[para];
- setOutputLevel();
- return true;
-}
-
-bool TownsPC98_MusicChannel::control_f2_setKeyOffTime(uint8 para) {
- _keyOffTime = para;
+bool TownsPC98_MusicChannel::control_dummy(uint8 para) {
+ _dataPtr--;
return true;
}
-bool TownsPC98_MusicChannel::control_f3_setFreqLSB(uint8 para) {
- _frqLSB = (int8) para;
+bool TownsPC98_MusicChannel::control_f2_duration(uint8 para) {
+ _duration = para;
return true;
}
-bool TownsPC98_MusicChannel::control_f4_setOutputLevel(uint8 para) {
- if (_drv->_fading)
- return true;
-
- _totalLevel = para;
- setOutputLevel();
+bool TownsPC98_MusicChannel::control_f3_pitchBend(uint8 para) {
+ _pitchBend = (int8) para;
return true;
}
-bool TownsPC98_MusicChannel::control_f5_setTempo(uint8 para) {
- _drv->setMusicTempo(para);
+bool TownsPC98_MusicChannel::control_f5_tempo(uint8 para) {
+ _driver->setMusicTempo(para);
return true;
}
@@ -482,7 +403,7 @@ bool TownsPC98_MusicChannel::control_f6_repeatSection(uint8 para) {
if (*_dataPtr) {
// repeat section until counter has reached zero
- _dataPtr = _drv->_trackPtr + READ_LE_UINT16(_dataPtr + 2);
+ _dataPtr = _driver->_trackPtr + READ_LE_UINT16(_dataPtr + 2);
} else {
// reset counter, advance to next section
_dataPtr[0] = _dataPtr[1];
@@ -520,13 +441,109 @@ bool TownsPC98_MusicChannel::control_f8_toggleVibrato(uint8 para) {
}
bool TownsPC98_MusicChannel::control_fa_writeReg(uint8 para) {
- _drv->writeReg(_part, para, *_dataPtr++);
+ writeReg(_part, para, *_dataPtr++);
+ return true;
+}
+
+bool TownsPC98_MusicChannel::control_fd_jump(uint8 para) {
+ uint8 *tmp = _driver->_trackPtr + READ_LE_UINT16(_dataPtr - 1);
+ _dataPtr = (tmp[1] == 1) ? tmp : (_dataPtr + 1);
+ return true;
+}
+
+void TownsPC98_MusicChannel::keyOn() {
+ // all operators on
+ uint8 value = _keyNum | 0xf0;
+ if (_part)
+ value |= 4;
+ uint8 regAddress = 0x28;
+ writeReg(0, regAddress, value);
+}
+
+void TownsPC98_MusicChannel::keyOff() {
+ // all operators off
+ uint8 value = _keyNum & 0x0f;
+ if (_part)
+ value |= 4;
+ uint8 regAddress = 0x28;
+ writeReg(0, regAddress, value);
+ _flags |= CHS_KEYOFF;
+}
+
+void TownsPC98_MusicChannel::setOutputLevel() {
+ static const uint8 carrier[] = { 0x08, 0x08, 0x08, 0x08, 0x0C, 0x0E, 0x0E, 0x0F };
+ uint8 outopr = carrier[_algorithm];
+ uint8 reg = 0x40 + _regOffset;
+
+ for (int i = 0; i < 4; i++) {
+ if (outopr & 1)
+ writeReg(_part, reg, _totalLevel);
+ outopr >>= 1;
+ reg += 4;
+ }
+}
+
+bool TownsPC98_MusicChannel::processControlEvent(uint8 cmd) {
+ uint8 para = *_dataPtr++;
+ return (*_controlEvents[cmd & 0x0f])(para);
+}
+
+bool TownsPC98_MusicChannel::control_f0_setPatch(uint8 para) {
+ _instr = para;
+ uint8 reg = _regOffset + 0x80;
+
+ for (int i = 0; i < 4; i++) {
+ // set release rate for each operator
+ writeReg(_part, reg, 0x0f);
+ reg += 4;
+ }
+
+ const uint8 *tptr = _driver->_patchData + ((uint32)_instr << 5);
+ reg = _regOffset + 0x30;
+
+ // write registers 0x30 to 0x8f
+ for (int i = 0; i < 6; i++) {
+ writeReg(_part, reg, tptr[0]);
+ reg += 4;
+ writeReg(_part, reg, tptr[2]);
+ reg += 4;
+ writeReg(_part, reg, tptr[1]);
+ reg += 4;
+ writeReg(_part, reg, tptr[3]);
+ reg += 4;
+ tptr += 4;
+ }
+
+ reg = _regOffset + 0xB0;
+ _algorithm = tptr[0] & 7;
+ // set feedback and algorithm
+ writeReg(_part, reg, tptr[0]);
+
+ setOutputLevel();
+ return true;
+}
+
+bool TownsPC98_MusicChannel::control_f1_presetOutputLevel(uint8 para) {
+ if (_fading)
+ return true;
+
+ _totalLevel = _driver->_levelPresets[para];
+ setOutputLevel();
+ return true;
+}
+
+bool TownsPC98_MusicChannel::control_f4_setOutputLevel(uint8 para) {
+ if (_fading)
+ return true;
+
+ _totalLevel = para;
+ setOutputLevel();
return true;
}
bool TownsPC98_MusicChannel::control_fb_incOutLevel(uint8 para) {
_dataPtr--;
- if (_drv->_fading)
+ if (_fading)
return true;
uint8 val = (_totalLevel + 3);
@@ -540,84 +557,103 @@ bool TownsPC98_MusicChannel::control_fb_incOutLevel(uint8 para) {
bool TownsPC98_MusicChannel::control_fc_decOutLevel(uint8 para) {
_dataPtr--;
- if (_drv->_fading)
+ if (_fading)
return true;
int8 val = (int8)(_totalLevel - 3);
if (val < 0)
val = 0;
- _totalLevel = (uint8) val;
+ _totalLevel = (uint8)val;
setOutputLevel();
return true;
}
-bool TownsPC98_MusicChannel::control_fd_jump(uint8 para) {
- uint8 *tmp = _drv->_trackPtr + READ_LE_UINT16(_dataPtr - 1);
- _dataPtr = (tmp[1] == 1) ? tmp : (_dataPtr + 1);
- return true;
-}
-
-bool TownsPC98_MusicChannel::control_dummy(uint8 para) {
- _dataPtr--;
- return true;
-}
-
bool TownsPC98_MusicChannel::control_ff_endOfTrack(uint8 para) {
uint16 val = READ_LE_UINT16(--_dataPtr);
if (val) {
// loop
- _dataPtr = _drv->_trackPtr + val;
+ _dataPtr = _driver->_trackPtr + val;
return true;
} else {
// quit parsing for active channel
--_dataPtr;
_flags |= CHS_EOT;
- _drv->_finishedChannelsFlag |= _idFlag;
+ _driver->_finishedChannelsFlag |= _idFlag;
keyOff();
return false;
}
}
-TownsPC98_MusicChannelSSG::TownsPC98_MusicChannelSSG(TownsPC98_AudioDriver *driver, uint8 regOffs,
- uint8 flgs, uint8 num, uint8 key, uint8 prt, uint8 id) :
- TownsPC98_MusicChannel(driver, regOffs, flgs, num, key, prt, id), controlEvents(0) {
+const uint8 TownsPC98_MusicChannel::_controlEventSize[16] = { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x04, 0x05, 0x02, 0x06, 0x02, 0x00, 0x00, 0x02, 0x00, 0x02 };
+
+#define CONTROL(x) _controlEvents.push_back(new ControlEvent(this, &TownsPC98_MusicChannelSSG::control_##x))
+TownsPC98_MusicChannelSSG::TownsPC98_MusicChannelSSG(TownsPC98_AudioDriver *driver, uint8 regOffs, uint8 flgs, uint8 num, uint8 key, uint8 prt, uint8 id) :
+TownsPC98_MusicChannel(driver, regOffs, flgs, num, key, prt, id), _algorithm(0x80),
+ _ssgStartLvl(0), _ssgTl(0), _ssgStep(0), _ssgTicksLeft(0), _ssgTargetLvl(0) {
+ CONTROL(f0_setPatch);
+ CONTROL(f1_setTotalLevel);
+ CONTROL(f2_duration);
+ CONTROL(f3_pitchBend);
+ CONTROL(f4_setAlgorithm);
+ CONTROL(f5_tempo);
+ CONTROL(f6_repeatSection);
+ CONTROL(f7_setupVibrato);
+ CONTROL(f8_toggleVibrato);
+ CONTROL(f9_loadCustomPatch);
+ CONTROL(fa_writeReg);
+ CONTROL(fb_incOutLevel);
+ CONTROL(fc_decOutLevel);
+ CONTROL(fd_jump);
+ CONTROL(dummy);
+ CONTROL(ff_endOfTrack);
+
+ if (!_envPatchData) {
+ _envPatchData = new uint8[256];
+ memcpy(_envPatchData, _envData, 256);
+ }
}
+#undef CONTROL
-void TownsPC98_MusicChannelSSG::init() {
- _algorithm = 0x80;
+TownsPC98_MusicChannelSSG::~TownsPC98_MusicChannelSSG() {
+ for (Common::Array<const ControlEvent*>::iterator i = _controlEvents.begin(); i != _controlEvents.end(); ++i)
+ delete *i;
+ delete[] _envPatchData;
+ _envPatchData = 0;
+}
+
+void TownsPC98_MusicChannelSSG::reset() {
+ TownsPC98_MusicChannel::reset();
+ _ssgStartLvl = _ssgTl = _ssgStep = _ssgTicksLeft = _ssgTargetLvl = 0;
+
+ // Unlike the original we restore the default patch data. This fixes a bug
+ // where certain sound effects would bring each other out of tune (e.g. the
+ // dragon's fire in Darm's house in Kyra 1 would sound different each time
+ // you triggered another sfx by dropping an item etc.)
+ uint8 i = (10 + _regOffset) << 4;
+ const uint8 *src = _envData;
+ _envPatchData[i] = src[i];
+ _envPatchData[i + 3] = src[i + 3];
+ _envPatchData[i + 4] = src[i + 4];
+ _envPatchData[i + 6] = src[i + 6];
+ _envPatchData[i + 8] = src[i + 8];
+ _envPatchData[i + 12] = src[i + 12];
+}
-#define Control(x) &TownsPC98_MusicChannelSSG::control_##x
- static const ControlEventFunc ctrlEventsSSG[] = {
- Control(f0_setPatch),
- Control(f1_setTotalLevel),
- Control(f2_setKeyOffTime),
- Control(f3_setFreqLSB),
- Control(f4_setAlgorithm),
- Control(f5_setTempo),
- Control(f6_repeatSection),
- Control(f7_setupVibrato),
- Control(f8_toggleVibrato),
- Control(f9_loadCustomPatch),
- Control(fa_writeReg),
- Control(fb_incOutLevel),
- Control(fc_decOutLevel),
- Control(fd_jump),
- Control(dummy),
- Control(ff_endOfTrack)
- };
-#undef Control
-
- controlEvents = ctrlEventsSSG;
+void TownsPC98_MusicChannelSSG::loadData(uint8 *data) {
+ _driver->preventRegisterWrite(_flags & CHS_PROTECT ? true : false);
+ TownsPC98_MusicChannel::loadData(data);
+ setOutputLevel(0);
+ _algorithm = 0x80;
}
void TownsPC98_MusicChannelSSG::processEvents() {
if (_flags & CHS_EOT)
return;
- _drv->preventRegisterWrite(_flags & CHS_PROTECT ? true : false);
+ _driver->preventRegisterWrite(_flags & CHS_PROTECT ? true : false);
- if (!_hold && _ticksLeft == _keyOffTime)
+ if (!_sustain && _ticksLeft == _duration)
nextShape();
if (!--_ticksLeft) {
@@ -637,23 +673,23 @@ void TownsPC98_MusicChannelSSG::processEvents() {
if (cmd == 0x80) {
nextShape();
- _hold = false;
+ _sustain = false;
} else {
- if (!_hold) {
+ if (!_sustain) {
_instr &= 0xf0;
- _ssgStep = _drv->_ssgPatches[_instr];
- _ssgTicksLeft = _drv->_ssgPatches[_instr + 1] & 0x7f;
- _ssgTargetLvl = _drv->_ssgPatches[_instr + 2];
- _ssgStartLvl = _drv->_ssgPatches[_instr + 3];
+ _ssgStep = _envPatchData[_instr];
+ _ssgTicksLeft = _envPatchData[_instr + 1] & 0x7f;
+ _ssgTargetLvl = _envPatchData[_instr + 2];
+ _ssgStartLvl = _envPatchData[_instr + 3];
_flags = (_flags & ~CHS_SSGOFF) | CHS_KEYOFF;
}
keyOn();
- if (_hold == false || cmd != _frqBlockMSB)
+ if (_sustain == false || cmd != _frqBlockMSB)
_flags |= CHS_RECALCFREQ;
- _hold = (para & 0x80) ? true : false;
+ _sustain = (para & 0x80) ? true : false;
_frqBlockMSB = cmd;
}
@@ -662,18 +698,18 @@ void TownsPC98_MusicChannelSSG::processEvents() {
if (!(_flags & CHS_SSGOFF)) {
if (--_ssgTicksLeft) {
- if (!_drv->_fading)
+ if (!_driver->_fading)
setOutputLevel(_ssgStartLvl);
return;
}
- _ssgTicksLeft = _drv->_ssgPatches[_instr + 1] & 0x7f;
+ _ssgTicksLeft = _envPatchData[_instr + 1] & 0x7f;
- if (_drv->_ssgPatches[_instr + 1] & 0x80) {
+ if (_envPatchData[_instr + 1] & 0x80) {
uint8 t = _ssgStartLvl - _ssgStep;
if (_ssgStep <= _ssgStartLvl && _ssgTargetLvl < t) {
- if (!_drv->_fading)
+ if (!_driver->_fading)
setOutputLevel(t);
return;
}
@@ -682,7 +718,7 @@ void TownsPC98_MusicChannelSSG::processEvents() {
uint8 p = (uint8)(t & 0xff);
if (t < 256 && _ssgTargetLvl > p) {
- if (!_drv->_fading)
+ if (!_driver->_fading)
setOutputLevel(p);
return;
}
@@ -691,9 +727,9 @@ void TownsPC98_MusicChannelSSG::processEvents() {
setOutputLevel(_ssgTargetLvl);
if (_ssgStartLvl && !(_instr & 8)) {
_instr += 4;
- _ssgStep = _drv->_ssgPatches[_instr];
- _ssgTicksLeft = _drv->_ssgPatches[_instr + 1] & 0x7f;
- _ssgTargetLvl = _drv->_ssgPatches[_instr + 2];
+ _ssgStep = _envPatchData[_instr];
+ _ssgTicksLeft = _envPatchData[_instr + 1] & 0x7f;
+ _ssgTargetLvl = _envPatchData[_instr + 2];
} else {
_flags |= CHS_SSGOFF;
setOutputLevel(0);
@@ -702,16 +738,18 @@ void TownsPC98_MusicChannelSSG::processEvents() {
}
void TownsPC98_MusicChannelSSG::processFrequency() {
+ static const uint16 noteFrequencies[] = { 0xee8, 0xe12, 0xd48, 0xc89, 0xbd5, 0xb2b, 0xa8a, 0x9f3, 0x964, 0x8dd, 0x85e, 0x7e6 };
+
if (_algorithm & 0x40)
return;
if (_flags & CHS_RECALCFREQ) {
_block = _frqBlockMSB >> 4;
- _frequency = READ_LE_UINT16(&_drv->_opnFreqTableSSG[(_frqBlockMSB & 0x0f) << 1]) + _frqLSB;
+ _frequency = noteFrequencies[_frqBlockMSB & 0x0f] + _pitchBend;
uint16 f = _frequency >> _block;
- _drv->writeReg(_part, _regOffset << 1, f & 0xff);
- _drv->writeReg(_part, (_regOffset << 1) + 1, f >> 8);
+ writeReg(0, _regOffset << 1, f & 0xff);
+ writeReg(0, (_regOffset << 1) + 1, f >> 8);
setupVibrato();
}
@@ -721,21 +759,30 @@ void TownsPC98_MusicChannelSSG::processFrequency() {
return;
uint16 f = _frequency >> _block;
- _drv->writeReg(_part, _regOffset << 1, f & 0xff);
- _drv->writeReg(_part, (_regOffset << 1) + 1, f >> 8);
+ writeReg(0, _regOffset << 1, f & 0xff);
+ writeReg(0, (_regOffset << 1) + 1, f >> 8);
}
}
-bool TownsPC98_MusicChannelSSG::processControlEvent(uint8 cmd) {
- uint8 para = *_dataPtr++;
- return (this->*controlEvents[cmd & 0x0f])(para);
+void TownsPC98_MusicChannelSSG::protect() {
+ _flags |= CHS_PROTECT;
}
-void TownsPC98_MusicChannelSSG::nextShape() {
- _instr = (_instr & 0xf0) + 0x0c;
- _ssgStep = _drv->_ssgPatches[_instr];
- _ssgTicksLeft = _drv->_ssgPatches[_instr + 1] & 0x7f;
- _ssgTargetLvl = _drv->_ssgPatches[_instr + 2];
+void TownsPC98_MusicChannelSSG::restore() {
+ _flags &= ~CHS_PROTECT;
+ keyOn();
+ writeReg(0, 8 + _regOffset, _ssgTl);
+ uint16 f = _frequency >> _block;
+ writeReg(0, _regOffset << 1, f & 0xff);
+ writeReg(0, (_regOffset << 1) + 1, f >> 8);
+}
+
+void TownsPC98_MusicChannelSSG::fadeStep() {
+ _fading = true;
+ _totalLevel--;
+ if ((int8)_totalLevel < 0)
+ _totalLevel = 0;
+ setOutputLevel(_ssgStartLvl);
}
void TownsPC98_MusicChannelSSG::keyOn() {
@@ -748,30 +795,17 @@ void TownsPC98_MusicChannelSSG::keyOn() {
t = (t << (_regOffset + 1)) | (t >> (7 - _regOffset));
if (!(_algorithm & 0x80))
- _drv->writeReg(_part, 6, _algorithm & 0x7f);
+ writeReg(0, 6, _algorithm & 0x7f);
- uint8 e = (_drv->_pc98a->readReg(0, 7) & c) | t;
- _drv->writeReg(_part, 7, e);
+ uint8 e = (readReg(0, 7) & c) | t;
+ writeReg(0, 7, e);
}
-void TownsPC98_MusicChannelSSG::protect() {
- _flags |= CHS_PROTECT;
-}
-
-void TownsPC98_MusicChannelSSG::restore() {
- _flags &= ~CHS_PROTECT;
- keyOn();
- _drv->writeReg(_part, 8 + _regOffset, _ssgTl);
- uint16 f = _frequency >> _block;
- _drv->writeReg(_part, _regOffset << 1, f & 0xff);
- _drv->writeReg(_part, (_regOffset << 1) + 1, f >> 8);
-}
-
-void TownsPC98_MusicChannelSSG::loadData(uint8 *data) {
- _drv->preventRegisterWrite(_flags & CHS_PROTECT ? true : false);
- TownsPC98_MusicChannel::loadData(data);
- setOutputLevel(0);
- _algorithm = 0x80;
+void TownsPC98_MusicChannelSSG::nextShape() {
+ _instr = (_instr & 0xf0) + 0x0c;
+ _ssgStep = _envPatchData[_instr];
+ _ssgTicksLeft = _envPatchData[_instr + 1] & 0x7f;
+ _ssgTargetLvl = _envPatchData[_instr + 2];
}
void TownsPC98_MusicChannelSSG::setOutputLevel(uint8 lvl) {
@@ -780,31 +814,12 @@ void TownsPC98_MusicChannelSSG::setOutputLevel(uint8 lvl) {
if (newTl == _ssgTl)
return;
_ssgTl = newTl;
- _drv->writeReg(_part, 8 + _regOffset, _ssgTl);
-}
-
-void TownsPC98_MusicChannelSSG::reset() {
- TownsPC98_MusicChannel::reset();
-
- // Unlike the original we restore the default patch data. This fixes a bug
- // where certain sound effects would bring each other out of tune (e.g. the
- // dragon's fire in Darm's house in Kyra 1 would sound different each time
- // you triggered another sfx by dropping an item etc.)
- uint8 i = (10 + _regOffset) << 4;
- const uint8 *src = &_drv->_drvTables[156];
- _drv->_ssgPatches[i] = src[i];
- _drv->_ssgPatches[i + 3] = src[i + 3];
- _drv->_ssgPatches[i + 4] = src[i + 4];
- _drv->_ssgPatches[i + 6] = src[i + 6];
- _drv->_ssgPatches[i + 8] = src[i + 8];
- _drv->_ssgPatches[i + 12] = src[i + 12];
+ writeReg(0, 8 + _regOffset, _ssgTl);
}
-void TownsPC98_MusicChannelSSG::fadeStep() {
- _totalLevel--;
- if ((int8)_totalLevel < 0)
- _totalLevel = 0;
- setOutputLevel(_ssgStartLvl);
+bool TownsPC98_MusicChannelSSG::processControlEvent(uint8 cmd) {
+ uint8 para = *_dataPtr++;
+ return (*_controlEvents[cmd & 0x0f])(para);
}
bool TownsPC98_MusicChannelSSG::control_f0_setPatch(uint8 para) {
@@ -816,7 +831,7 @@ bool TownsPC98_MusicChannelSSG::control_f0_setPatch(uint8 para) {
}
bool TownsPC98_MusicChannelSSG::control_f1_setTotalLevel(uint8 para) {
- if (!_drv->_fading)
+ if (!_fading)
_totalLevel = para;
return true;
}
@@ -827,19 +842,19 @@ bool TownsPC98_MusicChannelSSG::control_f4_setAlgorithm(uint8 para) {
}
bool TownsPC98_MusicChannelSSG::control_f9_loadCustomPatch(uint8 para) {
- _instr = (_drv->_sfxOffs + 10 + _regOffset) << 4;
- _drv->_ssgPatches[_instr] = *_dataPtr++;
- _drv->_ssgPatches[_instr + 3] = para;
- _drv->_ssgPatches[_instr + 4] = *_dataPtr++;
- _drv->_ssgPatches[_instr + 6] = *_dataPtr++;
- _drv->_ssgPatches[_instr + 8] = *_dataPtr++;
- _drv->_ssgPatches[_instr + 12] = *_dataPtr++;
+ _instr = (_driver->_sfxOffs + 10 + _regOffset) << 4;
+ _envPatchData[_instr] = *_dataPtr++;
+ _envPatchData[_instr + 3] = para;
+ _envPatchData[_instr + 4] = *_dataPtr++;
+ _envPatchData[_instr + 6] = *_dataPtr++;
+ _envPatchData[_instr + 8] = *_dataPtr++;
+ _envPatchData[_instr + 12] = *_dataPtr++;
return true;
}
bool TownsPC98_MusicChannelSSG::control_fb_incOutLevel(uint8 para) {
_dataPtr--;
- if (_drv->_fading)
+ if (_fading)
return true;
_totalLevel--;
@@ -851,7 +866,7 @@ bool TownsPC98_MusicChannelSSG::control_fb_incOutLevel(uint8 para) {
bool TownsPC98_MusicChannelSSG::control_fc_decOutLevel(uint8 para) {
_dataPtr--;
- if (_drv->_fading)
+ if (_fading)
return true;
if (_totalLevel + 1 < 0x10)
@@ -861,30 +876,68 @@ bool TownsPC98_MusicChannelSSG::control_fc_decOutLevel(uint8 para) {
}
bool TownsPC98_MusicChannelSSG::control_ff_endOfTrack(uint8 para) {
- if (!_drv->_sfxOffs) {
+ if (!_driver->_sfxOffs) {
uint16 val = READ_LE_UINT16(--_dataPtr);
if (val) {
// loop
- _dataPtr = _drv->_trackPtr + val;
+ _dataPtr = _driver->_trackPtr + val;
return true;
} else {
// stop parsing
- if (!_drv->_fading)
+ if (!_driver->_fading)
setOutputLevel(0);
--_dataPtr;
_flags |= CHS_EOT;
- _drv->_finishedSSGFlag |= _idFlag;
+ _driver->_finishedSSGFlag |= _idFlag;
}
} else {
// end of sfx track - restore ssg music channel
_flags |= CHS_EOT;
- _drv->_finishedSfxFlag |= _idFlag;
- _drv->_ssgChannels[_chanNum]->restore();
+ _driver->_finishedSfxFlag |= _idFlag;
+ _driver->_ssgChannels[_chanNum]->restore();
}
return false;
}
+uint8 *TownsPC98_MusicChannelSSG::_envPatchData = 0;
+
+const uint8 TownsPC98_MusicChannelSSG::_envData[256] = {
+ 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x81, 0x00, 0x00,
+ 0x00, 0x81, 0x00, 0x00, 0xFF, 0x81, 0x00, 0x00,
+ 0x00, 0x01, 0xFF, 0xFF, 0x37, 0x81, 0xC8, 0x00,
+ 0x00, 0x81, 0x00, 0x00, 0x0A, 0x81, 0x00, 0x00,
+ 0x00, 0x01, 0xFF, 0xFF, 0x37, 0x81, 0xC8, 0x00,
+ 0x01, 0x81, 0x00, 0x00, 0x0A, 0x81, 0x00, 0x00,
+ 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0x81, 0xBE, 0x00,
+ 0x00, 0x81, 0x00, 0x00, 0x0A, 0x81, 0x00, 0x00,
+ 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0x81, 0xBE, 0x00,
+ 0x01, 0x81, 0x00, 0x00, 0x0A, 0x81, 0x00, 0x00,
+ 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0x81, 0xBE, 0x00,
+ 0x04, 0x81, 0x00, 0x00, 0x0A, 0x81, 0x00, 0x00,
+ 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0x81, 0xBE, 0x00,
+ 0x0A, 0x81, 0x00, 0x00, 0x0A, 0x81, 0x00, 0x00,
+ 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0x81, 0x01, 0x00,
+ 0xFF, 0x81, 0x00, 0x00, 0xFF, 0x81, 0x00, 0x00,
+ 0xFF, 0x01, 0xFF, 0xFF, 0xFF, 0x81, 0xFF, 0x00,
+ 0x01, 0x81, 0x00, 0x00, 0x0A, 0x81, 0x00, 0x00,
+ 0x64, 0x01, 0xFF, 0x64, 0xFF, 0x81, 0xFF, 0x00,
+ 0x01, 0x81, 0x00, 0x00, 0x0A, 0x81, 0x00, 0x00,
+
+ 0x02, 0x01, 0xFF, 0x28, 0xFF, 0x81, 0xF0, 0x00,
+ 0x00, 0x81, 0x00, 0x00, 0x0A, 0x81, 0x00, 0x00,
+ 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0x81, 0xC8, 0x00,
+ 0x01, 0x81, 0x00, 0x00, 0x28, 0x81, 0x00, 0x00,
+ 0x00, 0x01, 0xFF, 0x78, 0x5F, 0x81, 0xA0, 0x00,
+ 0x05, 0x81, 0x00, 0x00, 0x28, 0x81, 0x00, 0x00,
+ 0x00, 0x01, 0xFF, 0xFF, 0x00, 0x81, 0x00, 0x00,
+ 0x00, 0x81, 0x00, 0x00, 0xFF, 0x81, 0x00, 0x00,
+ 0x00, 0x01, 0xFF, 0xFF, 0x00, 0x81, 0x00, 0x00,
+ 0x00, 0x81, 0x00, 0x00, 0xFF, 0x81, 0x00, 0x00,
+ 0x00, 0x01, 0xFF, 0xFF, 0x00, 0x81, 0x00, 0x00,
+ 0x00, 0x81, 0x00, 0x00, 0xFF, 0x81, 0x00, 0x00
+};
+
void TownsPC98_SfxChannel::loadData(uint8 *data) {
_flags = CHS_ALLOFF;
_ticksLeft = 1;
@@ -904,59 +957,55 @@ void TownsPC98_SfxChannel::loadData(uint8 *data) {
tmp[0] = tmp[1];
tmp += 4;
} else {
- tmp += _drv->_opnFxCmdLen[cmd - 240];
+ tmp += _controlEventSize[cmd - 240];
}
}
}
void TownsPC98_SfxChannel::reset() {
TownsPC98_MusicChannel::reset();
+ _ssgStartLvl = _ssgTl = _ssgStep = _ssgTicksLeft = _ssgTargetLvl = 0;
// Unlike the original we restore the default patch data. This fixes a bug
// where certain sound effects would bring each other out of tune (e.g. the
// dragon's fire in Darm's house in Kyra 1 would sound different each time
// you triggered another sfx by dropping an item etc.)
uint8 i = (13 + _regOffset) << 4;
- const uint8 *src = &_drv->_drvTables[156];
- _drv->_ssgPatches[i] = src[i];
- _drv->_ssgPatches[i + 3] = src[i + 3];
- _drv->_ssgPatches[i + 4] = src[i + 4];
- _drv->_ssgPatches[i + 6] = src[i + 6];
- _drv->_ssgPatches[i + 8] = src[i + 8];
- _drv->_ssgPatches[i + 12] = src[i + 12];
+ const uint8 *src = _envData;
+ _envPatchData[i] = src[i];
+ _envPatchData[i + 3] = src[i + 3];
+ _envPatchData[i + 4] = src[i + 4];
+ _envPatchData[i + 6] = src[i + 6];
+ _envPatchData[i + 8] = src[i + 8];
+ _envPatchData[i + 12] = src[i + 12];
}
#ifndef DISABLE_PC98_RHYTHM_CHANNEL
-TownsPC98_MusicChannelPCM::TownsPC98_MusicChannelPCM(TownsPC98_AudioDriver *driver, uint8 regOffs,
- uint8 flgs, uint8 num, uint8 key, uint8 prt, uint8 id) :
- TownsPC98_MusicChannel(driver, regOffs, flgs, num, key, prt, id), controlEvents(0) {
-}
-
-void TownsPC98_MusicChannelPCM::init() {
- _algorithm = 0x80;
-
-#define Control(x) &TownsPC98_MusicChannelPCM::control_##x
- static const ControlEventFunc ctrlEventsPCM[] = {
- Control(dummy),
- Control(f1_prcStart),
- Control(dummy),
- Control(dummy),
- Control(dummy),
- Control(dummy),
- Control(f6_repeatSection),
- Control(dummy),
- Control(dummy),
- Control(dummy),
- Control(fa_writeReg),
- Control(dummy),
- Control(dummy),
- Control(dummy),
- Control(dummy),
- Control(ff_endOfTrack)
- };
-#undef Control
-
- controlEvents = ctrlEventsPCM;
+#define CONTROL(x) _controlEvents.push_back(new ControlEvent(this, &TownsPC98_MusicChannelPCM::control_##x))
+TownsPC98_MusicChannelPCM::TownsPC98_MusicChannelPCM(TownsPC98_AudioDriver *driver, uint8 regOffs, uint8 flgs, uint8 num, uint8 key, uint8 prt, uint8 id) :
+TownsPC98_MusicChannel(driver, regOffs, flgs, num, key, prt, id), _algorithm(0x80) {
+ CONTROL(dummy);
+ CONTROL(f1_prcStart);
+ CONTROL(dummy);
+ CONTROL(dummy);
+ CONTROL(dummy);
+ CONTROL(dummy);
+ CONTROL(f6_repeatSection);
+ CONTROL(dummy);
+ CONTROL(dummy);
+ CONTROL(dummy);
+ CONTROL(fa_writeReg);
+ CONTROL(dummy);
+ CONTROL(dummy);
+ CONTROL(dummy);
+ CONTROL(dummy);
+ CONTROL(ff_endOfTrack);
+}
+#undef CONTROL
+
+TownsPC98_MusicChannelPCM::~TownsPC98_MusicChannelPCM() {
+ for (Common::Array<const ControlEvent*>::iterator i = _controlEvents.begin(); i != _controlEvents.end(); ++i)
+ delete *i;
}
void TownsPC98_MusicChannelPCM::loadData(uint8 *data) {
@@ -981,7 +1030,7 @@ void TownsPC98_MusicChannelPCM::processEvents() {
if (cmd == 0x80) {
loop = false;
} else if (cmd < 0xf0) {
- _drv->writeReg(_part, 0x10, cmd);
+ writeReg(0, 0x10, cmd);
} else if (!processControlEvent(cmd)) {
return;
}
@@ -992,12 +1041,12 @@ void TownsPC98_MusicChannelPCM::processEvents() {
bool TownsPC98_MusicChannelPCM::processControlEvent(uint8 cmd) {
uint8 para = *_dataPtr++;
- return (this->*controlEvents[cmd & 0x0f])(para);
+ return (*_controlEvents[cmd & 0x0f])(para);
}
bool TownsPC98_MusicChannelPCM::control_f1_prcStart(uint8 para) {
_totalLevel = para;
- _drv->writeReg(_part, 0x11, para);
+ writeReg(0, 0x11, para);
return true;
}
@@ -1005,13 +1054,13 @@ bool TownsPC98_MusicChannelPCM::control_ff_endOfTrack(uint8 para) {
uint16 val = READ_LE_UINT16(--_dataPtr);
if (val) {
// loop
- _dataPtr = _drv->_trackPtr + val;
+ _dataPtr = _driver->_trackPtr + val;
return true;
} else {
// quit parsing for active channel
--_dataPtr;
_flags |= CHS_EOT;
- _drv->_finishedRhythmFlag |= _idFlag;
+ _driver->_finishedRhythmFlag |= _idFlag;
return false;
}
}
@@ -1022,12 +1071,8 @@ TownsPC98_AudioDriver::TownsPC98_AudioDriver(Audio::Mixer *mixer, EmuType type)
#ifndef DISABLE_PC98_RHYTHM_CHANNEL
_rhythmChannel(0),
#endif
- _trackPtr(0), _sfxData(0), _sfxOffs(0), _ssgPatches(0),
- _patches(0), _sfxBuffer(0), _musicBuffer(0),
-
- _opnCarrier(_drvTables + 76), _opnFreqTable(_drvTables + 108), _opnFreqTableSSG(_drvTables + 132),
- _opnFxCmdLen(_drvTables + 36), _opnLvlPresets(_drvTables + (type == kTypeTowns ? 52 : 84)),
-
+ _sfxData(0), _sfxOffs(0), _patchData(0), _sfxBuffer(0), _musicBuffer(0), _trackPtr(0),
+ _levelPresets(type == kTypeTowns ? _levelPresetFMTOWNS : _levelPresetPC98),
_updateChannelsFlag(type == kType26 ? 0x07 : 0x3F), _finishedChannelsFlag(0),
_updateSSGFlag(type == kTypeTowns ? 0x00 : 0x07), _finishedSSGFlag(0),
_updateRhythmFlag(type == kType86 ?
@@ -1069,8 +1114,6 @@ TownsPC98_AudioDriver::~TownsPC98_AudioDriver() {
#ifndef DISABLE_PC98_RHYTHM_CHANNEL
delete _rhythmChannel;
#endif
-
- delete[] _ssgPatches;
}
bool TownsPC98_AudioDriver::init() {
@@ -1087,37 +1130,29 @@ bool TownsPC98_AudioDriver::init() {
_channels = new TownsPC98_MusicChannel *[_numChanFM];
for (int i = 0; i < _numChanFM; i++) {
int ii = i * 6;
- _channels[i] = new TownsPC98_MusicChannel(this, _drvTables[ii], _drvTables[ii + 1],
- _drvTables[ii + 2], _drvTables[ii + 3], _drvTables[ii + 4], _drvTables[ii + 5]);
- _channels[i]->init();
+ _channels[i] = new TownsPC98_MusicChannel(this, _channelPreset[ii], _channelPreset[ii + 1],
+ _channelPreset[ii + 2], _channelPreset[ii + 3], _channelPreset[ii + 4], _channelPreset[ii + 5]);
}
if (_numChanSSG) {
- _ssgPatches = new uint8[256];
- memcpy(_ssgPatches, _drvTables + 156, 256);
-
_ssgChannels = new TownsPC98_MusicChannelSSG *[_numChanSSG];
for (int i = 0; i < _numChanSSG; i++) {
int ii = i * 6;
- _ssgChannels[i] = new TownsPC98_MusicChannelSSG(this, _drvTables[ii], _drvTables[ii + 1],
- _drvTables[ii + 2], _drvTables[ii + 3], _drvTables[ii + 4], _drvTables[ii + 5]);
- _ssgChannels[i]->init();
+ _ssgChannels[i] = new TownsPC98_MusicChannelSSG(this, _channelPreset[ii], _channelPreset[ii + 1],
+ _channelPreset[ii + 2], _channelPreset[ii + 3], _channelPreset[ii + 4], _channelPreset[ii + 5]);
}
_sfxChannels = new TownsPC98_SfxChannel *[2];
for (int i = 0; i < 2; i++) {
int ii = (i + 1) * 6;
- _sfxChannels[i] = new TownsPC98_SfxChannel(this, _drvTables[ii], _drvTables[ii + 1],
- _drvTables[ii + 2], _drvTables[ii + 3], _drvTables[ii + 4], _drvTables[ii + 5]);
- _sfxChannels[i]->init();
+ _sfxChannels[i] = new TownsPC98_SfxChannel(this, _channelPreset[ii], _channelPreset[ii + 1],
+ _channelPreset[ii + 2], _channelPreset[ii + 3], _channelPreset[ii + 4], _channelPreset[ii + 5]);
}
}
#ifndef DISABLE_PC98_RHYTHM_CHANNEL
- if (_numChanRHY) {
+ if (_numChanRHY)
_rhythmChannel = new TownsPC98_MusicChannelPCM(this, 0, 0, 0, 0, 0, 1);
- _rhythmChannel->init();
- }
#endif
setMusicTempo(84);
@@ -1142,7 +1177,7 @@ void TownsPC98_AudioDriver::loadMusicData(uint8 *data, bool loadPaused) {
reset();
PC98AudioCore::MutexLock lock = _pc98a->stackLockMutex();
- uint8 *src_a = _trackPtr = _musicBuffer = data;
+ const uint8 *src_a = _trackPtr = _musicBuffer = data;
for (uint8 i = 0; i < 3; i++) {
_channels[i]->loadData(data + READ_LE_UINT16(src_a));
@@ -1168,7 +1203,7 @@ void TownsPC98_AudioDriver::loadMusicData(uint8 *data, bool loadPaused) {
preventRegisterWrite(false);
- _patches = src_a + 4;
+ _patchData = src_a + 4;
_finishedChannelsFlag = _finishedSSGFlag = _finishedRhythmFlag = 0;
_musicPlaying = !loadPaused;
@@ -1203,7 +1238,7 @@ void TownsPC98_AudioDriver::reset() {
_musicPlaying = false;
_sfxPlaying = false;
- _fading = false;
+ _fading = 0;
_looping = 0;
_musicTickCounter = 0;
_sfxData = 0;
@@ -1218,8 +1253,6 @@ void TownsPC98_AudioDriver::reset() {
if (_numChanSSG) {
for (int i = 0; i < 2; i++)
_sfxChannels[i]->reset();
-
- memcpy(_ssgPatches, _drvTables + 156, 256);
}
#ifndef DISABLE_PC98_RHYTHM_CHANNEL
@@ -1264,11 +1297,11 @@ void TownsPC98_AudioDriver::cont() {
_musicPlaying = true;
}
-bool TownsPC98_AudioDriver::looping() {
+bool TownsPC98_AudioDriver::looping() const {
return _looping == _updateChannelsFlag ? true : false;
}
-bool TownsPC98_AudioDriver::musicPlaying() {
+bool TownsPC98_AudioDriver::musicPlaying() const {
return _musicPlaying;
}
@@ -1280,6 +1313,10 @@ void TownsPC98_AudioDriver::setSoundEffectVolume(int volume) {
_pc98a->setSoundEffectVolume(volume);
}
+uint8 TownsPC98_AudioDriver::readReg(uint8 part, uint8 reg) {
+ return _pc98a->readReg(part, reg);
+}
+
void TownsPC98_AudioDriver::writeReg(uint8 part, uint8 reg, uint8 val) {
if (!_regWriteProtect)
_pc98a->writeReg(part, reg, val);
@@ -1377,76 +1414,24 @@ void TownsPC98_AudioDriver::setSfxTempo(uint16 tempo) {
writeReg(0, 0x25, tempo >> 8);
writeReg(0, 0x27, 0x33);
}
-const uint8 TownsPC98_AudioDriver::_drvTables[] = {
- // channel presets
+
+const uint8 TownsPC98_AudioDriver::_channelPreset[36] = {
0x00, 0x80, 0x00, 0x00, 0x00, 0x01,
0x01, 0x80, 0x01, 0x01, 0x00, 0x02,
0x02, 0x80, 0x02, 0x02, 0x00, 0x04,
0x00, 0x80, 0x03, 0x04, 0x01, 0x08,
0x01, 0x80, 0x04, 0x05, 0x01, 0x10,
- 0x02, 0x80, 0x05, 0x06, 0x01, 0x20,
-
- // control event size
- 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x04, 0x05,
- 0x02, 0x06, 0x02, 0x00, 0x00, 0x02, 0x00, 0x02,
+ 0x02, 0x80, 0x05, 0x06, 0x01, 0x20
+};
- // fmt level presets
+const uint8 TownsPC98_AudioDriver::_levelPresetFMTOWNS[24] = {
0x54, 0x50, 0x4C, 0x48, 0x44, 0x40, 0x3C, 0x38,
0x34, 0x30, 0x2C, 0x28, 0x24, 0x20, 0x1C, 0x18,
- 0x14, 0x10, 0x0C, 0x08, 0x04, 0x90, 0x90, 0x90,
-
- // carriers
- 0x08, 0x08, 0x08, 0x08, 0x0C, 0x0E, 0x0E, 0x0F,
+ 0x14, 0x10, 0x0C, 0x08, 0x04, 0x90, 0x90, 0x90
+};
- // pc98 level presets
+const uint8 TownsPC98_AudioDriver::_levelPresetPC98[24] = {
0x40, 0x3B, 0x38, 0x34, 0x30, 0x2A, 0x28, 0x25,
0x22, 0x20, 0x1D, 0x1A, 0x18, 0x15, 0x12, 0x10,
- 0x0D, 0x0A, 0x08, 0x05, 0x02, 0x90, 0x90, 0x90,
-
- // frequencies
- 0x6A, 0x02, 0x8F, 0x02, 0xB6, 0x02, 0xDF, 0x02,
- 0x0B, 0x03, 0x39, 0x03, 0x6A, 0x03, 0x9E, 0x03,
- 0xD5, 0x03, 0x10, 0x04, 0x4E, 0x04, 0x8F, 0x04,
-
- // ssg frequencies
- 0xE8, 0x0E, 0x12, 0x0E, 0x48, 0x0D, 0x89, 0x0C,
- 0xD5, 0x0B, 0x2B, 0x0B, 0x8A, 0x0A, 0xF3, 0x09,
- 0x64, 0x09, 0xDD, 0x08, 0x5E, 0x08, 0xE6, 0x07,
-
- // ssg patch data
- 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x81, 0x00, 0x00,
- 0x00, 0x81, 0x00, 0x00, 0xFF, 0x81, 0x00, 0x00,
- 0x00, 0x01, 0xFF, 0xFF, 0x37, 0x81, 0xC8, 0x00,
- 0x00, 0x81, 0x00, 0x00, 0x0A, 0x81, 0x00, 0x00,
- 0x00, 0x01, 0xFF, 0xFF, 0x37, 0x81, 0xC8, 0x00,
- 0x01, 0x81, 0x00, 0x00, 0x0A, 0x81, 0x00, 0x00,
- 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0x81, 0xBE, 0x00,
- 0x00, 0x81, 0x00, 0x00, 0x0A, 0x81, 0x00, 0x00,
- 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0x81, 0xBE, 0x00,
- 0x01, 0x81, 0x00, 0x00, 0x0A, 0x81, 0x00, 0x00,
- 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0x81, 0xBE, 0x00,
- 0x04, 0x81, 0x00, 0x00, 0x0A, 0x81, 0x00, 0x00,
- 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0x81, 0xBE, 0x00,
- 0x0A, 0x81, 0x00, 0x00, 0x0A, 0x81, 0x00, 0x00,
- 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0x81, 0x01, 0x00,
- 0xFF, 0x81, 0x00, 0x00, 0xFF, 0x81, 0x00, 0x00,
- 0xFF, 0x01, 0xFF, 0xFF, 0xFF, 0x81, 0xFF, 0x00,
- 0x01, 0x81, 0x00, 0x00, 0x0A, 0x81, 0x00, 0x00,
- 0x64, 0x01, 0xFF, 0x64, 0xFF, 0x81, 0xFF, 0x00,
- 0x01, 0x81, 0x00, 0x00, 0x0A, 0x81, 0x00, 0x00,
-
- 0x02, 0x01, 0xFF, 0x28, 0xFF, 0x81, 0xF0, 0x00,
- 0x00, 0x81, 0x00, 0x00, 0x0A, 0x81, 0x00, 0x00,
- 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0x81, 0xC8, 0x00,
- 0x01, 0x81, 0x00, 0x00, 0x28, 0x81, 0x00, 0x00,
- 0x00, 0x01, 0xFF, 0x78, 0x5F, 0x81, 0xA0, 0x00,
- 0x05, 0x81, 0x00, 0x00, 0x28, 0x81, 0x00, 0x00,
- 0x00, 0x01, 0xFF, 0xFF, 0x00, 0x81, 0x00, 0x00,
- 0x00, 0x81, 0x00, 0x00, 0xFF, 0x81, 0x00, 0x00,
- 0x00, 0x01, 0xFF, 0xFF, 0x00, 0x81, 0x00, 0x00,
- 0x00, 0x81, 0x00, 0x00, 0xFF, 0x81, 0x00, 0x00,
- 0x00, 0x01, 0xFF, 0xFF, 0x00, 0x81, 0x00, 0x00,
- 0x00, 0x81, 0x00, 0x00, 0xFF, 0x81, 0x00, 0x00
+ 0x0D, 0x0A, 0x08, 0x05, 0x02, 0x90, 0x90, 0x90
};
-
-#undef EUPHONY_FADEOUT_TICKS
diff --git a/audio/softsynth/fmtowns_pc98/towns_pc98_driver.h b/audio/softsynth/fmtowns_pc98/towns_pc98_driver.h
index 0b9edcf..448bb2a 100644
--- a/audio/softsynth/fmtowns_pc98/towns_pc98_driver.h
+++ b/audio/softsynth/fmtowns_pc98/towns_pc98_driver.h
@@ -53,13 +53,14 @@ public:
void pause();
void cont();
- bool looping();
- bool musicPlaying();
+ bool looping() const;
+ bool musicPlaying() const;
void setMusicVolume(int volume);
void setSoundEffectVolume(int volume);
private:
+ uint8 readReg(uint8 part, uint8 reg);
void writeReg(uint8 part, uint8 reg, uint8 val);
void preventRegisterWrite(bool prevent);
@@ -78,17 +79,9 @@ private:
TownsPC98_MusicChannelPCM *_rhythmChannel;
#endif
- const uint8 *_opnCarrier;
- const uint8 *_opnFreqTable;
- const uint8 *_opnFreqTableSSG;
- const uint8 *_opnFxCmdLen;
- const uint8 *_opnLvlPresets;
-
uint8 *_musicBuffer;
uint8 *_sfxBuffer;
- uint8 *_trackPtr;
- uint8 *_patches;
- uint8 *_ssgPatches;
+ const uint8 *_patchData;
uint8 _updateChannelsFlag;
uint8 _updateSSGFlag;
@@ -109,14 +102,19 @@ private:
uint8 *_sfxData;
uint16 _sfxOffsets[2];
+ uint8 *_trackPtr;
bool _regWriteProtect;
+
PC98AudioCore *_pc98a;
const int _numChanFM;
const int _numChanSSG;
const int _numChanRHY;
- static const uint8 _drvTables[];
+ static const uint8 _channelPreset[36];
+ static const uint8 _levelPresetFMTOWNS[24];
+ static const uint8 _levelPresetPC98[24];
+ const uint8 *_levelPresets;
bool _ready;
};
Commit: b789d50a55cc22e481d286a1038d3ec4092b23ec
https://github.com/scummvm/scummvm/commit/b789d50a55cc22e481d286a1038d3ec4092b23ec
Author: athrxx (athrxx at scummvm.org)
Date: 2019-03-07T21:28:35+01:00
Commit Message:
AUDIO: (FM-TOWNS/PC-98) - fix valgrind warning
(This didn't come up with the targets supported until now, but it does come up with SCI PC-98 music)
Changed paths:
audio/softsynth/fmtowns_pc98/towns_pc98_fmsynth.cpp
diff --git a/audio/softsynth/fmtowns_pc98/towns_pc98_fmsynth.cpp b/audio/softsynth/fmtowns_pc98/towns_pc98_fmsynth.cpp
index b73030e..e3d86b3 100644
--- a/audio/softsynth/fmtowns_pc98/towns_pc98_fmsynth.cpp
+++ b/audio/softsynth/fmtowns_pc98/towns_pc98_fmsynth.cpp
@@ -1317,17 +1317,15 @@ void TownsPC98_FmSynth::setLevelSSG(int vol) {
void TownsPC98_FmSynth::generateTables() {
delete[] _oprRates;
- _oprRates = new uint8[128];
+ _oprRates = new uint8[130];
WRITE_BE_UINT32(_oprRates + 32, _numChan == 6 ? 0x90900000 : 0x00081018);
WRITE_BE_UINT32(_oprRates + 36, _numChan == 6 ? 0x00001010 : 0x00081018);
memset(_oprRates, 0x90, 32);
- memset(&_oprRates[96], 0x80, 32);
+ memset(&_oprRates[96], 0x80, 34);
uint8 *dst = (uint8 *)_oprRates + 40;
for (int i = 0; i < 40; i += 4)
WRITE_BE_UINT32(dst + i, 0x00081018);
- for (int i = 0; i < 48; i += 4)
- WRITE_BE_UINT32(dst + i, 0x00081018);
dst += 40;
for (uint8 i = 0; i < 16; i ++) {
uint8 v = (i < 12) ? i : 12;
@@ -1335,8 +1333,8 @@ void TownsPC98_FmSynth::generateTables() {
}
delete[] _oprRateshift;
- _oprRateshift = new uint8[128];
- memset(_oprRateshift, 0, 128);
+ _oprRateshift = new uint8[130];
+ memset(_oprRateshift, 0, 130);
dst = (uint8 *)_oprRateshift + 32;
for (int i = 11; i; i--) {
memset(dst, i, 4);
Commit: 49e85f64cf0470439de59ea87e342986b9779efc
https://github.com/scummvm/scummvm/commit/49e85f64cf0470439de59ea87e342986b9779efc
Author: athrxx (athrxx at scummvm.org)
Date: 2019-03-07T21:28:41+01:00
Commit Message:
AUDIO: (FM-TOWNS/PC-98) - allow individual operator frequencies
(also add some sanity checks and make some more adjustments for SCI audio driver)
Changed paths:
audio/softsynth/fmtowns_pc98/towns_pc98_fmsynth.cpp
audio/softsynth/fmtowns_pc98/towns_pc98_fmsynth.h
diff --git a/audio/softsynth/fmtowns_pc98/towns_pc98_fmsynth.cpp b/audio/softsynth/fmtowns_pc98/towns_pc98_fmsynth.cpp
index e3d86b3..ce006b1 100644
--- a/audio/softsynth/fmtowns_pc98/towns_pc98_fmsynth.cpp
+++ b/audio/softsynth/fmtowns_pc98/towns_pc98_fmsynth.cpp
@@ -34,7 +34,8 @@ public:
void keyOn();
void keyOff();
- void frequency(int freq);
+ void frequencyHi(uint8 frqH);
+ void frequencyLo(uint8 frqL);
void updatePhaseIncrement();
void recalculateRates();
void generateOutput(int32 phasebuf, int32 *feedbuf, int32 &out);
@@ -48,11 +49,14 @@ public:
void sustainRate(uint32 value);
void sustainLevel(uint32 value);
void releaseRate(uint32 value);
+ void envelopeShape(uint32 value);
void totalLevel(uint32 value);
void ampModulation(bool enable);
void reset();
protected:
+ void frequency(int freq);
+
EnvelopeState _state;
bool _holdKey;
uint32 _feedbackLevel;
@@ -64,14 +68,18 @@ protected:
uint32 _specifiedDecayRate;
uint32 _specifiedSustainRate;
uint32 _specifiedReleaseRate;
+ uint32 _envelopeShapeSpecs;
uint32 _tickCount;
uint32 _sustainLevel;
bool _ampMod;
uint32 _frequency;
+ uint16 _freqTemp;
uint8 _kcode;
uint32 _phase;
uint32 _phaseIncrement;
+ uint32 _shapeState;
+ uint8 _shapeScale;
const int32 *_detn;
const uint8 *_rateTbl;
@@ -98,9 +106,9 @@ TownsPC98_FmSynthOperator::TownsPC98_FmSynthOperator(const uint32 timerbase, con
const uint32 *frqTable, const uint32 *sineTable, const int32 *tlevelOut, const int32 *detuneTable) :
_rtt(rtt), _rateTbl(rateTable), _rshiftTbl(shiftTable), _adTbl(attackDecayTable), _fTbl(frqTable),
_sinTbl(sineTable), _tLvlTbl(tlevelOut), _detnTbl(detuneTable), _tickLength(timerbase * 2),
- _specifiedAttackRate(0), _specifiedDecayRate(0), _specifiedReleaseRate(0), _specifiedSustainRate(0),
- _sustainLevel(0), _phase(0), _state(kEnvReady), _holdKey(false), _timer(0), _keyScale1(0),
- _keyScale2(0), _currentLevel(1023), _ampMod(false), _tickCount(0) {
+ _specifiedAttackRate(0), _specifiedDecayRate(0), _specifiedReleaseRate(0), _envelopeShapeSpecs(0), _specifiedSustainRate(0),
+ _sustainLevel(0), _phase(0), _shapeState(0), _shapeScale(0), _state(kEnvReady), _holdKey(false), _timer(0), _keyScale1(0),
+ _keyScale2(0), _freqTemp(0), _currentLevel(1023), _ampMod(false), _tickCount(0), _phaseIncrement(0) {
fs_a.rate = fs_a.shift = fs_d.rate = fs_d.shift = fs_s.rate = fs_s.shift = fs_r.rate = fs_r.shift = 0;
@@ -114,6 +122,7 @@ void TownsPC98_FmSynthOperator::keyOn() {
_holdKey = true;
_state = kEnvAttacking;
_phase = 0;
+ _shapeState = _envelopeShapeSpecs;
}
void TownsPC98_FmSynthOperator::keyOff() {
@@ -125,6 +134,15 @@ void TownsPC98_FmSynthOperator::keyOff() {
_state = kEnvReleasing;
}
+void TownsPC98_FmSynthOperator::frequencyHi(uint8 frqH) {
+ _freqTemp = (_freqTemp & 0xff) | ((frqH & 0x3F) << 8);
+}
+
+void TownsPC98_FmSynthOperator::frequencyLo(uint8 frqL) {
+ _freqTemp = (_freqTemp & 0xff00) | frqL;
+ frequency(_freqTemp);
+}
+
void TownsPC98_FmSynthOperator::frequency(int freq) {
uint8 block = (freq >> 11);
uint16 pos = (freq & 0x7ff);
@@ -132,6 +150,7 @@ void TownsPC98_FmSynthOperator::frequency(int freq) {
_kcode = (block << 2) | ((c < 7) ? 0 : ((c > 8) ? 3 : c - 6));
_frequency = _fTbl[pos << 1] >> (7 - block);
+ _freqTemp = 0;
}
void TownsPC98_FmSynthOperator::updatePhaseIncrement() {
@@ -196,13 +215,13 @@ void TownsPC98_FmSynthOperator::generateOutput(int32 phasebuf, int32 *feed, int3
targetTime = (1 << fs_d.shift) - 1;
nextState = kEnvSustaining;
targetLevel = _sustainLevel;
- levelIncrement = _adTbl[fs_d.rate + ((_tickCount >> fs_d.shift) & 7)];
+ levelIncrement = _adTbl[fs_d.rate + ((_tickCount >> fs_d.shift) & 7)] << _shapeScale;
break;
case kEnvSustaining:
targetTime = (1 << fs_s.shift) - 1;
nextState = kEnvSustaining;
- targetLevel = 1023;
- levelIncrement = _adTbl[fs_s.rate + ((_tickCount >> fs_s.shift) & 7)];
+ targetLevel = _shapeScale ? 832 : 1023;
+ levelIncrement = _adTbl[fs_s.rate + ((_tickCount >> fs_s.shift) & 7)] << _shapeScale;
break;
case kEnvReleasing:
targetTime = (1 << fs_r.shift) - 1;
@@ -219,13 +238,25 @@ void TownsPC98_FmSynthOperator::generateOutput(int32 phasebuf, int32 *feed, int3
if ((_state == kEnvAttacking && _currentLevel <= targetLevel) || (_state != kEnvAttacking && _currentLevel >= targetLevel)) {
if (_state != kEnvDecaying)
_currentLevel = targetLevel;
+ if (_state == kEnvSustaining && _shapeScale) {
+ _currentLevel += 191;
+ if (_shapeState & 1) {
+ if (!(_shapeState & 0x10))
+ _shapeState |= 0x40;
+ } else {
+ nextState = kEnvAttacking;
+ _phase = 0;
+ _currentLevel = 511;
+ _shapeState &= ~0x40;
+ }
+ }
_state = nextState;
}
}
}
- uint32 lvlout = _totalLevel + (uint32) _currentLevel;
-
+ uint32 lvlout = _totalLevel + ((uint32) _currentLevel ^ (_state != kEnvReleasing ? ((_shapeScale * (_shapeState & 4)) >> 3) * 1023 : 0));
+ _shapeState ^= (((_shapeState & 0x40) >> 2) | ((_shapeState & 2) << 1));
int32 outp = 0;
int32 *i = &outp, *o = &outp;
@@ -301,6 +332,11 @@ void TownsPC98_FmSynthOperator::releaseRate(uint32 value) {
recalculateRates();
}
+void TownsPC98_FmSynthOperator::envelopeShape(uint32 value) {
+ _envelopeShapeSpecs = value;
+ _shapeScale = (value & 8) >> 2;
+}
+
void TownsPC98_FmSynthOperator::totalLevel(uint32 value) {
_totalLevel = value << 3;
}
@@ -324,6 +360,7 @@ void TownsPC98_FmSynthOperator::reset() {
decayRate(0);
releaseRate(0);
sustainRate(0);
+ envelopeShape(0);
feedbackLevel(0);
totalLevel(127);
ampModulation(false);
@@ -369,6 +406,7 @@ private:
int _evpUpdateCnt;
uint8 _outN;
int _nTick;
+ uint8 _evpSwap;
int32 *_tlTable;
int32 *_tleTable;
@@ -389,6 +427,9 @@ private:
uint8 _noiseGenerator;
uint8 _chanEnable;
+ uint8 _envH;
+ uint8 _envL;
+ uint8 _flags;
uint8 **_reg;
@@ -473,12 +514,12 @@ private:
TownsPC98_FmSynthSquareSineSource::TownsPC98_FmSynthSquareSineSource(const uint32 timerbase, const uint32 rtt) : _tlTable(0),
_rtt(rtt), _tleTable(0), _updateRequest(-1), _tickLength(timerbase * 27), _ready(0), _reg(0), _rand(1), _outN(1),
_nTick(0), _evpUpdateCnt(0), _evpTimer(0x1f), _pReslt(0x1f), _attack(0), _cont(false), _evpUpdate(true),
- _timer(0), _noiseGenerator(0), _chanEnable(0), _volumeT(0x60),
+ _timer(0), _noiseGenerator(0), _chanEnable(0), _envH(0), _envL(0), _flags(0), _evpSwap(0), _volumeT(0x60),
_volMaskA(0), _volMaskB(0), _volumeA(Audio::Mixer::kMaxMixerVolume), _volumeB(Audio::Mixer::kMaxMixerVolume) {
memset(_channels, 0, sizeof(_channels));
memset(_updateRequestBuf, 0, sizeof(_updateRequestBuf));
- _reg = new uint8 *[11];
+ _reg = new uint8 *[14];
_reg[0] = &_channels[0].frqL;
_reg[1] = &_channels[0].frqH;
@@ -491,6 +532,9 @@ TownsPC98_FmSynthSquareSineSource::TownsPC98_FmSynthSquareSineSource(const uint3
_reg[8] = &_channels[0].vol;
_reg[9] = &_channels[1].vol;
_reg[10] = &_channels[2].vol;
+ _reg[11] = &_envL;
+ _reg[12] = &_envH;
+ _reg[13] = &_flags;
reset();
}
@@ -547,6 +591,7 @@ void TownsPC98_FmSynthSquareSineSource::reset() {
_cont = false;
_evpUpdate = true;
_timer = 0;
+ _evpSwap = 0;
for (int i = 0; i < 3; i++) {
_channels[i].tick = 0;
@@ -563,13 +608,23 @@ void TownsPC98_FmSynthSquareSineSource::writeReg(uint8 address, uint8 value, boo
if (!_ready)
return;
- if (address > 10 || *_reg[address] == value) {
- if ((address == 11 || address == 12 || address == 13) && value)
- warning("TownsPC98_FmSynthSquareSineSource: unsupported reg address: %d", address);
+ if (address > 13) {
+ warning("TownsPC98_FmSynthSquareSineSource: unsupported reg address: %d", address);
return;
}
if (!force) {
+ bool alreadyBuffered = false;
+ for (int i = 0; i < _updateRequest;) {
+ uint8 b = _updateRequestBuf[i++];
+ uint8 a = _updateRequestBuf[i++];
+ if (a == address)
+ alreadyBuffered = (b == value) ? true : false;
+ }
+
+ if (alreadyBuffered)
+ return;
+
if (_updateRequest >= 63) {
warning("TownsPC98_FmSynthSquareSineSource: event buffer overflow");
_updateRequest = -1;
@@ -583,7 +638,7 @@ void TownsPC98_FmSynthSquareSineSource::writeReg(uint8 address, uint8 value, boo
}
uint8 TownsPC98_FmSynthSquareSineSource::readReg(uint8 address) const {
- if (!_ready || address > 10)
+ if (!_ready || address > 13)
return 0;
return *_reg[address];
@@ -615,13 +670,15 @@ void TownsPC98_FmSynthSquareSineSource::nextTick(int32 *buffer, uint32 bufferSiz
}
if (_evpUpdate) {
- if (++_evpUpdateCnt >= 0) {
+ if (++_evpUpdateCnt >= (_envH << 8 | _envL)) {
_evpUpdateCnt = 0;
if (--_evpTimer < 0) {
if (_cont) {
- _evpTimer &= 0x1f;
+ _attack ^= (_evpSwap && _evpTimer & 0x20) ? 0x1F : 0;
+ _evpTimer &= 0x1F;
} else {
+ _attack ^= _evpSwap ? 0x1F : 0;
_evpUpdate = false;
_evpTimer = 0;
}
@@ -657,6 +714,15 @@ void TownsPC98_FmSynthSquareSineSource::updateRegs() {
uint8 b = _updateRequestBuf[i++];
uint8 a = _updateRequestBuf[i++];
writeReg(a, b, true);
+
+ if (a == 13) {
+ _attack = (_flags & 4) ? 0x1F : 0;
+ _cont = (_flags & 8) ? (_flags & 1) ^ 1: false;
+ _evpSwap = (_flags & 8) ? _flags & 2 : _attack;
+ _evpTimer = 0x1F;
+ _evpUpdate = true;
+ _pReslt = _evpTimer ^ _attack;
+ }
}
_updateRequest = -1;
}
@@ -959,7 +1025,6 @@ void TownsPC98_FmSynth::reset() {
_chanInternal[i].opr[ii]->reset();
memset(_chanInternal[i].feedbuf, 0, 3 * sizeof(int32));
_chanInternal[i].algorithm = 0;
- _chanInternal[i].frqTemp = 0;
_chanInternal[i].enableLeft = _chanInternal[i].enableRight = true;
_chanInternal[i].updateEnvelopeParameters = false;
}
@@ -982,9 +1047,9 @@ void TownsPC98_FmSynth::writeReg(uint8 part, uint8 regAddress, uint8 value) {
if (!_ready)
return;
- if (part > 1) {
+ if (part > (_numChan >> 2)) {
warning("TownsPC98_FmSynth::writeReg(): invalid part argument '%d'", part);
- part = 1;
+ return;
}
Common::StackLock lock(_mutex);
@@ -1000,14 +1065,24 @@ void TownsPC98_FmSynth::writeReg(uint8 part, uint8 regAddress, uint8 value) {
TownsPC98_FmSynthOperator **co = 0;
TownsPC98_FmSynthOperator *o = 0;
- if (regAddress > 0x2F) {
- c = &_chanInternal[(l & 3) + 3 * part];
- co = c->opr;
- o = c->opr[oprOrdr[(l - (l & 3)) >> 2]];
- } else if (regAddress == 0x28) {
+ bool checkAddress = false;
+ c = &_chanInternal[(l & 3) + 3 * part];
+ if (regAddress == 0x28) {
c = &_chanInternal[(value & 3) + ((value & 4) ? 3 : 0)];
- co = c->opr;
+ checkAddress = true;
+ } else if (h == 0xA0 && (_registers[0x27][0] & 0x40) && (l > 7 || l == 2 || l == 6)) {
+ c = &_chanInternal[3 * part + 2];
+ o = c->opr[l < 8 ? 3 : 2 - (l & 3)];
+ } else if (h != 0xA0 && h > 0x20) {
+ o = c->opr[oprOrdr[(l & ~3) >> 2]];
+ checkAddress = true;
+ }
+
+ if (checkAddress && (l & 3) == 3) {
+ warning("TownsPC98_FmSynth::writeReg(): invalid write attempt at reg address 0x%2x", regAddress);
+ return;
}
+ co = c->opr;
switch (h) {
case 0x00:
@@ -1027,9 +1102,9 @@ void TownsPC98_FmSynth::writeReg(uint8 part, uint8 regAddress, uint8 value) {
// Key on/off
for (int i = 0; i < 4; i++) {
if ((value >> (4 + i)) & 1)
- co[oprOrdr[i]]->keyOn();
+ co[i]->keyOn();
else
- co[oprOrdr[i]]->keyOff();
+ co[i]->keyOff();
}
} else if (l == 4) {
// Timer A
@@ -1082,6 +1157,7 @@ void TownsPC98_FmSynth::writeReg(uint8 part, uint8 regAddress, uint8 value) {
_timers[1].smpTillCb = _timers[1].smpPerCb;
_timers[1].smpTillCbRem = _timers[1].smpPerCbRem;
}
+
} else if (l == 2) {
// LFO
if (value & 8)
@@ -1130,26 +1206,30 @@ void TownsPC98_FmSynth::writeReg(uint8 part, uint8 regAddress, uint8 value) {
break;
case 0x90:
- warning("TownsPC98_FmSynth: TRYING TO USE SSG ENVELOPE SHAPES (NOT SUPPORTED)");
+ o->envelopeShape(value & 0x0f);
break;
case 0xa0:
// frequency
l &= ~3;
if (l == 0) {
- c->frqTemp = (c->frqTemp & 0xff00) | value;
c->updateEnvelopeParameters = true;
- c->fmIndex = (c->frqTemp >> 4 & 0x7f);
- for (int i = 0; i < 4; i++)
- co[i]->frequency(c->frqTemp);
+ if (o)
+ o->frequencyLo(value);
+ else
+ for (int i = 0; i < 4; i++)
+ co[i]->frequencyLo(value);
} else if (l == 4) {
- c->frqTemp = (c->frqTemp & 0xff) | (value << 8);
- } else if (l == 8) {
- // Ch 3/6 special mode frq
- warning("TownsPC98_FmSynth: TRYING TO USE CH 3/6 SPECIAL MODE FREQ (NOT SUPPORTED)");
- } else if (l == 12) {
- // Ch 3/6 special mode frq
- warning("TownsPC98_FmSynth: TRYING TO USE CH 3/6 SPECIAL MODE FREQ (NOT SUPPORTED)");
+ if (o)
+ o->frequencyHi(value);
+ else
+ for (int i = 0; i < 4; i++)
+ co[i]->frequencyHi(value);
+ } else if (l == 8 && o) {
+ c->updateEnvelopeParameters = true;
+ o->frequencyLo(value);
+ } else if (l == 12 && o) {
+ o->frequencyHi(value);
}
break;
diff --git a/audio/softsynth/fmtowns_pc98/towns_pc98_fmsynth.h b/audio/softsynth/fmtowns_pc98/towns_pc98_fmsynth.h
index ba484e2..58b7ccb 100644
--- a/audio/softsynth/fmtowns_pc98/towns_pc98_fmsynth.h
+++ b/audio/softsynth/fmtowns_pc98/towns_pc98_fmsynth.h
@@ -116,8 +116,6 @@ private:
frqModSvty = value << 5;
}
- uint16 frqTemp;
- uint8 fmIndex;
bool enableLeft;
bool enableRight;
bool updateEnvelopeParameters;
Commit: 1237eb496b64fdc8121c997dd851c17fabb648d6
https://github.com/scummvm/scummvm/commit/1237eb496b64fdc8121c997dd851c17fabb648d6
Author: athrxx (athrxx at scummvm.org)
Date: 2019-03-07T21:28:45+01:00
Commit Message:
AUDIO: (FM-TOWNS/PC-98) - initialize some uninitialized vars
(just to remove some analysis warnings)
Changed paths:
audio/softsynth/fmtowns_pc98/towns_euphony.cpp
diff --git a/audio/softsynth/fmtowns_pc98/towns_euphony.cpp b/audio/softsynth/fmtowns_pc98/towns_euphony.cpp
index d63f990..e80d29b 100644
--- a/audio/softsynth/fmtowns_pc98/towns_euphony.cpp
+++ b/audio/softsynth/fmtowns_pc98/towns_euphony.cpp
@@ -26,9 +26,10 @@
#include "common/textconsole.h"
EuphonyPlayer::EuphonyPlayer(Audio::Mixer *mixer) : _partConfig_enable(0), _partConfig_type(0), _partConfig_ordr(0), _partConfig_volume(0),
- _partConfig_transpose(0), _musicPos(0), _musicStart(0), _playing(false), _savedEventsChain(0),
- _tempoControlMode(0), _timerSetting(0), _tempoMode1PulseCounter(0), _parseToBar(0), _tempoMode1UpdateF8(0), _loop(false),
- _endOfTrack(false), _paused(false), _musicTrackSize(0) {
+ _partConfig_transpose(0), _musicPos(0), _musicStart(0), _playing(false), _savedEventsChain(0), _tempoModifier(0), _bar(0),
+ _beat(0), _defaultBarLength(0), _barLength(0), _playerUpdatesLeft(0), _updatesPerPulseRemainder(0), _updatesPerPulse(0),
+ _deltaTicks(0), _defaultTempo(0), _trackTempo(0), _tempoControlMode(0), _timerSetting(0), _tempoMode1PulseCounter(0),
+ _parseToBar(0), _tempoMode1UpdateF8(0), _loop(false), _endOfTrack(false), _paused(false), _musicTrackSize(0) {
_drivers[0] = _eupDriver = new EuphonyDriver(mixer, this);
_drivers[1] = new Type0Driver(this);
_drivers[2] = 0;
Commit: 8d4418fa365511e8d598823e4369cdc10f87f6b8
https://github.com/scummvm/scummvm/commit/8d4418fa365511e8d598823e4369cdc10f87f6b8
Author: athrxx (athrxx at scummvm.org)
Date: 2019-03-07T21:28:49+01:00
Commit Message:
AUDIO: (FM-TOWNS) - cleanup
Changed paths:
audio/softsynth/fmtowns_pc98/towns_euphony.cpp
audio/softsynth/fmtowns_pc98/towns_euphony.h
diff --git a/audio/softsynth/fmtowns_pc98/towns_euphony.cpp b/audio/softsynth/fmtowns_pc98/towns_euphony.cpp
index e80d29b..e989db3 100644
--- a/audio/softsynth/fmtowns_pc98/towns_euphony.cpp
+++ b/audio/softsynth/fmtowns_pc98/towns_euphony.cpp
@@ -25,24 +25,43 @@
#include "common/util.h"
#include "common/textconsole.h"
+#define EUP_EVENT(x) _euphonyEvents.push_back(new EuphonyEvent(this, &EuphonyPlayer::event_##x))
+
EuphonyPlayer::EuphonyPlayer(Audio::Mixer *mixer) : _partConfig_enable(0), _partConfig_type(0), _partConfig_ordr(0), _partConfig_volume(0),
- _partConfig_transpose(0), _musicPos(0), _musicStart(0), _playing(false), _savedEventsChain(0), _tempoModifier(0), _bar(0),
+ _partConfig_transpose(0), _musicPos(0), _musicStart(0), _playing(false), _pendingEventsChain(0), _tempoModifier(0), _bar(0),
_beat(0), _defaultBarLength(0), _barLength(0), _playerUpdatesLeft(0), _updatesPerPulseRemainder(0), _updatesPerPulse(0),
_deltaTicks(0), _defaultTempo(0), _trackTempo(0), _tempoControlMode(0), _timerSetting(0), _tempoMode1PulseCounter(0),
_parseToBar(0), _tempoMode1UpdateF8(0), _loop(false), _endOfTrack(false), _paused(false), _musicTrackSize(0) {
+ EUP_EVENT(notImpl);
+ EUP_EVENT(noteOn);
+ EUP_EVENT(polyphonicAftertouch);
+ EUP_EVENT(controlChange_pitchWheel);
+ EUP_EVENT(programChange_channelAftertouch);
+ EUP_EVENT(programChange_channelAftertouch);
+ EUP_EVENT(controlChange_pitchWheel);
+ EUP_EVENT(sysex);
+ EUP_EVENT(advanceBar);
+ EUP_EVENT(notImpl);
+ EUP_EVENT(notImpl);
+ EUP_EVENT(setTempo);
+ EUP_EVENT(notImpl);
+ EUP_EVENT(typeOrdrChange);
+
_drivers[0] = _eupDriver = new EuphonyDriver(mixer, this);
_drivers[1] = new Type0Driver(this);
_drivers[2] = 0;
resetTempo();
}
+#undef EUP_EVENT
+
EuphonyPlayer::~EuphonyPlayer() {
for (int i = 0; i < 3; i++)
delete _drivers[i];
- while (_savedEventsChain) {
- SavedEvent *evt = _savedEventsChain;
- _savedEventsChain = _savedEventsChain->next;
+ while (_pendingEventsChain) {
+ PendingEvent *evt = _pendingEventsChain;
+ _pendingEventsChain = _pendingEventsChain->next;
delete evt;
}
@@ -51,6 +70,9 @@ EuphonyPlayer::~EuphonyPlayer() {
delete[] _partConfig_ordr;
delete[] _partConfig_volume;
delete[] _partConfig_transpose;
+
+ for (EuphonyEventsArray::iterator i = _euphonyEvents.begin(); i != _euphonyEvents.end(); ++i)
+ delete *i;
}
bool EuphonyPlayer::init() {
@@ -67,9 +89,9 @@ bool EuphonyPlayer::init() {
if (!_drivers[0] || !_drivers[1])
return false;
- while (_savedEventsChain) {
- SavedEvent *evt = _savedEventsChain;
- _savedEventsChain = _savedEventsChain->next;
+ while (_pendingEventsChain) {
+ PendingEvent *evt = _pendingEventsChain;
+ _pendingEventsChain = _pendingEventsChain->next;
delete evt;
}
@@ -204,9 +226,9 @@ void EuphonyPlayer::reset() {
resetPartConfig();
- while (_savedEventsChain) {
- SavedEvent *evt = _savedEventsChain;
- _savedEventsChain = _savedEventsChain->next;
+ while (_pendingEventsChain) {
+ PendingEvent *evt = _pendingEventsChain;
+ _pendingEventsChain = _pendingEventsChain->next;
delete evt;
}
@@ -309,35 +331,15 @@ void EuphonyPlayer::updateParser() {
}
void EuphonyPlayer::updateCheckEot() {
- if (!_endOfTrack || _savedEventsChain)
+ if (!_endOfTrack || _pendingEventsChain)
return;
stop();
}
bool EuphonyPlayer::parseEvent() {
-#define EVENT(x) &EuphonyPlayer::event_##x
- static const EuphonyEvent events[] = {
- EVENT(notImpl),
- EVENT(noteOn),
- EVENT(polyphonicAftertouch),
- EVENT(controlChange_pitchWheel),
- EVENT(programChange_channelAftertouch),
- EVENT(programChange_channelAftertouch),
- EVENT(controlChange_pitchWheel),
-
- EVENT(sysex),
- EVENT(advanceBar),
- EVENT(notImpl),
- EVENT(notImpl),
- EVENT(setTempo),
- EVENT(notImpl),
- EVENT(typeOrdrChange)
- };
-#undef EVENT
-
uint cmd = _musicPos[0];
if (cmd != 0xfe && cmd != 0xfd) {
- bool result = (cmd >= 0xf0) ? (this->*events[((cmd - 0xf0) >> 1) + 7])() : (this->*events[(cmd - 0x80) >> 4])();
+ bool result = (cmd >= 0xf0) ? (*_euphonyEvents[((cmd - 0xf0) >> 1) + 7])() : (*_euphonyEvents[(cmd - 0x80) >> 4])();
if (!result) {
proceedToNextEvent();
return false;
@@ -369,8 +371,8 @@ void EuphonyPlayer::proceedToNextEvent() {
}
void EuphonyPlayer::updateHangingNotes() {
- SavedEvent *l = 0;
- SavedEvent *e = _savedEventsChain;
+ PendingEvent *l = 0;
+ PendingEvent *e = _pendingEventsChain;
while (e) {
if (--e->len) {
@@ -379,13 +381,13 @@ void EuphonyPlayer::updateHangingNotes() {
continue;
}
- SavedEvent *n = e->next;
+ PendingEvent *n = e->next;
if (l)
l->next = n;
- if (_savedEventsChain == e)
- _savedEventsChain = n;
+ if (_pendingEventsChain == e)
+ _pendingEventsChain = n;
- sendNoteEvent(e->type, e->evt, e->note, e->velo);
+ sendPendingEvent(e->type, e->evt, e->note, e->velo);
delete e;
e = n;
@@ -393,10 +395,10 @@ void EuphonyPlayer::updateHangingNotes() {
}
void EuphonyPlayer::clearHangingNotes() {
- while (_savedEventsChain) {
- SavedEvent *e = _savedEventsChain;
- _savedEventsChain = _savedEventsChain->next;
- sendNoteEvent(e->type, e->evt, e->note, e->velo);
+ while (_pendingEventsChain) {
+ PendingEvent *e = _pendingEventsChain;
+ _pendingEventsChain = _pendingEventsChain->next;
+ sendPendingEvent(e->type, e->evt, e->note, e->velo);
delete e;
}
}
@@ -445,9 +447,9 @@ bool EuphonyPlayer::event_noteOn() {
uint8 note = _musicPos[4];
uint8 velo = _musicPos[5];
- sendEvent(type, evt);
- sendEvent(type, applyTranspose(note));
- sendEvent(type, applyVolumeAdjust(velo));
+ sendByte(type, evt);
+ sendByte(type, applyTranspose(note));
+ sendByte(type, applyVolumeAdjust(velo));
proceedToNextEvent();
if (_musicPos[0] == 0xfe || _musicPos[0] == 0xfd)
@@ -456,7 +458,7 @@ bool EuphonyPlayer::event_noteOn() {
velo = _musicPos[5];
uint16 len = (_musicPos[1] & 0x0f) | ((_musicPos[2] & 0x0f) << 4) | ((_musicPos[3] & 0x0f) << 8) | ((_musicPos[4] & 0x0f) << 12);
- _savedEventsChain = new SavedEvent(evt, type, note, velo, len ? len : 1, _savedEventsChain);
+ _pendingEventsChain = new PendingEvent(evt, type, note, velo, len ? len : 1, _pendingEventsChain);
return false;
}
@@ -470,9 +472,9 @@ bool EuphonyPlayer::event_polyphonicAftertouch() {
uint8 evt = appendEvent(_musicPos[0], _musicPos[1]);
uint8 type = _partConfig_type[_musicPos[1]];
- sendEvent(type, evt);
- sendEvent(type, applyTranspose(_musicPos[4]));
- sendEvent(type, _musicPos[5]);
+ sendByte(type, evt);
+ sendByte(type, applyTranspose(_musicPos[4]));
+ sendByte(type, _musicPos[5]);
return false;
}
@@ -486,9 +488,9 @@ bool EuphonyPlayer::event_controlChange_pitchWheel() {
uint8 evt = appendEvent(_musicPos[0], _musicPos[1]);
uint8 type = _partConfig_type[_musicPos[1]];
- sendEvent(type, evt);
- sendEvent(type, _musicPos[4]);
- sendEvent(type, _musicPos[5]);
+ sendByte(type, evt);
+ sendByte(type, _musicPos[4]);
+ sendByte(type, _musicPos[5]);
return false;
}
@@ -502,21 +504,21 @@ bool EuphonyPlayer::event_programChange_channelAftertouch() {
uint8 evt = appendEvent(_musicPos[0], _musicPos[1]);
uint8 type = _partConfig_type[_musicPos[1]];
- sendEvent(type, evt);
- sendEvent(type, _musicPos[4]);
+ sendByte(type, evt);
+ sendByte(type, _musicPos[4]);
return false;
}
bool EuphonyPlayer::event_sysex() {
uint8 type = _partConfig_type[_musicPos[1]];
- sendEvent(type, 0xF0);
+ sendByte(type, 0xF0);
proceedToNextEvent();
for (bool loop = true; loop; ) {
for (int i = 0; i < 6; i++) {
if (_musicPos[i] != 0xFF) {
- sendEvent(type, _musicPos[i]);
+ sendByte(type, _musicPos[i]);
if (_musicPos[i] >= 0x80) {
loop = false;
break;
@@ -579,36 +581,36 @@ uint8 EuphonyPlayer::applyVolumeAdjust(uint8 in) {
return out & 0xff;
}
-void EuphonyPlayer::sendEvent(uint8 type, uint8 command) {
+void EuphonyPlayer::sendByte(uint8 type, uint8 command) {
int drv = ((type >> 4) + 1) & 3;
if (_drivers[drv])
_drivers[drv]->send(command);
}
-void EuphonyPlayer::sendNoteEvent(int type, int evt, int note, int velo) {
+void EuphonyPlayer::sendPendingEvent(int type, int evt, int note, int velo) {
if (velo)
evt &= 0x8f;
- sendEvent(type, evt);
- sendEvent(type, note);
- sendEvent(type, velo);
+ sendByte(type, evt);
+ sendByte(type, note);
+ sendByte(type, velo);
}
void EuphonyPlayer::sendControllerReset(int type, int part) {
- sendEvent(type, 0xb0 | part);
- sendEvent(type, 0x40);
- sendEvent(type, 0);
- sendEvent(type, 0xb0 | part);
- sendEvent(type, 0x7b);
- sendEvent(type, 0);
- sendEvent(type, 0xb0 | part);
- sendEvent(type, 0x79);
- sendEvent(type, 0x40);
+ sendByte(type, 0xb0 | part);
+ sendByte(type, 0x40);
+ sendByte(type, 0);
+ sendByte(type, 0xb0 | part);
+ sendByte(type, 0x7b);
+ sendByte(type, 0);
+ sendByte(type, 0xb0 | part);
+ sendByte(type, 0x79);
+ sendByte(type, 0x40);
}
void EuphonyPlayer::sendAllNotesOff(int type, int part) {
- sendEvent(type, 0xb0 | part);
- sendEvent(type, 0x40);
- sendEvent(type, 0);
+ sendByte(type, 0xb0 | part);
+ sendByte(type, 0x40);
+ sendByte(type, 0);
}
void EuphonyPlayer::sendTempo(int tempo) {
diff --git a/audio/softsynth/fmtowns_pc98/towns_euphony.h b/audio/softsynth/fmtowns_pc98/towns_euphony.h
index 65e55fa..6b9d94a 100644
--- a/audio/softsynth/fmtowns_pc98/towns_euphony.h
+++ b/audio/softsynth/fmtowns_pc98/towns_euphony.h
@@ -25,6 +25,7 @@
#include "audio/softsynth/fmtowns_pc98/towns_audio.h"
#include "common/array.h"
+#include "common/func.h"
class EuphonyBaseDriver {
public:
@@ -154,7 +155,6 @@ private:
uint8 appendEvent(uint8 evt, uint8 chan);
- typedef bool(EuphonyPlayer::*EuphonyEvent)();
bool event_notImpl();
bool event_noteOn();
bool event_polyphonicAftertouch();
@@ -169,8 +169,8 @@ private:
uint8 applyTranspose(uint8 in);
uint8 applyVolumeAdjust(uint8 in);
- void sendEvent(uint8 type, uint8 command);
- void sendNoteEvent(int type, int evt, int note, int velo);
+ void sendByte(uint8 type, uint8 command);
+ void sendPendingEvent(int type, int evt, int note, int velo);
void sendControllerReset(int type, int part);
void sendAllNotesOff(int type, int part);
void sendTempo(int tempo);
@@ -181,17 +181,21 @@ private:
int8 *_partConfig_volume;
int8 *_partConfig_transpose;
- struct SavedEvent {
- SavedEvent(int ev, int tp, int nt, int vl, int ln, SavedEvent *chain) : evt(ev), type(tp), note(nt), velo(vl), len(ln), next(chain) {}
+ struct PendingEvent {
+ PendingEvent(int ev, int tp, int nt, int vl, int ln, PendingEvent *chain) : evt(ev), type(tp), note(nt), velo(vl), len(ln), next(chain) {}
uint8 evt;
uint8 type;
uint8 note;
uint8 velo;
uint16 len;
- SavedEvent *next;
+ PendingEvent *next;
};
- SavedEvent *_savedEventsChain;
+ PendingEvent *_pendingEventsChain;
+
+ typedef Common::Functor0Mem<bool, EuphonyPlayer> EuphonyEvent;
+ typedef Common::Array<const EuphonyEvent*> EuphonyEventsArray;
+ EuphonyEventsArray _euphonyEvents;
uint8 _defaultBarLength;
uint8 _barLength;
More information about the Scummvm-git-logs
mailing list