From 641ffa5ee3b8036c1a03fc557d0f9705c824eb3e Mon Sep 17 00:00:00 2001 From: David Turner Date: Tue, 8 Jun 2010 20:29:33 +0000 Subject: Modification to remove false positive "Possible divide by zero" warnings given by cppcheck-1.43. These are incorrect as '/' operator has precedence over >>, but this does improve readability anyway. This bug in cppcheck has already been corrected: http://sourceforge.net/apps/trac/cppcheck/ticket/1714 svn-id: r49517 --- sound/softsynth/sid.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound/softsynth') diff --git a/sound/softsynth/sid.cpp b/sound/softsynth/sid.cpp index e0dfd2efc0..d600ac28f5 100644 --- a/sound/softsynth/sid.cpp +++ b/sound/softsynth/sid.cpp @@ -506,7 +506,7 @@ Filter::Filter() { + sizeof(f0_points_6581)/sizeof(*f0_points_6581) - 1, PointPlotter(f0_6581), 1.0); - mixer_DC = -0xfff*0xff/18 >> 7; + mixer_DC = (-0xfff*0xff/18) >> 7; f0 = f0_6581; f0_points = f0_points_6581; -- cgit v1.2.3 From bbad3f333a9227ccb1de633a0fe92d9e01ad7bb3 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Mon, 21 Jun 2010 21:36:36 +0000 Subject: Patch #1956501: "GUI/LAUNCHER: Midi device selection" svn-id: r50128 --- sound/softsynth/adlib.cpp | 16 ++++------------ sound/softsynth/fluidsynth.cpp | 13 ++----------- sound/softsynth/mt32.cpp | 23 +++++++---------------- sound/softsynth/ym2612.cpp | 16 ++++------------ 4 files changed, 17 insertions(+), 51 deletions(-) (limited to 'sound/softsynth') diff --git a/sound/softsynth/adlib.cpp b/sound/softsynth/adlib.cpp index 6697cef646..ffb359e816 100644 --- a/sound/softsynth/adlib.cpp +++ b/sound/softsynth/adlib.cpp @@ -27,6 +27,7 @@ #include "common/util.h" #include "sound/fmopl.h" #include "sound/musicplugin.h" +#include "common/translation.h" #ifdef DEBUG_ADLIB static int tick; @@ -1586,7 +1587,7 @@ void MidiDriver_ADLIB::adlib_note_on(int chan, byte note, int mod) { class AdLibEmuMusicPlugin : public MusicPluginObject { public: const char *getName() const { - return "AdLib Emulator"; + return _s("AdLib Emulator"); } const char *getId() const { @@ -1594,7 +1595,7 @@ public: } MusicDevices getDevices() const; - Common::Error createInstance(MidiDriver **mididriver) const; + Common::Error createInstance(MidiDriver **mididriver, MidiDriver::DeviceHandle = 0) const; }; MusicDevices AdLibEmuMusicPlugin::getDevices() const { @@ -1603,21 +1604,12 @@ MusicDevices AdLibEmuMusicPlugin::getDevices() const { return devices; } -Common::Error AdLibEmuMusicPlugin::createInstance(MidiDriver **mididriver) const { +Common::Error AdLibEmuMusicPlugin::createInstance(MidiDriver **mididriver, MidiDriver::DeviceHandle) const { *mididriver = new MidiDriver_ADLIB(g_system->getMixer()); return Common::kNoError; } -MidiDriver *MidiDriver_ADLIB_create() { - MidiDriver *mididriver; - - AdLibEmuMusicPlugin p; - p.createInstance(&mididriver); - - return mididriver; -} - //#if PLUGIN_ENABLED_DYNAMIC(ADLIB) //REGISTER_PLUGIN_DYNAMIC(ADLIB, PLUGIN_TYPE_MUSIC, AdLibEmuMusicPlugin); //#else diff --git a/sound/softsynth/fluidsynth.cpp b/sound/softsynth/fluidsynth.cpp index c3bd782cc1..fcb4591a20 100644 --- a/sound/softsynth/fluidsynth.cpp +++ b/sound/softsynth/fluidsynth.cpp @@ -230,7 +230,7 @@ public: } MusicDevices getDevices() const; - Common::Error createInstance(MidiDriver **mididriver) const; + Common::Error createInstance(MidiDriver **mididriver, MidiDriver::DeviceHandle = 0) const; }; MusicDevices FluidSynthMusicPlugin::getDevices() const { @@ -239,21 +239,12 @@ MusicDevices FluidSynthMusicPlugin::getDevices() const { return devices; } -Common::Error FluidSynthMusicPlugin::createInstance(MidiDriver **mididriver) const { +Common::Error FluidSynthMusicPlugin::createInstance(MidiDriver **mididriver, MidiDriver::DeviceHandle) const { *mididriver = new MidiDriver_FluidSynth(g_system->getMixer()); return Common::kNoError; } -MidiDriver *MidiDriver_FluidSynth_create() { - MidiDriver *mididriver; - - FluidSynthMusicPlugin p; - p.createInstance(&mididriver); - - return mididriver; -} - //#if PLUGIN_ENABLED_DYNAMIC(FLUIDSYNTH) //REGISTER_PLUGIN_DYNAMIC(FLUIDSYNTH, PLUGIN_TYPE_MUSIC, FluidSynthMusicPlugin); //#else diff --git a/sound/softsynth/mt32.cpp b/sound/softsynth/mt32.cpp index 612dce06b0..95263a040d 100644 --- a/sound/softsynth/mt32.cpp +++ b/sound/softsynth/mt32.cpp @@ -39,6 +39,7 @@ #include "common/system.h" #include "common/util.h" #include "common/archive.h" +#include "common/translation.h" #include "graphics/fontman.h" #include "graphics/surface.h" @@ -323,7 +324,7 @@ int MidiDriver_MT32::open() { } _initialising = true; - drawMessage(-1, "Initialising MT-32 Emulator"); + drawMessage(-1, _s("Initialising MT-32 Emulator")); if (!_synth->open(prop)) return MERR_DEVICE_NOT_AVAILABLE; _initialising = false; @@ -537,7 +538,7 @@ void MidiDriver_ThreadedMT32::onTimer() { class MT32EmuMusicPlugin : public MusicPluginObject { public: const char *getName() const { - return "MT-32 Emulator"; + return _s("MT-32 Emulator"); } const char *getId() const { @@ -545,7 +546,7 @@ public: } MusicDevices getDevices() const; - Common::Error createInstance(MidiDriver **mididriver) const; + Common::Error createInstance(MidiDriver **mididriver, MidiDriver::DeviceHandle = 0) const; }; MusicDevices MT32EmuMusicPlugin::getDevices() const { @@ -554,23 +555,13 @@ MusicDevices MT32EmuMusicPlugin::getDevices() const { return devices; } -Common::Error MT32EmuMusicPlugin::createInstance(MidiDriver **mididriver) const { - *mididriver = new MidiDriver_MT32(g_system->getMixer()); - - return Common::kNoError; -} - -MidiDriver *MidiDriver_MT32_create() { - // HACK: It will stay here until engine plugin loader overhaul +Common::Error MT32EmuMusicPlugin::createInstance(MidiDriver **mididriver, MidiDriver::DeviceHandle) const { if (ConfMan.hasKey("extrapath")) SearchMan.addDirectory("extrapath", ConfMan.get("extrapath")); - MidiDriver *mididriver; - - MT32EmuMusicPlugin p; - p.createInstance(&mididriver); + *mididriver = new MidiDriver_MT32(g_system->getMixer()); - return mididriver; + return Common::kNoError; } //#if PLUGIN_ENABLED_DYNAMIC(MT32) diff --git a/sound/softsynth/ym2612.cpp b/sound/softsynth/ym2612.cpp index e337bc4ab9..08331c6244 100644 --- a/sound/softsynth/ym2612.cpp +++ b/sound/softsynth/ym2612.cpp @@ -27,6 +27,7 @@ #include "sound/softsynth/ym2612.h" #include "common/util.h" #include "sound/musicplugin.h" +#include "common/translation.h" //////////////////////////////////////// // @@ -758,7 +759,7 @@ void MidiDriver_YM2612::removeLookupTables() { class TownsEmuMusicPlugin : public MusicPluginObject { public: const char *getName() const { - return "FM Towns Emulator"; + return _s("FM Towns Emulator"); } const char *getId() const { @@ -766,7 +767,7 @@ public: } MusicDevices getDevices() const; - Common::Error createInstance(MidiDriver **mididriver) const; + Common::Error createInstance(MidiDriver **mididriver, MidiDriver::DeviceHandle = 0) const; }; MusicDevices TownsEmuMusicPlugin::getDevices() const { @@ -775,21 +776,12 @@ MusicDevices TownsEmuMusicPlugin::getDevices() const { return devices; } -Common::Error TownsEmuMusicPlugin::createInstance(MidiDriver **mididriver) const { +Common::Error TownsEmuMusicPlugin::createInstance(MidiDriver **mididriver, MidiDriver::DeviceHandle) const { *mididriver = new MidiDriver_YM2612(g_system->getMixer()); return Common::kNoError; } -MidiDriver *MidiDriver_YM2612_create() { - MidiDriver *mididriver; - - TownsEmuMusicPlugin p; - p.createInstance(&mididriver); - - return mididriver; -} - //#if PLUGIN_ENABLED_DYNAMIC(TOWNS) //REGISTER_PLUGIN_DYNAMIC(TOWNS, PLUGIN_TYPE_MUSIC, TownsEmuMusicPlugin); //#else -- cgit v1.2.3 From 46ec88f74d9b7596cee2e6a167b1ccf361771601 Mon Sep 17 00:00:00 2001 From: Florian Kagerer Date: Tue, 22 Jun 2010 15:30:41 +0000 Subject: GUI/LAUNCHER: This should fix the regression concerning pc speaker / pcjr support caused by patch #1956501 svn-id: r50145 --- sound/softsynth/pcspk.cpp | 57 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) (limited to 'sound/softsynth') diff --git a/sound/softsynth/pcspk.cpp b/sound/softsynth/pcspk.cpp index 396d9328f1..8f66578a0b 100644 --- a/sound/softsynth/pcspk.cpp +++ b/sound/softsynth/pcspk.cpp @@ -24,6 +24,7 @@ */ #include "sound/softsynth/pcspk.h" +#include "sound/null.h" namespace Audio { @@ -128,3 +129,59 @@ int8 PCSpeaker::generateTriangle(uint32 x, uint32 oscLength) { } } // End of namespace Audio + + +// Plugin interface +// (This can only create a null driver since pc speaker support is not part of the +// midi driver architecture. But we need the plugin for the options menu in the launcher +// and for MidiDriver::detectDevice() which is more or less used by all engines.) + +class PCSpeakerMusicPlugin : public NullMusicPlugin { +public: + const char *getName() const { + return _s("PC Speaker Emulator"); + } + + const char *getId() const { + return "pcspk"; + } + + MusicDevices getDevices() const; +}; + +MusicDevices PCSpeakerMusicPlugin::getDevices() const { + MusicDevices devices; + devices.push_back(MusicDevice(this, _s(""), MT_PCSPK)); + return devices; +} + +class PCjrMusicPlugin : public NullMusicPlugin { +public: + const char *getName() const { + return _s("IBM PCjr Emulator"); + } + + const char *getId() const { + return "pcjr"; + } + + MusicDevices getDevices() const; +}; + +MusicDevices PCjrMusicPlugin::getDevices() const { + MusicDevices devices; + devices.push_back(MusicDevice(this, _s(""), MT_PCJR)); + return devices; +} + +//#if PLUGIN_ENABLED_DYNAMIC(PCSPK) + //REGISTER_PLUGIN_DYNAMIC(PCSPK, PLUGIN_TYPE_MUSIC, PCSpeakerMusicPlugin); +//#else + REGISTER_PLUGIN_STATIC(PCSPK, PLUGIN_TYPE_MUSIC, PCSpeakerMusicPlugin); +//#endif + +//#if PLUGIN_ENABLED_DYNAMIC(PCJR) + //REGISTER_PLUGIN_DYNAMIC(PCJR, PLUGIN_TYPE_MUSIC, PCjrMusicPlugin); +//#else + REGISTER_PLUGIN_STATIC(PCJR, PLUGIN_TYPE_MUSIC, PCjrMusicPlugin); +//#endif \ No newline at end of file -- cgit v1.2.3 From 3962f8ba59925ea3ffa5e27e738c2edc9434b74c Mon Sep 17 00:00:00 2001 From: Florian Kagerer Date: Fri, 25 Jun 2010 18:47:52 +0000 Subject: AUDIO: some fixes in the audio device code (no sound option, new GUIO flags) svn-id: r50281 --- sound/softsynth/pcspk.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound/softsynth') diff --git a/sound/softsynth/pcspk.cpp b/sound/softsynth/pcspk.cpp index 8f66578a0b..fae2b7eef3 100644 --- a/sound/softsynth/pcspk.cpp +++ b/sound/softsynth/pcspk.cpp @@ -184,4 +184,4 @@ MusicDevices PCjrMusicPlugin::getDevices() const { //REGISTER_PLUGIN_DYNAMIC(PCJR, PLUGIN_TYPE_MUSIC, PCjrMusicPlugin); //#else REGISTER_PLUGIN_STATIC(PCJR, PLUGIN_TYPE_MUSIC, PCjrMusicPlugin); -//#endif \ No newline at end of file +//#endif -- cgit v1.2.3 From 063cef0c284cda74f6ad366182818ac4d3dfca83 Mon Sep 17 00:00:00 2001 From: Jordi Vilalta Prat Date: Sat, 26 Jun 2010 15:48:03 +0000 Subject: GUI: Add and improve some messages to translate svn-id: r50324 --- sound/softsynth/pcspk.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound/softsynth') diff --git a/sound/softsynth/pcspk.cpp b/sound/softsynth/pcspk.cpp index fae2b7eef3..bdf9f112e8 100644 --- a/sound/softsynth/pcspk.cpp +++ b/sound/softsynth/pcspk.cpp @@ -151,7 +151,7 @@ public: MusicDevices PCSpeakerMusicPlugin::getDevices() const { MusicDevices devices; - devices.push_back(MusicDevice(this, _s(""), MT_PCSPK)); + devices.push_back(MusicDevice(this, "", MT_PCSPK)); return devices; } @@ -170,7 +170,7 @@ public: MusicDevices PCjrMusicPlugin::getDevices() const { MusicDevices devices; - devices.push_back(MusicDevice(this, _s(""), MT_PCJR)); + devices.push_back(MusicDevice(this, "", MT_PCJR)); return devices; } -- cgit v1.2.3 From 0b48a71c9955b39117e2eb35b3e398f5c95c008a Mon Sep 17 00:00:00 2001 From: Max Horn Date: Sat, 17 Jul 2010 18:41:38 +0000 Subject: Remove PalmOS port svn-id: r50964 --- sound/softsynth/opl/mame.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound/softsynth') diff --git a/sound/softsynth/opl/mame.cpp b/sound/softsynth/opl/mame.cpp index 9e7cbfe3dc..f6da659918 100644 --- a/sound/softsynth/opl/mame.cpp +++ b/sound/softsynth/opl/mame.cpp @@ -33,7 +33,7 @@ #include "mame.h" -#if defined (_WIN32_WCE) || defined (__SYMBIAN32__) || defined(PALMOS_MODE) || defined(__GP32__) || defined(GP2X) || defined (__MAEMO__) || defined(__DS__) || defined (__MINT__) || defined(__N64__) +#if defined (_WIN32_WCE) || defined (__SYMBIAN32__) || defined(__GP32__) || defined(GP2X) || defined (__MAEMO__) || defined(__DS__) || defined (__MINT__) || defined(__N64__) #include "common/config-manager.h" #endif @@ -1212,7 +1212,7 @@ FM_OPL *makeAdLibOPL(int rate) { // We need to emulate one YM3812 chip int env_bits = FMOPL_ENV_BITS_HQ; int eg_ent = FMOPL_EG_ENT_HQ; -#if defined (_WIN32_WCE) || defined(__SYMBIAN32__) || defined(PALMOS_MODE) || defined(__GP32__) || defined (GP2X) || defined(__MAEMO__) || defined(__DS__) || defined (__MINT__) || defined(__N64__) +#if defined (_WIN32_WCE) || defined(__SYMBIAN32__) || defined(__GP32__) || defined (GP2X) || defined(__MAEMO__) || defined(__DS__) || defined (__MINT__) || defined(__N64__) if (ConfMan.hasKey("FM_high_quality") && ConfMan.getBool("FM_high_quality")) { env_bits = FMOPL_ENV_BITS_HQ; eg_ent = FMOPL_EG_ENT_HQ; -- cgit v1.2.3 From e5e94d45118781902465024fc9a85c7aa0bfd3ce Mon Sep 17 00:00:00 2001 From: Johannes Schickel Date: Wed, 21 Jul 2010 18:17:51 +0000 Subject: Strip trailing whitespaces in our common code base. svn-id: r51094 --- sound/softsynth/mt32.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound/softsynth') diff --git a/sound/softsynth/mt32.cpp b/sound/softsynth/mt32.cpp index 95263a040d..54366a4300 100644 --- a/sound/softsynth/mt32.cpp +++ b/sound/softsynth/mt32.cpp @@ -149,7 +149,7 @@ static void drawProgress(float progress) { Common::Rect r(x, y, x + w, y + h); uint32 col; - + if (screenFormat.bytesPerPixel > 1) col = screenFormat.RGBToColor(0, 171, 0); else @@ -184,7 +184,7 @@ static void drawMessage(int offset, const Common::String &text) { uint16 y = g_system->getHeight() / 2 - h / 2 + offset * (h + 1); uint32 col; - + if (screenFormat.bytesPerPixel > 1) col = screenFormat.RGBToColor(0, 0, 0); else -- cgit v1.2.3 From 780b04367738c42f5b1704b495248894f132deb7 Mon Sep 17 00:00:00 2001 From: Torbjörn Andersson Date: Wed, 21 Jul 2010 18:59:23 +0000 Subject: Janitorial: Removed extra semi-colon. svn-id: r51096 --- sound/softsynth/opl/dbopl.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound/softsynth') diff --git a/sound/softsynth/opl/dbopl.cpp b/sound/softsynth/opl/dbopl.cpp index db07eaf8cc..857ed78436 100644 --- a/sound/softsynth/opl/dbopl.cpp +++ b/sound/softsynth/opl/dbopl.cpp @@ -418,7 +418,7 @@ Bits Operator::TemplateVolume( ) { } //In sustain phase, but not sustaining, do regular release case RELEASE: - vol += RateForward( releaseAdd );; + vol += RateForward( releaseAdd ); if ( GCC_UNLIKELY(vol >= ENV_MAX) ) { volume = ENV_MAX; SetState( OFF ); -- cgit v1.2.3 From 9c8b4655053063fcdd5311ee0e5df5a4bd19cf92 Mon Sep 17 00:00:00 2001 From: Florian Kagerer Date: Mon, 2 Aug 2010 18:30:25 +0000 Subject: KYRA: FM-Towns audio driver rewrite - FM-Towns euphony driver completely rewritten based on KYRA FM-Towns and LOOM towns disasm. - Split all the emu and driver code from sound_towns.cpp into different files to make things a bit less confusing. - Move the driver code to common space since the exact same euphony driver is used by LOOM which means we could get rid of the outdated and incomplete ym2612 driver/emu implementation (which doesn't even do things like instrument loading, pan position, etc). I haven't tried to add this to the Scumm engine yet, since I am not familiar with it and my priority was to get the driver finished first. But from the look of disasm it shouldn't be difficult to do. - Introduce a generic FM-Towns audio interface based on FM-Towns system file disasm which was necessary for the euphony driver rewrite. Every FM-Towns game I have seen so far seems to access the audio hardware via these system functions. This interface implementation will also allow reasonably simple creation of new FM-Towns audio drivers (e.g. this could be used for Kings Quest 5 FM-Towns or others). - Move the PC98 driver to common space, too, since I have a strong feeling that this driver is also used in the PC98 version of Future Wars - This also improves KYRA FM-Towns music quality, sound effects accuracy and music fading. svn-id: r51645 --- sound/softsynth/fmtowns_pc98/towns_audio.cpp | 1479 ++++++++++++++++++++ sound/softsynth/fmtowns_pc98/towns_audio.h | 162 +++ sound/softsynth/fmtowns_pc98/towns_euphony.cpp | 886 ++++++++++++ sound/softsynth/fmtowns_pc98/towns_euphony.h | 178 +++ sound/softsynth/fmtowns_pc98/towns_pc98_driver.cpp | 1403 +++++++++++++++++++ sound/softsynth/fmtowns_pc98/towns_pc98_driver.h | 110 ++ .../softsynth/fmtowns_pc98/towns_pc98_fmsynth.cpp | 1461 +++++++++++++++++++ sound/softsynth/fmtowns_pc98/towns_pc98_fmsynth.h | 171 +++ 8 files changed, 5850 insertions(+) create mode 100644 sound/softsynth/fmtowns_pc98/towns_audio.cpp create mode 100644 sound/softsynth/fmtowns_pc98/towns_audio.h create mode 100644 sound/softsynth/fmtowns_pc98/towns_euphony.cpp create mode 100644 sound/softsynth/fmtowns_pc98/towns_euphony.h create mode 100644 sound/softsynth/fmtowns_pc98/towns_pc98_driver.cpp create mode 100644 sound/softsynth/fmtowns_pc98/towns_pc98_driver.h create mode 100644 sound/softsynth/fmtowns_pc98/towns_pc98_fmsynth.cpp create mode 100644 sound/softsynth/fmtowns_pc98/towns_pc98_fmsynth.h (limited to 'sound/softsynth') diff --git a/sound/softsynth/fmtowns_pc98/towns_audio.cpp b/sound/softsynth/fmtowns_pc98/towns_audio.cpp new file mode 100644 index 0000000000..0d5a16b35f --- /dev/null +++ b/sound/softsynth/fmtowns_pc98/towns_audio.cpp @@ -0,0 +1,1479 @@ +/* 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. + * + * $URL$ + * $Id$ + * + */ + +#include "sound/softsynth/fmtowns_pc98/towns_audio.h" +#include "common/endian.h" + + +class TownsAudio_PcmChannel { +friend class TownsAudioInterface; +public: + TownsAudio_PcmChannel(); + ~TownsAudio_PcmChannel(); + +private: + void loadExtData(uint8 *buffer, uint32 size); + void setupLoop(uint32 start, uint32 len); + void clear(); + + void envAttack(); + void envDecay(); + void envSustain(); + void envRelease(); + + uint8 *curInstrument; + uint8 note; + uint8 velo; + + int8 *data; + int8 *dataEnd; + + int8 *loopEnd; + uint32 loopLen; + + uint16 stepNote; + uint16 stepPitch; + uint16 step; + + uint8 panLeft; + uint8 panRight; + + uint32 pos; + + uint8 envTotalLevel; + uint8 envAttackRate; + uint8 envDecayRate; + uint8 envSustainLevel; + uint8 envSustainRate; + uint8 envReleaseRate; + + int16 envStep; + int16 envCurrentLevel; + + EnvelopeState envState; + + int8 *extData; +}; + +class TownsAudio_WaveTable { +friend class TownsAudioInterface; +public: + TownsAudio_WaveTable(); + ~TownsAudio_WaveTable(); + +private: + void readHeader(const uint8 *buffer); + void readData(const uint8 *buffer); + void clear(); + + char name[9]; + int32 id; + uint32 size; + uint32 loopStart; + uint32 loopLen; + uint16 rate; + uint16 rateOffs; + uint16 baseNote; + int8 *data; +}; + +TownsAudioInterface::TownsAudioInterface(Audio::Mixer *mixer, TownsAudioInterfacePluginDriver *driver) : TownsPC98_FmSynth(mixer, kTypeTowns), + _fmInstruments(0), _pcmInstruments(0), _pcmChan(0), _waveTables(0), _waveTablesTotalDataSize(0), + _baserate(55125.0f / (float)mixer->getOutputRate()), _tickLength(0), _timer(0), _drv(driver), _ready(false) { + +#define INTCB(x) &TownsAudioInterface::intf_##x + static const TownsAudioIntfCallback intfCb[] = { + // 0 + INTCB(reset), + INTCB(keyOn), + INTCB(keyOff), + INTCB(setPanPos), + // 4 + INTCB(setInstrument), + INTCB(loadInstrument), + INTCB(notImpl), + INTCB(setPitch), + // 8 + INTCB(setLevel), + INTCB(chanOff), + INTCB(notImpl), + INTCB(notImpl), + // 12 + INTCB(notImpl), + INTCB(notImpl), + INTCB(notImpl), + INTCB(notImpl), + // 16 + INTCB(notImpl), + INTCB(writeReg), + INTCB(notImpl), + INTCB(bufferedWriteReg), + // 20 + INTCB(readRegBuffer), + INTCB(setTimerA), + INTCB(setTimerB), + INTCB(enableTimerA), + // 24 + INTCB(enableTimerB), + INTCB(notImpl), + INTCB(notImpl), + INTCB(notImpl), + // 28 + INTCB(notImpl), + INTCB(notImpl), + INTCB(notImpl), + INTCB(notImpl), + // 32 + INTCB(notImpl), + INTCB(reserveEffectChannels), + INTCB(loadWaveTable), + INTCB(unloadWaveTable), + // 36 + INTCB(notImpl), + INTCB(pcmPlayEffect), + INTCB(notImpl), + INTCB(pcmChanOff), + // 40 + INTCB(pcmEffectPlaying), + INTCB(notImpl), + INTCB(notImpl), + INTCB(notImpl), + // 44 + INTCB(notImpl), + INTCB(notImpl), + INTCB(notImpl), + INTCB(notImpl), + // 48 + INTCB(notImpl), + INTCB(notImpl), + INTCB(fmKeyOn), + INTCB(fmKeyOff), + // 52 + INTCB(fmSetPanPos), + INTCB(fmSetInstrument), + INTCB(fmLoadInstrument), + INTCB(notImpl), + // 56 + INTCB(fmSetPitch), + INTCB(fmSetLevel), + INTCB(fmReset), + INTCB(notImpl), + // 60 + INTCB(notImpl), + INTCB(notImpl), + INTCB(notImpl), + INTCB(notImpl), + // 64 + INTCB(notImpl), + INTCB(notImpl), + INTCB(notImpl), + INTCB(cdaSetVolume), + // 68 + INTCB(cdaReset), + INTCB(notImpl), + INTCB(notImpl), + INTCB(notImpl), + // 72 + INTCB(notImpl), + INTCB(notImpl), + INTCB(notImpl), + INTCB(notImpl), + // 76 + INTCB(notImpl), + INTCB(notImpl), + INTCB(notImpl), + INTCB(notImpl), + // 80 + INTCB(pcmUpdateEnvelopeGenerator), + INTCB(notImpl) + + }; +#undef INTCB + + _intfOpcodes = intfCb; + + memset(_fmSaveReg, 0, sizeof(_fmSaveReg)); + _timerBase = (uint32)(_baserate * 1000000.0f); + _tickLength = 2 * _timerBase; +} + +TownsAudioInterface::~TownsAudioInterface() { + delete[] _fmSaveReg[0]; + delete[] _fmSaveReg[1]; + delete[] _fmInstruments; + delete[] _pcmInstruments; + delete[] _waveTables; + delete[] _pcmChan; +} + +bool TownsAudioInterface::init() { + if (_ready) + return true; + + if (!_drv) + return false; + + if (!TownsPC98_FmSynth::init()) + return false; + + _fmSaveReg[0] = new uint8[256]; + _fmSaveReg[1] = new uint8[256]; + _fmInstruments = new uint8[128 * 48]; + _pcmInstruments = new uint8[32 * 128]; + _waveTables = new TownsAudio_WaveTable[128]; + _pcmChan = new TownsAudio_PcmChannel[8]; + + _timer = 0; + + callback(0); + + _ready = true; + return true; +} + +int TownsAudioInterface::callback(int command, ...) { + va_list args; + va_start(args, command); + + if (command > 81) { + va_end(args); + return 4; + } + + Common::StackLock lock(_mutex); + int res = (this->*_intfOpcodes[command])(args); + + va_end(args); + return res; +} + +void TownsAudioInterface::nextTickEx(int32 *buffer, uint32 bufferSize) { + if (!_ready) + return; + + for (uint32 i = 0; i < bufferSize; i++) { + _timer += _tickLength; + while (_timer > 0x5B8D80) { + _timer -= 0x5B8D80; + + for (int ii = 0; ii < 8; ii++) { + if ((_pcmChanKeyPlaying & _chanFlags[ii]) || (_pcmChanEffectPlaying & _chanFlags[ii])) { + TownsAudio_PcmChannel *s = &_pcmChan[ii]; + s->pos += s->step; + + if (&s->data[s->pos >> 11] >= s->loopEnd) { + if (s->loopLen) { + s->pos -= s->loopLen; + } else { + s->pos = 0; + _pcmChanEffectPlaying &= ~_chanFlags[ii]; + _pcmChanKeyPlaying &= ~_chanFlags[ii]; + } + } + } + } + } + + int32 finOutL = 0; + int32 finOutR = 0; + + for (int ii = 0; ii < 8; ii++) { + if (_pcmChanOut & _chanFlags[ii]) { + int32 o = _pcmChan[ii].data[_pcmChan[ii].pos >> 11] * _pcmChan[ii].velo; + if (_pcmChan[ii].panLeft) + finOutL += ((o * _pcmChan[ii].panLeft) >> 3); + if (_pcmChan[ii].panRight) + finOutR += ((o *_pcmChan[ii].panRight) >> 3); + if (!((_pcmChanKeyPlaying & _chanFlags[ii]) || (_pcmChanEffectPlaying & _chanFlags[ii]))) + _pcmChanOut &= ~_chanFlags[ii]; + } + } + + buffer[i << 1] += finOutL; + buffer[(i << 1) + 1] += finOutR; + } +} + +void TownsAudioInterface::timerCallbackA() { + Common::StackLock lock(_mutex); + if (_drv && _ready) + _drv->timerCallback(0); +} + +void TownsAudioInterface::timerCallbackB() { + Common::StackLock lock(_mutex); + if (_ready) { + if (_drv) + _drv->timerCallback(1); + for (int i = 0; i < 8; i++) + pcmUpdateEnvelopeGenerator(i); + } +} + +int TownsAudioInterface::intf_reset(va_list &args) { + Common::StackLock lock(_mutex); + fmReset(); + pcmReset(); + cdaReset(); + return 0; +} + +int TownsAudioInterface::intf_keyOn(va_list &args) { + int chan = va_arg(args, int); + int note = va_arg(args, int); + int velo = va_arg(args, int); + return (chan & 0x40) ? pcmKeyOn(chan, note, velo) : fmKeyOn(chan, note, velo); +} + +int TownsAudioInterface::intf_keyOff(va_list &args) { + int chan = va_arg(args, int); + return (chan & 0x40) ? pcmKeyOff(chan) : fmKeyOff(chan); +} + +int TownsAudioInterface::intf_setPanPos(va_list &args) { + int chan = va_arg(args, int); + int mode = va_arg(args, int); + return (chan & 0x40) ? pcmSetPanPos(chan, mode) : fmSetPanPos(chan, mode); +} + +int TownsAudioInterface::intf_setInstrument(va_list &args) { + int chan = va_arg(args, int); + int instrId = va_arg(args, int); + return (chan & 0x40) ? pcmSetInstrument(chan, instrId) : fmSetInstrument(chan, instrId); +} + +int TownsAudioInterface::intf_loadInstrument(va_list &args) { + int chanType = va_arg(args, int); + int instrId = va_arg(args, int); + uint8 *instrData = va_arg(args, uint8*); + return (chanType & 0x40) ? pcmLoadInstrument(instrId, instrData) : fmLoadInstrument(instrId, instrData); +} + +int TownsAudioInterface::intf_setPitch(va_list &args) { + int chan = va_arg(args, int); + int16 pitch = (int16)(va_arg(args, int) & 0xffff); + return (chan & 0x40) ? pcmSetPitch(chan, pitch) : fmSetPitch(chan, pitch); +} + +int TownsAudioInterface::intf_setLevel(va_list &args) { + int chan = va_arg(args, int); + int lvl = va_arg(args, int); + return (chan & 0x40) ? pcmSetLevel(chan, lvl) : fmSetLevel(chan, lvl); +} + +int TownsAudioInterface::intf_chanOff(va_list &args) { + int chan = va_arg(args, int); + return (chan & 0x40) ? pcmChanOff(chan) : fmChanOff(chan); +} + +int TownsAudioInterface::intf_writeReg(va_list &args) { + int part = va_arg(args, int) ? 1 : 0; + int reg = va_arg(args, int); + int val = va_arg(args, int); + if ((!part && reg < 0x20) || (part && reg < 0x30) || (reg > 0xb6)) + return 3; + + bufferedWriteReg(part, reg, val); + return 0; +} + +int TownsAudioInterface::intf_bufferedWriteReg(va_list &args) { + int part = va_arg(args, int) ? 1 : 0; + int reg = va_arg(args, int); + int val = va_arg(args, int); + + if ((!part && reg < 0x20) || (part && reg < 0x30) || (reg > 0xef)) + return 3; + + _fmSaveReg[part][reg] = val; + return 0; +} + +int TownsAudioInterface::intf_readRegBuffer(va_list &args) { + int part = va_arg(args, int) ? 1 : 0; + int reg = va_arg(args, int); + uint8 *dst = va_arg(args, uint8*); + *dst = 0; + + if ((!part && reg < 0x20) || (part && reg < 0x30) || (reg > 0xef)) + return 3; + + *dst = _fmSaveReg[part][reg]; + return 0; +} + +int TownsAudioInterface::intf_setTimerA(va_list &args) { + int enable = va_arg(args, int); + int tempo = va_arg(args, int); + + if (enable) { + bufferedWriteReg(0, 0x25, tempo & 3); + bufferedWriteReg(0, 0x24, (tempo >> 2) & 0xff); + bufferedWriteReg(0, 0x27, _fmSaveReg[0][0x27] | 0x05); + } else { + bufferedWriteReg(0, 0x27, (_fmSaveReg[0][0x27] & 0xfa) | 0x10); + } + + return 0; +} + +int TownsAudioInterface::intf_setTimerB(va_list &args) { + int enable = va_arg(args, int); + int tempo = va_arg(args, int); + + if (enable) { + bufferedWriteReg(0, 0x26, tempo & 0xff); + bufferedWriteReg(0, 0x27, _fmSaveReg[0][0x27] | 0x0A); + } else { + bufferedWriteReg(0, 0x27, (_fmSaveReg[0][0x27] & 0xf5) | 0x20); + } + + return 0; +} + +int TownsAudioInterface::intf_enableTimerA(va_list &args) { + bufferedWriteReg(0, 0x27, _fmSaveReg[0][0x27] | 0x15); + return 0; +} + +int TownsAudioInterface::intf_enableTimerB(va_list &args) { + bufferedWriteReg(0, 0x27, _fmSaveReg[0][0x27] | 0x2a); + return 0; +} + +int TownsAudioInterface::intf_reserveEffectChannels(va_list &args) { + int numChan = va_arg(args, int); + if (numChan > 8) + return 3; + if ((numChan << 13) + _waveTablesTotalDataSize > 65536) + return 5; + + if (numChan == _numReservedChannels) + return 0; + + if (numChan < _numReservedChannels) { + int c = 8 - _numReservedChannels; + for (int i = numChan; i; i--) { + uint8 f = ~_chanFlags[c--]; + _pcmChanEffectPlaying &= f; + } + } else { + int c = 7 - _numReservedChannels; + for (int i = numChan - _numReservedChannels; i; i--) { + uint8 f = ~_chanFlags[c--]; + _pcmChanKeyPressed &= f; + _pcmChanKeyPlaying &= f; + } + } + + static const uint8 reserveChanFlags[] = { 0x00, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE, 0xFF }; + _numReservedChannels = numChan; + _pcmChanReserved = reserveChanFlags[_numReservedChannels]; + + return 0; +} + +int TownsAudioInterface::intf_loadWaveTable(va_list &args) { + uint8 *data = va_arg(args, uint8*); + if (_numWaveTables > 127) + return 3; + + TownsAudio_WaveTable w; + w.readHeader(data); + if (!w.size) + return 6; + + if (_waveTablesTotalDataSize + w.size > 65504) + return 5; + + for (int i = 0; i < _numWaveTables; i++) { + if (_waveTables[i].id == w.id) + return 10; + } + + TownsAudio_WaveTable *s = &_waveTables[_numWaveTables++]; + s->readHeader(data); + s->readData(data + 32); + + _waveTablesTotalDataSize += w.size; + + return 0; +} + +int TownsAudioInterface::intf_unloadWaveTable(va_list &args) { + int id = va_arg(args, int); + + if (id == -1) { + for (int i = 0; i < 128; i++) + _waveTables[i].clear(); + _numWaveTables = 0; + _waveTablesTotalDataSize = 0; + } else { + if (_waveTables) { + for (int i = 0; i < _numWaveTables; i++) { + if (_waveTables[i].id == id) { + _numWaveTables--; + _waveTablesTotalDataSize -= _waveTables[i].size; + _waveTables[i].clear(); + for (; i < _numWaveTables; i++) + memcpy(&_waveTables[i], &_waveTables[i + 1], sizeof(TownsAudio_WaveTable)); + return 0; + } + return 9; + } + } + } + + return 0; +} + +int TownsAudioInterface::intf_pcmPlayEffect(va_list &args) { + int chan = va_arg(args, int); + int note = va_arg(args, int); + int velo = va_arg(args, int); + uint8 *data = va_arg(args, uint8*); + + if (chan < 0x40 || chan > 0x47) + return 1; + + if (note & 0x80 || velo & 0x80) + return 3; + + chan -= 0x40; + + if (!(_pcmChanReserved & _chanFlags[chan])) + return 7; + + if ((_pcmChanEffectPlaying & _chanFlags[chan])) + return 2; + + TownsAudio_WaveTable w; + w.readHeader(data); + + if (!w.size < (w.loopStart + w.loopLen)) + return 13; + + if (!w.size) + return 6; + + TownsAudio_PcmChannel *p = &_pcmChan[chan]; + + _pcmChanNote[chan] = note; + _pcmChanVelo[chan] = velo; + + p->note = note; + p->velo = velo << 1; + + p->loadExtData(data + 32, w.size); + p->setupLoop(w.loopStart, w.loopLen); + + pcmCalcPhaseStep(p, &w); + if (p->step > 2048) + p->step = 2048; + + _pcmChanEffectPlaying |= _chanFlags[chan]; + _pcmChanOut |= _chanFlags[chan]; + + return 0; +} + +int TownsAudioInterface::intf_pcmChanOff(va_list &args) { + int chan = va_arg(args, int); + pcmChanOff(chan); + return 0; +} + +int TownsAudioInterface::intf_pcmEffectPlaying(va_list &args) { + int chan = va_arg(args, int); + if (chan < 0x40 || chan > 0x47) + return 1; + chan -= 0x40; + return (_pcmChanEffectPlaying & _chanFlags[chan]) ? true : false; +} + +int TownsAudioInterface::intf_fmKeyOn(va_list &args) { + int chan = va_arg(args, int); + int note = va_arg(args, int); + int velo = va_arg(args, int); + return fmKeyOn(chan, note, velo); +} + +int TownsAudioInterface::intf_fmKeyOff(va_list &args) { + int chan = va_arg(args, int); + return fmKeyOff(chan); +} + +int TownsAudioInterface::intf_fmSetPanPos(va_list &args) { + int chan = va_arg(args, int); + int mode = va_arg(args, int); + return fmSetPanPos(chan, mode); +} + +int TownsAudioInterface::intf_fmSetInstrument(va_list &args) { + int chan = va_arg(args, int); + int instrId = va_arg(args, int); + return fmSetInstrument(chan, instrId); +} + +int TownsAudioInterface::intf_fmLoadInstrument(va_list &args) { + int instrId = va_arg(args, int); + uint8 *instrData = va_arg(args, uint8*); + return fmLoadInstrument(instrId, instrData); +} + +int TownsAudioInterface::intf_fmSetPitch(va_list &args) { + int chan = va_arg(args, int); + uint16 freq = va_arg(args, int) & 0xffff; + return fmSetPitch(chan, freq); +} + +int TownsAudioInterface::intf_fmSetLevel(va_list &args) { + int chan = va_arg(args, int); + int lvl = va_arg(args, int); + return fmSetLevel(chan, lvl); +} + +int TownsAudioInterface::intf_fmReset(va_list &args) { + fmReset(); + return 0; +} + +int TownsAudioInterface::intf_cdaReset(va_list &args) { + cdaReset(); + return 0; +} + +int TownsAudioInterface::intf_pcmUpdateEnvelopeGenerator(va_list &args) { + for (int i = 0; i < 8; i++) + pcmUpdateEnvelopeGenerator(i); + return 0; +} + +int TownsAudioInterface::intf_cdaSetVolume(va_list &args) { + /*int unk = va_arg(args, int); + int volume1 = va_arg(args, int); + int volume2 = va_arg(args, int);*/ + return 0; +} + +int TownsAudioInterface::intf_notImpl(va_list &args) { + return 4; +} + +void TownsAudioInterface::fmReset() { + TownsPC98_FmSynth::reset(); + + _fmChanPlaying = 0; + memset(_fmChanNote, 0, sizeof(_fmChanNote)); + memset(_fmChanPitch, 0, sizeof(_fmChanPitch)); + + memset(_fmSaveReg[0], 0, 240); + memset(&_fmSaveReg[0][240], 0x7f, 16); + memset(_fmSaveReg[1], 0, 256); + memset(&_fmSaveReg[1][240], 0x7f, 16); + _fmSaveReg[0][243] = _fmSaveReg[0][247] = _fmSaveReg[0][251] = _fmSaveReg[0][255] = + _fmSaveReg[1][243] = _fmSaveReg[1][247] = _fmSaveReg[1][251] = _fmSaveReg[1][255] = 0xff; + + for (int i = 0; i < 128; i++) + fmLoadInstrument(i, _fmDefaultInstrument); + + bufferedWriteReg(0, 0x21, 0); + bufferedWriteReg(0, 0x2C, 0x80); + bufferedWriteReg(0, 0x2B, 0); + bufferedWriteReg(0, 0x27, 0x30); + + for (int i = 0; i < 6; i++) { + fmKeyOff(i); + fmSetInstrument(i, 0); + fmSetLevel(i, 127); + } +} + +int TownsAudioInterface::fmKeyOn(int chan, int note, int velo) { + if (chan > 5) + return 1; + if (note < 12 || note > 107 || (velo & 0x80)) + return 3; + if (_fmChanPlaying & _chanFlags[chan]) + return 2; + + _fmChanPlaying |= _chanFlags[chan]; + note -= 12; + + _fmChanNote[chan] = note; + int16 pitch = _fmChanPitch[chan]; + + uint8 part = chan > 2 ? 1 : 0; + if (chan > 2) + chan -= 3; + + int frq = 0; + uint8 bl = 0; + + if (note) { + frq = _frequency[(note - 1) % 12]; + bl = (note - 1) / 12; + } else { + frq = 616; + } + + frq += pitch; + + if (frq < 616) { + if (!bl) { + frq = 616; + } else { + frq += 616; + --bl; + } + } else if (frq > 1232) { + if (bl == 7) { + frq = 15500; + } else { + frq -= 616; + ++bl; + } + } + + frq |= (bl << 11); + + bufferedWriteReg(part, chan + 0xa4, (frq >> 8) & 0xff); + bufferedWriteReg(part, chan + 0xa0, frq & 0xff); + + velo = (velo >> 2) + 96; + uint16 c = _carrier[_fmSaveReg[part][0xb0 + chan] & 7]; + _fmSaveReg[part][0xe0 + chan] = velo; + + for (uint8 reg = 0x40 + chan; reg < 0x50; reg += 4) { + c += c; + if (c & 0x100) { + c &= 0xff; + bufferedWriteReg(part, reg, (((((((_fmSaveReg[part][0x80 + reg] ^ 0x7f) * velo) >> 7) + 1) * _fmSaveReg[part][0xd0 + chan]) >> 7) + 1) ^ 0x7f); + } + } + + uint8 v = chan; + if (part) + v |= 4; + + for (uint8 reg = 0x80 + chan; reg < 0x90; reg += 4) + writeReg(part, reg, _fmSaveReg[part][reg] | 0x0f); + + writeReg(0, 0x28, v); + + for (uint8 reg = 0x80 + chan; reg < 0x90; reg += 4) + writeReg(part, reg, _fmSaveReg[part][reg]); + + bufferedWriteReg(0, 0x28, v | 0xf0); + + return 0; +} + +int TownsAudioInterface::fmKeyOff(int chan) { + if (chan > 5) + return 1; + _fmChanPlaying &= ~_chanFlags[chan]; + if (chan > 2) + chan++; + bufferedWriteReg(0, 0x28, chan); + return 0; +} + +int TownsAudioInterface::fmChanOff(int chan) { + if (chan > 5) + return 1; + _fmChanPlaying &= ~_chanFlags[chan]; + + uint8 part = chan > 2 ? 1 : 0; + if (chan > 2) + chan -= 3; + + for (uint8 reg = 0x80 + chan; reg < 0x90; reg += 4) + writeReg(part, reg, _fmSaveReg[part][reg] | 0x0f); + + if (part) + chan += 4; + writeReg(0, 0x28, chan); + return 0; +} + +int TownsAudioInterface::fmSetPanPos(int chan, int value) { + if (chan > 5) + return 1; + + uint8 part = chan > 2 ? 1 : 0; + if (chan > 2) + chan -= 3; + + if (value > 0x40) + value = 0x40; + else if (value < 0x40) + value = 0x80; + else + value = 0xC0; + + bufferedWriteReg(part, 0xb4 + chan, (_fmSaveReg[part][0xb4 + chan] & 0x3f) | value); + return 0; +} + +int TownsAudioInterface::fmSetInstrument(int chan, int instrId) { + if (chan > 5) + return 1; + if (instrId > 127) + return 3; + + uint8 part = chan > 2 ? 1 : 0; + if (chan > 2) + chan -= 3; + + uint8 *src = &_fmInstruments[instrId * 48 + 8]; + + uint16 c = _carrier[src[24] & 7]; + uint8 reg = 0x30 + chan; + + for (; reg < 0x40; reg += 4) + bufferedWriteReg(part, reg, *src++); + + for (; reg < 0x50; reg += 4) { + uint8 v = *src++; + _fmSaveReg[part][0x80 + reg] = _fmSaveReg[part][reg] = v; + c += c; + if (c & 0x100) { + c &= 0xff; + v = 127; + } + writeReg(part, reg, v); + } + + for (; reg < 0x90; reg += 4) + bufferedWriteReg(part, reg, *src++); + + reg += 0x20; + bufferedWriteReg(part, reg, *src++); + + uint8 v = *src++; + reg += 4; + if (v < 64) + v |= (_fmSaveReg[part][reg] & 0xc0); + bufferedWriteReg(part, reg, v); + + return 0; +} + +int TownsAudioInterface::fmLoadInstrument(int instrId, const uint8 *data) { + if (instrId > 127) + return 3; + assert(data); + memcpy(&_fmInstruments[instrId * 48], data, 48); + return 0; +} + +int TownsAudioInterface::fmSetPitch(int chan, int pitch) { + if (chan > 5) + return 1; + + uint8 bl = _fmChanNote[chan]; + int frq = 0; + + if (pitch < 0) { + if (bl) { + if (pitch < -8008) + pitch = -8008; + pitch *= -1; + pitch /= 13; + frq = _frequency[(bl - 1) % 12] - pitch; + bl = (bl - 1) / 12; + _fmChanPitch[chan] = -pitch; + + if (frq < 616) { + if (bl) { + frq += 616; + bl--; + } else { + frq = 616; + bl = 0; + } + } + } else { + frq = 616; + bl = 0; + } + + } else if (pitch > 0) { + if (bl < 96) { + if (pitch > 8008) + pitch = 8008; + pitch /= 13; + + if (bl) { + frq = _frequency[(bl - 1) % 12] + pitch; + bl = (bl - 1) / 12; + } else { + frq = 616; + bl = 0; + } + + _fmChanPitch[chan] = pitch; + + if (frq > 1232) { + if (bl < 7) { + frq -= 616; + bl++; + } else { + frq = 1164; + bl = 7; + } + } else { + if (bl >= 7 && frq > 1164) + frq = 1164; + } + + } else { + frq = 1164; + bl = 7; + } + } else { + _fmChanPitch[chan] = 0; + if (bl) { + frq = _frequency[(bl - 1) % 12]; + bl = (bl - 1) / 12; + } else { + frq = 616; + bl = 0; + } + } + + uint8 part = chan > 2 ? 1 : 0; + if (chan > 2) + chan -= 3; + + frq |= (bl << 11); + + bufferedWriteReg(part, chan + 0xa4, (frq >> 8)); + bufferedWriteReg(part, chan + 0xa0, (frq & 0xff)); + + return 0; +} + +int TownsAudioInterface::fmSetLevel(int chan, int lvl) { + if (chan > 5) + return 1; + if (lvl > 127) + return 3; + + uint8 part = chan > 2 ? 1 : 0; + if (chan > 2) + chan -= 3; + + uint16 c = _carrier[_fmSaveReg[part][0xb0 + chan] & 7]; + _fmSaveReg[part][0xd0 + chan] = lvl; + + for (uint8 reg = 0x40 + chan; reg < 0x50; reg += 4) { + c += c; + if (c & 0x100) { + c &= 0xff; + bufferedWriteReg(part, reg, (((((((_fmSaveReg[part][0x80 + reg] ^ 0x7f) * lvl) >> 7) + 1) * _fmSaveReg[part][0xe0 + chan]) >> 7) + 1) ^ 0x7f); + } + } + return 0; +} + +void TownsAudioInterface::bufferedWriteReg(uint8 part, uint8 regAddress, uint8 value) { + _fmSaveReg[part][regAddress] = value; + writeReg(part, regAddress, value); +} + +void TownsAudioInterface::pcmReset() { + _pcmChanOut = 0; + _pcmChanReserved = _pcmChanKeyPressed = _pcmChanEffectPlaying = _pcmChanKeyPlaying = 0; + _numReservedChannels = 0; + + memset(_pcmChanNote, 0, 8); + memset(_pcmChanVelo, 0, 8); + memset(_pcmChanLevel, 0, 8); + + for (int i = 0; i < 8; i++) + _pcmChan[i].clear(); + + memset(_pcmInstruments, 0, 128 * 32); + static uint8 name[] = { 0x4E, 0x6F, 0x20, 0x44, 0x61, 0x74, 0x61, 0x21 }; + for (int i = 0; i < 32; i++) + memcpy(_pcmInstruments + i * 128, name, 8); + + for (int i = 0; i < 128; i++) + _waveTables[i].clear(); + _numWaveTables = 0; + _waveTablesTotalDataSize = 0; + + for (int i = 0x40; i < 0x48; i++) { + pcmSetInstrument(i, 0); + pcmSetLevel(i, 127); + } +} + +int TownsAudioInterface::pcmKeyOn(int chan, int note, int velo) { + if (chan < 0x40 || chan > 0x47) + return 1; + + if (note & 0x80 || velo & 0x80) + return 3; + + chan -= 0x40; + + if ((_pcmChanReserved & _chanFlags[chan]) || (_pcmChanKeyPressed & _chanFlags[chan])) + return 2; + + _pcmChanNote[chan] = note; + _pcmChanVelo[chan] = velo; + + TownsAudio_PcmChannel *p = &_pcmChan[chan]; + p->note = note; + + uint8 *instr = _pcmChan[chan].curInstrument; + int i = 0; + for (; i < 8; i++) { + if (note <= instr[16 + 2 * i]) + break; + } + + if (i == 8) + return 8; + + int il = i << 3; + p->note += instr[il + 70]; + + p->envTotalLevel = instr[il + 64]; + p->envAttackRate = instr[il + 65]; + p->envDecayRate = instr[il + 66]; + p->envSustainLevel = instr[il + 67]; + p->envSustainRate = instr[il + 68]; + p->envReleaseRate = instr[il + 69]; + p->envStep = 0; + + int32 id = (int32)READ_LE_UINT32(&instr[i * 4 + 32]); + + for (i = 0; i < _numWaveTables; i++) { + if (id == _waveTables[i].id) + break; + } + + if (i == _numWaveTables) + return 9; + + TownsAudio_WaveTable *w = &_waveTables[i]; + + p->data = w->data; + p->dataEnd = w->data + w->size; + p->setupLoop(w->loopStart, w->loopLen); + + pcmCalcPhaseStep(p, w); + + uint32 lvl = _pcmChanLevel[chan] * _pcmChanVelo[chan]; + p->envTotalLevel = ((p->envTotalLevel * lvl) >> 14) & 0xff; + p->envSustainLevel = ((p->envSustainLevel * lvl) >> 14) & 0xff; + + p->envAttack(); + p->velo = (p->envCurrentLevel >> 8) << 1; + + _pcmChanKeyPressed |= _chanFlags[chan]; + _pcmChanKeyPlaying |= _chanFlags[chan]; + _pcmChanOut |= _chanFlags[chan]; + + return 0; +} + +int TownsAudioInterface::pcmKeyOff(int chan) { + if (chan < 0x40 || chan > 0x47) + return 1; + + chan -= 0x40; + _pcmChanKeyPressed &= ~_chanFlags[chan]; + _pcmChan[chan].envRelease(); + return 0; +} + +int TownsAudioInterface::pcmChanOff(int chan) { + if (chan < 0x40 || chan > 0x47) + return 1; + + chan -= 0x40; + + _pcmChanKeyPressed &= ~_chanFlags[chan]; + _pcmChanEffectPlaying &= ~_chanFlags[chan]; + _pcmChanKeyPlaying &= ~_chanFlags[chan]; + _pcmChanOut &= ~_chanFlags[chan]; + + return 0; +} + +int TownsAudioInterface::pcmSetPanPos(int chan, int mode) { + if (chan > 0x47) + return 1; + if (mode & 0x80) + return 3; + + chan -= 0x40; + uint8 blc = 0x77; + + if (mode > 64) { + mode -= 64; + blc = ((blc ^ (mode >> 3)) + (mode << 4)) & 0xff; + } else if (mode < 64) { + mode = (mode >> 3) ^ 7; + blc = ((119 + mode) ^ (mode << 4)) & 0xff; + } + + _pcmChan[chan].panLeft = blc & 0x0f; + _pcmChan[chan].panRight = blc >> 4; + + return 0; +} + +int TownsAudioInterface::pcmSetInstrument(int chan, int instrId) { + if (chan > 0x47) + return 1; + if (instrId > 31) + return 3; + chan -= 0x40; + _pcmChan[chan].curInstrument = &_pcmInstruments[instrId * 128]; + return 0; +} + +int TownsAudioInterface::pcmLoadInstrument(int instrId, const uint8 *data) { + if (instrId > 31) + return 3; + assert(data); + memcpy(&_pcmInstruments[instrId * 128], data, 128); + return 0; +} + +int TownsAudioInterface::pcmSetPitch(int chan, int pitch) { + if (chan > 0x47) + return 1; + + if (pitch < -8192 || pitch > 8191) + return 3; + + chan -= 0x40; + TownsAudio_PcmChannel *p = &_pcmChan[chan]; + + uint32 pts = 0x4000; + + if (pitch < 0) + pts = (0x20000000 / (-pitch + 0x2001)) >> 2; + else if (pitch > 0) + pts = (((pitch + 0x2001) << 16) / 0x2000) >> 2; + + p->stepPitch = pts & 0xffff; + p->step = (p->stepNote * p->stepPitch) >> 14; + +// if (_pcmChanUnkFlag & _chanFlags[chan]) +// unk[chan] = (((p->step * 1000) << 11) / 98) / 20833; + + /*else*/ if ((_pcmChanEffectPlaying & _chanFlags[chan]) && (p->step > 2048)) + p->step = 2048; + + return 0; +} + +int TownsAudioInterface::pcmSetLevel(int chan, int lvl) { + if (chan > 0x47) + return 1; + + if (lvl & 0x80) + return 3; + + chan -= 0x40; + TownsAudio_PcmChannel *p = &_pcmChan[chan]; + + if (_pcmChanReserved & _chanFlags[chan]) { + _pcmChanVelo[chan] = lvl; + p->velo = lvl << 1; + } else { + int32 t = p->envStep * lvl; + if (_pcmChanLevel[chan]) + t /= _pcmChanLevel[chan]; + p->envStep = t; + t = p->envCurrentLevel * lvl; + if (_pcmChanLevel[chan]) + t /= _pcmChanLevel[chan]; + p->envCurrentLevel = t; + _pcmChanLevel[chan] = lvl; + p->velo = p->envCurrentLevel >> 8; + } + + return 0; +} + +void TownsAudioInterface::pcmUpdateEnvelopeGenerator(int chan) { + TownsAudio_PcmChannel *p = &_pcmChan[chan]; + if (!p->envCurrentLevel) { + _pcmChanKeyPlaying &= ~_chanFlags[chan]; + p->envState = kEnvReady; + } + + if (!(_pcmChanKeyPlaying & _chanFlags[chan])) + return; + + switch (p->envState) { + case kEnvAttacking: + if (((p->envCurrentLevel + p->envStep) >> 8) > p->envTotalLevel) { + p->envDecay(); + return; + } else { + p->envCurrentLevel += p->envStep; + } + break; + + case kEnvDecaying: + if (((p->envCurrentLevel - p->envStep) >> 8) < p->envSustainLevel) { + p->envSustain(); + return; + } else { + p->envCurrentLevel -= p->envStep; + } + break; + + case kEnvSustaining: + case kEnvReleasing: + p->envCurrentLevel -= p->envStep; + if (p->envCurrentLevel <= 0) + p->envCurrentLevel = 0; + break; + + default: + break; + } + p->velo = (p->envCurrentLevel >> 8) << 1; +} + +void TownsAudioInterface::pcmCalcPhaseStep(TownsAudio_PcmChannel *p, TownsAudio_WaveTable *w) { + int8 diff = p->note - w->baseNote; + uint16 r = w->rate + w->rateOffs; + uint16 bl = 0; + uint32 s = 0; + + if (diff < 0) { + diff -= 1; + bl = diff % 12; + diff /= 12; + s = (r >> diff); + if (bl) + s = (s * _pcmPhase2[bl]) >> 16; + + } else if (diff > 0) { + bl = diff % 12; + diff /= 12; + s = (r << diff); + if (bl) + s += ((s * _pcmPhase1[bl]) >> 16); + + } else { + s = r; + } + + p->stepNote = s & 0xffff; + p->step = (s * p->stepPitch) >> 14; +} + +void TownsAudioInterface::cdaReset() { + +} + +const uint8 TownsAudioInterface::_chanFlags[] = { + 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 +}; + +const uint16 TownsAudioInterface::_frequency[] = { + 0x028C, 0x02B4, 0x02DC, 0x030A, 0x0338, 0x0368, 0x039C, 0x03D4, 0x040E, 0x044A, 0x048C, 0x04D0 +}; + +const uint8 TownsAudioInterface::_carrier[] = { + 0x10, 0x10, 0x10, 0x10, 0x30, 0x70, 0x70, 0xF0 +}; + +const uint8 TownsAudioInterface::_fmDefaultInstrument[] = { + 0x45, 0x4C, 0x45, 0x50, 0x49, 0x41, 0x4E, 0x4F, 0x01, 0x0A, 0x02, 0x01, + 0x1E, 0x32, 0x05, 0x00, 0x9C, 0xDC, 0x9C, 0xDC, 0x07, 0x03, 0x14, 0x08, + 0x00, 0x03, 0x05, 0x05, 0x55, 0x45, 0x27, 0xA7, 0x04, 0xC0, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +const uint16 TownsAudioInterface::_pcmPhase1[] = { + 0x879B, 0x0F37, 0x1F58, 0x306E, 0x4288, 0x55B6, 0x6A08, 0x7F8F, 0x965E, 0xAE88, 0xC882, 0xE341 +}; + +const uint16 TownsAudioInterface::_pcmPhase2[] = { + 0xFEFE, 0xF1A0, 0xE411, 0xD744, 0xCB2F, 0xBFC7, 0xB504, 0xAAE2, 0xA144, 0x9827, 0x8FAC +}; + +TownsAudio_PcmChannel::TownsAudio_PcmChannel() { + extData = 0; + clear(); +} + +TownsAudio_PcmChannel::~TownsAudio_PcmChannel() { + clear(); +} + +void TownsAudio_PcmChannel::loadExtData(uint8 *buffer, uint32 size) { + delete[] extData; + extData = new int8[size]; + int8 *src = (int8*)buffer; + int8 *dst = extData; + for (uint32 i = 0; i < size; i++) + *dst++ = *src & 0x80 ? (*src++ & 0x7f) : -*src++; + + data = extData; + dataEnd = extData + size; + pos = 0; +} + +void TownsAudio_PcmChannel::setupLoop(uint32 start, uint32 len) { + loopLen = len << 11; + loopEnd = loopLen ? &data[(start + loopLen) >> 11] : dataEnd; + pos = start; +} + +void TownsAudio_PcmChannel::clear() { + curInstrument = 0; + note = 0; + velo = 0; + + data = 0; + dataEnd = 0; + loopLen = 0; + + pos = 0; + loopEnd = 0; + + step = 0; + stepNote = 0x4000; + stepPitch = 0x4000; + + panLeft = panRight = 0; + + envTotalLevel = envAttackRate = envDecayRate = envSustainLevel = + envSustainRate = envReleaseRate = 0; + envStep = envCurrentLevel = 0; + + envState = kEnvReady; + + delete[] extData; + extData = 0; +} + +void TownsAudio_PcmChannel::envAttack() { + envState = kEnvAttacking; + int16 t = envTotalLevel << 8; + if (envAttackRate == 127) { + envStep = 0; + } else if (envAttackRate) { + envStep = t / envAttackRate; + envCurrentLevel = 1; + } else { + envCurrentLevel = t; + envDecay(); + } +} + +void TownsAudio_PcmChannel::envDecay() { + envState = kEnvDecaying; + int16 t = envTotalLevel - envSustainLevel; + if (t < 0 || envDecayRate == 127) { + envStep = 0; + } else if (envDecayRate) { + envStep = (t << 8) / envDecayRate; + } else { + envCurrentLevel = envSustainLevel << 8; + envSustain(); + } +} + +void TownsAudio_PcmChannel::envSustain() { + envState = kEnvSustaining; + if (envSustainLevel && envSustainRate) + envStep = (envSustainRate == 127) ? 0 : (envCurrentLevel / envSustainRate) >> 1; + else + envStep = envCurrentLevel = 1; +} + +void TownsAudio_PcmChannel::envRelease() { + envState = kEnvReleasing; + if (envReleaseRate == 127) + envStep = 0; + else if (envReleaseRate) + envStep = envCurrentLevel / envReleaseRate; + else + envStep = envCurrentLevel = 1; +} + +TownsAudio_WaveTable::TownsAudio_WaveTable() { + data = 0; + clear(); +} + +TownsAudio_WaveTable::~TownsAudio_WaveTable() { + clear(); +} + +void TownsAudio_WaveTable::readHeader(const uint8 *buffer) { + memcpy(name, buffer, 8); + name[8] = 0; + id = READ_LE_UINT32(&buffer[8]); + size = READ_LE_UINT32(&buffer[12]); + loopStart = READ_LE_UINT32(&buffer[16]); + loopLen = READ_LE_UINT32(&buffer[20]); + rate = READ_LE_UINT16(&buffer[24]); + rateOffs = READ_LE_UINT16(&buffer[26]); + baseNote = READ_LE_UINT32(&buffer[28]); +} + +void TownsAudio_WaveTable::readData(const uint8 *buffer) { + if (!size) + return; + + delete[] data; + data = new int8[size]; + + const int8 *src = (const int8*)buffer; + int8 *dst = data; + for (uint32 i = 0; i < size; i++) + *dst++ = *src & 0x80 ? (*src++ & 0x7f) : -*src++; +} + +void TownsAudio_WaveTable::clear() { + name[0] = name[8] = 0; + id = -1; + size = 0; + loopStart = 0; + loopLen = 0; + rate = 0; + rateOffs = 0; + baseNote = 0; + delete[] data; + data = 0; +} + diff --git a/sound/softsynth/fmtowns_pc98/towns_audio.h b/sound/softsynth/fmtowns_pc98/towns_audio.h new file mode 100644 index 0000000000..82d390d9b6 --- /dev/null +++ b/sound/softsynth/fmtowns_pc98/towns_audio.h @@ -0,0 +1,162 @@ +/* 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. + * + * $URL$ + * $Id$ + * + */ + +#ifndef TOWNS_AUDIO_H +#define TOWNS_AUDIO_H + +#include "sound/softsynth/fmtowns_pc98/towns_pc98_fmsynth.h" + +class TownsAudioInterfacePluginDriver { +public: + virtual void timerCallback(int timerId) = 0; +}; + +class TownsAudio_PcmChannel; +class TownsAudio_WaveTable; + +class TownsAudioInterface : public TownsPC98_FmSynth { +public: + TownsAudioInterface(Audio::Mixer *mixer, TownsAudioInterfacePluginDriver *driver); + ~TownsAudioInterface(); + + bool init(); + + int callback(int command, ...); + +private: + void nextTickEx(int32 *buffer, uint32 bufferSize); + + void timerCallbackA(); + void timerCallbackB(); + + typedef int (TownsAudioInterface::*TownsAudioIntfCallback)(va_list&); + const TownsAudioIntfCallback *_intfOpcodes; + + int intf_reset(va_list &args); + int intf_keyOn(va_list &args); + int intf_keyOff(va_list &args); + int intf_setPanPos(va_list &args); + int intf_setInstrument(va_list &args); + int intf_loadInstrument(va_list &args); + int intf_setPitch(va_list &args); + int intf_setLevel(va_list &args); + int intf_chanOff(va_list &args); + int intf_writeReg(va_list &args); + int intf_bufferedWriteReg(va_list &args); + int intf_readRegBuffer(va_list &args); + int intf_setTimerA(va_list &args); + int intf_setTimerB(va_list &args); + int intf_enableTimerA(va_list &args); + int intf_enableTimerB(va_list &args); + int intf_reserveEffectChannels(va_list &args); + int intf_loadWaveTable(va_list &args); + int intf_unloadWaveTable(va_list &args); + int intf_pcmPlayEffect(va_list &args); + int intf_pcmChanOff(va_list &args); + int intf_pcmEffectPlaying(va_list &args); + int intf_fmKeyOn(va_list &args); + int intf_fmKeyOff(va_list &args); + int intf_fmSetPanPos(va_list &args); + int intf_fmSetInstrument(va_list &args); + int intf_fmLoadInstrument(va_list &args); + int intf_fmSetPitch(va_list &args); + int intf_fmSetLevel(va_list &args); + int intf_fmReset(va_list &args); + int intf_cdaSetVolume(va_list &args); + int intf_cdaReset(va_list &args); + int intf_pcmUpdateEnvelopeGenerator(va_list &args); + + int intf_notImpl(va_list &args); + + void fmReset(); + int fmKeyOn(int chan, int note, int velo); + int fmKeyOff(int chan); + int fmChanOff(int chan); + int fmSetPanPos(int chan, int mode); + int fmSetInstrument(int chan, int instrId); + int fmLoadInstrument(int instrId, const uint8 *data); + int fmSetPitch(int chan, int pitch); + int fmSetLevel(int chan, int lvl); + + void bufferedWriteReg(uint8 part, uint8 regAddress, uint8 value); + + uint8 _fmChanPlaying; + uint8 _fmChanNote[6]; + int16 _fmChanPitch[6]; + + uint8 *_fmSaveReg[2]; + uint8 *_fmInstruments; + + void pcmReset(); + int pcmKeyOn(int chan, int note, int velo); + int pcmKeyOff(int chan); + int pcmChanOff(int chan); + int pcmSetPanPos(int chan, int mode); + int pcmSetInstrument(int chan, int instrId); + int pcmLoadInstrument(int instrId, const uint8 *data); + int pcmSetPitch(int chan, int pitch); + int pcmSetLevel(int chan, int lvl); + void pcmUpdateEnvelopeGenerator(int chan); + + TownsAudio_PcmChannel *_pcmChan; + uint8 _pcmChanOut; + uint8 _pcmChanReserved; + uint8 _pcmChanKeyPressed; + uint8 _pcmChanEffectPlaying; + uint8 _pcmChanKeyPlaying; + + uint8 _pcmChanNote[8]; + uint8 _pcmChanVelo[8]; + uint8 _pcmChanLevel[8]; + + uint8 _numReservedChannels; + uint8 *_pcmInstruments; + + TownsAudio_WaveTable *_waveTables; + uint8 _numWaveTables; + uint32 _waveTablesTotalDataSize; + + void pcmCalcPhaseStep(TownsAudio_PcmChannel *p, TownsAudio_WaveTable *w); + + void cdaReset(); + + const float _baserate; + uint32 _timerBase; + uint32 _tickLength; + uint32 _timer; + + TownsAudioInterfacePluginDriver *_drv; + bool _ready; + + static const uint8 _chanFlags[]; + static const uint16 _frequency[]; + static const uint8 _carrier[]; + static const uint8 _fmDefaultInstrument[]; + static const uint16 _pcmPhase1[]; + static const uint16 _pcmPhase2[]; +}; + +#endif + diff --git a/sound/softsynth/fmtowns_pc98/towns_euphony.cpp b/sound/softsynth/fmtowns_pc98/towns_euphony.cpp new file mode 100644 index 0000000000..54b5d5b1d6 --- /dev/null +++ b/sound/softsynth/fmtowns_pc98/towns_euphony.cpp @@ -0,0 +1,886 @@ +/* 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. + * + * $URL$ + * $Id$ + * + */ + +#include "sound/softsynth/fmtowns_pc98/towns_euphony.h" +#include "common/endian.h" + +TownsEuphonyDriver::TownsEuphonyDriver(Audio::Mixer *mixer) : _activeChannels(0), _sustainChannels(0), + _assignedChannels(0), _paraCount(0), _command(0), _tEnable(0), _tMode(0), _tOrdr(0), _tLevel(0), + _tTranspose(0), _musicPos(0), _musicStart(0), _playing(false), _eventBuffer(0), _bufferedEventsCount(0), + _tempoControlMode(0) { + _para[0] = _para[1] = 0; + _intf = new TownsAudioInterface(mixer, this); + resetTempo(); +} + +TownsEuphonyDriver::~TownsEuphonyDriver() { + delete[] _activeChannels; + delete[] _sustainChannels; + delete[] _assignedChannels; + + delete[] _tEnable; + delete[] _tMode; + delete[] _tOrdr; + delete[] _tLevel; + delete[] _tTranspose; + + delete _intf; +} + +bool TownsEuphonyDriver::init() { + if (!_intf->init()) + return false; + + _activeChannels = new int8[16]; + _sustainChannels = new int8[16]; + _assignedChannels = new ActiveChannel[128]; + _eventBuffer = new DlEvent[64]; + + _tEnable = new uint8[32]; + _tMode = new uint8[32]; + _tOrdr = new uint8[32]; + _tLevel = new int8[32]; + _tTranspose = new int8[32]; + + reset(); + + cdaSetVolume(1, 118, 118); + + return true; +} + +void TownsEuphonyDriver::reset() { + _intf->callback(0); + + _intf->callback(74); + _intf->callback(70); + _intf->callback(75, 3); + + setTimerA(true, 1); + setTimerA(false, 1); + setTimerB(true, 221); + + _paraCount = _command = _para[0] = _para[1] = 0; + memset(_sustainChannels, 0, 16); + memset(_activeChannels, -1, 16); + for (int i = 0; i < 128; i++) { + _assignedChannels[i].chan = _assignedChannels[i].next = -1; + _assignedChannels[i].note = _assignedChannels[i].sub = 0; + } + + int e = 0; + for (int i = 0; i < 6; i++) + assignChannel(i, e++); + for (int i = 0x40; i < 0x48; i++) + assignChannel(i, e++); + + resetTables(); + + memset(_eventBuffer, 0, 64 * sizeof(DlEvent)); + _bufferedEventsCount = 0; + + _playing = _endOfTrack = _suspendParsing = _loop = false; + _elapsedEvents = 0; + _tempoDiff = 0; + + resetTempo(); + + if (_tempoControlMode == 1) { + //if (///) + // return; + setTempoIntern(_defaultTempo); + } else { + setTempoIntern(_defaultTempo); + } + + resetControl(); +} + +void TownsEuphonyDriver::loadInstrument(int chanType, int id, const uint8 *data) { + _intf->callback(5, chanType, id, data); +} + +void TownsEuphonyDriver::loadWaveTable(const uint8 *data) { + _intf->callback(34, data); +} + +void TownsEuphonyDriver::unloadWaveTable(int id) { + _intf->callback(35, id); +} + +void TownsEuphonyDriver::reserveSfxChannels(int num) { + _intf->callback(33, num); +} + +int TownsEuphonyDriver::setMusicTempo(int tempo) { + if (tempo > 250) + return 3; + _defaultTempo = tempo; + _trackTempo = tempo; + setTempoIntern(tempo); + return 0; +} + +int TownsEuphonyDriver::startMusicTrack(const uint8 *data, int trackSize, int startTick) { + if (_playing) + return 2; + + _musicPos = _musicStart = data; + _defaultBaseTickLen = _baseTickLen = startTick; + _musicTrackSize = trackSize; + _timeStampBase = _timeStampDest = 0; + _tickCounter = 0; + _playing = true; + + return 0; +} + +void TownsEuphonyDriver::setMusicLoop(bool loop) { + _loop = loop; +} + +void TownsEuphonyDriver::stopParser() { + if (_playing) { + _playing = false; + _pulseCount = 0; + _endOfTrack = false; + flushEventBuffer(); + resetControl(); + } +} + +void TownsEuphonyDriver::playSoundEffect(int chan, int note, int velo, const uint8 *data) { + _intf->callback(37, chan, note, velo, data); +} + +void TownsEuphonyDriver::stopSoundEffect(int chan) { + _intf->callback(39, chan); +} + +bool TownsEuphonyDriver::soundEffectIsPlaying(int chan) { + return _intf->callback(40, chan) ? true : false; +} + +void TownsEuphonyDriver::chanStereo(int chan, int mode) { + _intf->callback(3, chan, mode); +} + +void TownsEuphonyDriver::chanPitch(int chan, int pitch) { + _intf->callback(7, chan, pitch); +} + +void TownsEuphonyDriver::chanVolume(int chan, int vol) { + _intf->callback(8, chan, vol); +} + +void TownsEuphonyDriver::cdaSetVolume(int a, int vol1, int vol2) { + _intf->callback(67, a, vol1, vol2); +} + +int TownsEuphonyDriver::chanEnable(int tableEntry, int val) { + if (tableEntry > 31) + return 3; + _tEnable[tableEntry] = val; + return 0; +} + +int TownsEuphonyDriver::chanMode(int tableEntry, int val) { + if (tableEntry > 31) + return 3; + _tMode[tableEntry] = val; + return 0; +} + +int TownsEuphonyDriver::chanOrdr(int tableEntry, int val) { + if (tableEntry > 31) + return 3; + if (val < 16) + _tOrdr[tableEntry] = val; + return 0; +} + +int TownsEuphonyDriver::chanLevel(int tableEntry, int val) { + if (tableEntry > 31) + return 3; + if (val <= 40) + _tLevel[tableEntry] = (int8) (val & 0xff); + return 0; +} + +int TownsEuphonyDriver::chanTranspose(int tableEntry, int val) { + if (tableEntry > 31) + return 3; + if (val <= 40) + _tTranspose[tableEntry] = (int8) (val & 0xff); + return 0; +} + +int TownsEuphonyDriver::assignChannel(int chan, int tableEntry) { + if (tableEntry > 15 || chan > 127 || chan < 0) + return 3; + + ActiveChannel *a = &_assignedChannels[chan]; + if (a->chan == tableEntry) + return 0; + + if (a->chan != -1) { + int8 *b = &_activeChannels[a->chan]; + while(*b != chan) { + b = &_assignedChannels[*b].next; + if (*b == -1 && *b != chan) + return 3; + } + + *b = a->next; + + if (a->note) + _intf->callback(2, chan); + + a->chan = a->next = -1; + a->note = 0; + } + + a->next = _activeChannels[tableEntry]; + _activeChannels[tableEntry] = chan; + a->chan = tableEntry; + a->note = a->sub = 0; + + return 0; +} + +void TownsEuphonyDriver::timerCallback(int timerId) { + switch (timerId) { + case 0: + updatePulseCount(); + while (_pulseCount > 0) { + --_pulseCount; + updateTimeStampBase(); + if (!_playing) + continue; + updateEventBuffer(); + updateParser(); + updateCheckEot(); + } + break; + default: + break; + } +} + +void TownsEuphonyDriver::resetTables() { + memset(_tEnable, 0xff, 32); + memset(_tMode, 0xff, 16); + memset(_tMode + 16, 0, 16); + for (int i = 0; i < 32; i++) + _tOrdr[i] = i & 0x0f; + memset(_tLevel, 0, 32); + memset(_tTranspose, 0, 32); +} + +void TownsEuphonyDriver::resetTempo() { + _defaultBaseTickLen = _baseTickLen = 0x33; + _pulseCount = 0; + _extraTimingControlRemainder = 0; + _extraTimingControl = 16; + _tempoModifier = 0; + _timeStampDest = 0; + _deltaTicks = 0; + _tickCounter = 0; + _defaultTempo = 90; + _trackTempo = 90; +} + +void TownsEuphonyDriver::setTempoIntern(int tempo) { + tempo = CLIP(tempo + _tempoModifier, 0, 500); + if (_tempoControlMode == 0) { + _timerSetting = 34750 / (tempo + 30); + _extraTimingControl = 16; + + while (_timerSetting < 126) { + _timerSetting <<= 1; + _extraTimingControl <<= 1; + } + + while (_timerSetting > 383) { + _timerSetting >>= 1; + _extraTimingControl >>= 1; + } + + setTimerA(true, -(_timerSetting - 2)); + + } else if (_tempoControlMode == 1) { + _timerSetting = 312500 / (tempo + 30); + _extraTimingControl = 16; + while (_timerSetting < 1105) { + _timerSetting <<= 1; + _extraTimingControl <<= 1; + } + + } else if (_tempoControlMode == 2) { + _timerSetting = 625000 / (tempo + 30); + _extraTimingControlRemainder = 0; + } +} + +void TownsEuphonyDriver::setTimerA(bool enable, int tempo) { + _intf->callback(21, enable ? 255 : 0, tempo); +} + +void TownsEuphonyDriver::setTimerB(bool enable, int tempo) { + _intf->callback(22, enable ? 255 : 0, tempo); +} + +void TownsEuphonyDriver::updatePulseCount() { + int tc = _extraTimingControl + _extraTimingControlRemainder; + _extraTimingControlRemainder = tc & 0x0f; + tc >>= 4; + _tempoDiff -= tc; + + while (_tempoDiff < 0) { + _elapsedEvents++; + _tempoDiff += 4; + } + + if (_playing && !_suspendParsing) + _pulseCount += tc; +} + +void TownsEuphonyDriver::updateTimeStampBase() { + static const uint16 table[] = { 0x180, 0xC0, 0x80, 0x60, 0x40, 0x30, 0x20, 0x18 }; + if ((uint32)(table[_baseTickLen >> 4] * ((_baseTickLen & 0x0f) + 1)) > ++_tickCounter) + return; + ++_timeStampDest; + _tickCounter = 0; + _deltaTicks = 0; +} + +void TownsEuphonyDriver::updateParser() { + for (bool loop = true; loop; ) { + uint8 cmd = _musicPos[0]; + + if (cmd == 0xff || cmd == 0xf7) { + jumpNextLoop(); + + } else if (cmd < 0x90) { + _endOfTrack = true; + flushEventBuffer(); + loop = false; + + } else if (_timeStampBase > _timeStampDest) { + loop = false; + + } else { + if (_timeStampBase == _timeStampDest) { + uint16 timeStamp = READ_LE_UINT16(&_musicPos[2]); + uint8 l = (timeStamp & 0xff) + (timeStamp & 0xff); + timeStamp = ((timeStamp & 0xff00) | l) >> 1; + if (timeStamp > _tickCounter) + loop = false; + } + + if (loop) { + if (parseNext()) + loop = false; + } + } + } +} + +void TownsEuphonyDriver::updateCheckEot() { + if (!_endOfTrack || _bufferedEventsCount) + return; + stopParser(); +} + +bool TownsEuphonyDriver::parseNext() { +#define OPC(x) &TownsEuphonyDriver::evt##x + static const EuphonyOpcode opcodes[] = { + OPC(NotImpl), + OPC(SetupNote), + OPC(PolyphonicAftertouch), + OPC(ControlPitch), + OPC(InstrumentChanAftertouch), + OPC(InstrumentChanAftertouch), + OPC(ControlPitch) + }; +#undef OPC + + uint cmd = _musicPos[0]; + if (cmd != 0xfe && cmd != 0xfd) { + if (cmd >= 0xf0 ) { + cmd &= 0x0f; + if (cmd == 0) + evtLoadInstrument(); + else if (cmd == 2) + evtAdvanceTimestampOffset(); + else if (cmd == 8) + evtTempo(); + else if (cmd == 12) + evtModeOrdrChange(); + jumpNextLoop(); + return false; + + } else if (!(this->*opcodes[(cmd - 0x80) >> 4])()) { + jumpNextLoop(); + return false; + } + } + + if (cmd == 0xfd) { + _suspendParsing = true; + return true; + } + + if (!_loop) { + _endOfTrack = true; + return true; + } + + _endOfTrack = false; + _musicPos = _musicStart; + _timeStampBase = _timeStampDest = _tickCounter = 0; + _baseTickLen = _defaultBaseTickLen; + + return false; +} + +void TownsEuphonyDriver::jumpNextLoop() { + _musicPos += 6; + if (_musicPos >= _musicStart + _musicTrackSize) + _musicPos = _musicStart; +} + +void TownsEuphonyDriver::updateEventBuffer() { + DlEvent *e = _eventBuffer; + for (int i = _bufferedEventsCount; i; e++) { + if (e->evt == 0) + continue; + if (--e->len) { + --i; + continue; + } + processBufferNote(e->mode, e->evt, e->note, e->velo); + e->evt = 0; + --i; + --_bufferedEventsCount; + } +} + +void TownsEuphonyDriver::flushEventBuffer() { + DlEvent *e = _eventBuffer; + for (int i = _bufferedEventsCount; i; e++) { + if (e->evt == 0) + continue; + processBufferNote(e->mode, e->evt, e->note, e->velo); + e->evt = 0; + --i; + --_bufferedEventsCount; + } +} + +void TownsEuphonyDriver::processBufferNote(int mode, int evt, int note, int velo) { + if (!velo) + evt &= 0x8f; + sendEvent(mode, evt); + sendEvent(mode, note); + sendEvent(mode, velo); +} + +void TownsEuphonyDriver::resetControl() { + for (int i = 0; i < 32; i++) { + if (_tOrdr[i] > 15) { + for (int ii = 0; ii < 16; ii++) + resetControlIntern(_tMode[i], ii); + } else { + resetControlIntern(_tMode[i], _tOrdr[i]); + } + } +} + +void TownsEuphonyDriver::resetControlIntern(int mode, int chan) { + sendEvent(mode, 0xb0 | chan); + sendEvent(mode, 0x40); + sendEvent(mode, 0); + sendEvent(mode, 0xb0 | chan); + sendEvent(mode, 0x7b); + sendEvent(mode, 0); + sendEvent(mode, 0xb0 | chan); + sendEvent(mode, 0x79); + sendEvent(mode, 0x40); +} + +uint8 TownsEuphonyDriver::appendEvent(uint8 evt, uint8 chan) { + if (evt >= 0x80 && evt < 0xf0 && _tOrdr[chan] < 16) + return (evt & 0xf0) | _tOrdr[chan]; + return evt; +} + +void TownsEuphonyDriver::sendEvent(uint8 mode, uint8 command) { + if (mode == 0) { + warning("TownsEuphonyDriver: Mode 0 not implemented."); + + } else if (mode == 0x10) { + warning("TownsEuphonyDriver: Mode 0x10 not implemented."); + + } else if (mode == 0xff) { + if (command >= 0xf0) { + _paraCount = 1; + _command = 0; + } else if (command >= 0x80) { + _paraCount = 1; + _command = command; + } else if (_command >= 0x80) { + switch ((_command - 0x80) >> 4) { + case 0: + if (_paraCount < 2) { + _paraCount++; + _para[0] = command; + } else { + _paraCount = 1; + _para[1] = command; + sendNoteOff(); + } + break; + + case 1: + if (_paraCount < 2) { + _paraCount++; + _para[0] = command; + } else { + _paraCount = 1; + _para[1] = command; + if (command) + sendNoteOn(); + else + sendNoteOff(); + } + break; + + case 2: + if (_paraCount < 2) { + _paraCount++; + _para[0] = command; + } else { + _paraCount = 1; + } + break; + + case 3: + if (_paraCount < 2) { + _paraCount++; + _para[0] = command; + } else { + _paraCount = 1; + _para[1] = command; + + if (_para[0] == 7) + sendChanVolume(); + else if (_para[0] == 10) + sendPanPosition(); + else if (_para[0] == 64) + sendAllNotesOff(); + } + break; + + case 4: + _paraCount = 1; + _para[0] = command; + sendSetInstrument(); + break; + + case 5: + _paraCount = 1; + _para[0] = command; + break; + + case 6: + if (_paraCount < 2) { + _paraCount++; + _para[0] = command; + } else { + _paraCount = 1; + _para[1] = command; + sendPitch(); + } + break; + } + } + } +} + +bool TownsEuphonyDriver::evtSetupNote() { + if (_musicPos[1] > 31) + return false; + if (!_tEnable[_musicPos[1]]) { + jumpNextLoop(); + return (_musicPos[0] == 0xfe || _musicPos[0] == 0xfd) ? true : false; + } + uint8 evt = appendEvent(_musicPos[0], _musicPos[1]); + uint8 mode = _tMode[_musicPos[1]]; + uint8 note = _musicPos[4]; + uint8 velo = _musicPos[5]; + + sendEvent(mode, evt); + sendEvent(mode, prepTranspose(note)); + sendEvent(mode, prepVelo(velo)); + + jumpNextLoop(); + if (_musicPos[0] == 0xfe || _musicPos[0] == 0xfd) + return true; + + velo = _musicPos[5]; + uint16 len = ((((_musicPos[1] << 4) | (_musicPos[2] << 8)) >> 4) & 0xff) | ((((_musicPos[3] << 4) | (_musicPos[4] << 8)) >> 4) << 8); + + int i = 0; + for (; i < 64; i++) { + if (_eventBuffer[i].evt == 0) + break; + } + + if (i == 64) { + processBufferNote(mode, evt, note, velo); + } else { + _eventBuffer[i].evt = evt; + _eventBuffer[i].mode = mode; + _eventBuffer[i].note = note; + _eventBuffer[i].velo = velo; + _eventBuffer[i].len = len ? len : 1; + _bufferedEventsCount++; + } + + return false; +} + +bool TownsEuphonyDriver::evtPolyphonicAftertouch() { + if (_musicPos[1] > 31) + return false; + if (!_tEnable[_musicPos[1]]) + return false; + + uint8 evt = appendEvent(_musicPos[0], _musicPos[1]); + uint8 mode = _tMode[_musicPos[1]]; + + sendEvent(mode, evt); + sendEvent(mode, prepTranspose(_musicPos[4])); + sendEvent(mode, _musicPos[5]); + + return false; +} + +bool TownsEuphonyDriver::evtControlPitch() { + if (_musicPos[1] > 31) + return false; + if (!_tEnable[_musicPos[1]]) + return false; + + uint8 evt = appendEvent(_musicPos[0], _musicPos[1]); + uint8 mode = _tMode[_musicPos[1]]; + + sendEvent(mode, evt); + sendEvent(mode, _musicPos[4]); + sendEvent(mode, _musicPos[5]); + + return false; +} + +bool TownsEuphonyDriver::evtInstrumentChanAftertouch() { + if (_musicPos[1] > 31) + return false; + if (!_tEnable[_musicPos[1]]) + return false; + + uint8 evt = appendEvent(_musicPos[0], _musicPos[1]); + uint8 mode = _tMode[_musicPos[1]]; + + sendEvent(mode, evt); + sendEvent(mode, _musicPos[4]); + + return false; +} + +bool TownsEuphonyDriver::evtLoadInstrument() { + return false; +} + +bool TownsEuphonyDriver::evtAdvanceTimestampOffset() { + ++_timeStampBase; + _baseTickLen = _musicPos[1]; + return false; +} + +bool TownsEuphonyDriver::evtTempo() { + uint8 l = _musicPos[4] << 1; + _trackTempo = (l | (_musicPos[5] << 8)) >> 1; + setTempoIntern(_trackTempo); + return false; +} + +bool TownsEuphonyDriver::evtModeOrdrChange() { + if (_musicPos[1] > 31) + return false; + if (!_tEnable[_musicPos[1]]) + return false; + + if (_musicPos[4] == 1) + _tMode[_musicPos[1]] = _musicPos[5]; + else if (_musicPos[4] == 2) + _tOrdr[_musicPos[1]] = _musicPos[5]; + + return false; +} + +uint8 TownsEuphonyDriver::prepTranspose(uint8 in) { + int out = _tTranspose[_musicPos[1]]; + if (!out) + return in; + out += (in & 0x7f); + + if (out > 127) + out -= 12; + + if (out < 0) + out += 12; + + return out & 0xff; +} + +uint8 TownsEuphonyDriver::prepVelo(uint8 in) { + int out = _tLevel[_musicPos[1]]; + out += (in & 0x7f); + out = CLIP(out, 1, 127); + + return out & 0xff; +} + +void TownsEuphonyDriver::sendNoteOff() { + int8 *chan = &_activeChannels[_command & 0x0f]; + if (*chan == -1) + return; + + while (_assignedChannels[*chan].note != _para[0]) { + chan = &_assignedChannels[*chan].next; + if (*chan == -1) + return; + } + + if (_sustainChannels[_command & 0x0f]) { + _assignedChannels[*chan].note |= 0x80; + } else { + _assignedChannels[*chan].note = 0; + _intf->callback(2, *chan); + } +} + +void TownsEuphonyDriver::sendNoteOn() { + if (!_para[0]) + return; + int8 *chan = &_activeChannels[_command & 0x0f]; + if (*chan == -1) + return; + + do { + _assignedChannels[*chan].sub++; + chan = &_assignedChannels[*chan].next; + } while (*chan != -1); + + chan = &_activeChannels[_command & 0x0f]; + + int d = 0; + int c = 0; + bool found = false; + + do { + if (!_assignedChannels[*chan].note) { + found = true; + break; + } + if (d <= _assignedChannels[*chan].sub) { + c = *chan; + d = _assignedChannels[*chan].sub; + } + chan = &_assignedChannels[*chan].next; + } while (*chan != -1); + + if (found) + c = *chan; + else + _intf->callback(2, c); + + _assignedChannels[c].note = _para[0]; + _assignedChannels[c].sub = 0; + _intf->callback(1, c, _para[0], _para[1]); +} + +void TownsEuphonyDriver::sendChanVolume() { + int8 *chan = &_activeChannels[_command & 0x0f]; + while (*chan != -1) { + _intf->callback(8, *chan, _para[1] & 0x7f); + chan = &_assignedChannels[*chan].next; + }; +} + +void TownsEuphonyDriver::sendPanPosition() { + int8 *chan = &_activeChannels[_command & 0x0f]; + while (*chan != -1) { + _intf->callback(3, *chan, _para[1] & 0x7f); + chan = &_assignedChannels[*chan].next; + }; +} + +void TownsEuphonyDriver::sendAllNotesOff() { + if (_para[1] > 63) { + _sustainChannels[_command & 0x0f] = -1; + return; + } + + _sustainChannels[_command & 0x0f] = 0; + int8 *chan = &_activeChannels[_command & 0x0f]; + while (*chan != -1) { + if (_assignedChannels[*chan].note & 0x80) { + _assignedChannels[*chan].note = 0; + _intf->callback(2, *chan); + } + chan = &_assignedChannels[*chan].next; + }; +} + +void TownsEuphonyDriver::sendSetInstrument() { + int8 *chan = &_activeChannels[_command & 0x0f]; + while (*chan != -1) { + _intf->callback(4, *chan, _para[0]); + _intf->callback(7, *chan, 0); + chan = &_assignedChannels[*chan].next; + }; +} + +void TownsEuphonyDriver::sendPitch() { + int8 *chan = &_activeChannels[_command & 0x0f]; + while (*chan != -1) { + _para[0] += _para[0]; + int16 pitch = (((READ_LE_UINT16(_para)) >> 1) & 0x3fff) - 0x2000; + _intf->callback(7, *chan, pitch); + chan = &_assignedChannels[*chan].next; + }; +} diff --git a/sound/softsynth/fmtowns_pc98/towns_euphony.h b/sound/softsynth/fmtowns_pc98/towns_euphony.h new file mode 100644 index 0000000000..315e4ab4f0 --- /dev/null +++ b/sound/softsynth/fmtowns_pc98/towns_euphony.h @@ -0,0 +1,178 @@ +/* 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. + * + * $URL$ + * $Id$ + * + */ + +#ifndef TOWNS_EUP_H +#define TOWNS_EUP_H + +#include "sound/softsynth/fmtowns_pc98/towns_audio.h" + +class TownsEuphonyDriver : public TownsAudioInterfacePluginDriver { +public: + TownsEuphonyDriver(Audio::Mixer *mixer); + virtual ~TownsEuphonyDriver(); + + bool init(); + void reset(); + + void loadInstrument(int chanType, int id, const uint8 *data); + void loadWaveTable(const uint8 *data); + void unloadWaveTable(int id); + void reserveSfxChannels(int num); + + int setMusicTempo(int tempo); + int startMusicTrack(const uint8 *data, int trackSize, int startTick); + void setMusicLoop(bool loop); + void stopParser(); + + void playSoundEffect(int chan, int note, int velo, const uint8 *data); + void stopSoundEffect(int chan); + bool soundEffectIsPlaying(int chan); + + void chanStereo(int chan, int mode); + void chanPitch(int chan, int pitch); + void chanVolume(int chan, int vol); + + void cdaSetVolume(int a, int vol1, int vol2); + + int chanEnable(int tableEntry, int val); + int chanMode(int tableEntry, int val); + int chanOrdr(int tableEntry, int val); + int chanLevel(int tableEntry, int val); + int chanTranspose(int tableEntry, int val); + + int assignChannel(int chan, int tableEntry); + + void timerCallback(int timerId); + + TownsAudioInterface *intf() { return _intf; } + +private: + void resetTables(); + + void resetTempo(); + void setTempoIntern(int tempo); + void setTimerA(bool enable, int tempo); + void setTimerB(bool enable, int tempo); + + void updatePulseCount(); + void updateTimeStampBase(); + void updateParser(); + void updateCheckEot(); + + bool parseNext(); + void jumpNextLoop(); + + void updateEventBuffer(); + void flushEventBuffer(); + void processBufferNote(int mode, int evt, int note, int velo); + + void resetControl(); + void resetControlIntern(int mode, int chan); + uint8 appendEvent(uint8 evt, uint8 chan); + + void sendEvent(uint8 mode, uint8 command); + + typedef bool(TownsEuphonyDriver::*EuphonyOpcode)(); + bool evtSetupNote(); + bool evtPolyphonicAftertouch(); + bool evtControlPitch(); + bool evtInstrumentChanAftertouch(); + bool evtLoadInstrument(); + bool evtAdvanceTimestampOffset(); + bool evtTempo(); + bool evtModeOrdrChange(); + bool evtNotImpl() { return false; } + + uint8 prepTranspose(uint8 in); + uint8 prepVelo(uint8 in); + + void sendNoteOff(); + void sendNoteOn(); + void sendChanVolume(); + void sendPanPosition(); + void sendAllNotesOff(); + void sendSetInstrument(); + void sendPitch(); + + int8 *_activeChannels; + int8 *_sustainChannels; + + struct ActiveChannel { + int8 chan; + int8 next; + uint8 note; + uint8 sub; + } *_assignedChannels; + + uint8 *_tEnable; + uint8 *_tMode; + uint8 *_tOrdr; + int8 *_tLevel; + int8 *_tTranspose; + + struct DlEvent { + uint8 evt; + uint8 mode; + uint8 note; + uint8 velo; + uint16 len; + } *_eventBuffer; + int _bufferedEventsCount; + + uint8 _para[2]; + uint8 _paraCount; + uint8 _command; + + uint8 _defaultBaseTickLen; + uint8 _baseTickLen; + uint32 _pulseCount; + int _tempoControlMode; + int _extraTimingControlRemainder; + int _extraTimingControl; + int _timerSetting; + int8 _tempoDiff; + int _tempoModifier; + uint32 _timeStampDest; + uint32 _timeStampBase; + int8 _elapsedEvents; + uint8 _deltaTicks; + uint32 _tickCounter; + uint8 _defaultTempo; + int _trackTempo; + + bool _loop; + bool _playing; + bool _endOfTrack; + bool _suspendParsing; + + const uint8 *_musicStart; + const uint8 *_musicPos; + uint32 _musicTrackSize; + + TownsAudioInterface *_intf; +}; + +#endif + diff --git a/sound/softsynth/fmtowns_pc98/towns_pc98_driver.cpp b/sound/softsynth/fmtowns_pc98/towns_pc98_driver.cpp new file mode 100644 index 0000000000..1279429e7c --- /dev/null +++ b/sound/softsynth/fmtowns_pc98/towns_pc98_driver.cpp @@ -0,0 +1,1403 @@ +/* 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. + * + * $URL$ + * $Id$ + * + */ + +#include "sound/softsynth/fmtowns_pc98/towns_pc98_driver.h" +#include "common/endian.h" + +class TownsPC98_MusicChannel { +public: + 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 + } ChannelState; + + 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(); + + const uint8 _idFlag; + +protected: + void setupVibrato(); + bool processVibrato(); + + 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_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 _instr; + uint8 _totalLevel; + uint8 _frqBlockMSB; + int8 _frqLSB; + uint8 _keyOffTime; + bool _hold; + uint8 *_dataPtr; + uint8 _vbrInitDelayHi; + uint8 _vbrInitDelayLo; + int16 _vbrModInitVal; + uint8 _vbrDuration; + 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; + const uint8 _keyNum; + const uint8 _part; + + TownsPC98_AudioDriver *_drv; + + typedef bool (TownsPC98_MusicChannel::*ControlEventFunc)(uint8 para); + const ControlEventFunc *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(); + + 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 setOutputLevel(uint8 lvl); + + bool control_f0_setPatch(uint8 para); + bool control_f1_setTotalLevel(uint8 para); + bool control_f4_setAlgorithm(uint8 para); + bool control_f9_loadCustomPatch(uint8 para); + bool control_fb_incOutLevel(uint8 para); + bool control_fc_decOutLevel(uint8 para); + bool control_ff_endOfTrack(uint8 para); + + typedef bool (TownsPC98_MusicChannelSSG::*ControlEventFunc)(uint8 para); + const ControlEventFunc *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_MusicChannelSSG(driver, regOffs, flgs, num, key, prt, id) {} + ~TownsPC98_SfxChannel() {} + + void loadData(uint8 *data); + void reset(); +}; + +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(); + + void loadData(uint8 *data); + void processEvents(); + bool processControlEvent(uint8 cmd); + +private: + bool control_f1_prcStart(uint8 para); + bool control_ff_endOfTrack(uint8 para); + + typedef bool (TownsPC98_MusicChannelPCM::*ControlEventFunc)(uint8 para); + const ControlEventFunc *controlEvents; +}; + +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; +} + +TownsPC98_MusicChannel::~TownsPC98_MusicChannel() { +} + +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::keyOff() { + // all operators off + uint8 value = _keyNum & 0x0f; + if (_part) + value |= 4; + uint8 regAddress = 0x28; + _drv->writeReg(0, regAddress, value); + _flags |= CHS_KEYOFF; +} + +void TownsPC98_MusicChannel::keyOn() { + // all operators on + uint8 value = _keyNum | 0xf0; + if (_part) + value |= 4; + uint8 regAddress = 0x28; + _drv->writeReg(0, regAddress, value); +} + +void TownsPC98_MusicChannel::loadData(uint8 *data) { + _flags = (_flags & ~CHS_EOT) | CHS_ALLOFF; + _ticksLeft = 1; + _dataPtr = data; + _totalLevel = 0x7F; + + uint8 *tmp = _dataPtr; + for (bool loop = true; loop; ) { + uint8 cmd = *tmp++; + if (cmd < 0xf0) { + tmp++; + } else if (cmd == 0xff) { + if (READ_LE_UINT16(tmp)) { + _drv->_looping |= _idFlag; + tmp += _drv->_opnFxCmdLen[cmd - 240]; + } else + loop = false; + } else if (cmd == 0xf6) { + // reset repeat section countdown + tmp[0] = tmp[1]; + tmp += 4; + } else { + tmp += _drv->_opnFxCmdLen[cmd - 240]; + } + } +} + +void TownsPC98_MusicChannel::processEvents() { + if (_flags & CHS_EOT) + return; + + if (!_hold && _ticksLeft == _keyOffTime) + keyOff(); + + if (--_ticksLeft) + return; + + if (!_hold) + keyOff(); + + uint8 cmd = 0; + bool loop = true; + + while (loop) { + cmd = *_dataPtr++; + if (cmd < 0xf0) + loop = false; + else if (!processControlEvent(cmd)) + return; + } + + uint8 para = *_dataPtr++; + + if (cmd == 0x80) { + keyOff(); + _hold = false; + } else { + keyOn(); + + if (_hold == false || cmd != _frqBlockMSB) + _flags |= CHS_RECALCFREQ; + + _hold = (para & 0x80) ? true : false; + _frqBlockMSB = cmd; + } + + _ticksLeft = para & 0x7f; +} + +void TownsPC98_MusicChannel::processFrequency() { + if (_flags & CHS_RECALCFREQ) { + + _frequency = (((const uint16 *)_drv->_opnFreqTable)[_frqBlockMSB & 0x0f] + _frqLSB) | (((_frqBlockMSB & 0x70) >> 1) << 8); + + _drv->writeReg(_part, _regOffset + 0xa4, (_frequency >> 8)); + _drv->writeReg(_part, _regOffset + 0xa0, (_frequency & 0xff)); + + setupVibrato(); + } + + if (!(_flags & CHS_VBROFF)) { + if (!processVibrato()) + return; + + _drv->writeReg(_part, _regOffset + 0xa4, (_frequency >> 8)); + _drv->writeReg(_part, _regOffset + 0xa0, (_frequency & 0xff)); + } +} + +void TownsPC98_MusicChannel::setupVibrato() { + _vbrCurDelay = _vbrInitDelayHi; + if (_flags & CHS_KEYOFF) { + _vbrModCurVal = _vbrModInitVal; + _vbrCurDelay += _vbrInitDelayLo; + } + _vbrDurLeft = (_vbrDuration >> 1); + _flags &= ~(CHS_KEYOFF | CHS_RECALCFREQ); +} + +bool TownsPC98_MusicChannel::processVibrato() { + if (--_vbrCurDelay) + return false; + + _vbrCurDelay = _vbrInitDelayHi; + _frequency += _vbrModCurVal; + + if (!--_vbrDurLeft) { + _vbrDurLeft = _vbrDuration; + _vbrModCurVal = -_vbrModCurVal; + } + + 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(); +} + +void TownsPC98_MusicChannel::reset() { + _hold = false; + _keyOffTime = 0; + _ticksLeft = 1; + + _flags = (_flags & ~CHS_EOT) | CHS_ALLOFF; + + _totalLevel = 0; + _algorithm = 0; + _flags = CHS_EOT; + _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; +} + +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; + return true; +} + +bool TownsPC98_MusicChannel::control_f3_setFreqLSB(uint8 para) { + _frqLSB = (int8) para; + return true; +} + +bool TownsPC98_MusicChannel::control_f4_setOutputLevel(uint8 para) { + if (_drv->_fading) + return true; + + _totalLevel = para; + setOutputLevel(); + return true; +} + +bool TownsPC98_MusicChannel::control_f5_setTempo(uint8 para) { + _drv->setMusicTempo(para); + return true; +} + +bool TownsPC98_MusicChannel::control_f6_repeatSection(uint8 para) { + _dataPtr--; + _dataPtr[0]--; + + if (*_dataPtr) { + // repeat section until counter has reached zero + _dataPtr = _drv->_trackPtr + READ_LE_UINT16(_dataPtr + 2); + } else { + // reset counter, advance to next section + _dataPtr[0] = _dataPtr[1]; + _dataPtr += 4; + } + return true; +} + +bool TownsPC98_MusicChannel::control_f7_setupVibrato(uint8 para) { + _vbrInitDelayHi = _dataPtr[0]; + _vbrInitDelayLo = para; + _vbrModInitVal = (int16) READ_LE_UINT16(_dataPtr + 1); + _vbrDuration = _dataPtr[3]; + _dataPtr += 4; + _flags = (_flags & ~CHS_VBROFF) | CHS_KEYOFF | CHS_RECALCFREQ; + return true; +} + +bool TownsPC98_MusicChannel::control_f8_toggleVibrato(uint8 para) { + if (para == 0x10) { + if (*_dataPtr++) { + _flags = (_flags & ~CHS_VBROFF) | CHS_KEYOFF; + } else { + _flags |= CHS_VBROFF; + } + } else { + /* NOT IMPLEMENTED + uint8 skipChannels = para / 36; + uint8 entry = para % 36; + TownsPC98_AudioDriver::TownsPC98_MusicChannel *t = &chan[skipChannels]; + + t->unnamedEntries[entry] = *_dataPtr++;*/ + } + return true; +} + +bool TownsPC98_MusicChannel::control_fa_writeReg(uint8 para) { + _drv->writeReg(_part, para, *_dataPtr++); + return true; +} + +bool TownsPC98_MusicChannel::control_fb_incOutLevel(uint8 para) { + _dataPtr--; + if (_drv->_fading) + return true; + + uint8 val = (_totalLevel + 3); + if (val > 0x7f) + val = 0x7f; + + _totalLevel = val; + setOutputLevel(); + return true; +} + +bool TownsPC98_MusicChannel::control_fc_decOutLevel(uint8 para) { + _dataPtr--; + if (_drv->_fading) + return true; + + int8 val = (int8) (_totalLevel - 3); + if (val < 0) + val = 0; + + _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; + return true; + } else { + // quit parsing for active channel + --_dataPtr; + _flags |= CHS_EOT; + _drv->_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) { +} + +void TownsPC98_MusicChannelSSG::init() { + _algorithm = 0x80; + + #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::processEvents() { + if (_flags & CHS_EOT) + return; + + _drv->toggleRegProtection(_flags & CHS_PROTECT ? true : false); + + if (!_hold && _ticksLeft == _keyOffTime) + nextShape(); + + if (!--_ticksLeft) { + + uint8 cmd = 0; + bool loop = true; + + while (loop) { + cmd = *_dataPtr++; + if (cmd < 0xf0) + loop = false; + else if (!processControlEvent(cmd)) + return; + } + + uint8 para = *_dataPtr++; + + if (cmd == 0x80) { + nextShape(); + _hold = false; + } else { + if (!_hold) { + _instr &= 0xf0; + _ssgStep = _drv->_ssgPatches[_instr]; + _ssgTicksLeft = _drv->_ssgPatches[_instr + 1] & 0x7f; + _ssgTargetLvl = _drv->_ssgPatches[_instr + 2]; + _ssgStartLvl = _drv->_ssgPatches[_instr + 3]; + _flags = (_flags & ~CHS_SSGOFF) | CHS_KEYOFF; + } + + keyOn(); + + if (_hold == false || cmd != _frqBlockMSB) + _flags |= CHS_RECALCFREQ; + + _hold = (para & 0x80) ? true : false; + _frqBlockMSB = cmd; + } + + _ticksLeft = para & 0x7f; + } + + if (!(_flags & CHS_SSGOFF)) { + if (--_ssgTicksLeft) { + if (!_drv->_fading) + setOutputLevel(_ssgStartLvl); + return; + } + + _ssgTicksLeft = _drv->_ssgPatches[_instr + 1] & 0x7f; + + if (_drv->_ssgPatches[_instr + 1] & 0x80) { + uint8 t = _ssgStartLvl - _ssgStep; + + if (_ssgStep <= _ssgStartLvl && _ssgTargetLvl < t) { + if (!_drv->_fading) + setOutputLevel(t); + return; + } + } else { + int t = _ssgStartLvl + _ssgStep; + uint8 p = (uint8) (t & 0xff); + + if (t < 256 && _ssgTargetLvl > p) { + if (!_drv->_fading) + setOutputLevel(p); + return; + } + } + + setOutputLevel(_ssgTargetLvl); + if (_ssgStartLvl && !(_instr & 8)){ + _instr += 4; + _ssgStep = _drv->_ssgPatches[_instr]; + _ssgTicksLeft = _drv->_ssgPatches[_instr + 1] & 0x7f; + _ssgTargetLvl = _drv->_ssgPatches[_instr + 2]; + } else { + _flags |= CHS_SSGOFF; + setOutputLevel(0); + } + } +} + +void TownsPC98_MusicChannelSSG::processFrequency() { + if (_algorithm & 0x40) + return; + + if (_flags & CHS_RECALCFREQ) { + _block = _frqBlockMSB >> 4; + _frequency = ((const uint16 *)_drv->_opnFreqTableSSG)[_frqBlockMSB & 0x0f] + _frqLSB; + + uint16 f = _frequency >> _block; + _drv->writeReg(_part, _regOffset << 1, f & 0xff); + _drv->writeReg(_part, (_regOffset << 1) + 1, f >> 8); + + setupVibrato(); + } + + if (!(_flags & (CHS_EOT | CHS_VBROFF | CHS_SSGOFF))) { + if (!processVibrato()) + return; + + uint16 f = _frequency >> _block; + _drv->writeReg(_part, _regOffset << 1, f & 0xff); + _drv->writeReg(_part, (_regOffset << 1) + 1, f >> 8); + } +} + +bool TownsPC98_MusicChannelSSG::processControlEvent(uint8 cmd) { + uint8 para = *_dataPtr++; + return (this->*controlEvents[cmd & 0x0f])(para); +} + +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::keyOn() { + uint8 c = 0x7b; + uint8 t = (_algorithm & 0xC0) << 1; + if (_algorithm & 0x80) + t |= 4; + + c = (c << (_regOffset + 1)) | (c >> (7 - _regOffset)); + t = (t << (_regOffset + 1)) | (t >> (7 - _regOffset)); + + if (!(_algorithm & 0x80)) + _drv->writeReg(_part, 6, _algorithm & 0x7f); + + uint8 e = (_drv->readSSGStatus() & c) | t; + _drv->writeReg(_part, 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->toggleRegProtection(_flags & CHS_PROTECT ? true : false); + TownsPC98_MusicChannel::loadData(data); + setOutputLevel(0); + _algorithm = 0x80; +} + +void TownsPC98_MusicChannelSSG::setOutputLevel(uint8 lvl) { + _ssgStartLvl = lvl; + uint16 newTl = (((uint16)_totalLevel + 1) * (uint16)lvl) >> 8; + 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]; +} + +void TownsPC98_MusicChannelSSG::fadeStep() { + _totalLevel--; + if ((int8)_totalLevel < 0) + _totalLevel = 0; + setOutputLevel(_ssgStartLvl); +} + +bool TownsPC98_MusicChannelSSG::control_f0_setPatch(uint8 para) { + _instr = para << 4; + para = (para >> 3) & 0x1e; + if (para) + return control_f4_setAlgorithm(para | 0x40); + return true; +} + +bool TownsPC98_MusicChannelSSG::control_f1_setTotalLevel(uint8 para) { + if (!_drv->_fading) + _totalLevel = para; + return true; +} + +bool TownsPC98_MusicChannelSSG::control_f4_setAlgorithm(uint8 para) { + _algorithm = para; + return true; +} + +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++; + return true; +} + +bool TownsPC98_MusicChannelSSG::control_fb_incOutLevel(uint8 para) { + _dataPtr--; + if (_drv->_fading) + return true; + + _totalLevel--; + if ((int8)_totalLevel < 0) + _totalLevel = 0; + + return true; +} + +bool TownsPC98_MusicChannelSSG::control_fc_decOutLevel(uint8 para) { + _dataPtr--; + if (_drv->_fading) + return true; + + if (_totalLevel + 1 < 0x10) + _totalLevel++; + + return true; +} + +bool TownsPC98_MusicChannelSSG::control_ff_endOfTrack(uint8 para) { + if (!_drv->_sfxOffs) { + uint16 val = READ_LE_UINT16(--_dataPtr); + if (val) { + // loop + _dataPtr = _drv->_trackPtr + val; + return true; + } else { + // stop parsing + if (!_drv->_fading) + setOutputLevel(0); + --_dataPtr; + _flags |= CHS_EOT; + _drv->_finishedSSGFlag |= _idFlag; + } + } else { + // end of sfx track - restore ssg music channel + _flags |= CHS_EOT; + _drv->_finishedSfxFlag |= _idFlag; + _drv->_ssgChannels[_chanNum]->restore(); + } + + return false; +} + +void TownsPC98_SfxChannel::loadData(uint8 *data) { + _flags = CHS_ALLOFF; + _ticksLeft = 1; + _dataPtr = data; + _ssgTl = 0xff; + _algorithm = 0x80; + + uint8 *tmp = _dataPtr; + for (bool loop = true; loop; ) { + uint8 cmd = *tmp++; + if (cmd < 0xf0) { + tmp++; + } else if (cmd == 0xff) { + loop = false; + } else if (cmd == 0xf6) { + // reset repeat section countdown + tmp[0] = tmp[1]; + tmp += 4; + } else { + tmp += _drv->_opnFxCmdLen[cmd - 240]; + } + } +} + +void TownsPC98_SfxChannel::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 = (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]; +} + +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; +} + +void TownsPC98_MusicChannelPCM::loadData(uint8 *data) { + _flags = (_flags & ~CHS_EOT) | CHS_ALLOFF; + _ticksLeft = 1; + _dataPtr = data; + _totalLevel = 0x7F; +} + +void TownsPC98_MusicChannelPCM::processEvents() { + if (_flags & CHS_EOT) + return; + + if (--_ticksLeft) + return; + + uint8 cmd = 0; + bool loop = true; + + while (loop) { + cmd = *_dataPtr++; + if (cmd == 0x80) { + loop = false; + } else if (cmd < 0xf0) { + _drv->writeReg(_part, 0x10, cmd); + } else if (!processControlEvent(cmd)) { + return; + } + } + + _ticksLeft = *_dataPtr++; +} + +bool TownsPC98_MusicChannelPCM::processControlEvent(uint8 cmd) { + uint8 para = *_dataPtr++; + return (this->*controlEvents[cmd & 0x0f])(para); +} + +bool TownsPC98_MusicChannelPCM::control_f1_prcStart(uint8 para) { + _totalLevel = para; + _drv->writeReg(_part, 0x11, para); + return true; +} + +bool TownsPC98_MusicChannelPCM::control_ff_endOfTrack(uint8 para) { + uint16 val = READ_LE_UINT16(--_dataPtr); + if (val) { + // loop + _dataPtr = _drv->_trackPtr + val; + return true; + } else { + // quit parsing for active channel + --_dataPtr; + _flags |= CHS_EOT; + _drv->_finishedRhythmFlag |= _idFlag; + return false; + } +} + +TownsPC98_AudioDriver::TownsPC98_AudioDriver(Audio::Mixer *mixer, EmuType type) : TownsPC98_FmSynth(mixer, type), + _channels(0), _ssgChannels(0), _sfxChannels(0), _rhythmChannel(0), + _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)), + + _updateChannelsFlag(type == kType26 ? 0x07 : 0x3F), _finishedChannelsFlag(0), + _updateSSGFlag(type == kTypeTowns ? 0x00 : 0x07), _finishedSSGFlag(0), + _updateRhythmFlag(type == kType86 ? 0x01 : 0x00), _finishedRhythmFlag(0), + _updateSfxFlag(0), _finishedSfxFlag(0), + + _musicTickCounter(0), + + _musicVolume(255), _sfxVolume(255), + + _musicPlaying(false), _sfxPlaying(false), _fading(false), _looping(0), _ready(false) { + + _sfxOffsets[0] = _sfxOffsets[1] = 0; +} + +TownsPC98_AudioDriver::~TownsPC98_AudioDriver() { + reset(); + + if (_channels) { + for (int i = 0; i < _numChan; i++) + delete _channels[i]; + delete[] _channels; + } + + if (_ssgChannels) { + for (int i = 0; i < _numSSG; i++) + delete _ssgChannels[i]; + delete[] _ssgChannels; + } + + if (_sfxChannels) { + for (int i = 0; i < 2; i++) + delete _sfxChannels[i]; + delete[] _sfxChannels; + } + + delete _rhythmChannel; + + delete[] _ssgPatches; +} + +bool TownsPC98_AudioDriver::init() { + if (_ready) { + reset(); + return true; + } + + TownsPC98_FmSynth::init(); + + setVolumeChannelMasks(-1, 0); + + _channels = new TownsPC98_MusicChannel *[_numChan]; + for (int i = 0; i < _numChan; 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) { + _ssgPatches = new uint8[256]; + memcpy(_ssgPatches, _drvTables + 156, 256); + + _ssgChannels = new TownsPC98_MusicChannelSSG *[_numSSG]; + for (int i = 0; i < _numSSG; 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(); + } + + _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(); + } + } + + if (_hasPercussion) { + _rhythmChannel = new TownsPC98_MusicChannelPCM(this, 0, 0, 0, 0, 0, 1); + _rhythmChannel->init(); + } + + setMusicTempo(84); + setSfxTempo(654); + + _ready = true; + + return true; +} + +void TownsPC98_AudioDriver::loadMusicData(uint8 *data, bool loadPaused) { + if (!_ready) { + warning("TownsPC98_AudioDriver: Driver must be initialized before loading data"); + return; + } + + if (!data) { + warning("TownsPC98_AudioDriver: Invalid music file data"); + return; + } + + reset(); + + Common::StackLock lock(_mutex); + uint8 *src_a = _trackPtr = _musicBuffer = data; + + for (uint8 i = 0; i < 3; i++) { + _channels[i]->loadData(data + READ_LE_UINT16(src_a)); + src_a += 2; + } + + for (int i = 0; i < _numSSG; i++) { + _ssgChannels[i]->loadData(data + READ_LE_UINT16(src_a)); + src_a += 2; + } + + for (uint8 i = 3; i < _numChan; i++) { + _channels[i]->loadData(data + READ_LE_UINT16(src_a)); + src_a += 2; + } + + if (_hasPercussion) { + _rhythmChannel->loadData(data + READ_LE_UINT16(src_a)); + src_a += 2; + } + + toggleRegProtection(false); + + _patches = src_a + 4; + _finishedChannelsFlag = _finishedSSGFlag = _finishedRhythmFlag = 0; + + _musicPlaying = (loadPaused ? false : true); +} + +void TownsPC98_AudioDriver::loadSoundEffectData(uint8 *data, uint8 trackNum) { + if (!_ready) { + warning("TownsPC98_AudioDriver: Driver must be initialized before loading data"); + return; + } + + if (!_sfxChannels) { + warning("TownsPC98_AudioDriver: Sound effects not supported by this configuration"); + return; + } + + if (!data) { + warning("TownsPC98_AudioDriver: Invalid sound effects file data"); + return; + } + + Common::StackLock lock(_mutex); + _sfxData = _sfxBuffer = data; + _sfxOffsets[0] = READ_LE_UINT16(&_sfxData[(trackNum << 2)]); + _sfxOffsets[1] = READ_LE_UINT16(&_sfxData[(trackNum << 2) + 2]); + _sfxPlaying = true; + _finishedSfxFlag = 0; +} + +void TownsPC98_AudioDriver::reset() { + Common::StackLock lock(_mutex); + + _musicPlaying = false; + _sfxPlaying = false; + _fading = false; + _looping = 0; + _musicTickCounter = 0; + _sfxData = 0; + + TownsPC98_FmSynth::reset(); + + for (int i = 0; i < _numChan; i++) + _channels[i]->reset(); + for (int i = 0; i < _numSSG; i++) + _ssgChannels[i]->reset(); + + if (_numSSG) { + for (int i = 0; i < 2; i++) + _sfxChannels[i]->reset(); + + memcpy(_ssgPatches, _drvTables + 156, 256); + } + + if (_rhythmChannel) + _rhythmChannel->reset(); +} + +void TownsPC98_AudioDriver::fadeStep() { + if (!_musicPlaying) + return; + + Common::StackLock lock(_mutex); + for (int j = 0; j < _numChan; j++) { + if (_updateChannelsFlag & _channels[j]->_idFlag) + _channels[j]->fadeStep(); + } + + for (int j = 0; j < _numSSG; j++) { + if (_updateSSGFlag & _ssgChannels[j]->_idFlag) + _ssgChannels[j]->fadeStep(); + } + + if (!_fading) { + _fading = 19; + if (_hasPercussion) { + if (_updateRhythmFlag & _rhythmChannel->_idFlag) + _rhythmChannel->reset(); + } + } else { + if (!--_fading) + reset(); + } +} + +void TownsPC98_AudioDriver::timerCallbackB() { + _sfxOffs = 0; + + if (_musicPlaying) { + _musicTickCounter++; + + for (int i = 0; i < _numChan; i++) { + if (_updateChannelsFlag & _channels[i]->_idFlag) { + _channels[i]->processEvents(); + _channels[i]->processFrequency(); + } + } + + for (int i = 0; i < _numSSG; i++) { + if (_updateSSGFlag & _ssgChannels[i]->_idFlag) { + _ssgChannels[i]->processEvents(); + _ssgChannels[i]->processFrequency(); + } + } + + if (_hasPercussion) + if (_updateRhythmFlag & _rhythmChannel->_idFlag) + _rhythmChannel->processEvents(); + } + + toggleRegProtection(false); + + if (_finishedChannelsFlag == _updateChannelsFlag && _finishedSSGFlag == _updateSSGFlag && _finishedRhythmFlag == _updateRhythmFlag) + _musicPlaying = false; +} + +void TownsPC98_AudioDriver::timerCallbackA() { + if (_sfxChannels && _sfxPlaying) { + if (_sfxData) + startSoundEffect(); + + _sfxOffs = 3; + _trackPtr = _sfxBuffer; + + for (int i = 0; i < 2; i++) { + if (_updateSfxFlag & _sfxChannels[i]->_idFlag) { + _sfxChannels[i]->processEvents(); + _sfxChannels[i]->processFrequency(); + } + } + + _trackPtr = _musicBuffer; + } + + if (_updateSfxFlag && _finishedSfxFlag == _updateSfxFlag) { + _sfxPlaying = false; + _updateSfxFlag = 0; + setVolumeChannelMasks(-1, 0); + } +} + +void TownsPC98_AudioDriver::setMusicTempo(uint8 tempo) { + writeReg(0, 0x26, tempo); + writeReg(0, 0x27, 0x33); +} + +void TownsPC98_AudioDriver::setSfxTempo(uint16 tempo) { + writeReg(0, 0x24, tempo & 0xff); + writeReg(0, 0x25, tempo >> 8); + writeReg(0, 0x27, 0x33); +} + +void TownsPC98_AudioDriver::startSoundEffect() { + int volFlags = 0; + + for (int i = 0; i < 2; i++) { + if (_sfxOffsets[i]) { + _ssgChannels[i + 1]->protect(); + _sfxChannels[i]->reset(); + _sfxChannels[i]->loadData(_sfxData + _sfxOffsets[i]); + _updateSfxFlag |= _sfxChannels[i]->_idFlag; + volFlags |= (_sfxChannels[i]->_idFlag << _numChan); + } else { + _ssgChannels[i + 1]->restore(); + _updateSfxFlag &= ~_sfxChannels[i]->_idFlag; + } + } + + setVolumeChannelMasks(~volFlags, volFlags); + _sfxData = 0; +} + +const uint8 TownsPC98_AudioDriver::_drvTables[] = { + // channel presets + 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, + + // fmt level presets + 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, + + // pc98 level presets + 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 +}; + +#undef EUPHONY_FADEOUT_TICKS + diff --git a/sound/softsynth/fmtowns_pc98/towns_pc98_driver.h b/sound/softsynth/fmtowns_pc98/towns_pc98_driver.h new file mode 100644 index 0000000000..f7d09df09d --- /dev/null +++ b/sound/softsynth/fmtowns_pc98/towns_pc98_driver.h @@ -0,0 +1,110 @@ +/* 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. + * + * $URL$ + * $Id$ + * + */ + +#ifndef TOWNS_PC98_AUDIODRIVER_H +#define TOWNS_PC98_AUDIODRIVER_H + +#include "sound/softsynth/fmtowns_pc98/towns_pc98_fmsynth.h" + +class TownsPC98_AudioDriver : public TownsPC98_FmSynth { +friend class TownsPC98_MusicChannel; +friend class TownsPC98_MusicChannelSSG; +friend class TownsPC98_SfxChannel; +friend class TownsPC98_MusicChannelPCM; +public: + TownsPC98_AudioDriver(Audio::Mixer *mixer, EmuType type); + ~TownsPC98_AudioDriver(); + + void loadMusicData(uint8 *data, bool loadPaused = false); + void loadSoundEffectData(uint8 *data, uint8 trackNum); + bool init(); + void reset(); + + void fadeStep(); + + void pause() { _musicPlaying = false; } + void cont() { _musicPlaying = true; } + + void timerCallbackB(); + void timerCallbackA(); + + bool looping() { return _looping == _updateChannelsFlag ? true : false; } + bool musicPlaying() { return _musicPlaying; } + + void setMusicVolume(int volume) { _musicVolume = volume; setVolumeIntern(_musicVolume, _sfxVolume); } + void setSoundEffectVolume(int volume) { _sfxVolume = volume; setVolumeIntern(_musicVolume, _sfxVolume); } + +protected: + void startSoundEffect(); + + void setMusicTempo(uint8 tempo); + void setSfxTempo(uint16 tempo); + + TownsPC98_MusicChannel **_channels; + TownsPC98_MusicChannelSSG **_ssgChannels; + TownsPC98_SfxChannel **_sfxChannels; + TownsPC98_MusicChannelPCM *_rhythmChannel; + + 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; + + uint8 _updateChannelsFlag; + uint8 _updateSSGFlag; + uint8 _updateRhythmFlag; + uint8 _updateSfxFlag; + uint8 _finishedChannelsFlag; + uint8 _finishedSSGFlag; + uint8 _finishedRhythmFlag; + uint8 _finishedSfxFlag; + + bool _musicPlaying; + bool _sfxPlaying; + uint8 _fading; + uint8 _looping; + uint32 _musicTickCounter; + + int _sfxOffs; + uint8 *_sfxData; + uint16 _sfxOffsets[2]; + + uint16 _musicVolume; + uint16 _sfxVolume; + + static const uint8 _drvTables[]; + + bool _ready; +}; + +#endif + diff --git a/sound/softsynth/fmtowns_pc98/towns_pc98_fmsynth.cpp b/sound/softsynth/fmtowns_pc98/towns_pc98_fmsynth.cpp new file mode 100644 index 0000000000..5436c8e0c7 --- /dev/null +++ b/sound/softsynth/fmtowns_pc98/towns_pc98_fmsynth.cpp @@ -0,0 +1,1461 @@ +/* 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. + * + * $URL$ + * $Id$ + * + */ + +#include "sound/softsynth/fmtowns_pc98/towns_pc98_fmsynth.h" +#include "common/endian.h" + +class TownsPC98_FmSynthOperator { +public: + TownsPC98_FmSynthOperator(const uint32 timerbase, const uint8 *rateTable, + const uint8 *shiftTable, const uint8 *attackDecayTable, const uint32 *frqTable, + const uint32 *sineTable, const int32 *tlevelOut, const int32 *detuneTable); + ~TownsPC98_FmSynthOperator() {} + + void keyOn(); + void keyOff(); + void frequency(int freq); + void updatePhaseIncrement(); + void recalculateRates(); + void generateOutput(int32 phasebuf, int32 *feedbuf, int32 &out); + + void feedbackLevel(int32 level) {_feedbackLevel = level ? level + 6 : 0; } + void detune(int value) { _detn = &_detnTbl[value << 5]; } + void multiple(uint32 value) { _multiple = value ? (value << 1) : 1; } + void attackRate(uint32 value) { _specifiedAttackRate = value; } + bool scaleRate(uint8 value); + void decayRate(uint32 value) { _specifiedDecayRate = value; recalculateRates(); } + void sustainRate(uint32 value) { _specifiedSustainRate = value; recalculateRates(); } + void sustainLevel(uint32 value) { _sustainLevel = (value == 0x0f) ? 0x3e0 : value << 5; } + void releaseRate(uint32 value) { _specifiedReleaseRate = value; recalculateRates(); } + void totalLevel(uint32 value) { _totalLevel = value << 3; } + void ampModulation(bool enable) { _ampMod = enable; } + void reset(); + +protected: + EnvelopeState _state; + bool _playing; + uint32 _feedbackLevel; + uint32 _multiple; + uint32 _totalLevel; + uint8 _keyScale1; + uint8 _keyScale2; + uint32 _specifiedAttackRate; + uint32 _specifiedDecayRate; + uint32 _specifiedSustainRate; + uint32 _specifiedReleaseRate; + uint32 _tickCount; + uint32 _sustainLevel; + + bool _ampMod; + uint32 _frequency; + uint8 _kcode; + uint32 _phase; + uint32 _phaseIncrement; + const int32 *_detn; + + const uint8 *_rateTbl; + const uint8 *_rshiftTbl; + const uint8 *_adTbl; + const uint32 *_fTbl; + const uint32 *_sinTbl; + const int32 *_tLvlTbl; + const int32 *_detnTbl; + + const uint32 _tickLength; + uint32 _timer; + int32 _currentLevel; + + struct EvpState { + uint8 rate; + uint8 shift; + } fs_a, fs_d, fs_s, fs_r; +}; + +TownsPC98_FmSynthOperator::TownsPC98_FmSynthOperator(const uint32 timerbase, const uint8 *rateTable, + const uint8 *shiftTable, const uint8 *attackDecayTable, const uint32 *frqTable, + const uint32 *sineTable, const int32 *tlevelOut, const int32 *detuneTable) : + _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), + _phase(0), _state(kEnvReady), _playing(false), _timer(0), _keyScale1(0), + _keyScale2(0), _currentLevel(1023), _ampMod(false), _tickCount(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; + + reset(); +} + +void TownsPC98_FmSynthOperator::keyOn() { + if (_playing) + return; + + _playing = true; + _state = kEnvAttacking; + _phase = 0; +} + +void TownsPC98_FmSynthOperator::keyOff() { + if (!_playing) + return; + + _playing = false; + if (_state != kEnvReady) + _state = kEnvReleasing; +} + +void TownsPC98_FmSynthOperator::frequency(int freq) { + uint8 block = (freq >> 11); + uint16 pos = (freq & 0x7ff); + uint8 c = pos >> 7; + + _kcode = (block << 2) | ((c < 7) ? 0 : ((c > 8) ? 3 : c - 6 )); + _frequency = _fTbl[pos << 1] >> (7 - block); +} + +void TownsPC98_FmSynthOperator::updatePhaseIncrement() { + _phaseIncrement = ((_frequency + _detn[_kcode]) * _multiple) >> 1; + uint8 keyscale = _kcode >> _keyScale1; + if (_keyScale2 != keyscale) { + _keyScale2 = keyscale; + recalculateRates(); + } +} + +void TownsPC98_FmSynthOperator::recalculateRates() { + int k = _keyScale2; + int r = _specifiedAttackRate ? (_specifiedAttackRate << 1) + 0x20 : 0; + fs_a.rate = ((r + k) < 94) ? _rateTbl[r + k] : 136; + fs_a.shift = ((r + k) < 94) ? _rshiftTbl[r + k] : 0; + + r = _specifiedDecayRate ? (_specifiedDecayRate << 1) + 0x20 : 0; + fs_d.rate = _rateTbl[r + k]; + fs_d.shift = _rshiftTbl[r + k]; + + r = _specifiedSustainRate ? (_specifiedSustainRate << 1) + 0x20 : 0; + fs_s.rate = _rateTbl[r + k]; + fs_s.shift = _rshiftTbl[r + k]; + + r = (_specifiedReleaseRate << 2) + 0x22; + fs_r.rate = _rateTbl[r + k]; + fs_r.shift = _rshiftTbl[r + k]; +} + +void TownsPC98_FmSynthOperator::generateOutput(int32 phasebuf, int32 *feed, int32 &out) { + if (_state == kEnvReady) + return; + + _timer += _tickLength; + while (_timer > 0x5B8D80) { + _timer -= 0x5B8D80; + ++_tickCount; + + int32 levelIncrement = 0; + uint32 targetTime = 0; + int32 targetLevel = 0; + EnvelopeState nextState = kEnvReady; + + switch (_state) { + case kEnvReady: + return; + case kEnvAttacking: + targetLevel = 0; + nextState = kEnvDecaying; + if ((_specifiedAttackRate << 1) + _keyScale2 < 64) { + targetTime = (1 << fs_a.shift) - 1; + levelIncrement = (~_currentLevel * _adTbl[fs_a.rate + ((_tickCount >> fs_a.shift) & 7)]) >> 4; + break; + } else { + _currentLevel = targetLevel; + _state = nextState; + } + // Fall through + case kEnvDecaying: + targetTime = (1 << fs_d.shift) - 1; + nextState = kEnvSustaining; + targetLevel = _sustainLevel; + levelIncrement = _adTbl[fs_d.rate + ((_tickCount >> fs_d.shift) & 7)]; + break; + case kEnvSustaining: + targetTime = (1 << fs_s.shift) - 1; + nextState = kEnvSustaining; + targetLevel = 1023; + levelIncrement = _adTbl[fs_s.rate + ((_tickCount >> fs_s.shift) & 7)]; + break; + case kEnvReleasing: + targetTime = (1 << fs_r.shift) - 1; + nextState = kEnvReady; + targetLevel = 1023; + levelIncrement = _adTbl[fs_r.rate + ((_tickCount >> fs_r.shift) & 7)]; + break; + } + + if (!(_tickCount & targetTime)) { + _currentLevel += levelIncrement; + if ((_state == kEnvAttacking && _currentLevel <= targetLevel) || (_state != kEnvAttacking && _currentLevel >= targetLevel)) { + if (_state != kEnvDecaying) + _currentLevel = targetLevel; + _state = nextState; + } + } + } + + uint32 lvlout = _totalLevel + (uint32) _currentLevel; + + + int32 outp = 0; + int32 *i = &outp, *o = &outp; + int phaseShift = 0; + + if (feed) { + o = &feed[0]; + i = &feed[1]; + phaseShift = _feedbackLevel ? ((*o + *i) << _feedbackLevel) : 0; + *o = *i; + } else { + phaseShift = phasebuf << 15; + } + + if (lvlout < 832) { + uint32 index = (lvlout << 3) + _sinTbl[(((int32)((_phase & 0xffff0000) + + phaseShift)) >> 16) & 0x3ff]; + *i = ((index < 6656) ? _tLvlTbl[index] : 0); + } else { + *i = 0; + } + + _phase += _phaseIncrement; + out += *o; +} + +void TownsPC98_FmSynthOperator::reset(){ + keyOff(); + _timer = 0; + _keyScale2 = 0; + _currentLevel = 1023; + + frequency(0); + detune(0); + scaleRate(0); + multiple(0); + updatePhaseIncrement(); + attackRate(0); + decayRate(0); + releaseRate(0); + sustainRate(0); + feedbackLevel(0); + totalLevel(127); + ampModulation(false); +} + +bool TownsPC98_FmSynthOperator::scaleRate(uint8 value) { + value = 3 - value; + if (_keyScale1 != value) { + _keyScale1 = value; + return true; + } + + int k = _keyScale2; + int r = _specifiedAttackRate ? (_specifiedAttackRate << 1) + 0x20 : 0; + fs_a.rate = ((r + k) < 94) ? _rateTbl[r + k] : 136; + fs_a.shift = ((r + k) < 94) ? _rshiftTbl[r + k] : 0; + return false; +} + +class TownsPC98_FmSynthSquareSineSource { +public: + TownsPC98_FmSynthSquareSineSource(const uint32 timerbase); + ~TownsPC98_FmSynthSquareSineSource(); + + void init(const int *rsTable, const int *rseTable); + void reset(); + void writeReg(uint8 address, uint8 value, bool force = false); + + void nextTick(int32 *buffer, uint32 bufferSize); + + void setVolumeIntern(int volA, int volB) { _volumeA = volA; _volumeB = volB; } + void setVolumeChannelMasks(int channelMaskA, int channelMaskB) { _volMaskA = channelMaskA; _volMaskB = channelMaskB; } + + uint8 chanEnable() const { return _chanEnable; } +private: + void updateRegs(); + + uint8 _updateRequestBuf[64]; + int _updateRequest; + int _rand; + + int8 _evpTimer; + uint32 _pReslt; + uint8 _attack; + + bool _evpUpdate, _cont; + + int _evpUpdateCnt; + uint8 _outN; + int _nTick; + + int32 *_tlTable; + int32 *_tleTable; + + const uint32 _tickLength; + uint32 _timer; + + struct Channel { + int tick; + uint8 smp; + uint8 out; + + uint8 frqL; + uint8 frqH; + uint8 vol; + } _channels[3]; + + uint8 _noiseGenerator; + uint8 _chanEnable; + + uint8 **_reg; + + uint16 _volumeA; + uint16 _volumeB; + int _volMaskA; + int _volMaskB; + + bool _ready; +}; + +class TownsPC98_FmSynthPercussionSource { +public: + TownsPC98_FmSynthPercussionSource(const uint32 timerbase); + ~TownsPC98_FmSynthPercussionSource() { delete[] _reg; } + + void init(const uint8 *instrData = 0); + void reset(); + void writeReg(uint8 address, uint8 value); + + void nextTick(int32 *buffer, uint32 bufferSize); + + void setVolumeIntern(int volA, int volB) { _volumeA = volA; _volumeB = volB; } + void setVolumeChannelMasks(int channelMaskA, int channelMaskB) { _volMaskA = channelMaskA; _volMaskB = channelMaskB; } + +private: + struct RhtChannel { + const uint8 *data; + + const uint8 *start; + const uint8 *end; + const uint8 *pos; + uint32 size; + bool active; + uint8 level; + + int8 decState; + uint8 decStep; + + int16 samples[2]; + int out; + + uint8 startPosH; + uint8 startPosL; + uint8 endPosH; + uint8 endPosL; + }; + + void recalcOuput(RhtChannel *ins); + void advanceInput(RhtChannel *ins); + + RhtChannel _rhChan[6]; + + uint8 _totalLevel; + + const uint32 _tickLength; + uint32 _timer; + + uint8 **_reg; + + uint16 _volumeA; + uint16 _volumeB; + int _volMaskA; + int _volMaskB; + + bool _ready; +}; + +TownsPC98_FmSynthSquareSineSource::TownsPC98_FmSynthSquareSineSource(const uint32 timerbase) : _tlTable(0), + _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), + _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[0] = &_channels[0].frqL; + _reg[1] = &_channels[0].frqH; + _reg[2] = &_channels[1].frqL; + _reg[3] = &_channels[1].frqH; + _reg[4] = &_channels[2].frqL; + _reg[5] = &_channels[2].frqH; + _reg[6] = &_noiseGenerator; + _reg[7] = &_chanEnable; + _reg[8] = &_channels[0].vol; + _reg[9] = &_channels[1].vol; + _reg[10] = &_channels[2].vol; + + reset(); +} + +TownsPC98_FmSynthSquareSineSource::~TownsPC98_FmSynthSquareSineSource() { + delete[] _tlTable; + delete[] _tleTable; + delete[] _reg; +} + +void TownsPC98_FmSynthSquareSineSource::init(const int *rsTable, const int *rseTable) { + if (_ready) { + reset(); + return; + } + + delete[] _tlTable; + delete[] _tleTable; + _tlTable = new int32[16]; + _tleTable = new int32[32]; + float a, b, d; + d = 801.0f; + + for (int i = 0; i < 16; i++) { + b = 1.0f / rsTable[i]; + a = 1.0f / d + b + 1.0f / 1000.0f; + float v = (b / a) * 32767.0f; + _tlTable[i] = (int32) v; + + b = 1.0f / rseTable[i]; + a = 1.0f / d + b + 1.0f / 1000.0f; + v = (b / a) * 32767.0f; + _tleTable[i] = (int32) v; + } + + for (int i = 16; i < 32; i++) { + b = 1.0f / rseTable[i]; + a = 1.0f / d + b + 1.0f / 1000.0f; + float v = (b / a) * 32767.0f; + _tleTable[i] = (int32) v; + } + + _ready = true; +} + +void TownsPC98_FmSynthSquareSineSource::reset() { + _rand = 1; + _outN = 1; + _updateRequest = -1; + _nTick = _evpUpdateCnt = 0; + _evpTimer = 0x1f; + _pReslt = 0x1f; + _attack = 0; + _cont = false; + _evpUpdate = true; + _timer = 0; + + for (int i = 0; i < 3; i++) { + _channels[i].tick = 0; + _channels[i].smp = _channels[i].out = 0; + } + + for (int i = 0; i < 14; i++) + writeReg(i, 0, true); + + writeReg(7, 0xbf, true); +} + +void TownsPC98_FmSynthSquareSineSource::writeReg(uint8 address, uint8 value, bool force) { + 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); + return; + } + + if (!force) { + if (_updateRequest >= 63) { + warning("TownsPC98_FmSynthSquareSineSource: event buffer overflow"); + _updateRequest = -1; + } + _updateRequestBuf[++_updateRequest] = value; + _updateRequestBuf[++_updateRequest] = address; + return; + } + + *_reg[address] = value; +} + +void TownsPC98_FmSynthSquareSineSource::nextTick(int32 *buffer, uint32 bufferSize) { + if (!_ready) + return; + + for (uint32 i = 0; i < bufferSize; i++) { + _timer += _tickLength; + while (_timer > 0x5B8D80) { + _timer -= 0x5B8D80; + + if (++_nTick >= (_noiseGenerator & 0x1f)) { + if ((_rand + 1) & 2) + _outN ^= 1; + + _rand = (((_rand & 1) ^ ((_rand >> 3) & 1)) << 16) | (_rand >> 1); + _nTick = 0; + } + + for (int ii = 0; ii < 3; ii++) { + if (++_channels[ii].tick >= (((_channels[ii].frqH & 0x0f) << 8) | _channels[ii].frqL)) { + _channels[ii].tick = 0; + _channels[ii].smp ^= 1; + } + _channels[ii].out = (_channels[ii].smp | ((_chanEnable >> ii) & 1)) & (_outN | ((_chanEnable >> (ii + 3)) & 1)); + } + + if (_evpUpdate) { + if (++_evpUpdateCnt >= 0) { + _evpUpdateCnt = 0; + + if (--_evpTimer < 0) { + if (_cont) { + _evpTimer &= 0x1f; + } else { + _evpUpdate = false; + _evpTimer = 0; + } + } + } + } + _pReslt = _evpTimer ^ _attack; + updateRegs(); + } + + int32 finOut = 0; + for (int ii = 0; ii < 3; ii++) { + int32 finOutTemp = ((_channels[ii].vol >> 4) & 1) ? _tleTable[_channels[ii].out ? _pReslt : 0] : _tlTable[_channels[ii].out ? (_channels[ii].vol & 0x0f) : 0]; + + if ((1 << ii) & _volMaskA) + finOutTemp = (finOutTemp * _volumeA) / Audio::Mixer::kMaxMixerVolume; + + if ((1 << ii) & _volMaskB) + finOutTemp = (finOutTemp * _volumeB) / Audio::Mixer::kMaxMixerVolume; + + finOut += finOutTemp; + } + + finOut /= 3; + + buffer[i << 1] += finOut; + buffer[(i << 1) + 1] += finOut; + } +} + +void TownsPC98_FmSynthSquareSineSource::updateRegs() { + for (int i = 0; i < _updateRequest;) { + uint8 b = _updateRequestBuf[i++]; + uint8 a = _updateRequestBuf[i++]; + writeReg(a, b, true); + } + _updateRequest = -1; +} + +TownsPC98_FmSynthPercussionSource::TownsPC98_FmSynthPercussionSource(const uint32 timerbase) : + _tickLength(timerbase * 2), _timer(0), _ready(false), _volMaskA(0), _volMaskB(0), _volumeA(Audio::Mixer::kMaxMixerVolume), _volumeB(Audio::Mixer::kMaxMixerVolume) { + + memset(_rhChan, 0, sizeof(RhtChannel) * 6); + _reg = new uint8 *[40]; + + _reg[0] = _reg[1] = _reg[2] = _reg[3] = _reg[4] = _reg[5] = _reg[6] = _reg[7] = _reg[8] = _reg[9] = _reg[10] = _reg[11] = _reg[12] = _reg[13] = _reg[14] = _reg[15] = 0; + _reg[16] = &_rhChan[0].startPosL; + _reg[17] = &_rhChan[1].startPosL; + _reg[18] = &_rhChan[2].startPosL; + _reg[19] = &_rhChan[3].startPosL; + _reg[20] = &_rhChan[4].startPosL; + _reg[21] = &_rhChan[5].startPosL; + _reg[22] = &_rhChan[0].startPosH; + _reg[23] = &_rhChan[1].startPosH; + _reg[24] = &_rhChan[2].startPosH; + _reg[25] = &_rhChan[3].startPosH; + _reg[26] = &_rhChan[4].startPosH; + _reg[27] = &_rhChan[5].startPosH; + _reg[28] = &_rhChan[0].endPosL; + _reg[29] = &_rhChan[1].endPosL; + _reg[30] = &_rhChan[2].endPosL; + _reg[31] = &_rhChan[3].endPosL; + _reg[32] = &_rhChan[4].endPosL; + _reg[33] = &_rhChan[5].endPosL; + _reg[34] = &_rhChan[0].endPosH; + _reg[35] = &_rhChan[1].endPosH; + _reg[36] = &_rhChan[2].endPosH; + _reg[37] = &_rhChan[3].endPosH; + _reg[38] = &_rhChan[4].endPosH; + _reg[39] = &_rhChan[5].endPosH; +} + +void TownsPC98_FmSynthPercussionSource::init(const uint8 *instrData) { + if (_ready) { + reset(); + return; + } + + const uint8 *start = instrData; + const uint8 *pos = start; + + if (instrData) { + for (int i = 0; i < 6; i++) { + _rhChan[i].data = start + READ_BE_UINT16(pos); + pos += 2; + _rhChan[i].size = READ_BE_UINT16(pos); + pos += 2; + } + reset(); + _ready = true; + } else { + memset(_rhChan, 0, sizeof(RhtChannel) * 6); + _ready = false; + } +} + +void TownsPC98_FmSynthPercussionSource::reset() { + _timer = 0; + _totalLevel = 63; + + for (int i = 0; i < 6; i++) { + RhtChannel *s = &_rhChan[i]; + s->pos = s->start = s->data; + s->end = s->data + s->size; + s->active = false; + s->level = 0; + s->out = 0; + s->decStep = 1; + s->decState = 0; + s->samples[0] = s->samples[1] = 0; + s->startPosH = s->startPosL = s->endPosH = s->endPosL = 0; + } +} + +void TownsPC98_FmSynthPercussionSource::writeReg(uint8 address, uint8 value) { + if (!_ready) + return; + + uint8 h = address >> 4; + uint8 l = address & 15; + + if (address > 15) + *_reg[address] = value; + + if (address == 0) { + if (value & 0x80) { + //key off + for (int i = 0; i < 6; i++) { + if ((value >> i) & 1) + _rhChan[i].active = false; + } + } else { + //key on + for (int i = 0; i < 6; i++) { + if ((value >> i) & 1) { + RhtChannel *s = &_rhChan[i]; + s->pos = s->start; + s->active = true; + s->out = 0; + s->samples[0] = s->samples[1] = 0; + s->decStep = 1; + s->decState = 0; + } + } + } + } else if (address == 1) { + // total level + _totalLevel = (value & 63) ^ 63; + for (int i = 0; i < 6; i++) + recalcOuput(&_rhChan[i]); + } else if (!h && l & 8) { + // instrument level + l &= 7; + _rhChan[l].level = (value & 0x1f) ^ 0x1f; + recalcOuput(&_rhChan[l]); + } else if (h & 3) { + l &= 7; + if (h == 1) { + // set start offset + _rhChan[l].start = _rhChan[l].data + ((_rhChan[l].startPosH << 8 | _rhChan[l].startPosL) << 8); + } else if (h == 2) { + // set end offset + _rhChan[l].end = _rhChan[l].data + ((_rhChan[l].endPosH << 8 | _rhChan[l].endPosL) << 8) + 255; + } + } +} + +void TownsPC98_FmSynthPercussionSource::nextTick(int32 *buffer, uint32 bufferSize) { + if (!_ready) + return; + + for (uint32 i = 0; i < bufferSize; i++) { + _timer += _tickLength; + while (_timer > 0x5B8D80) { + _timer -= 0x5B8D80; + + for (int ii = 0; ii < 6; ii++) { + RhtChannel *s = &_rhChan[ii]; + if (s->active) { + recalcOuput(s); + if (s->decStep) { + advanceInput(s); + if (s->pos == s->end) + s->active = false; + } + s->decStep ^= 1; + } + } + } + + int32 finOut = 0; + + for (int ii = 0; ii < 6; ii++) { + if (_rhChan[ii].active) + finOut += _rhChan[ii].out; + } + + finOut <<= 1; + + if (1 & _volMaskA) + finOut = (finOut * _volumeA) / Audio::Mixer::kMaxMixerVolume; + + if (1 & _volMaskB) + finOut = (finOut * _volumeB) / Audio::Mixer::kMaxMixerVolume; + + buffer[i << 1] += finOut; + buffer[(i << 1) + 1] += finOut; + } +} + +void TownsPC98_FmSynthPercussionSource::recalcOuput(RhtChannel *ins) { + uint32 s = _totalLevel + ins->level; + uint32 x = s > 62 ? 0 : (1 + (s >> 3)); + int32 y = s > 62 ? 0 : (15 - (s & 7)); + ins->out = ((ins->samples[ins->decStep] * y) >> x) & ~3; +} + +void TownsPC98_FmSynthPercussionSource::advanceInput(RhtChannel *ins) { + static const int8 adjustIndex[] = {-1, -1, -1, -1, 2, 5, 7, 9 }; + + static const int16 stepTable[] = { 16, 17, 19, 21, 23, 25, 28, 31, 34, 37, 41, 45, 50, 55, + 60, 66, 73, 80, 88, 97, 107, 118, 130, 143, 157, 173, 190, 209, 230, 253, 279, 307, 337, + 371, 408, 449, 494, 544, 598, 658, 724, 796, 876, 963, 1060, 1166, 1282, 1411, 1552 + }; + + uint8 cur = (int8) *ins->pos++; + + for (int i = 0; i < 2; i++) { + int b = (2 * (cur & 7) + 1) * stepTable[ins->decState] / 8; + ins->samples[i] = CLIP(ins->samples[i ^ 1] + (cur & 8 ? b : -b), -2048, 2047); + ins->decState = CLIP(ins->decState + adjustIndex[cur & 7], 0, 48); + cur >>= 4; + } +} + +TownsPC98_FmSynth::TownsPC98_FmSynth(Audio::Mixer *mixer, EmuType type) : + _mixer(mixer), + _chanInternal(0), _ssg(0), _prc(0), + _numChan(type == kType26 ? 3 : 6), _numSSG(type == kTypeTowns ? 0 : 3), _hasPercussion(type == kType86 ? true : false), + _oprRates(0), _oprRateshift(0), _oprAttackDecay(0), _oprFrq(0), _oprSinTbl(0), _oprLevelOut(0), _oprDetune(0), + _baserate(55125.0f / (float)mixer->getOutputRate()), + _volMaskA(0), _volMaskB(0), _volumeA(255), _volumeB(255), + _regProtectionFlag(false), _ready(false) { + + memset(&_timers[0], 0, sizeof(ChipTimer)); + memset(&_timers[1], 0, sizeof(ChipTimer)); + _timers[0].cb = &TownsPC98_FmSynth::timerCallbackA; + _timers[1].cb = &TownsPC98_FmSynth::timerCallbackB; + _timerbase = (uint32)(_baserate * 1000000.0f); +} + +TownsPC98_FmSynth::~TownsPC98_FmSynth() { + Common::StackLock lock(_mutex); + _mixer->stopHandle(_soundHandle); + delete _ssg; + delete _prc; + delete[] _chanInternal; + + delete[] _oprRates; + delete[] _oprRateshift; + delete[] _oprFrq; + delete[] _oprAttackDecay; + delete[] _oprSinTbl; + delete[] _oprLevelOut; + delete[] _oprDetune; +} + +bool TownsPC98_FmSynth::init() { + if (_ready) { + reset(); + return true; + } + + generateTables(); + + _chanInternal = new ChanInternal[_numChan]; + for (int i = 0; i < _numChan; i++) { + memset(&_chanInternal[i], 0, sizeof(ChanInternal)); + for (int j = 0; j < 4; ++j) + _chanInternal[i].opr[j] = new TownsPC98_FmSynthOperator(_timerbase, _oprRates, _oprRateshift, _oprAttackDecay, _oprFrq, _oprSinTbl, _oprLevelOut, _oprDetune); + } + + if (_numSSG) { + _ssg = new TownsPC98_FmSynthSquareSineSource(_timerbase); + _ssg->init(&_ssgTables[0], &_ssgTables[16]); + } + + if (_hasPercussion) { + _prc = new TownsPC98_FmSynthPercussionSource(_timerbase); + _prc->init(_percussionData); + } + + _mixer->playStream(Audio::Mixer::kPlainSoundType, + &_soundHandle, this, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO, true); + + _ready = true; + + return true; +} + +void TownsPC98_FmSynth::reset() { + for (int i = 0; i < _numChan; i++) { + for (int ii = 0; ii < 4; ii++) + _chanInternal[i].opr[ii]->reset(); + memset(_chanInternal[i].feedbuf, 0, 3); + _chanInternal[i].algorithm = 0; + _chanInternal[i].frqTemp = 0; + _chanInternal[i].enableLeft = _chanInternal[i].enableRight = true; + _chanInternal[i].updateEnvelopeParameters = false; + } + + writeReg(0, 0x27, 0x33); + + if (_ssg) + _ssg->reset(); + + if (_prc) + _prc->reset(); +} + +void TownsPC98_FmSynth::writeReg(uint8 part, uint8 regAddress, uint8 value) { + if (_regProtectionFlag || !_ready) + return; + + static const uint8 oprOrdr[] = { 0, 2, 1, 3 }; + + Common::StackLock lock(_mutex); + + uint8 h = regAddress & 0xf0; + uint8 l = (regAddress & 0x0f); + + ChanInternal *c = 0; + 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) { + c = &_chanInternal[(value & 3) + ((value & 4) ? 3 : 0)]; + co = c->opr; + } + + switch (h) { + case 0x00: + // ssg + if (_ssg) + _ssg->writeReg(l, value); + break; + case 0x10: + // pcm rhythm channel + if (_prc) + _prc->writeReg(l, value); + break; + case 0x20: + if (l == 8) { + // Key on/off + for (int i = 0; i < 4; i++) { + if ((value >> (4 + i)) & 1) + co[oprOrdr[i]]->keyOn(); + else + co[oprOrdr[i]]->keyOff(); + } + } else if (l == 4) { + // Timer A + _timers[0].value = (_timers[0].value & 3) | (value << 2); + } else if (l == 5) { + // Timer A + _timers[0].value = (_timers[0].value & 0x3fc) | (value & 3); + } else if (l == 6) { + // Timer B + _timers[1].value = value & 0xff; + } else if (l == 7) { + if (value & 1) { + float spc = (float)(0x400 - _timers[0].value) / _baserate; + if (spc < 1) { + warning("TownsPC98_FmSynth: Invalid Timer A setting: %d", _timers[0].value); + spc = 1; + } + + _timers[0].smpPerCb = (int32) spc; + _timers[0].smpPerCbRem = (uint32) ((spc - (float)_timers[0].smpPerCb) * 1000000.0f); + _timers[0].smpTillCb = _timers[0].smpPerCb; + _timers[0].smpTillCbRem = _timers[0].smpPerCbRem; + _timers[0].enabled = true; + } else { + _timers[0].enabled = false; + } + + if (value & 2) { + float spc = (float)(0x100 - _timers[1].value) * 16.0f / _baserate; + if (spc < 1) { + warning("TownsPC98_FmSynth: Invalid Timer B setting: %d", _timers[1].value); + spc = 1; + } + + _timers[1].smpPerCb = (int32) spc; + _timers[1].smpPerCbRem = (uint32) ((spc - (float)_timers[1].smpPerCb) * 1000000.0f); + _timers[1].smpTillCb = _timers[1].smpPerCb; + _timers[1].smpTillCbRem = _timers[1].smpPerCbRem; + _timers[1].enabled = true; + } else { + _timers[1].enabled = false; + } + + if (value & 0x10) { + _timers[0].smpTillCb = _timers[0].smpPerCb; + _timers[0].smpTillCbRem = _timers[0].smpTillCbRem; + } + + if (value & 0x20) { + _timers[1].smpTillCb = _timers[1].smpPerCb; + _timers[1].smpTillCbRem = _timers[1].smpTillCbRem; + } + } else if (l == 2) { + // LFO + if (value & 8) + warning("TownsPC98_FmSynth: TRYING TO USE LFO (NOT SUPPORTED)"); + } else if (l == 10 || l == 11) { + // DAC + if (l == 11 && (value & 0x80)) + warning("TownsPC98_FmSynth: TRYING TO USE DAC (NOT SUPPORTED)"); + } + break; + + case 0x30: + // detune, multiple + o->detune((value >> 4) & 7); + o->multiple(value & 0x0f); + c->updateEnvelopeParameters = true; + break; + + case 0x40: + // total level + o->totalLevel(value & 0x7f); + break; + + case 0x50: + // rate scaling, attack rate + o->attackRate(value & 0x1f); + if (o->scaleRate(value >> 6)) + c->updateEnvelopeParameters = true; + break; + + case 0x60: + // first decay rate, amplitude modulation + o->decayRate(value & 0x1f); + o->ampModulation(value & 0x80 ? true : false); + break; + + case 0x70: + // secondary decay rate + o->sustainRate(value & 0x1f); + break; + + case 0x80: + // secondary amplitude, release rate; + o->sustainLevel(value >> 4); + o->releaseRate(value & 0x0f); + break; + + case 0x90: + warning("TownsPC98_FmSynth: TRYING TO USE SSG ENVELOPE SHAPES (NOT SUPPORTED)"); + break; + + case 0xa0: + // frequency + l &= ~3; + if (l == 0) { + c->frqTemp = (c->frqTemp & 0xff00) | value; + c->updateEnvelopeParameters = true; + for (int i = 0; i < 4; i++) + co[i]->frequency(c->frqTemp); + } 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)"); + } + break; + + case 0xb0: + l &= ~3; + if (l == 0) { + // feedback, _algorithm + co[0]->feedbackLevel((value >> 3) & 7); + c->algorithm = value & 7; + } else if (l == 4) { + // stereo, LFO sensitivity + c->enableLeft = value & 0x80 ? true : false; + c->enableRight = value & 0x40 ? true : false; + c->ampModSensitivity((value & 0x30) >> 4); + c->frqModSensitivity(value & 3); + } + break; + + default: + warning("TownsPC98_FmSynth: UNKNOWN ADDRESS %d", regAddress); + } +} + +int TownsPC98_FmSynth::readBuffer(int16 *buffer, const int numSamples) { + Common::StackLock lock(_mutex); + + memset(buffer, 0, sizeof(int16) * numSamples); + int32 *tmp = new int32[numSamples]; + int32 *tmpStart = tmp; + memset(tmp, 0, sizeof(int32) * numSamples); + int32 samplesLeft = numSamples >> 1; + + while (samplesLeft) { + int32 render = samplesLeft; + + for (int i = 0; i < 2; i++) { + if (_timers[i].enabled && _timers[i].cb) { + if (!_timers[i].smpTillCb) { + (this->*_timers[i].cb)(); + _timers[i].smpTillCb = _timers[i].smpPerCb; + + _timers[i].smpTillCbRem += _timers[i].smpPerCbRem; + if (_timers[i].smpTillCbRem >= _timerbase) { + _timers[i].smpTillCb++; + _timers[i].smpTillCbRem -= _timerbase; + } + } + render = MIN(render, _timers[i].smpTillCb); + } + } + + samplesLeft -= render; + + for (int i = 0; i < 2; i++) { + if (_timers[i].enabled && _timers[i].cb) { + _timers[i].smpTillCb -= render; + } + } + + nextTick(tmp, render); + + if (_ssg) + _ssg->nextTick(tmp, render); + if (_prc) + _prc->nextTick(tmp, render); + + nextTickEx(tmp, render); + + for (int i = 0; i < render; ++i) { + int32 l = CLIP(tmp[i << 1], -32767, 32767); + buffer[i << 1] = (int16) l; + int32 r = CLIP(tmp[(i << 1) + 1], -32767, 32767); + buffer[(i << 1) + 1] = (int16) r; + } + + buffer += (render << 1); + tmp += (render << 1); + } + + delete[] tmpStart; + return numSamples; +} + +uint8 TownsPC98_FmSynth::readSSGStatus() { + return _ssg->chanEnable(); +} + +void TownsPC98_FmSynth::setVolumeIntern(int volA, int volB) { + Common::StackLock lock(_mutex); + _volumeA = volA; + _volumeB = volB; + if (_ssg) + _ssg->setVolumeIntern(volA, volB); + if (_prc) + _prc->setVolumeIntern(volA, volB); +} + +void TownsPC98_FmSynth::setVolumeChannelMasks(int channelMaskA, int channelMaskB) { + Common::StackLock lock(_mutex); + _volMaskA = channelMaskA; + _volMaskB = channelMaskB; + if (_ssg) + _ssg->setVolumeChannelMasks(_volMaskA >> _numChan, _volMaskB >> _numChan); + if (_prc) + _prc->setVolumeChannelMasks(_volMaskA >> (_numChan + _numSSG), _volMaskB >> (_numChan + _numSSG)); +} + +void TownsPC98_FmSynth::generateTables() { + delete[] _oprRates; + _oprRates = new uint8[128]; + + 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); + 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; + *dst++ = ((4 + v) << 3); + } + + delete[] _oprRateshift; + _oprRateshift = new uint8[128]; + memset(_oprRateshift, 0, 128); + dst = (uint8 *)_oprRateshift + 32; + for (int i = 11; i; i--) { + memset(dst, i, 4); + dst += 4; + } + + delete[] _oprFrq; + _oprFrq = new uint32[0x1000]; + for (uint32 i = 0; i < 0x1000; i++) + _oprFrq[i] = (uint32)(_baserate * (float)(i << 11)); + + delete[] _oprAttackDecay; + _oprAttackDecay = new uint8[152]; + memset(_oprAttackDecay, 0, 152); + for (int i = 0; i < 36; i++) + WRITE_BE_UINT32(_oprAttackDecay + (i << 2), _adtStat[i]); + + delete[] _oprSinTbl; + _oprSinTbl = new uint32[1024]; + for (int i = 0; i < 1024; i++) { + double val = sin((double) (((i << 1) + 1) * PI / 1024.0)); + double d_dcb = log(1.0 / (double)ABS(val)) / log(2.0) * 256.0; + int32 i_dcb = (int32)(2.0 * d_dcb); + i_dcb = (i_dcb & 1) ? (i_dcb >> 1) + 1 : (i_dcb >> 1); + _oprSinTbl[i] = (i_dcb << 1) + (val >= 0.0 ? 0 : 1); + } + + delete[] _oprLevelOut; + _oprLevelOut = new int32[0x1a00]; + for (int i = 0; i < 256; i++) { + double val = floor(65536.0 / pow(2.0, 0.00390625 * (double)(1 + i))); + int32 val_int = ((int32) val) >> 4; + _oprLevelOut[i << 1] = (val_int & 1) ? ((val_int >> 1) + 1) << 2 : (val_int >> 1) << 2; + _oprLevelOut[(i << 1) + 1] = -_oprLevelOut[i << 1]; + for (int ii = 1; ii < 13; ii++) { + _oprLevelOut[(i << 1) + (ii << 9)] = _oprLevelOut[i << 1] >> ii; + _oprLevelOut[(i << 1) + (ii << 9) + 1] = -_oprLevelOut[(i << 1) + (ii << 9)]; + } + } + + uint8 *dtt = new uint8[128]; + memset(dtt, 0, 36); + memset(dtt + 36, 1, 8); + memcpy(dtt + 44, _detSrc, 84); + + delete[] _oprDetune; + _oprDetune = new int32[256]; + for (int i = 0; i < 128; i++) { + _oprDetune[i] = (int32) ((float)dtt[i] * _baserate * 64.0); + _oprDetune[i + 128] = -_oprDetune[i]; + } + + delete[] dtt; +} + +void TownsPC98_FmSynth::nextTick(int32 *buffer, uint32 bufferSize) { + if (!_ready) + return; + + for (int i = 0; i < _numChan; i++) { + TownsPC98_FmSynthOperator **o = _chanInternal[i].opr; + + if (_chanInternal[i].updateEnvelopeParameters) { + _chanInternal[i].updateEnvelopeParameters = false; + for (int ii = 0; ii < 4 ; ii++) + o[ii]->updatePhaseIncrement(); + } + + for (uint32 ii = 0; ii < bufferSize ; ii++) { + int32 phbuf1, phbuf2, output; + phbuf1 = phbuf2 = output = 0; + + int32 *leftSample = &buffer[ii * 2]; + int32 *rightSample = &buffer[ii * 2 + 1]; + int32 *del = &_chanInternal[i].feedbuf[2]; + int32 *feed = _chanInternal[i].feedbuf; + + switch (_chanInternal[i].algorithm) { + case 0: + o[0]->generateOutput(0, feed, phbuf1); + o[2]->generateOutput(*del, 0, phbuf2); + *del = 0; + o[1]->generateOutput(phbuf1, 0, *del); + o[3]->generateOutput(phbuf2, 0, output); + break; + case 1: + o[0]->generateOutput(0, feed, phbuf1); + o[2]->generateOutput(*del, 0, phbuf2); + o[1]->generateOutput(0, 0, phbuf1); + o[3]->generateOutput(phbuf2, 0, output); + *del = phbuf1; + break; + case 2: + o[0]->generateOutput(0, feed, phbuf2); + o[2]->generateOutput(*del, 0, phbuf2); + o[1]->generateOutput(0, 0, phbuf1); + o[3]->generateOutput(phbuf2, 0, output); + *del = phbuf1; + break; + case 3: + o[0]->generateOutput(0, feed, phbuf2); + o[2]->generateOutput(0, 0, *del); + o[1]->generateOutput(phbuf2, 0, phbuf1); + o[3]->generateOutput(*del, 0, output); + *del = phbuf1; + break; + case 4: + o[0]->generateOutput(0, feed, phbuf1); + o[2]->generateOutput(0, 0, phbuf2); + o[1]->generateOutput(phbuf1, 0, output); + o[3]->generateOutput(phbuf2, 0, output); + *del = 0; + break; + case 5: + o[0]->generateOutput(0, feed, phbuf1); + o[2]->generateOutput(*del, 0, output); + o[1]->generateOutput(phbuf1, 0, output); + o[3]->generateOutput(phbuf1, 0, output); + *del = phbuf1; + break; + case 6: + o[0]->generateOutput(0, feed, phbuf1); + o[2]->generateOutput(0, 0, output); + o[1]->generateOutput(phbuf1, 0, output); + o[3]->generateOutput(0, 0, output); + *del = 0; + break; + case 7: + o[0]->generateOutput(0, feed, output); + o[2]->generateOutput(0, 0, output); + o[1]->generateOutput(0, 0, output); + o[3]->generateOutput(0, 0, output); + *del = 0; + break; + }; + + int32 finOut = (output << 2) / ((_numChan + _numSSG - 3) / 3); + + if ((1 << i) & _volMaskA) + finOut = (finOut * _volumeA) / Audio::Mixer::kMaxMixerVolume; + + if ((1 << i) & _volMaskB) + finOut = (finOut * _volumeB) / Audio::Mixer::kMaxMixerVolume; + + if (_chanInternal[i].enableLeft) + *leftSample += finOut; + + if (_chanInternal[i].enableRight) + *rightSample += finOut; + } + } +} + +const uint32 TownsPC98_FmSynth::_adtStat[] = { + 0x00010001, 0x00010001, 0x00010001, 0x01010001, + 0x00010101, 0x00010101, 0x00010101, 0x01010101, + 0x01010101, 0x01010101, 0x01010102, 0x01010102, + 0x01020102, 0x01020102, 0x01020202, 0x01020202, + 0x02020202, 0x02020202, 0x02020204, 0x02020204, + 0x02040204, 0x02040204, 0x02040404, 0x02040404, + 0x04040404, 0x04040404, 0x04040408, 0x04040408, + 0x04080408, 0x04080408, 0x04080808, 0x04080808, + 0x08080808, 0x08080808, 0x10101010, 0x10101010 +}; + +const uint8 TownsPC98_FmSynth::_detSrc[] = { + 0x02, 0x02, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, + 0x04, 0x04, 0x04, 0x05, 0x05, 0x06, 0x06, 0x07, + 0x08, 0x08, 0x08, 0x08, 0x01, 0x01, 0x01, 0x01, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, + 0x04, 0x04, 0x04, 0x05, 0x05, 0x06, 0x06, 0x07, + 0x08, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, + 0x10, 0x10, 0x10, 0x10, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x03, 0x03, 0x03, 0x04, 0x04, 0x04, 0x05, + 0x05, 0x06, 0x06, 0x07, 0x08, 0x08, 0x09, 0x0a, + 0x0b, 0x0c, 0x0d, 0x0e, 0x10, 0x11, 0x13, 0x14, + 0x16, 0x16, 0x16, 0x16 +}; + +const int TownsPC98_FmSynth::_ssgTables[] = { + 0x01202A, 0x0092D2, 0x006B42, 0x0053CB, 0x003DF8, 0x003053, 0x0022DA, 0x001A8C, + 0x00129B, 0x000DC1, 0x000963, 0x0006C9, 0x000463, 0x0002FA, 0x0001B6, 0x0000FB, + 0x0193B6, 0x01202A, 0x00CDB1, 0x0092D2, 0x007D7D, 0x006B42, 0x005ECD, 0x0053CB, + 0x00480F, 0x003DF8, 0x0036B9, 0x003053, 0x00290A, 0x0022DA, 0x001E6B, 0x001A8C, + 0x001639, 0x00129B, 0x000FFF, 0x000DC1, 0x000B5D, 0x000963, 0x0007FB, 0x0006C9, + 0x000575, 0x000463, 0x00039D, 0x0002FA, 0x000242, 0x0001B6, 0x00014C, 0x0000FB +}; + +const uint8 TownsPC98_FmSynth::_percussionData[] = { + 0,24,1,192,1,216,2,128,4,88,23,64,27,152,1,128,29,24,2,128,31,152,0,128,136,128,128,128,0,136,97,103,153,139,34,163,72,195,27,69,1,154,137,35,8,51,169,122,164,75,133,203,81,146,168,121,185,68,202,8,33,237,49,177,12,133,140,17,160,42,161,10,0,137,176, 57, + 233,41,160,136,235,65,177,137,128,26,164,28,3,157,51,137,1,152,113,161,40,146,115,192,56,5,169,66,161,56,1,50,145,59,39,168,97,1,160,57,7,153,50,153,32,2,25,129,32,20,186,66,129,24,153,164,142,130,169,153,26,242,138,217,9,128,204,58,209,172,40, 176, 141, + 128,155,144,203,139,0,235,9,177,172,0,185,168,138,25,240,59,211,139,19,176,90,160,17,26,132,41,1,5,25,3,50,144,115,147,42,39,152,41,3,56,193,105,130,155,66,200,26,19,218,154,49,201,171,138,176,251,139,185,172,136,189,139,145,207,41,160,171,152, 186, 139, + 186,141,128,218,171,51,217,170,56,163,12,4,155,81,147,42,37,152,32,54,136,49,50,48,37,32,69,0,17,50,50,83,2,16,68,20,8,66,4,154,84,145,24,33,24,32,17,18,145,32,22,168,49,163,1,33,50,184,115,129,25,66,1,24,67,2,80,35,40,53,2,65,51,19,67,37,0,52,35,49, 37, + 34,49,37,17,52,17,35,35,35,34,32,49,33,152,34,145,24,24,128,138,128,184,9,177,171,168,185,155,152,172,155,186,172,185,172,155,186,173,153,202,187,185,202,170,171,202,186,169,170,170,171,139,154,171,153,154,169,10,168,154,128,168,154,0,153, 152, 136, 137, + 128,153,0,152,8,128,137,0,136,136,8,9,8,9,8,24,153,128,136,153,144,0,161,138,1,169,136,128,160,168,152,153,138,137,154,153,153,154,153,170,168,170,185,168,169,154,169,171,153,169,170,153,152,154,153,137,169,137,136,144,152,144,128,128,144,129,129, 0, 33, + 0,17,17,17,33,33,18,18,34,34,34,34,34,34,35,19,35,19,35,35,18,19,18,35,18,33,0,8,8,8,8,8,8,8,160,205,65,176,171,203,16,240,95,242,120,145,156,66,177,26,19,153,9,35,35,239,56,132,138,154,50,145,203,25,32,20,237,24,130,138,160,27,39,173,50,203,64,145, 139, + 18,168,48,146,171,65,18,176,12,52,128,25,5,57,240,104,161,25,129,18,188,114,160,26,36,200,154,18,1,128,186,73,162,173,32,184,25,144,137,234,8,154,32,160,158,18,187,81,2,235,41,36,144,154,17,67,128,33,160,114,146,26,37,33,232,41,130,41,178,29,50, 251, 24, + 1,153,138,160,76,179,155,11,0,38,252,41,146,41,178,27,193,43,39,170,136,17,129,8,49,233,48,129,11,6,26,130,136,128,64,1,248,105,145,9,16,144,140,5,25,168,16,186,48,5,171,217,57,134,171,8,34,188,20,203,41,6,155,161,89,164,140,2,136,51,202,41,131, 56, 144, + 8,97,144,146,13,69,200,42,130,25,152,57,6,220,88,177,26,148,9,168,8,67,192,156,65,145,137,10,4,154,18,157,67,160,154,1,50,188,82,170,82,185,49,220,97,144,10,8,16,145,9,136,18,202,51,184,141,114,179,139,24,19,8,250,121,160,40,160,10,18,152,168,42,35, 216, + 187,120,145,18,156,203,84,144,9,144,26,66,161,13,1,128,17,154,18,142,6,154,65,192,29,35,186,64,192,24,9,146,56,185,16,248,121,176,40,129,136,171,96,147,140,50,203,64,144,41,128,161,187,71,200,24,129,24,217,56,20,220,24,4,169,9,1,33,201,26,134,141,51,201, + 25,16,33,235,32,144,33,153,169,99,160,11,3,136,58,210,33,203,48,163,17,219,128,140,38,8,184,141,50,131,159,33,128,153,25,18,153,88,242,43,3,9,136,157,53,202,40,145,25,2,204,105,146,156,66,152,8,153,33,128,129,136,153,50,186,55,188,51,249,64,178, 27, 128, + 48,177,156,18,35,175,51,189,32,51,234,155,69,184,26,2,152,9,17,136,144,137,50,235,115,216,24,2,170,67,187,49,129,155,4,27,129,56,232,43,39,203,40,3,154,169,66,184,114,224,25,2,9,128,11,35,155,18,11,202,84,169,26,5,154,8,160,98,185,17,187,50, 23, 188, 33, + 1,139,4,154,90,147,12,3,43,2,170,171,103,193,28,132,137,8,129,24,170,50,201,42,35,202,169,52,201,33,218,40,39,203,0,40,147,29,163,139,83,185,1,4,159,34,160,12,21,155,40,129,137,58,151,13,2,136,144,16,153,40,17,131,207,51,144,140,4,154,17,146,170,73, 163, + 44,164,12,152,37,203,17,128,144,139,23,154,128,138,38,216,41,1,0,233,73,131,171,49,136,9,164,46,3,171,32,0,145,157,38,187,64,176,58,134,155,18,136,217,64,1,200,140,38,153,170,66,161,8,169,65,185,98,200,41,3,155,144,58,23,187,1,145,40,147,189,32, 68, 249, + 1,112,255,199,195,19,108,76,187,247,247,183,40,168,212,245,199,227,68,45,59,10,145,177,198,24,130,76,26,193,180,129,0,162,42,160,199,162,0,16,152,137,132,168,195,130,162,181,227,163,161,179,211,180,179,164,128,162,161,194,164,179,40,153,195,213,146, 178, + 147,176,50,186,161,196,151,58,16,28,162,160,131,122,155,33,241,146,128,40,26,128,154,36,170,89,59,9,24,144,77,161,8,177,112,139,33,232,148,24,41,61,9,26,162,32,30,58,153,32,59,73,59,11,79,137,57,9,49,30,24,153,131,25,106,61,153,73,28,56,27, 41, 137, 148, + 76,43,74,58,13,161,3,171,149,32,77,10,74,42,168,16,0,123,138,129,162,178,225,50,140,161,0,147,10,129,41,244,210,165,1,152,24,162,184,166,32,144,59,216,132,177,8,145,67,143,146,160,183,162,130,24,192,32,225,146,144,33,44,73,30,129,137,32,76, 152, 25, 161, + 2,154,32,177,132,232,2,136,210,128,149,177,32,58,27,168,225,133,8,44,107,136,25,136,17,26,58,46,16,11,145,17,144,79,136,144,136,145,152,33,31,162,130,200,82,153,74,137,147,26,0,13,133,170,149,16,192,0,178,0,128,152,182,150,9,16,9,137,33,59,63,10,152, 32, + 179,192,5,154,228,182,145,130,144,42,128,242,2,136,41,168,17,76,57,31,129,136,17,47,8,41,138,32,138,123,59,58,10,136,161,4,46,25,145,136,129,25,56,28,91,41,154,108,9,16,44,24,137,48,15,0,194,162,41,194,56,241,163,146,0,139,7,186,150,129,152,1,208,33,176, + 136,164,163,185,7,138,130,242,162,163,177,88,136,184,166,146,0,25,25,177,199,146,16,136,9,145,178,178,0,147,138,229,18,152,25,144,163,246,162,129,129,184,5,152,178,145,148,136,146,95,152,128,144,33,170,81,11,40,202,131,0,243,24,1,11,148,42, 24, 163, 140, + 120,9,76,58,153,145,56,30,72,46,42,9,8,57,91,76,59,26,160,129,41,76,10,57,192,163,129,16,225,2,27,40,200,48,91,226,40,145,43,177,177,182,196,145,33,184,165,17,192,163,194,129,211,128,162,197,129,0,136,211,146,8,162,144,0,167,160,1,176,150,137,1, 24, 243, + 0,129,145,25,123,169,130,168,132,41,63,42,136,137,120,26,136,8,24,89,29,58,177,193,147,1,26,162,176,167,180,8,49,28,29,178,162,88,43,42,57,43,61,8,29,129,128,128,123,137,24,243,16,136,16,46,0,169,149,128,1,60,153,72,154,90,25,25,25,8,91,73,12,16,137,144, + 72,11,8,167,128,129,9,138,166,193,147,162,123,137,145,1,162,26,1,219,147,129,210,147,243,1,243,16,144,145,160,131,200,4,59,75,57,218,2,178,77,24,60,11,147,10,50,141,64,27,185,122,161,41,128,90,136,24,46,16,139,16,24,28,124,9,41,8,26,121,10,42,40,139,129, + 0,201,135,137,56,176,176,35,215,145,1,26,145,144,160,135,138,1,177,146,146,161,65,242,136,164,177,1,1,186,151,208,148,129,10,32,241,145,163,178,17,168,136,151,168,2,148,185,133,176,130,129,154,163,215,0,146,136,40,211,161,131,171,81,144,170, 21, 184, 56, + 195,168,133,177,91,16,187,5,145,153,66,172,18,177,42,120,138,27,134,26,106,42,138,146,184,66,75,46,41,168,0,145,57,91,75,27,24,27,48,169,40,122,9,109,10,8,177,146,16,74,30,129,160,162,146,41,124,138,24,145,152,3,1,14,3,139,1,192,161,151,177,122,8, 10, 0, + 176,130,129,27,88,225,0,2,154,129,129,193,49,203,81,153,226,33,0,30,0,176,179,18,9,96,156,162,148,160,129,2,29,195,128,0,56,156,20,232,129,128,32,10,144,74,183,9,145,162,1,162,138,23,171,1,164,224,34,43,43,177,200,135,161,91,57,154,177,148, 145, 146, 58, + 108,136,170,35,208,177,34,128,44,129,155,151,243,16,1,154,72,193,144,18,11,122,160,153,5,192,24,130,184,132,226,0,128,153,131,181,136,65,154,128,17,170,39,28,59,144,168,80,25,47,24,26,144,32,47,41,153,161,148,8,92,9,9,129,144,33,26,47,24,137,108, 25, 10, + 17,10,73,75,47,24,184,48,8,45,57,138,136,150,10,48,139,136,35,203,121,8,27,179,161,106,0,29,16,176,179,3,185,19,227,41,145,168,61,197,177,20,10,57,42,250,147,196,16,41,138,24,195,208,135,137,0,145,160,2,210,146,195,177,132,136,153,167,210,146,162, 40, 8, + 138,148,227,145,17,137,40,169,179,130,242,2,196,9,146,145,169,167,146,130,137,136,51,220,17,163,28,74,10,76,40,140,5,137,43,18,12,107,137,40,8,201,50,0,143,3,138,161,134,138,104,169,16,162,160,121,25,28,129,152,32,56,14,16,184,146,3,46,25, 176, 129, 179, + 193,17,130,202,135,8,57,25,154,148,184,120,9,153,211,165,24,128,26,17,242,161,18,185,81,42,11,17,12,25,181,137,66,42,47,41,184,166,129,24,91,27,136,196,0,0,74,28,178,161,149,160,32,8,225,32,128,59,8,169,50,139,47,72,186,16,132,9,122,9,160,146,144,89,153, + 10,149,178,0,121,11,146,152,162,48,13,123,177,24,0,106,27,9,144,132,12,17,0,168,0,181,56,169,129,242,195,129,17,154,64,161,244,16,137,24,144,144,164,129,75,42,176,149,9,179,148,203,4,166,136,163,128,227,163,8,57,11,30,165,0,74,59,62,9,208,131,144,40, 76, + 26,27,196,129,1,25,43,49,174,67,153,136,106,152,41,25,28,2,43,44,104,45,59,8,43,128,144,120,25,12,17,152,9,130,155,151,145,74,40,13,48,192,58,90,43,43,177,146,49,31,75,24,217,131,0,76,26,152,149,161,24,74,154,193,166,145,32,27,161,164,176,135,152,24,193, + 162,146,164,58,227,193,148,161,128,18,234,130,180,145,2,200,1,163,186,98,184,129,149,153,49,42,186,151,242,129,1,43,8,177,212,165,8,40,137,24,8,144,90,9,25,48,44,46,24,138,40,144,108,58,27,128,181,128,80,29,42,152,162,130,25,106,136,11,148,8,144,128,136, + 112,139,80,153,24,136,129,46,0,60,129,208,1,3,13,57,168,144,1,242,17,9,26,2,185,27,55,140,73,137,179,16,192,3,145,143,33,9,171,135,160,17,137,10,151,168,3,178,44,17,208,144,167,0,40,155,16,167,152,18,144,26,160,199,1,136,91,136,160,178,150,161,1,10, 181, + 145,161,1,145,161,198,2,9,90,137,177,160,150,40,29,129,144,145,162,57,77,169,16,148,42,42,40,141,34,170,121,154,210,131,162,107,8,9,160,195,40,73,139,18,224,162,34,139,0,244,178,163,24,26,146,194,166,49,29,42,137,130,192,16,93,128,154,19,59, 11, 122, 11, + 146,177,120,42,26,43,164,152,17,60,63,137,128,48,10,58,92,9,59,91,75,139,32,25,25,61,74,28,177,40,130,74,29,73,168,130,128,48,14,8,77,9,25,26,179,211,32,78,26,41,152,161,180,89,59,9,153,166,160,3,26,57,106,154,88,184,40,1,27,58,73,143,131,169,3,161, 184, + 122,152,16,181,145,129,17,15,129,193,147,145,192,33,193,162,183,163,136,178,129,178,197,2,41,216,131,168,163,181,226,163,178,1,33,187,166,212,129,1,27,24,162,184,151,8,16,160,144,181,210,72,168,128,32,42,25,40,142,5,185,88,58,11,58,177,32,129,63,42, 136, + 186,53,29,75,58,144,144,129,77,128,11,144,133,29,40,152,24,161,129,80,155,60,3,12,89,8,60,152,152,49,136,47,57,224,129,16,41,90,139,162,147,170,51,169,27,17,95,26,26,160,5,139,48,76,10,228,146,1,136,44,161,147,209,130,137,73,224,1,162,195,32,210,177,180, + 179,148,145,154,132,242,146,1,152,32,192,1,144,155,7,177,168,5,138,178,148,152,150,136,89,152,9,41,196,145,40,28,16,8,10,178,167,24,1,44,123,137,136,145,194,48,27,74,26,192,179,135,136,88,27,10,177,163,164,128,73,24,31,8,0,192,149,144,129,9,106, 41, 200, + 161,151,41,138,0,24,226,162,49,42,11,90,136,136,152,17,145,10,63,40,11,56,245,162,16,26,73,11,144,135,137,58,106,10,25,8,57,137,28,33,129,156,113,10,10,161,18,8,153,77,3,217,0,1,242,128,193,18,128,75,60,178,154,37,45,58,29,144,1,184,66,41,29, 8, 145, 10, + 194,33,148,170,107,89,139,128,163,178,16,63,59,176,144,151,129,42,74,10,129,192,2,128,154,97,192,0,177,128,178,183,16,16,155,149,145,184,84,138,8,192,161,20,225,0,130,138,165,0,28,148,153,18,209,128,88,153,89,152,9,17,9,29,130,43,122,153,24, 32, 202, 49, + 24,43,106,154,130,193,27,51,29,28,133,138,65,11,123,25,10,40,152,44,130,26,43,148,45,73,140,33,8,153,88,128,61,144,42,59,225,128,18,155,50,75,186,20,202,120,144,42,92,176,162,165,25,2,169,152,135,185,19,152,8,146,160,123,195,137,132,209,0,16, 11, 2, 242, + 146,164,152,73,193,136,130,178,1,136,169,23,169,128,164,242,129,178,129,32,138,180,167,153,132,8,138,2,209,4,138,1,128,138,92,136,44,129,136,162,33,63,40,141,2,160,144,106,137,64,155,17,129,60,30,146,26,17,28,48,46,169,51,154,91,137,41,26,32,143,18, 138, + 1,32,28,123,177,9,181,195,56,57,14,145,161,17,17,31,41,152,145,194,194,20,153,41,9,243,129,180,0,128,45,16,43,170,135,144,16,25,42,137,242,163,194,16,0,57,14,130,194,178,16,33,30,8,59,211,163,160,5,137,44,10,17,170,3,120,9,44,146,136,131,140, 91, 9, 171, + 7,161,32,73,13,8,161,40,106,11,25,129,59,0,49,31,42,28,40,11,0,81,176,61,32,138,25,178,241,148,136,106,8,136,128,177,90,8,155,96,176,9,18,217,132,129,10,81,156,40,178,161,36,169,76,147,203,150,0,10,146,200,147,149,128,144,148,154,182,24,0,137,11,134,211, + 24,136,129,145,209,33,8,43,163,243,88,41,13,0,160,145,33,31,32,185,145,4,155,17,32,47,161,128,73,160,44,56,176,75,74,12,35,141,104,137,9,89,152,58,56,44,41,30,41,40,157,48,128,154,88,41,42,8,14,3,184,59,120,152,9,56,10,128,41,57,227,186,52,152,62, 8, 56, + 242,0,58,8,156,34,243,128,24,176,51,169,58,183,192,146,164,177,18,170,7,177,208,132,161,24,136,27,147,243,128,133,10,24,161,161,178,214,17,160,25,16,161,137,165,192,48,27,72,58,218,133,162,26,72,27,10,197,178,49,138,89,56,142,1,24,11,0,44,105, 10, 25, 0, + 194,9,3,47,8,138,147,18,28,48,202,147,199,146,25,161,0,145,194,163,57,11,146,248,130,32,57,63,154,16,48,14,128,144,209,133,26,56,154,182,162,195,18,152,44,194,180,168,5,24,137,138,35,192,232,66,176,161,24,41,26,244,129,163,160,75,129,226,147,40, 145, 61, + 13,130,177,17,137,112,170,130,0,136,75,152,177,241,34,0,59,156,51,186,178,91,132,137,137,122,1,45,28,50,172,57,108,8,26,136,32,152,46,144,131,171,4,152,18,141,148,1,216,32,9,60,169,66,152,128,72,90,201,1,17,201,136,3,195,26,73,133,200,176, 150, 146, 169, + 24,33,178,184,151,73,11,28,72,44,153,82,153,17,42,57,78,153,8,160,0,1,123,11,19,171,195,18,59,31,129,10,162,2,58,96,142,130,26,75,128,176,17,180,123,9,90,137,211,145,32,26,76,43,145,130,12,90,41,27,58,160,160,128,178,7,76,59,0,203,180,147,33,62,10,0,243, + 129,146,73,29,145,144,0,26,56,153,185,83,8,76,27,166,161,193,146,131,224,145,165,161,40,168,149,162,226,2,136,138,163,131,211,0,59,146,218,148,1,192,16,16,58,248,88,144,177,136,1,58,45,9,195,197,147,48,29,10,0,162,176,64,122,9,10,17,9,153,56, 75, 27, 31, + 72,136,9,129,129,61,45,59,10,161,18,122,43,59,41,169,34,155,130,131,219,120,162,27,49,208,160,131,156,66,12,145,50,240,16,136,12,162,40,129,130,15,129,162,146,180,83,139,58,217,129,177,4,0,169,197,163,144,242,131,168,179,179,17,197,145,178,164, 128, 160, + 211,2,244,163,145,162,129,212,177,163,17,208,163,195,180,57,24,170,182,164,129,0,60,60,169,149,162,177,122,26,24,136,136,133,43,27,178,56,77,24,128,240,0,2,44,46,8,128,193,146,64,27,42,16,193,25,0,192,148,11,52,47,153,147,243,0,24,73,28,144, 161, 150, 9, + 8,73,170,2,162,25,27,147,167,131,29,1,168,200,165,16,91,137,8,162,176,35,41,31,24,169,50,168,58,123,144,48,128,13,73,169,144,16,57,123,44,200,163,56,153,80,10,176,146,57,94,8,152,131,9,168,125,26,145,177,132,137,41,60,26,144,243,32,192,34,60, 43, 26, 16, + 249,164,16,58,61,11,130,243,146,2,42,44,27,128,165,137,49,45,28,16,43,8,211,48,28,152,105,9,9,163,161,169,35,107,42,232,164,130,168,72,42,168,210,148,144,136,129,3,217,194,50,27,192,41,210,147,40,76,226,1,161,1,155,132,145,147,171,67,173,210,132,161,106, + 137,56,169,209,131,64,13,129,9,194,17,57,61,169,17,128,40,31,16,10,162,57,61,75,139,40,242,17,58,59,138,179,144,50,105,140,179,243,57,40,26,9,243,130,24,29,57,128,210,129,25,59,91,137,162,178,72,27,181,168,19,129,8,184,231,147,178,32,28,184,198,148, 144, + 1,26,128,16,192,2,26,144,244,129,0,16,10,197,177,181,1,41,9,178,165,211,129,25,145,137,210,147,152,210,163,132,194,17,91,169,145,181,130,9,89,137,152,178,4,128,9,63,160,128,106,8,25,43,10,32,47,26,123,152,24,40,25,27,18,186,35,158,64,42,216,33,25,58, 58, + 45,184,147,29,72,46,9,0,178,146,58,77,26,25,209,165,128,145,17,153,128,129,148,240,129,1,40,31,0,152,242,163,16,59,44,24,243,146,128,1,26,26,179,213,145,130,176,131,40,25,145,219,179,167,8,33,59,14,176,166,16,136,74,128,176,128,149,8,8,209,148,152,0, 72, + 153,161,178,35,62,75,154,163,153,19,62,170,133,179,136,89,12,129,164,144,3,47,58,193,177,148,0,61,43,10,129,17,41,61,43,25,8,126,26,25,137,145,34,44,45,129,216,179,1,90,25,137,32,227,8,16,9,170,49,31,32,29,128,145,148,75,25,75,153,162,192,35,12, 80, 136, + 176,8,194,24,1,176,21,154,145,80,251,130,2,30,9,8,130,145,128,98,27,26,129,136,162,15,33,168,59,65,177,77,141,1,128,168,113,10,137,178,163,146,132,74,153,224,164,33,184,19,184,228,161,17,91,152,25,146,152,44,121,9,160,145,17,25,28,93,128,152,2,25,27,161, + 210,129,146,45,179,227,163,162,9,40,193,148,179,57,107,140,196,32,25,57,47,136,210,130,24,40,28,152,210,182,145,40,8,129,184,147,147,140,163,166,160,34,45,144,194,161,134,41,46,152,162,162,3,44,58,75,209,162,144,57,129,47,152,130,59,16,248,129,17,26, 57, + 9,29,167,2,60,42,138,136,209,130,90,42,42,176,146,178,120,28,8,160,145,16,33,31,1,8,160,129,128,242,164,32,152,177,146,213,196,128,40,26,160,163,180,146,108,60,144,144,136,147,137,40,90,161,3,17,219,243,33,184,130,60,136,243,178,179,132,26,8,168,212,147, + 16,57,42,31,145,145,160,32,43,184,66,45,180,33,140,226,1,91,152,16,144,193,162,48,77,25,137,153,17,178,78,0,0,16,14,90,152,153,19,129,13,123,137,129,160,1,73,44,9,129,0,153,120,10,9,162,195,32,139,28,151,161,2,128,26,45,193,146,48,29,146,153, 194, 5, 59, + 29,128,144,195,1,64,43,208,178,149,8,9,16,240,163,129,16,42,185,181,211,24,48,45,137,149,9,24,41,75,184,177,4,43,91,128,180,16,144,29,25,184,167,1,59,60,153,148,161,146,91,42,186,4,24,145,123,11,2,178,77,136,26,25,195,40,115,61,27,168,177,3,59,79,26, 25, + 144,1,48,13,56,154,248,1,16,9,129,8,2,178,31,130,153,162,20,15,33,170,56,40,29,28,128,152,149,144,56,120,11,162,212,129,144,145,59,180,243,147,145,144,16,152,48,241,0,161,176,1,134,10,129,200,166,144,128,121,26,24,177,178,196,48,75,138,41,180,195,26, 24, + 89,138,24,33,187,41,84,155,57,79,136,160,210,130,0,58,58,168,243,132,27,41,75,138,3,8,61,8,29,145,179,76,24,28,146,208,2,49,140,75,196,144,0,40,44,179,208,3,176,33,15,177,2,160,106,8,160,164,164,8,73,27,226,179,161,1,57,1,196,211,128,40,156,145,166, 178, + 131,29,128,145,162,165,40,27,216,146,135,144,40,160,194,177,145,20,139,200,151,178,17,136,40,25,205,130,17,11,17,129,156,38,26,25,137,179,163,11,79,16,12,146,147,143,89,25,136,136,25,48,26,46,129,40,29,42,29,8,145,2,56,27,62,8,25,212,161,48,43, 144, 129, + 29,145,144,41,106,10,107,43,184,131,1,36,61,13,138,2,194,1,16,27,75,186,181,151,8,1,161,138,211,129,2,59,248,129,16,0,144,63,152,150,136,24,25,128,30,161,128,17,24,225,146,10,16,0,9,227,183,129,40,60,26,162,194,181,24,90,9,24,0,176,161,193,194,35,12, 63, + 8,210,162,1,32,78,28,152,164,144,16,48,45,137,162,147,168,152,98,27,43,33,12,160,165,129,137,63,41,153,153,151,16,91,26,8,8,9,56,10,46,24,146,57,168,160,166,241,129,32,140,16,145,179,164,137,113,138,208,131,26,25,1,42,178,196,106,24,171,18,196,8, 18, 29, + 41,194,128,3,249,57,162,152,48,184,120,160,208,33,137,74,57,187,149,129,26,35,158,72,128,168,32,26,25,180,75,2,136,15,163,161,136,120,27,41,160,128,182,56,60,25,12,178,151,128,168,72,10,152,4,177,26,147,137,113,44,42,33,220,2,152,41,82,11, 210, 163, 184, + 133,162,10,196,128,3,234,40,149,152,161,1,44,129,194,4,225,16,58,168,24,194,146,146,154,49,21,218,33,152,248,129,194,147,0,28,1,195,162,20,140,42,25,160,198,1,33,136,142,3,25,24,141,16,177,208,112,0,138,41,160,130,45,60,32,170,73,24,75,59,161,176,49,159, + 97,26,168,149,145,32,28,25,184,211,129,179,74,73,8,153,136,193,151,160,32,48,143,9,147,181,145,32,60,9,187,133,166,144,32,152,25,136,161,150,168,145,81,10,42,0,169,182,148,136,58,41,187,182,211,131,16,137,25,243,144,129,2,9,8,202,7,25,185,21,144,136,153, + 65,184,137,56,151,10,153,49,16,145,14,56,176,11,192,19,89,91,44,168,147,2,8,147,63,27,1,136,229,129,73,26,136,26,137,81,170,147,77,72,12,42,42,192,24,104,91,26,27,65,177,27,32,41,60,14,136,17,170,150,129,24,58,11,16,251,162,19,57,31,0,152,129,145,17, 61, + 14,1,129,27,129,66,169,178,74,12,11,19,198,145,75,33,138,174,133,1,184,57,40,136,169,20,1,60,174,20,154,201,67,26,162,151,42,16,138,59,130,204,20,169,59,180,59,114,184,56,178,242,128,130,43,8,194,3,229,144,33,185,144,34,181,145,168,17,149,153,74,35, 220, + 129,128,1,88,59,75,225,136,130,168,17,144,12,151,8,25,179,8,1,240,16,8,25,145,211,41,130,138,115,169,160,163,168,84,154,74,0,170,144,211,149,2,30,128,137,9,149,1,144,58,60,57,153,178,150,17,29,27,74,25,195,152,56,15,1,25,26,152,149,80,153,57,73,140, 128, + 160,144,113,27,56,28,25,4,42,44,137,60,171,130,50,240,8,5,139,145,1,105,137,200,80,137,145,146,178,179,160,46,16,240,195,131,128,144,24,164,198,128,0,136,137,131,194,165,177,2,161,147,11,144,188,181,148,144,23,0,28,224,128,131,192,32,1,224,1,168,132,145, + 9,41,208,58,137,179,151,145,16,1,30,8,145,178,1,47,32,186,72,169,146,75,8,41,48,136,89,13,48,9,10,124,26,11,42,32,129,91,77,16,12,128,42,57,138,10,60,2,63,9,0,93,128,152,90,8,10,24,40,44,144,29,49,188,48,72,25,30,177,33,128,186,120,129,186,133, 152, 130, + 24,156,51,154,8,226,2,56,155,2,179,233,167,128,24,129,176,136,151,8,184,0,33,224,152,21,177,24,10,163,16,250,17,130,171,83,137,136,37,12,56,242,154,17,160,145,82,13,3,201,128,18,137,24,162,63,162,8,107,178,128,57,158,32,24,200,18,0,106,154,73,16, 248, 8, + 73,137,57,75,0,128,12,65,137,59,75,28,144,129,122,0,58,140,160,195,145,105,56,28,153,145,164,88,8,28,25,153,9,162,113,89,153,136,33,234,147,128,41,72,11,138,151,144,145,16,43,58,248,130,178,42,4,40,10,196,154,147,216,24,7,136,10,161,148,210,161, 98, 138, + 137,128,146,176,33,105,27,43,163,49,185,6,10,136,43,67,174,161,162,151,137,1,64,200,193,24,64,200,56,145,242,24,57,137,1,128,3,162,175,80,128,162,152,25,58,175,17,17,0,200,64,168,162,91,1,154,44,211,177,35,64,160,161,144,4,241,41,209,162,25,1,3,242, 176, + 134,153,42,41,136,135,154,2,130,46,41,161,153,180,145,34,26,46,18,242,137,146,129,25,128,11,151,161,40,179,27,122,168,59,137,181,50,172,36,56,15,9,129,137,128,75,2,58,12,52,141,8,24,58,153,157,122,145,9,1,80,27,184,32,74,219,50,57,168,153,180,48,28, 143, + 131,144,178,65,13,48,168,162,147,155,121,9,170,5,16,153,21,29,144,161,91,0,184,57,128,137,17,159,88,178,128,105,152,9,162,33,164,141,88,178,224,1,0,16,27,185,150,161,9,4,139,16,128,160,194,144,65,180,46,40,136,27,135,160,16,44,57,145,236,2,195,40,75,177, + 2,200,179,146,186,104,50,141,24,169,165,148,11,97,10,11,130,177,49,57,78,42,154,128,165,59,33,28,30,1,136,16,192,41,128,152,123,136,24,1,169,113,10,11,49,153,14,147,19,45,43,8,176,210,148,8,16,11,96,144,192,163,150,10,128,43,26,150,178,165,24,41,171, 18, + 27,215,1,8,128,136,40,35,208,11,161,193,18,73,154,133,155,165,164,10,49,154,8,199,0,2,168,64,192,0,40,162,43,202,180,150,10,106,24,185,145,131,184,113,43,24,162,187,73,146,42,81,171,121,58,155,151,16,43,32,31,9,160,146,17,136,94,10,24,145,25, 9, 130, 59, + 65,13,91,25,169,146,176,112,42,59,16,217,130,20,13,25,9,40,161,138,68,169,154,18,62,154,180,145,135,152,56,58,155,165,211,8,40,42,10,198,1,2,184,57,184,224,51,154,27,134,168,19,202,73,75,184,35,176,75,24,25,209,51,157,19,30,184,179,3,33,148,45, 232, 146, + 129,168,41,32,170,149,193,35,136,16,50,191,56,146,173,149,16,24,41,30,129,168,209,3,57,31,0,16,176,147,41,152,10,17,181,14,40,144,49,170,75,97,141,25,162,146,72,177,92,137,137,19,137,153,113,154,2,41,60,129,217,2,211,152,73,42,193,197,146,147, 10, 59, 0, + 192,196,132,41,160,25,88,169,16,40,241,1,153,81,28,10,147,161,209,88,75,9,161,162,180,16,43,57,235,33,56,156,129,144,2,135,31,128,145,136,163,56,59,154,57,167,160,105,137,0,138,163,3,41,47,185,211,131,41,41,60,139,182,146,16,16,43,242,144,145,129,16,179, + 183,1,26,9,147,240,131,160,91,74,152,184,166,178,33,140,9,4,162,233,34,136,129,144,163,60,142,144,149,128,33,73,13,161,194,131,0,26,56,142,128,163,128,1,233,56,209,41,145,194,147,179,149,64,30,8,128,216,18,24,43,43,32,153,25,74,109,137,153,48,8,137, 122, + 25,144,26,43,59,30,33,41,27,24,96,153,160,50,76,27,47,152,145,163,73,40,14,152,131,176,74,90,8,8,200,67,155,154,50,49,155,28,124,177,152,1,2,17,62,138,180,176,4,25,9,177,245,162,129,40,25,176,164,130,172,4,8,181,194,49,11,168,154,165,133,152,40,136, 226, + 179,19,26,185,16,167,194,16,25,57,243,136,147,1,31,25,184,132,160,33,62,138,129,130,41,121,137,153,145,26,17,107,136,179,1,61,60,26,162,168,148,64,31,25,32,168,152,64,31,137,8,129,33,62,24,137,8,16,59,47,153,33,162,91,59,41,170,145,5,43,60,41,13,178,134, + 57,153,12,194,227,8,2,128,57,208,162,19,216,32,178,25,128,160,48,194,195,37,155,10,33,251,163,146,16,136,12,166,195,160,148,129,176,147,178,150,160,72,162,162,193,162,60,200,145,5,144,25,122,216,129,161,130,0,10,73,1,241,2,9,168,33,13,161,165,24,64, 203, + 50,1,14,9,9,129,161,106,33,27,13,164,128,40,41,107,169,160,33,136,60,92,168,152,2,91,57,176,129,0,144,47,136,162,164,128,80,43,154,179,213,130,74,27,0,145,145,167,58,59,160,9,26,76,8,171,5,49,28,44,169,162,183,130,72,28,144,179,228,2,25,26,129, 186, 151, + 1,75,128,169,17,178,15,57,170,16,166,16,57,8,139,162,181,1,8,152,164,181,41,81,43,10,242,145,57,139,89,8,193,18,154,32,176,10,165,129,137,147,177,134,0,25,25,201,147,227,129,72,59,185,167,128,129,160,91,25,176,130,147,145,9,160,5,202,17,16, 186, 136, 37, + 177,56,76,42,169,186,48,9,145,57,24,128,41,169,134,137,145,147,28,41,168,131,228,32,27,9,60,129,178,64,60,45,25,9,24,152,49,31,136,57,42,0,25,12,181,18,153,57,96,169,177,132,153,123,9,152,129,177,17,74,43,24,169,128,121,137,25,1,139,96,42,10,146,178, 18, + 44,29,1,161,164,146,31,137,146,177,19,1,10,26,209,165,146,43,40,138,240,130,18,144,25,40,212,1,58,11,152,196,147,10,74,26,152,225,130,146,58,60,210,145,16,148,16,185,192,18,44,42,57,199,162,1,9,87,47,186,215,231,197,179,180,195,212,164,32,59,92, 126, 62, + 41,59,76,59,60,168,179,213,197,163,72,44,25,74,126,127,127,79,26,177,148,90,27,225,247,165,0,152,147,123,138,211,164,72,126,127,46,210,196,163,228,215,64,11,210,180,1,8,58,153,1,224,149,57,76,27,24,76,42,43,136,128,243,179,130,106,60,42,42,92,28,243,231, + 147,24,57,44,58,94,45,8,57,139,214,148,40,77,26,9,16,10,144,64,62,43,25,123,59,138,162,48,63,26,41,92,60,43,176,3,59,232,214,164,16,75,75,76,60,153,179,33,62,26,136,40,75,169,197,163,129,57,60,59,75,138,145,64,63,138,179,1,42,136,90,43,176,214,180,1, 25, + 152,195,129,129,106,76,60,137,145,178,2,25,10,228,130,57,59,44,41,154,165,105,76,44,144,16,76,26,41,76,26,152,1,58,26,9,193,165,16,92,26,41,77,59,76,76,60,26,136,161,130,152,195,163,211,146,0,57,11,211,130,8,25,40,62,153,162,17,109,60,153,146,40, 76, 60, + 26,160,179,211,163,32,60,42,153,179,194,199,130,24,58,43,58,27,128,161,195,129,226,196,147,90,59,75,44,136,128,145,160,148,123,59,42,26,41,26,57,27,192,215,147,57,59,27,161,145,213,130,106,76,43,9,144,162,129,177,181,130,136,194,146,40,10,129,25,210,146, + 178,197,196,179,196,130,8,41,9,144,178,130,209,182,17,92,43,176,147,144,212,130,136,0,177,130,73,62,10,161,130,91,75,59,43,57,46,25,41,77,10,177,164,16,26,136,210,197,179,130,128,57,77,43,25,75,10,227,179,180,179,146,128,57,185,183,163,145,0,8,8,10, 119, + 114,120,16,210,244,60,28,41,25,152,149,56,161,35,44,89,27,24,136,24,164,211,17,233,176,136,192,129,179,17,17,25,0,10,46,160,132,49,66,24,132,177,147,193,56,72,26,29,232,168,176,12,137,41,139,147,9,1,41,15,91,136,35,148,21,18,48,40,1,168,167,144,0,42,172, + 177,204,193,155,232,152,152,26,152,41,146,17,6,4,65,34,35,135,4,16,32,9,24,186,176,0,250,153,204,186,173,154,153,177,3,65,41,34,145,134,35,65,98,49,50,50,2,33,169,138,155,175,170,172,204,192,138,234,136,155,136,10,32,18,5,52,48,24,162,17,67,54,66,51, 34, + 131,184,174,234,153,10,9,40,0,152,251,168,142,154,9,16,33,49,33,128,154,170,156,34,54,54,33,68,0,1,136,201,137,26,88,48,35,99,8,152,189,189,187,155,171,16,24,130,145,188,175,203,144,49,115,67,67,50,19,2,1,0,0,130,131,1,136,206,216,188,203, 204, 187, 187, + 156,153,0,0,51,17,34,24,112,20,69,67,67,34,19,0,136,169,185,137,186,232,185,219,201,203,187,173,170,154,153,129,131,6,2,19,49,49,21,65,19,53,51,83,34,16,168,201,154,172,156,138,0,1,24,201,233,186,204,186,171,137,3,37,48,24,128,201,202,202,129,17, 48, 21, + 22,20,19,19,32,16,2,66,52,68,4,3,1,203,235,188,189,186,171,153,137,153,170,219,170,140,9,17,53,115,50,52,67,51,51,51,17,130,0,145,154,169,188,236,187,190,203,187,172,171,138,136,17,33,18,2,34,98,98,50,50,52,66,34,35,2,19,24,169,203,203,188,219, 169, 154, + 9,137,171,204,188,203,184,136,34,83,50,33,153,184,170,170,152,40,57,19,36,50,50,18,35,17,2,49,49,66,66,66,34,17,168,233,202,202,170,171,170,186,219,203,188,188,154,138,25,33,68,52,68,67,67,36,51,36,18,17,17,136,8,170,176,202,188,206,202,171,172,186, 169, + 153,8,25,144,128,1,34,68,52,68,51,52,34,49,18,34,2,144,136,155,140,187,186,186,154,154,185,185,153,9,9,0,24,0,128,144,168,169,170,154,154,153,9,8,16,8,0,144,19,35,68,51,52,67,51,66,34,50,33,1,144,185,186,172,204,187,188,173,172,186,172,186, 154, 138, 41, + 33,52,53,83,50,51,52,52,37,34,34,18,16,144,152,154,187,219,203,188,173,186,186,186,170,154,153,138,144,16,17,67,82,50,51,21,34,19,33,2,18,33,1,8,153,169,153,153,136,128,0,136,154,153,153,8,8,1,16,0,169,170,187,171,171,154,153,153,152,153,153,0,16,51, 83, + 66,50,67,50,51,67,51,52,35,18,136,186,219,187,189,186,171,187,173,187,188,187,203,138,9,16,33,50,52,53,67,67,147,8,128,128,128,128,128,128,128,128,0,240,255,55,232,23,220,0,148,1,9,18,148,10,189,32,163,62,160,5,137,12,149,42,153,144,34,42,8, 1, 138, 181, + 45,136,18,144,105,138,1,160,14,128,132,145,186,37,138,41,192,48,145,46,160,33,44,24,225,16,13,132,136,137,16,148,25,170,194,82,152,136,91,24,42,169,33,233,131,179,24,185,149,16,57,172,164,18,10,211,160,147,211,33,138,243,129,16,41,193,0,43, 132, 155, 73, + 58,145,244,145,43,35,9,171,16,110,25,8,28,74,162,128,26,27,82,45,136,153,18,8,136,8 +}; diff --git a/sound/softsynth/fmtowns_pc98/towns_pc98_fmsynth.h b/sound/softsynth/fmtowns_pc98/towns_pc98_fmsynth.h new file mode 100644 index 0000000000..1f9d610d9d --- /dev/null +++ b/sound/softsynth/fmtowns_pc98/towns_pc98_fmsynth.h @@ -0,0 +1,171 @@ +/* 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. + * + * $URL$ + * $Id$ + * + */ + +#ifndef TOWNS_PC98_FMSYNTH_H +#define TOWNS_PC98_FMSYNTH_H + +#include "sound/audiostream.h" +#include "sound/mixer.h" +#include "common/list.h" + +class TownsPC98_FmSynthOperator; +class TownsPC98_FmSynthSquareSineSource; +class TownsPC98_FmSynthPercussionSource; + +enum EnvelopeState { + kEnvReady, + kEnvAttacking, + kEnvDecaying, + kEnvSustaining, + kEnvReleasing +}; + +class TownsPC98_FmSynth : public Audio::AudioStream { +public: + enum EmuType { + kTypeTowns, + kType26, + kType86 + }; + + TownsPC98_FmSynth(Audio::Mixer *mixer, EmuType type); + virtual ~TownsPC98_FmSynth(); + + virtual bool init(); + virtual void reset(); + + void writeReg(uint8 part, uint8 regAddress, uint8 value); + + // AudioStream interface + int readBuffer(int16 *buffer, const int numSamples); + bool isStereo() const { return true; } + bool endOfData() const { return false; } + int getRate() const { return _mixer->getOutputRate(); } + +protected: + // Implement this in your inherited class if your driver generates + // additional output that has to be inserted into the buffer. + virtual void nextTickEx(int32 *buffer, uint32 bufferSize) {} + + void toggleRegProtection(bool prot) { _regProtectionFlag = prot; } + uint8 readSSGStatus(); + + virtual void timerCallbackA() = 0; + virtual void timerCallbackB() = 0; + + // The audio driver can store and apply two different audio settings + // (usually for music and sound effects). The channel mask will determine + // which channels get effected by the setting. The first bits will be + // the normal fm channels, the next bits the ssg channels and the final + // bit the rhythm channel. + void setVolumeIntern(int volA, int volB); + void setVolumeChannelMasks(int channelMaskA, int channelMaskB); + + const int _numChan; + const int _numSSG; + const bool _hasPercussion; + + Common::Mutex _mutex; +private: + void generateTables(); + void nextTick(int32 *buffer, uint32 bufferSize); + void generateOutput(int32 &leftSample, int32 &rightSample, int32 *del, int32 *feed); + + struct ChanInternal { + ChanInternal() { + memset(this, 0, sizeof(ChanInternal)); + } + + ~ChanInternal() { + for (uint i = 0; i < ARRAYSIZE(opr); ++i) + delete opr[i]; + } + + void ampModSensitivity(uint32 value) { ampModSvty = (1 << (3 - value)) - (((value >> 1) & 1) | (value & 1)); } + void frqModSensitivity(uint32 value) { frqModSvty = value << 5; } + + uint16 frqTemp; + bool enableLeft; + bool enableRight; + bool updateEnvelopeParameters; + int32 feedbuf[3]; + uint8 algorithm; + + uint32 ampModSvty; + uint32 frqModSvty; + + + TownsPC98_FmSynthOperator *opr[4]; + }; + + TownsPC98_FmSynthSquareSineSource *_ssg; + TownsPC98_FmSynthPercussionSource *_prc; + ChanInternal *_chanInternal; + + uint8 *_oprRates; + uint8 *_oprRateshift; + uint8 *_oprAttackDecay; + uint32 *_oprFrq; + uint32 *_oprSinTbl; + int32 *_oprLevelOut; + int32 *_oprDetune; + + bool _regProtectionFlag; + + typedef void (TownsPC98_FmSynth::*ChipTimerProc)(); + + struct ChipTimer { + bool enabled; + uint16 value; + + int32 smpTillCb; + uint32 smpTillCbRem; + int32 smpPerCb; + uint32 smpPerCbRem; + + ChipTimerProc cb; + }; + + ChipTimer _timers[2]; + + int _volMaskA, _volMaskB; + uint16 _volumeA, _volumeB; + + const float _baserate; + uint32 _timerbase; + + Audio::Mixer *_mixer; + Audio::SoundHandle _soundHandle; + + static const uint8 _percussionData[]; + static const uint32 _adtStat[]; + static const uint8 _detSrc[]; + static const int _ssgTables[]; + + bool _ready; +}; + +#endif + -- cgit v1.2.3 From add6d6772ad6c2160bce854fc13694feb16e0d06 Mon Sep 17 00:00:00 2001 From: Florian Kagerer Date: Mon, 2 Aug 2010 18:53:23 +0000 Subject: KYRA/TOWNS AUDIO: try to fix last regression svn-id: r51648 --- sound/softsynth/fmtowns_pc98/towns_pc98_driver.h | 5 ++ .../softsynth/fmtowns_pc98/towns_pc98_fmsynth.cpp | 67 --------------------- sound/softsynth/fmtowns_pc98/towns_pc98_fmsynth.h | 68 +++++++++++++++++++++- 3 files changed, 72 insertions(+), 68 deletions(-) (limited to 'sound/softsynth') diff --git a/sound/softsynth/fmtowns_pc98/towns_pc98_driver.h b/sound/softsynth/fmtowns_pc98/towns_pc98_driver.h index f7d09df09d..a0dd870549 100644 --- a/sound/softsynth/fmtowns_pc98/towns_pc98_driver.h +++ b/sound/softsynth/fmtowns_pc98/towns_pc98_driver.h @@ -28,6 +28,11 @@ #include "sound/softsynth/fmtowns_pc98/towns_pc98_fmsynth.h" +class TownsPC98_MusicChannel; +class TownsPC98_MusicChannelSSG; +class TownsPC98_SfxChannel; +class TownsPC98_MusicChannelPCM; + class TownsPC98_AudioDriver : public TownsPC98_FmSynth { friend class TownsPC98_MusicChannel; friend class TownsPC98_MusicChannelSSG; diff --git a/sound/softsynth/fmtowns_pc98/towns_pc98_fmsynth.cpp b/sound/softsynth/fmtowns_pc98/towns_pc98_fmsynth.cpp index 5436c8e0c7..7fb4519844 100644 --- a/sound/softsynth/fmtowns_pc98/towns_pc98_fmsynth.cpp +++ b/sound/softsynth/fmtowns_pc98/towns_pc98_fmsynth.cpp @@ -26,73 +26,6 @@ #include "sound/softsynth/fmtowns_pc98/towns_pc98_fmsynth.h" #include "common/endian.h" -class TownsPC98_FmSynthOperator { -public: - TownsPC98_FmSynthOperator(const uint32 timerbase, const uint8 *rateTable, - const uint8 *shiftTable, const uint8 *attackDecayTable, const uint32 *frqTable, - const uint32 *sineTable, const int32 *tlevelOut, const int32 *detuneTable); - ~TownsPC98_FmSynthOperator() {} - - void keyOn(); - void keyOff(); - void frequency(int freq); - void updatePhaseIncrement(); - void recalculateRates(); - void generateOutput(int32 phasebuf, int32 *feedbuf, int32 &out); - - void feedbackLevel(int32 level) {_feedbackLevel = level ? level + 6 : 0; } - void detune(int value) { _detn = &_detnTbl[value << 5]; } - void multiple(uint32 value) { _multiple = value ? (value << 1) : 1; } - void attackRate(uint32 value) { _specifiedAttackRate = value; } - bool scaleRate(uint8 value); - void decayRate(uint32 value) { _specifiedDecayRate = value; recalculateRates(); } - void sustainRate(uint32 value) { _specifiedSustainRate = value; recalculateRates(); } - void sustainLevel(uint32 value) { _sustainLevel = (value == 0x0f) ? 0x3e0 : value << 5; } - void releaseRate(uint32 value) { _specifiedReleaseRate = value; recalculateRates(); } - void totalLevel(uint32 value) { _totalLevel = value << 3; } - void ampModulation(bool enable) { _ampMod = enable; } - void reset(); - -protected: - EnvelopeState _state; - bool _playing; - uint32 _feedbackLevel; - uint32 _multiple; - uint32 _totalLevel; - uint8 _keyScale1; - uint8 _keyScale2; - uint32 _specifiedAttackRate; - uint32 _specifiedDecayRate; - uint32 _specifiedSustainRate; - uint32 _specifiedReleaseRate; - uint32 _tickCount; - uint32 _sustainLevel; - - bool _ampMod; - uint32 _frequency; - uint8 _kcode; - uint32 _phase; - uint32 _phaseIncrement; - const int32 *_detn; - - const uint8 *_rateTbl; - const uint8 *_rshiftTbl; - const uint8 *_adTbl; - const uint32 *_fTbl; - const uint32 *_sinTbl; - const int32 *_tLvlTbl; - const int32 *_detnTbl; - - const uint32 _tickLength; - uint32 _timer; - int32 _currentLevel; - - struct EvpState { - uint8 rate; - uint8 shift; - } fs_a, fs_d, fs_s, fs_r; -}; - TownsPC98_FmSynthOperator::TownsPC98_FmSynthOperator(const uint32 timerbase, const uint8 *rateTable, const uint8 *shiftTable, const uint8 *attackDecayTable, const uint32 *frqTable, const uint32 *sineTable, const int32 *tlevelOut, const int32 *detuneTable) : diff --git a/sound/softsynth/fmtowns_pc98/towns_pc98_fmsynth.h b/sound/softsynth/fmtowns_pc98/towns_pc98_fmsynth.h index 1f9d610d9d..7ef9880f83 100644 --- a/sound/softsynth/fmtowns_pc98/towns_pc98_fmsynth.h +++ b/sound/softsynth/fmtowns_pc98/towns_pc98_fmsynth.h @@ -30,7 +30,6 @@ #include "sound/mixer.h" #include "common/list.h" -class TownsPC98_FmSynthOperator; class TownsPC98_FmSynthSquareSineSource; class TownsPC98_FmSynthPercussionSource; @@ -42,6 +41,73 @@ enum EnvelopeState { kEnvReleasing }; +class TownsPC98_FmSynthOperator { +public: + TownsPC98_FmSynthOperator(const uint32 timerbase, const uint8 *rateTable, + const uint8 *shiftTable, const uint8 *attackDecayTable, const uint32 *frqTable, + const uint32 *sineTable, const int32 *tlevelOut, const int32 *detuneTable); + ~TownsPC98_FmSynthOperator() {} + + void keyOn(); + void keyOff(); + void frequency(int freq); + void updatePhaseIncrement(); + void recalculateRates(); + void generateOutput(int32 phasebuf, int32 *feedbuf, int32 &out); + + void feedbackLevel(int32 level) {_feedbackLevel = level ? level + 6 : 0; } + void detune(int value) { _detn = &_detnTbl[value << 5]; } + void multiple(uint32 value) { _multiple = value ? (value << 1) : 1; } + void attackRate(uint32 value) { _specifiedAttackRate = value; } + bool scaleRate(uint8 value); + void decayRate(uint32 value) { _specifiedDecayRate = value; recalculateRates(); } + void sustainRate(uint32 value) { _specifiedSustainRate = value; recalculateRates(); } + void sustainLevel(uint32 value) { _sustainLevel = (value == 0x0f) ? 0x3e0 : value << 5; } + void releaseRate(uint32 value) { _specifiedReleaseRate = value; recalculateRates(); } + void totalLevel(uint32 value) { _totalLevel = value << 3; } + void ampModulation(bool enable) { _ampMod = enable; } + void reset(); + +protected: + EnvelopeState _state; + bool _playing; + uint32 _feedbackLevel; + uint32 _multiple; + uint32 _totalLevel; + uint8 _keyScale1; + uint8 _keyScale2; + uint32 _specifiedAttackRate; + uint32 _specifiedDecayRate; + uint32 _specifiedSustainRate; + uint32 _specifiedReleaseRate; + uint32 _tickCount; + uint32 _sustainLevel; + + bool _ampMod; + uint32 _frequency; + uint8 _kcode; + uint32 _phase; + uint32 _phaseIncrement; + const int32 *_detn; + + const uint8 *_rateTbl; + const uint8 *_rshiftTbl; + const uint8 *_adTbl; + const uint32 *_fTbl; + const uint32 *_sinTbl; + const int32 *_tLvlTbl; + const int32 *_detnTbl; + + const uint32 _tickLength; + uint32 _timer; + int32 _currentLevel; + + struct EvpState { + uint8 rate; + uint8 shift; + } fs_a, fs_d, fs_s, fs_r; +}; + class TownsPC98_FmSynth : public Audio::AudioStream { public: enum EmuType { -- cgit v1.2.3 From 7575c2be0b337cb88df0fe59ca297f38c34879c5 Mon Sep 17 00:00:00 2001 From: Florian Kagerer Date: Mon, 2 Aug 2010 18:56:51 +0000 Subject: KYRA/TOWNS AUDIO: and another fix svn-id: r51649 --- sound/softsynth/fmtowns_pc98/towns_audio.h | 1 + 1 file changed, 1 insertion(+) (limited to 'sound/softsynth') diff --git a/sound/softsynth/fmtowns_pc98/towns_audio.h b/sound/softsynth/fmtowns_pc98/towns_audio.h index 82d390d9b6..6c68601673 100644 --- a/sound/softsynth/fmtowns_pc98/towns_audio.h +++ b/sound/softsynth/fmtowns_pc98/towns_audio.h @@ -30,6 +30,7 @@ class TownsAudioInterfacePluginDriver { public: + virtual ~TownsAudioInterfacePluginDriver() {} virtual void timerCallback(int timerId) = 0; }; -- cgit v1.2.3 From f14940cbb577648bad3a9495e02e335aa6f8952e Mon Sep 17 00:00:00 2001 From: Johannes Schickel Date: Mon, 2 Aug 2010 19:05:12 +0000 Subject: FM-TOWNS/PC98 Sound: Strip trailing whitespaces/tabs. svn-id: r51651 --- sound/softsynth/fmtowns_pc98/towns_audio.cpp | 96 +++++++++++----------- sound/softsynth/fmtowns_pc98/towns_audio.h | 18 ++-- sound/softsynth/fmtowns_pc98/towns_euphony.cpp | 38 ++++----- sound/softsynth/fmtowns_pc98/towns_euphony.h | 8 +- sound/softsynth/fmtowns_pc98/towns_pc98_driver.cpp | 8 +- .../softsynth/fmtowns_pc98/towns_pc98_fmsynth.cpp | 12 +-- sound/softsynth/fmtowns_pc98/towns_pc98_fmsynth.h | 2 +- 7 files changed, 91 insertions(+), 91 deletions(-) (limited to 'sound/softsynth') diff --git a/sound/softsynth/fmtowns_pc98/towns_audio.cpp b/sound/softsynth/fmtowns_pc98/towns_audio.cpp index 0d5a16b35f..cd94939f9d 100644 --- a/sound/softsynth/fmtowns_pc98/towns_audio.cpp +++ b/sound/softsynth/fmtowns_pc98/towns_audio.cpp @@ -46,7 +46,7 @@ private: uint8 *curInstrument; uint8 note; uint8 velo; - + int8 *data; int8 *dataEnd; @@ -73,10 +73,10 @@ private: int16 envCurrentLevel; EnvelopeState envState; - + int8 *extData; }; - + class TownsAudio_WaveTable { friend class TownsAudioInterface; public: @@ -233,10 +233,10 @@ bool TownsAudioInterface::init() { return true; if (!_drv) - return false; + return false; if (!TownsPC98_FmSynth::init()) - return false; + return false; _fmSaveReg[0] = new uint8[256]; _fmSaveReg[1] = new uint8[256]; @@ -423,7 +423,7 @@ int TownsAudioInterface::intf_readRegBuffer(va_list &args) { *dst = _fmSaveReg[part][reg]; return 0; } - + int TownsAudioInterface::intf_setTimerA(va_list &args) { int enable = va_arg(args, int); int tempo = va_arg(args, int); @@ -449,7 +449,7 @@ int TownsAudioInterface::intf_setTimerB(va_list &args) { } else { bufferedWriteReg(0, 0x27, (_fmSaveReg[0][0x27] & 0xf5) | 0x20); } - + return 0; } @@ -466,10 +466,10 @@ int TownsAudioInterface::intf_enableTimerB(va_list &args) { int TownsAudioInterface::intf_reserveEffectChannels(va_list &args) { int numChan = va_arg(args, int); if (numChan > 8) - return 3; + return 3; if ((numChan << 13) + _waveTablesTotalDataSize > 65536) return 5; - + if (numChan == _numReservedChannels) return 0; @@ -477,14 +477,14 @@ int TownsAudioInterface::intf_reserveEffectChannels(va_list &args) { int c = 8 - _numReservedChannels; for (int i = numChan; i; i--) { uint8 f = ~_chanFlags[c--]; - _pcmChanEffectPlaying &= f; + _pcmChanEffectPlaying &= f; } } else { int c = 7 - _numReservedChannels; for (int i = numChan - _numReservedChannels; i; i--) { uint8 f = ~_chanFlags[c--]; _pcmChanKeyPressed &= f; - _pcmChanKeyPlaying &= f; + _pcmChanKeyPlaying &= f; } } @@ -499,7 +499,7 @@ int TownsAudioInterface::intf_loadWaveTable(va_list &args) { uint8 *data = va_arg(args, uint8*); if (_numWaveTables > 127) return 3; - + TownsAudio_WaveTable w; w.readHeader(data); if (!w.size) @@ -524,7 +524,7 @@ int TownsAudioInterface::intf_loadWaveTable(va_list &args) { int TownsAudioInterface::intf_unloadWaveTable(va_list &args) { int id = va_arg(args, int); - + if (id == -1) { for (int i = 0; i < 128; i++) _waveTables[i].clear(); @@ -557,7 +557,7 @@ int TownsAudioInterface::intf_pcmPlayEffect(va_list &args) { if (chan < 0x40 || chan > 0x47) return 1; - + if (note & 0x80 || velo & 0x80) return 3; @@ -579,7 +579,7 @@ int TownsAudioInterface::intf_pcmPlayEffect(va_list &args) { return 6; TownsAudio_PcmChannel *p = &_pcmChan[chan]; - + _pcmChanNote[chan] = note; _pcmChanVelo[chan] = velo; @@ -693,9 +693,9 @@ void TownsAudioInterface::fmReset() { memset(&_fmSaveReg[0][240], 0x7f, 16); memset(_fmSaveReg[1], 0, 256); memset(&_fmSaveReg[1][240], 0x7f, 16); - _fmSaveReg[0][243] = _fmSaveReg[0][247] = _fmSaveReg[0][251] = _fmSaveReg[0][255] = + _fmSaveReg[0][243] = _fmSaveReg[0][247] = _fmSaveReg[0][251] = _fmSaveReg[0][255] = _fmSaveReg[1][243] = _fmSaveReg[1][247] = _fmSaveReg[1][251] = _fmSaveReg[1][255] = 0xff; - + for (int i = 0; i < 128; i++) fmLoadInstrument(i, _fmDefaultInstrument); @@ -728,7 +728,7 @@ int TownsAudioInterface::fmKeyOn(int chan, int note, int velo) { uint8 part = chan > 2 ? 1 : 0; if (chan > 2) chan -= 3; - + int frq = 0; uint8 bl = 0; @@ -778,12 +778,12 @@ int TownsAudioInterface::fmKeyOn(int chan, int note, int velo) { if (part) v |= 4; - for (uint8 reg = 0x80 + chan; reg < 0x90; reg += 4) + for (uint8 reg = 0x80 + chan; reg < 0x90; reg += 4) writeReg(part, reg, _fmSaveReg[part][reg] | 0x0f); writeReg(0, 0x28, v); - for (uint8 reg = 0x80 + chan; reg < 0x90; reg += 4) + for (uint8 reg = 0x80 + chan; reg < 0x90; reg += 4) writeReg(part, reg, _fmSaveReg[part][reg]); bufferedWriteReg(0, 0x28, v | 0xf0); @@ -874,7 +874,7 @@ int TownsAudioInterface::fmSetInstrument(int chan, int instrId) { bufferedWriteReg(part, reg, *src++); uint8 v = *src++; - reg += 4; + reg += 4; if (v < 64) v |= (_fmSaveReg[part][reg] & 0xc0); bufferedWriteReg(part, reg, v); @@ -886,7 +886,7 @@ int TownsAudioInterface::fmLoadInstrument(int instrId, const uint8 *data) { if (instrId > 127) return 3; assert(data); - memcpy(&_fmInstruments[instrId * 48], data, 48); + memcpy(&_fmInstruments[instrId * 48], data, 48); return 0; } @@ -901,7 +901,7 @@ int TownsAudioInterface::fmSetPitch(int chan, int pitch) { if (bl) { if (pitch < -8008) pitch = -8008; - pitch *= -1; + pitch *= -1; pitch /= 13; frq = _frequency[(bl - 1) % 12] - pitch; bl = (bl - 1) / 12; @@ -915,7 +915,7 @@ int TownsAudioInterface::fmSetPitch(int chan, int pitch) { frq = 616; bl = 0; } - } + } } else { frq = 616; bl = 0; @@ -926,7 +926,7 @@ int TownsAudioInterface::fmSetPitch(int chan, int pitch) { if (pitch > 8008) pitch = 8008; pitch /= 13; - + if (bl) { frq = _frequency[(bl - 1) % 12] + pitch; bl = (bl - 1) / 12; @@ -934,7 +934,7 @@ int TownsAudioInterface::fmSetPitch(int chan, int pitch) { frq = 616; bl = 0; } - + _fmChanPitch[chan] = pitch; if (frq > 1232) { @@ -948,8 +948,8 @@ int TownsAudioInterface::fmSetPitch(int chan, int pitch) { } else { if (bl >= 7 && frq > 1164) frq = 1164; - } - + } + } else { frq = 1164; bl = 7; @@ -986,7 +986,7 @@ int TownsAudioInterface::fmSetLevel(int chan, int lvl) { uint8 part = chan > 2 ? 1 : 0; if (chan > 2) chan -= 3; - + uint16 c = _carrier[_fmSaveReg[part][0xb0 + chan] & 7]; _fmSaveReg[part][0xd0 + chan] = lvl; @@ -1016,12 +1016,12 @@ void TownsAudioInterface::pcmReset() { for (int i = 0; i < 8; i++) _pcmChan[i].clear(); - + memset(_pcmInstruments, 0, 128 * 32); static uint8 name[] = { 0x4E, 0x6F, 0x20, 0x44, 0x61, 0x74, 0x61, 0x21 }; for (int i = 0; i < 32; i++) memcpy(_pcmInstruments + i * 128, name, 8); - + for (int i = 0; i < 128; i++) _waveTables[i].clear(); _numWaveTables = 0; @@ -1036,7 +1036,7 @@ void TownsAudioInterface::pcmReset() { int TownsAudioInterface::pcmKeyOn(int chan, int note, int velo) { if (chan < 0x40 || chan > 0x47) return 1; - + if (note & 0x80 || velo & 0x80) return 3; @@ -1047,7 +1047,7 @@ int TownsAudioInterface::pcmKeyOn(int chan, int note, int velo) { _pcmChanNote[chan] = note; _pcmChanVelo[chan] = velo; - + TownsAudio_PcmChannel *p = &_pcmChan[chan]; p->note = note; @@ -1109,7 +1109,7 @@ int TownsAudioInterface::pcmKeyOff(int chan) { return 1; chan -= 0x40; - _pcmChanKeyPressed &= ~_chanFlags[chan]; + _pcmChanKeyPressed &= ~_chanFlags[chan]; _pcmChan[chan].envRelease(); return 0; } @@ -1165,7 +1165,7 @@ int TownsAudioInterface::pcmLoadInstrument(int instrId, const uint8 *data) { if (instrId > 31) return 3; assert(data); - memcpy(&_pcmInstruments[instrId * 128], data, 128); + memcpy(&_pcmInstruments[instrId * 128], data, 128); return 0; } @@ -1184,14 +1184,14 @@ int TownsAudioInterface::pcmSetPitch(int chan, int pitch) { if (pitch < 0) pts = (0x20000000 / (-pitch + 0x2001)) >> 2; else if (pitch > 0) - pts = (((pitch + 0x2001) << 16) / 0x2000) >> 2; + pts = (((pitch + 0x2001) << 16) / 0x2000) >> 2; p->stepPitch = pts & 0xffff; p->step = (p->stepNote * p->stepPitch) >> 14; // if (_pcmChanUnkFlag & _chanFlags[chan]) // unk[chan] = (((p->step * 1000) << 11) / 98) / 20833; - + /*else*/ if ((_pcmChanEffectPlaying & _chanFlags[chan]) && (p->step > 2048)) p->step = 2048; @@ -1201,13 +1201,13 @@ int TownsAudioInterface::pcmSetPitch(int chan, int pitch) { int TownsAudioInterface::pcmSetLevel(int chan, int lvl) { if (chan > 0x47) return 1; - + if (lvl & 0x80) return 3; chan -= 0x40; TownsAudio_PcmChannel *p = &_pcmChan[chan]; - + if (_pcmChanReserved & _chanFlags[chan]) { _pcmChanVelo[chan] = lvl; p->velo = lvl << 1; @@ -1262,7 +1262,7 @@ void TownsAudioInterface::pcmUpdateEnvelopeGenerator(int chan) { if (p->envCurrentLevel <= 0) p->envCurrentLevel = 0; break; - + default: break; } @@ -1295,11 +1295,11 @@ void TownsAudioInterface::pcmCalcPhaseStep(TownsAudio_PcmChannel *p, TownsAudio_ } p->stepNote = s & 0xffff; - p->step = (s * p->stepPitch) >> 14; + p->step = (s * p->stepPitch) >> 14; } void TownsAudioInterface::cdaReset() { - + } const uint8 TownsAudioInterface::_chanFlags[] = { @@ -1340,7 +1340,7 @@ TownsAudio_PcmChannel::~TownsAudio_PcmChannel() { void TownsAudio_PcmChannel::loadExtData(uint8 *buffer, uint32 size) { delete[] extData; - extData = new int8[size]; + extData = new int8[size]; int8 *src = (int8*)buffer; int8 *dst = extData; for (uint32 i = 0; i < size; i++) @@ -1361,7 +1361,7 @@ void TownsAudio_PcmChannel::clear() { curInstrument = 0; note = 0; velo = 0; - + data = 0; dataEnd = 0; loopLen = 0; @@ -1380,14 +1380,14 @@ void TownsAudio_PcmChannel::clear() { envStep = envCurrentLevel = 0; envState = kEnvReady; - + delete[] extData; extData = 0; } void TownsAudio_PcmChannel::envAttack() { envState = kEnvAttacking; - int16 t = envTotalLevel << 8; + int16 t = envTotalLevel << 8; if (envAttackRate == 127) { envStep = 0; } else if (envAttackRate) { @@ -1405,7 +1405,7 @@ void TownsAudio_PcmChannel::envDecay() { if (t < 0 || envDecayRate == 127) { envStep = 0; } else if (envDecayRate) { - envStep = (t << 8) / envDecayRate; + envStep = (t << 8) / envDecayRate; } else { envCurrentLevel = envSustainLevel << 8; envSustain(); @@ -1457,7 +1457,7 @@ void TownsAudio_WaveTable::readData(const uint8 *buffer) { delete[] data; data = new int8[size]; - + const int8 *src = (const int8*)buffer; int8 *dst = data; for (uint32 i = 0; i < size; i++) diff --git a/sound/softsynth/fmtowns_pc98/towns_audio.h b/sound/softsynth/fmtowns_pc98/towns_audio.h index 6c68601673..84bc7d0454 100644 --- a/sound/softsynth/fmtowns_pc98/towns_audio.h +++ b/sound/softsynth/fmtowns_pc98/towns_audio.h @@ -44,7 +44,7 @@ public: bool init(); - int callback(int command, ...); + int callback(int command, ...); private: void nextTickEx(int32 *buffer, uint32 bufferSize); @@ -70,7 +70,7 @@ private: int intf_setTimerA(va_list &args); int intf_setTimerB(va_list &args); int intf_enableTimerA(va_list &args); - int intf_enableTimerB(va_list &args); + int intf_enableTimerB(va_list &args); int intf_reserveEffectChannels(va_list &args); int intf_loadWaveTable(va_list &args); int intf_unloadWaveTable(va_list &args); @@ -90,26 +90,26 @@ private: int intf_pcmUpdateEnvelopeGenerator(va_list &args); int intf_notImpl(va_list &args); - + void fmReset(); int fmKeyOn(int chan, int note, int velo); int fmKeyOff(int chan); int fmChanOff(int chan); - int fmSetPanPos(int chan, int mode); + int fmSetPanPos(int chan, int mode); int fmSetInstrument(int chan, int instrId); int fmLoadInstrument(int instrId, const uint8 *data); int fmSetPitch(int chan, int pitch); int fmSetLevel(int chan, int lvl); void bufferedWriteReg(uint8 part, uint8 regAddress, uint8 value); - + uint8 _fmChanPlaying; uint8 _fmChanNote[6]; int16 _fmChanPitch[6]; uint8 *_fmSaveReg[2]; uint8 *_fmInstruments; - + void pcmReset(); int pcmKeyOn(int chan, int note, int velo); int pcmKeyOff(int chan); @@ -127,14 +127,14 @@ private: uint8 _pcmChanKeyPressed; uint8 _pcmChanEffectPlaying; uint8 _pcmChanKeyPlaying; - + uint8 _pcmChanNote[8]; uint8 _pcmChanVelo[8]; uint8 _pcmChanLevel[8]; uint8 _numReservedChannels; uint8 *_pcmInstruments; - + TownsAudio_WaveTable *_waveTables; uint8 _numWaveTables; uint32 _waveTablesTotalDataSize; @@ -156,7 +156,7 @@ private: static const uint8 _carrier[]; static const uint8 _fmDefaultInstrument[]; static const uint16 _pcmPhase1[]; - static const uint16 _pcmPhase2[]; + static const uint16 _pcmPhase2[]; }; #endif diff --git a/sound/softsynth/fmtowns_pc98/towns_euphony.cpp b/sound/softsynth/fmtowns_pc98/towns_euphony.cpp index 54b5d5b1d6..ec6829a99e 100644 --- a/sound/softsynth/fmtowns_pc98/towns_euphony.cpp +++ b/sound/softsynth/fmtowns_pc98/towns_euphony.cpp @@ -63,7 +63,7 @@ bool TownsEuphonyDriver::init() { _tOrdr = new uint8[32]; _tLevel = new int8[32]; _tTranspose = new int8[32]; - + reset(); cdaSetVolume(1, 118, 118); @@ -97,7 +97,7 @@ void TownsEuphonyDriver::reset() { assignChannel(i, e++); resetTables(); - + memset(_eventBuffer, 0, 64 * sizeof(DlEvent)); _bufferedEventsCount = 0; @@ -114,7 +114,7 @@ void TownsEuphonyDriver::reset() { } else { setTempoIntern(_defaultTempo); } - + resetControl(); } @@ -152,8 +152,8 @@ int TownsEuphonyDriver::startMusicTrack(const uint8 *data, int trackSize, int st _musicTrackSize = trackSize; _timeStampBase = _timeStampDest = 0; _tickCounter = 0; - _playing = true; - + _playing = true; + return 0; } @@ -240,7 +240,7 @@ int TownsEuphonyDriver::chanTranspose(int tableEntry, int val) { int TownsEuphonyDriver::assignChannel(int chan, int tableEntry) { if (tableEntry > 15 || chan > 127 || chan < 0) return 3; - + ActiveChannel *a = &_assignedChannels[chan]; if (a->chan == tableEntry) return 0; @@ -461,7 +461,7 @@ bool TownsEuphonyDriver::parseNext() { _endOfTrack = false; _musicPos = _musicStart; _timeStampBase = _timeStampDest = _tickCounter = 0; - _baseTickLen = _defaultBaseTickLen; + _baseTickLen = _defaultBaseTickLen; return false; } @@ -543,7 +543,7 @@ void TownsEuphonyDriver::sendEvent(uint8 mode, uint8 command) { } else if (mode == 0x10) { warning("TownsEuphonyDriver: Mode 0x10 not implemented."); - + } else if (mode == 0xff) { if (command >= 0xf0) { _paraCount = 1; @@ -574,8 +574,8 @@ void TownsEuphonyDriver::sendEvent(uint8 mode, uint8 command) { if (command) sendNoteOn(); else - sendNoteOff(); - } + sendNoteOff(); + } break; case 2: @@ -584,7 +584,7 @@ void TownsEuphonyDriver::sendEvent(uint8 mode, uint8 command) { _para[0] = command; } else { _paraCount = 1; - } + } break; case 3: @@ -658,7 +658,7 @@ bool TownsEuphonyDriver::evtSetupNote() { if (_eventBuffer[i].evt == 0) break; } - + if (i == 64) { processBufferNote(mode, evt, note, velo); } else { @@ -678,7 +678,7 @@ bool TownsEuphonyDriver::evtPolyphonicAftertouch() { return false; if (!_tEnable[_musicPos[1]]) return false; - + uint8 evt = appendEvent(_musicPos[0], _musicPos[1]); uint8 mode = _tMode[_musicPos[1]]; @@ -694,7 +694,7 @@ bool TownsEuphonyDriver::evtControlPitch() { return false; if (!_tEnable[_musicPos[1]]) return false; - + uint8 evt = appendEvent(_musicPos[0], _musicPos[1]); uint8 mode = _tMode[_musicPos[1]]; @@ -710,7 +710,7 @@ bool TownsEuphonyDriver::evtInstrumentChanAftertouch() { return false; if (!_tEnable[_musicPos[1]]) return false; - + uint8 evt = appendEvent(_musicPos[0], _musicPos[1]); uint8 mode = _tMode[_musicPos[1]]; @@ -826,8 +826,8 @@ void TownsEuphonyDriver::sendNoteOn() { if (found) c = *chan; else - _intf->callback(2, c); - + _intf->callback(2, c); + _assignedChannels[c].note = _para[0]; _assignedChannels[c].sub = 0; _intf->callback(1, c, _para[0], _para[1]); @@ -836,7 +836,7 @@ void TownsEuphonyDriver::sendNoteOn() { void TownsEuphonyDriver::sendChanVolume() { int8 *chan = &_activeChannels[_command & 0x0f]; while (*chan != -1) { - _intf->callback(8, *chan, _para[1] & 0x7f); + _intf->callback(8, *chan, _para[1] & 0x7f); chan = &_assignedChannels[*chan].next; }; } @@ -844,7 +844,7 @@ void TownsEuphonyDriver::sendChanVolume() { void TownsEuphonyDriver::sendPanPosition() { int8 *chan = &_activeChannels[_command & 0x0f]; while (*chan != -1) { - _intf->callback(3, *chan, _para[1] & 0x7f); + _intf->callback(3, *chan, _para[1] & 0x7f); chan = &_assignedChannels[*chan].next; }; } diff --git a/sound/softsynth/fmtowns_pc98/towns_euphony.h b/sound/softsynth/fmtowns_pc98/towns_euphony.h index 315e4ab4f0..06f6ed2d63 100644 --- a/sound/softsynth/fmtowns_pc98/towns_euphony.h +++ b/sound/softsynth/fmtowns_pc98/towns_euphony.h @@ -68,9 +68,9 @@ public: TownsAudioInterface *intf() { return _intf; } -private: +private: void resetTables(); - + void resetTempo(); void setTempoIntern(int tempo); void setTimerA(bool enable, int tempo); @@ -93,7 +93,7 @@ private: uint8 appendEvent(uint8 evt, uint8 chan); void sendEvent(uint8 mode, uint8 command); - + typedef bool(TownsEuphonyDriver::*EuphonyOpcode)(); bool evtSetupNote(); bool evtPolyphonicAftertouch(); @@ -118,7 +118,7 @@ private: int8 *_activeChannels; int8 *_sustainChannels; - + struct ActiveChannel { int8 chan; int8 next; diff --git a/sound/softsynth/fmtowns_pc98/towns_pc98_driver.cpp b/sound/softsynth/fmtowns_pc98/towns_pc98_driver.cpp index 1279429e7c..ee1b50d355 100644 --- a/sound/softsynth/fmtowns_pc98/towns_pc98_driver.cpp +++ b/sound/softsynth/fmtowns_pc98/towns_pc98_driver.cpp @@ -246,7 +246,7 @@ void TownsPC98_MusicChannel::loadData(uint8 *data) { _dataPtr = data; _totalLevel = 0x7F; - uint8 *tmp = _dataPtr; + uint8 *tmp = _dataPtr; for (bool loop = true; loop; ) { uint8 cmd = *tmp++; if (cmd < 0xf0) { @@ -894,7 +894,7 @@ void TownsPC98_SfxChannel::loadData(uint8 *data) { _ssgTl = 0xff; _algorithm = 0x80; - uint8 *tmp = _dataPtr; + uint8 *tmp = _dataPtr; for (bool loop = true; loop; ) { uint8 cmd = *tmp++; if (cmd < 0xf0) { @@ -1309,7 +1309,7 @@ void TownsPC98_AudioDriver::setSfxTempo(uint16 tempo) { void TownsPC98_AudioDriver::startSoundEffect() { int volFlags = 0; - + for (int i = 0; i < 2; i++) { if (_sfxOffsets[i]) { _ssgChannels[i + 1]->protect(); @@ -1322,7 +1322,7 @@ void TownsPC98_AudioDriver::startSoundEffect() { _updateSfxFlag &= ~_sfxChannels[i]->_idFlag; } } - + setVolumeChannelMasks(~volFlags, volFlags); _sfxData = 0; } diff --git a/sound/softsynth/fmtowns_pc98/towns_pc98_fmsynth.cpp b/sound/softsynth/fmtowns_pc98/towns_pc98_fmsynth.cpp index 7fb4519844..03023e776b 100644 --- a/sound/softsynth/fmtowns_pc98/towns_pc98_fmsynth.cpp +++ b/sound/softsynth/fmtowns_pc98/towns_pc98_fmsynth.cpp @@ -502,7 +502,7 @@ void TownsPC98_FmSynthSquareSineSource::nextTick(int32 *buffer, uint32 bufferSiz finOut += finOutTemp; } - finOut /= 3; + finOut /= 3; buffer[i << 1] += finOut; buffer[(i << 1) + 1] += finOut; @@ -862,14 +862,14 @@ void TownsPC98_FmSynth::writeReg(uint8 part, uint8 regAddress, uint8 value) { _timers[0].smpPerCb = (int32) spc; _timers[0].smpPerCbRem = (uint32) ((spc - (float)_timers[0].smpPerCb) * 1000000.0f); - _timers[0].smpTillCb = _timers[0].smpPerCb; + _timers[0].smpTillCb = _timers[0].smpPerCb; _timers[0].smpTillCbRem = _timers[0].smpPerCbRem; _timers[0].enabled = true; } else { _timers[0].enabled = false; - } + } - if (value & 2) { + if (value & 2) { float spc = (float)(0x100 - _timers[1].value) * 16.0f / _baserate; if (spc < 1) { warning("TownsPC98_FmSynth: Invalid Timer B setting: %d", _timers[1].value); @@ -884,7 +884,7 @@ void TownsPC98_FmSynth::writeReg(uint8 part, uint8 regAddress, uint8 value) { } else { _timers[1].enabled = false; } - + if (value & 0x10) { _timers[0].smpTillCb = _timers[0].smpPerCb; _timers[0].smpTillCbRem = _timers[0].smpTillCbRem; @@ -1065,7 +1065,7 @@ void TownsPC98_FmSynth::setVolumeChannelMasks(int channelMaskA, int channelMaskB if (_ssg) _ssg->setVolumeChannelMasks(_volMaskA >> _numChan, _volMaskB >> _numChan); if (_prc) - _prc->setVolumeChannelMasks(_volMaskA >> (_numChan + _numSSG), _volMaskB >> (_numChan + _numSSG)); + _prc->setVolumeChannelMasks(_volMaskA >> (_numChan + _numSSG), _volMaskB >> (_numChan + _numSSG)); } void TownsPC98_FmSynth::generateTables() { diff --git a/sound/softsynth/fmtowns_pc98/towns_pc98_fmsynth.h b/sound/softsynth/fmtowns_pc98/towns_pc98_fmsynth.h index 7ef9880f83..fbe85f5b24 100644 --- a/sound/softsynth/fmtowns_pc98/towns_pc98_fmsynth.h +++ b/sound/softsynth/fmtowns_pc98/towns_pc98_fmsynth.h @@ -82,7 +82,7 @@ protected: uint32 _specifiedReleaseRate; uint32 _tickCount; uint32 _sustainLevel; - + bool _ampMod; uint32 _frequency; uint8 _kcode; -- cgit v1.2.3 From 7f2e880f705937702bbddf8c224e0574e7a85d56 Mon Sep 17 00:00:00 2001 From: Johannes Schickel Date: Mon, 2 Aug 2010 19:27:44 +0000 Subject: TOWNS/PC98 Driver: Some formatting fixes. svn-id: r51653 --- sound/softsynth/fmtowns_pc98/towns_audio.cpp | 109 ++++---- sound/softsynth/fmtowns_pc98/towns_audio.h | 2 +- sound/softsynth/fmtowns_pc98/towns_euphony.cpp | 172 ++++++------ sound/softsynth/fmtowns_pc98/towns_euphony.h | 8 +- sound/softsynth/fmtowns_pc98/towns_pc98_driver.cpp | 46 ++-- sound/softsynth/fmtowns_pc98/towns_pc98_driver.h | 28 +- .../softsynth/fmtowns_pc98/towns_pc98_fmsynth.cpp | 291 +++++++++++---------- sound/softsynth/fmtowns_pc98/towns_pc98_fmsynth.h | 71 +++-- 8 files changed, 399 insertions(+), 328 deletions(-) (limited to 'sound/softsynth') diff --git a/sound/softsynth/fmtowns_pc98/towns_audio.cpp b/sound/softsynth/fmtowns_pc98/towns_audio.cpp index cd94939f9d..1207cb121f 100644 --- a/sound/softsynth/fmtowns_pc98/towns_audio.cpp +++ b/sound/softsynth/fmtowns_pc98/towns_audio.cpp @@ -283,7 +283,7 @@ void TownsAudioInterface::nextTickEx(int32 *buffer, uint32 bufferSize) { TownsAudio_PcmChannel *s = &_pcmChan[ii]; s->pos += s->step; - if (&s->data[s->pos >> 11] >= s->loopEnd) { + if (&s->data[s->pos >> 11] >= s->loopEnd) { if (s->loopLen) { s->pos -= s->loopLen; } else { @@ -305,7 +305,7 @@ void TownsAudioInterface::nextTickEx(int32 *buffer, uint32 bufferSize) { if (_pcmChan[ii].panLeft) finOutL += ((o * _pcmChan[ii].panLeft) >> 3); if (_pcmChan[ii].panRight) - finOutR += ((o *_pcmChan[ii].panRight) >> 3); + finOutR += ((o * _pcmChan[ii].panRight) >> 3); if (!((_pcmChanKeyPlaying & _chanFlags[ii]) || (_pcmChanEffectPlaying & _chanFlags[ii]))) _pcmChanOut &= ~_chanFlags[ii]; } @@ -326,7 +326,7 @@ void TownsAudioInterface::timerCallbackB() { Common::StackLock lock(_mutex); if (_ready) { if (_drv) - _drv->timerCallback(1); + _drv->timerCallback(1); for (int i = 0; i < 8; i++) pcmUpdateEnvelopeGenerator(i); } @@ -367,7 +367,7 @@ int TownsAudioInterface::intf_setInstrument(va_list &args) { int TownsAudioInterface::intf_loadInstrument(va_list &args) { int chanType = va_arg(args, int); int instrId = va_arg(args, int); - uint8 *instrData = va_arg(args, uint8*); + uint8 *instrData = va_arg(args, uint8 *); return (chanType & 0x40) ? pcmLoadInstrument(instrId, instrData) : fmLoadInstrument(instrId, instrData); } @@ -414,7 +414,7 @@ int TownsAudioInterface::intf_bufferedWriteReg(va_list &args) { int TownsAudioInterface::intf_readRegBuffer(va_list &args) { int part = va_arg(args, int) ? 1 : 0; int reg = va_arg(args, int); - uint8 *dst = va_arg(args, uint8*); + uint8 *dst = va_arg(args, uint8 *); *dst = 0; if ((!part && reg < 0x20) || (part && reg < 0x30) || (reg > 0xef)) @@ -496,7 +496,7 @@ int TownsAudioInterface::intf_reserveEffectChannels(va_list &args) { } int TownsAudioInterface::intf_loadWaveTable(va_list &args) { - uint8 *data = va_arg(args, uint8*); + uint8 *data = va_arg(args, uint8 *); if (_numWaveTables > 127) return 3; @@ -553,7 +553,7 @@ int TownsAudioInterface::intf_pcmPlayEffect(va_list &args) { int chan = va_arg(args, int); int note = va_arg(args, int); int velo = va_arg(args, int); - uint8 *data = va_arg(args, uint8*); + uint8 *data = va_arg(args, uint8 *); if (chan < 0x40 || chan > 0x47) return 1; @@ -639,7 +639,7 @@ int TownsAudioInterface::intf_fmSetInstrument(va_list &args) { int TownsAudioInterface::intf_fmLoadInstrument(va_list &args) { int instrId = va_arg(args, int); - uint8 *instrData = va_arg(args, uint8*); + uint8 *instrData = va_arg(args, uint8 *); return fmLoadInstrument(instrId, instrData); } @@ -694,7 +694,7 @@ void TownsAudioInterface::fmReset() { memset(_fmSaveReg[1], 0, 256); memset(&_fmSaveReg[1][240], 0x7f, 16); _fmSaveReg[0][243] = _fmSaveReg[0][247] = _fmSaveReg[0][251] = _fmSaveReg[0][255] = - _fmSaveReg[1][243] = _fmSaveReg[1][247] = _fmSaveReg[1][251] = _fmSaveReg[1][255] = 0xff; + _fmSaveReg[1][243] = _fmSaveReg[1][247] = _fmSaveReg[1][251] = _fmSaveReg[1][255] = 0xff; for (int i = 0; i < 128; i++) fmLoadInstrument(i, _fmDefaultInstrument); @@ -1192,7 +1192,8 @@ int TownsAudioInterface::pcmSetPitch(int chan, int pitch) { // if (_pcmChanUnkFlag & _chanFlags[chan]) // unk[chan] = (((p->step * 1000) << 11) / 98) / 20833; - /*else*/ if ((_pcmChanEffectPlaying & _chanFlags[chan]) && (p->step > 2048)) + /*else*/ + if ((_pcmChanEffectPlaying & _chanFlags[chan]) && (p->step > 2048)) p->step = 2048; return 0; @@ -1238,33 +1239,33 @@ void TownsAudioInterface::pcmUpdateEnvelopeGenerator(int chan) { return; switch (p->envState) { - case kEnvAttacking: - if (((p->envCurrentLevel + p->envStep) >> 8) > p->envTotalLevel) { - p->envDecay(); - return; - } else { - p->envCurrentLevel += p->envStep; - } - break; - - case kEnvDecaying: - if (((p->envCurrentLevel - p->envStep) >> 8) < p->envSustainLevel) { - p->envSustain(); - return; - } else { - p->envCurrentLevel -= p->envStep; - } - break; + case kEnvAttacking: + if (((p->envCurrentLevel + p->envStep) >> 8) > p->envTotalLevel) { + p->envDecay(); + return; + } else { + p->envCurrentLevel += p->envStep; + } + break; - case kEnvSustaining: - case kEnvReleasing: + case kEnvDecaying: + if (((p->envCurrentLevel - p->envStep) >> 8) < p->envSustainLevel) { + p->envSustain(); + return; + } else { p->envCurrentLevel -= p->envStep; - if (p->envCurrentLevel <= 0) - p->envCurrentLevel = 0; - break; + } + break; - default: - break; + case kEnvSustaining: + case kEnvReleasing: + p->envCurrentLevel -= p->envStep; + if (p->envCurrentLevel <= 0) + p->envCurrentLevel = 0; + break; + + default: + break; } p->velo = (p->envCurrentLevel >> 8) << 1; } @@ -1341,7 +1342,7 @@ TownsAudio_PcmChannel::~TownsAudio_PcmChannel() { void TownsAudio_PcmChannel::loadExtData(uint8 *buffer, uint32 size) { delete[] extData; extData = new int8[size]; - int8 *src = (int8*)buffer; + int8 *src = (int8 *)buffer; int8 *dst = extData; for (uint32 i = 0; i < size; i++) *dst++ = *src & 0x80 ? (*src++ & 0x7f) : -*src++; @@ -1358,31 +1359,31 @@ void TownsAudio_PcmChannel::setupLoop(uint32 start, uint32 len) { } void TownsAudio_PcmChannel::clear() { - curInstrument = 0; - note = 0; - velo = 0; + curInstrument = 0; + note = 0; + velo = 0; - data = 0; - dataEnd = 0; - loopLen = 0; + data = 0; + dataEnd = 0; + loopLen = 0; - pos = 0; - loopEnd = 0; + pos = 0; + loopEnd = 0; - step = 0; - stepNote = 0x4000; - stepPitch = 0x4000; + step = 0; + stepNote = 0x4000; + stepPitch = 0x4000; - panLeft = panRight = 0; + panLeft = panRight = 0; - envTotalLevel = envAttackRate = envDecayRate = envSustainLevel = - envSustainRate = envReleaseRate = 0; - envStep = envCurrentLevel = 0; + envTotalLevel = envAttackRate = envDecayRate = envSustainLevel = + envSustainRate = envReleaseRate = 0; + envStep = envCurrentLevel = 0; - envState = kEnvReady; + envState = kEnvReady; - delete[] extData; - extData = 0; + delete[] extData; + extData = 0; } void TownsAudio_PcmChannel::envAttack() { @@ -1458,7 +1459,7 @@ void TownsAudio_WaveTable::readData(const uint8 *buffer) { delete[] data; data = new int8[size]; - const int8 *src = (const int8*)buffer; + const int8 *src = (const int8 *)buffer; int8 *dst = data; for (uint32 i = 0; i < size; i++) *dst++ = *src & 0x80 ? (*src++ & 0x7f) : -*src++; diff --git a/sound/softsynth/fmtowns_pc98/towns_audio.h b/sound/softsynth/fmtowns_pc98/towns_audio.h index 84bc7d0454..22784699bc 100644 --- a/sound/softsynth/fmtowns_pc98/towns_audio.h +++ b/sound/softsynth/fmtowns_pc98/towns_audio.h @@ -52,7 +52,7 @@ private: void timerCallbackA(); void timerCallbackB(); - typedef int (TownsAudioInterface::*TownsAudioIntfCallback)(va_list&); + typedef int (TownsAudioInterface::*TownsAudioIntfCallback)(va_list &); const TownsAudioIntfCallback *_intfOpcodes; int intf_reset(va_list &args); diff --git a/sound/softsynth/fmtowns_pc98/towns_euphony.cpp b/sound/softsynth/fmtowns_pc98/towns_euphony.cpp index ec6829a99e..db25846b47 100644 --- a/sound/softsynth/fmtowns_pc98/towns_euphony.cpp +++ b/sound/softsynth/fmtowns_pc98/towns_euphony.cpp @@ -225,7 +225,7 @@ int TownsEuphonyDriver::chanLevel(int tableEntry, int val) { if (tableEntry > 31) return 3; if (val <= 40) - _tLevel[tableEntry] = (int8) (val & 0xff); + _tLevel[tableEntry] = (int8)(val & 0xff); return 0; } @@ -233,7 +233,7 @@ int TownsEuphonyDriver::chanTranspose(int tableEntry, int val) { if (tableEntry > 31) return 3; if (val <= 40) - _tTranspose[tableEntry] = (int8) (val & 0xff); + _tTranspose[tableEntry] = (int8)(val & 0xff); return 0; } @@ -247,7 +247,7 @@ int TownsEuphonyDriver::assignChannel(int chan, int tableEntry) { if (a->chan != -1) { int8 *b = &_activeChannels[a->chan]; - while(*b != chan) { + while (*b != chan) { b = &_assignedChannels[*b].next; if (*b == -1 && *b != chan) return 3; @@ -272,20 +272,20 @@ int TownsEuphonyDriver::assignChannel(int chan, int tableEntry) { void TownsEuphonyDriver::timerCallback(int timerId) { switch (timerId) { - case 0: - updatePulseCount(); - while (_pulseCount > 0) { - --_pulseCount; - updateTimeStampBase(); - if (!_playing) - continue; - updateEventBuffer(); - updateParser(); - updateCheckEot(); - } - break; - default: - break; + case 0: + updatePulseCount(); + while (_pulseCount > 0) { + --_pulseCount; + updateTimeStampBase(); + if (!_playing) + continue; + updateEventBuffer(); + updateParser(); + updateCheckEot(); + } + break; + default: + break; } } @@ -377,7 +377,7 @@ void TownsEuphonyDriver::updateTimeStampBase() { } void TownsEuphonyDriver::updateParser() { - for (bool loop = true; loop; ) { + for (bool loop = true; loop;) { uint8 cmd = _musicPos[0]; if (cmd == 0xff || cmd == 0xf7) { @@ -429,7 +429,7 @@ bool TownsEuphonyDriver::parseNext() { uint cmd = _musicPos[0]; if (cmd != 0xfe && cmd != 0xfd) { - if (cmd >= 0xf0 ) { + if (cmd >= 0xf0) { cmd &= 0x0f; if (cmd == 0) evtLoadInstrument(); @@ -553,78 +553,78 @@ void TownsEuphonyDriver::sendEvent(uint8 mode, uint8 command) { _command = command; } else if (_command >= 0x80) { switch ((_command - 0x80) >> 4) { - case 0: - if (_paraCount < 2) { - _paraCount++; - _para[0] = command; - } else { - _paraCount = 1; - _para[1] = command; - sendNoteOff(); - } - break; - - case 1: - if (_paraCount < 2) { - _paraCount++; - _para[0] = command; - } else { - _paraCount = 1; - _para[1] = command; - if (command) - sendNoteOn(); - else - sendNoteOff(); - } - break; - - case 2: - if (_paraCount < 2) { - _paraCount++; - _para[0] = command; - } else { - _paraCount = 1; - } - break; - - case 3: - if (_paraCount < 2) { - _paraCount++; - _para[0] = command; - } else { - _paraCount = 1; - _para[1] = command; - - if (_para[0] == 7) - sendChanVolume(); - else if (_para[0] == 10) - sendPanPosition(); - else if (_para[0] == 64) - sendAllNotesOff(); - } - break; - - case 4: + case 0: + if (_paraCount < 2) { + _paraCount++; + _para[0] = command; + } else { _paraCount = 1; + _para[1] = command; + sendNoteOff(); + } + break; + + case 1: + if (_paraCount < 2) { + _paraCount++; _para[0] = command; - sendSetInstrument(); - break; + } else { + _paraCount = 1; + _para[1] = command; + if (command) + sendNoteOn(); + else + sendNoteOff(); + } + break; + + case 2: + if (_paraCount < 2) { + _paraCount++; + _para[0] = command; + } else { + _paraCount = 1; + } + break; - case 5: + case 3: + if (_paraCount < 2) { + _paraCount++; + _para[0] = command; + } else { _paraCount = 1; + _para[1] = command; + + if (_para[0] == 7) + sendChanVolume(); + else if (_para[0] == 10) + sendPanPosition(); + else if (_para[0] == 64) + sendAllNotesOff(); + } + break; + + case 4: + _paraCount = 1; + _para[0] = command; + sendSetInstrument(); + break; + + case 5: + _paraCount = 1; + _para[0] = command; + break; + + case 6: + if (_paraCount < 2) { + _paraCount++; _para[0] = command; - break; - - case 6: - if (_paraCount < 2) { - _paraCount++; - _para[0] = command; - } else { - _paraCount = 1; - _para[1] = command; - sendPitch(); - } - break; + } else { + _paraCount = 1; + _para[1] = command; + sendPitch(); + } + break; } } } diff --git a/sound/softsynth/fmtowns_pc98/towns_euphony.h b/sound/softsynth/fmtowns_pc98/towns_euphony.h index 06f6ed2d63..c869b612a3 100644 --- a/sound/softsynth/fmtowns_pc98/towns_euphony.h +++ b/sound/softsynth/fmtowns_pc98/towns_euphony.h @@ -66,7 +66,9 @@ public: void timerCallback(int timerId); - TownsAudioInterface *intf() { return _intf; } + TownsAudioInterface *intf() { + return _intf; + } private: void resetTables(); @@ -103,7 +105,9 @@ private: bool evtAdvanceTimestampOffset(); bool evtTempo(); bool evtModeOrdrChange(); - bool evtNotImpl() { return false; } + bool evtNotImpl() { + return false; + } uint8 prepTranspose(uint8 in); uint8 prepVelo(uint8 in); diff --git a/sound/softsynth/fmtowns_pc98/towns_pc98_driver.cpp b/sound/softsynth/fmtowns_pc98/towns_pc98_driver.cpp index ee1b50d355..2853f616a3 100644 --- a/sound/softsynth/fmtowns_pc98/towns_pc98_driver.cpp +++ b/sound/softsynth/fmtowns_pc98/towns_pc98_driver.cpp @@ -29,7 +29,7 @@ class TownsPC98_MusicChannel { public: TownsPC98_MusicChannel(TownsPC98_AudioDriver *driver, uint8 regOffs, uint8 flgs, uint8 num, - uint8 key, uint8 prt, uint8 id); + uint8 key, uint8 prt, uint8 id); virtual ~TownsPC98_MusicChannel(); virtual void init(); @@ -116,7 +116,7 @@ protected: class TownsPC98_MusicChannelSSG : public TownsPC98_MusicChannel { public: TownsPC98_MusicChannelSSG(TownsPC98_AudioDriver *driver, uint8 regOffs, - uint8 flgs, uint8 num, uint8 key, uint8 prt, uint8 id); + uint8 flgs, uint8 num, uint8 key, uint8 prt, uint8 id); virtual ~TownsPC98_MusicChannelSSG() {} void init(); @@ -152,7 +152,7 @@ protected: class TownsPC98_SfxChannel : public TownsPC98_MusicChannelSSG { public: TownsPC98_SfxChannel(TownsPC98_AudioDriver *driver, uint8 regOffs, - uint8 flgs, uint8 num, uint8 key, uint8 prt, uint8 id) : + uint8 flgs, uint8 num, uint8 key, uint8 prt, uint8 id) : TownsPC98_MusicChannelSSG(driver, regOffs, flgs, num, key, prt, id) {} ~TownsPC98_SfxChannel() {} @@ -163,7 +163,7 @@ public: class TownsPC98_MusicChannelPCM : public TownsPC98_MusicChannel { public: TownsPC98_MusicChannelPCM(TownsPC98_AudioDriver *driver, uint8 regOffs, - uint8 flgs, uint8 num, uint8 key, uint8 prt, uint8 id); + uint8 flgs, uint8 num, uint8 key, uint8 prt, uint8 id); ~TownsPC98_MusicChannelPCM() {} void init(); @@ -180,7 +180,7 @@ private: }; 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), + 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; @@ -197,7 +197,7 @@ TownsPC98_MusicChannel::~TownsPC98_MusicChannel() { } void TownsPC98_MusicChannel::init() { - #define Control(x) &TownsPC98_MusicChannel::control_##x +#define Control(x) &TownsPC98_MusicChannel::control_##x static const ControlEventFunc ctrlEvents[] = { Control(f0_setPatch), Control(f1_presetOutputLevel), @@ -216,7 +216,7 @@ void TownsPC98_MusicChannel::init() { Control(dummy), Control(ff_endOfTrack) }; - #undef Control +#undef Control controlEvents = ctrlEvents; } @@ -247,7 +247,7 @@ void TownsPC98_MusicChannel::loadData(uint8 *data) { _totalLevel = 0x7F; uint8 *tmp = _dataPtr; - for (bool loop = true; loop; ) { + for (bool loop = true; loop;) { uint8 cmd = *tmp++; if (cmd < 0xf0) { tmp++; @@ -545,7 +545,7 @@ bool TownsPC98_MusicChannel::control_fc_decOutLevel(uint8 para) { if (_drv->_fading) return true; - int8 val = (int8) (_totalLevel - 3); + int8 val = (int8)(_totalLevel - 3); if (val < 0) val = 0; @@ -582,14 +582,14 @@ bool TownsPC98_MusicChannel::control_ff_endOfTrack(uint8 para) { } 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) { + uint8 flgs, uint8 num, uint8 key, uint8 prt, uint8 id) : + TownsPC98_MusicChannel(driver, regOffs, flgs, num, key, prt, id), controlEvents(0) { } void TownsPC98_MusicChannelSSG::init() { _algorithm = 0x80; - #define Control(x) &TownsPC98_MusicChannelSSG::control_##x +#define Control(x) &TownsPC98_MusicChannelSSG::control_##x static const ControlEventFunc ctrlEventsSSG[] = { Control(f0_setPatch), Control(f1_setTotalLevel), @@ -608,7 +608,7 @@ void TownsPC98_MusicChannelSSG::init() { Control(dummy), Control(ff_endOfTrack) }; - #undef Control +#undef Control controlEvents = ctrlEventsSSG; } @@ -681,7 +681,7 @@ void TownsPC98_MusicChannelSSG::processEvents() { } } else { int t = _ssgStartLvl + _ssgStep; - uint8 p = (uint8) (t & 0xff); + uint8 p = (uint8)(t & 0xff); if (t < 256 && _ssgTargetLvl > p) { if (!_drv->_fading) @@ -691,7 +691,7 @@ void TownsPC98_MusicChannelSSG::processEvents() { } setOutputLevel(_ssgTargetLvl); - if (_ssgStartLvl && !(_instr & 8)){ + if (_ssgStartLvl && !(_instr & 8)) { _instr += 4; _ssgStep = _drv->_ssgPatches[_instr]; _ssgTicksLeft = _drv->_ssgPatches[_instr + 1] & 0x7f; @@ -895,7 +895,7 @@ void TownsPC98_SfxChannel::loadData(uint8 *data) { _algorithm = 0x80; uint8 *tmp = _dataPtr; - for (bool loop = true; loop; ) { + for (bool loop = true; loop;) { uint8 cmd = *tmp++; if (cmd < 0xf0) { tmp++; @@ -929,14 +929,14 @@ void TownsPC98_SfxChannel::reset() { } 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) { + 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 +#define Control(x) &TownsPC98_MusicChannelPCM::control_##x static const ControlEventFunc ctrlEventsPCM[] = { Control(dummy), Control(f1_prcStart), @@ -955,7 +955,7 @@ void TownsPC98_MusicChannelPCM::init() { Control(dummy), Control(ff_endOfTrack) }; - #undef Control +#undef Control controlEvents = ctrlEventsPCM; } @@ -1079,7 +1079,7 @@ bool TownsPC98_AudioDriver::init() { for (int i = 0; i < _numChan; 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]); + _drvTables[ii + 2], _drvTables[ii + 3], _drvTables[ii + 4], _drvTables[ii + 5]); _channels[i]->init(); } @@ -1091,7 +1091,7 @@ bool TownsPC98_AudioDriver::init() { for (int i = 0; i < _numSSG; 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]); + _drvTables[ii + 2], _drvTables[ii + 3], _drvTables[ii + 4], _drvTables[ii + 5]); _ssgChannels[i]->init(); } @@ -1099,7 +1099,7 @@ bool TownsPC98_AudioDriver::init() { 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]); + _drvTables[ii + 2], _drvTables[ii + 3], _drvTables[ii + 4], _drvTables[ii + 5]); _sfxChannels[i]->init(); } } diff --git a/sound/softsynth/fmtowns_pc98/towns_pc98_driver.h b/sound/softsynth/fmtowns_pc98/towns_pc98_driver.h index a0dd870549..18daee1e72 100644 --- a/sound/softsynth/fmtowns_pc98/towns_pc98_driver.h +++ b/sound/softsynth/fmtowns_pc98/towns_pc98_driver.h @@ -49,17 +49,31 @@ public: void fadeStep(); - void pause() { _musicPlaying = false; } - void cont() { _musicPlaying = true; } + void pause() { + _musicPlaying = false; + } + void cont() { + _musicPlaying = true; + } void timerCallbackB(); void timerCallbackA(); - bool looping() { return _looping == _updateChannelsFlag ? true : false; } - bool musicPlaying() { return _musicPlaying; } - - void setMusicVolume(int volume) { _musicVolume = volume; setVolumeIntern(_musicVolume, _sfxVolume); } - void setSoundEffectVolume(int volume) { _sfxVolume = volume; setVolumeIntern(_musicVolume, _sfxVolume); } + bool looping() { + return _looping == _updateChannelsFlag ? true : false; + } + bool musicPlaying() { + return _musicPlaying; + } + + void setMusicVolume(int volume) { + _musicVolume = volume; + setVolumeIntern(_musicVolume, _sfxVolume); + } + void setSoundEffectVolume(int volume) { + _sfxVolume = volume; + setVolumeIntern(_musicVolume, _sfxVolume); + } protected: void startSoundEffect(); diff --git a/sound/softsynth/fmtowns_pc98/towns_pc98_fmsynth.cpp b/sound/softsynth/fmtowns_pc98/towns_pc98_fmsynth.cpp index 03023e776b..c7cd83560d 100644 --- a/sound/softsynth/fmtowns_pc98/towns_pc98_fmsynth.cpp +++ b/sound/softsynth/fmtowns_pc98/towns_pc98_fmsynth.cpp @@ -27,13 +27,13 @@ #include "common/endian.h" TownsPC98_FmSynthOperator::TownsPC98_FmSynthOperator(const uint32 timerbase, const uint8 *rateTable, - const uint8 *shiftTable, const uint8 *attackDecayTable, const uint32 *frqTable, - const uint32 *sineTable, const int32 *tlevelOut, const int32 *detuneTable) : + const uint8 *shiftTable, const uint8 *attackDecayTable, const uint32 *frqTable, + const uint32 *sineTable, const int32 *tlevelOut, const int32 *detuneTable) : _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), - _phase(0), _state(kEnvReady), _playing(false), _timer(0), _keyScale1(0), - _keyScale2(0), _currentLevel(1023), _ampMod(false), _tickCount(0) { + _phase(0), _state(kEnvReady),_ playing(false), _timer(0), _keyScale1(0), + _keyScale2(0), _currentLevel(1023), _ampMod(false), _tickCount(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; @@ -63,7 +63,7 @@ void TownsPC98_FmSynthOperator::frequency(int freq) { uint16 pos = (freq & 0x7ff); uint8 c = pos >> 7; - _kcode = (block << 2) | ((c < 7) ? 0 : ((c > 8) ? 3 : c - 6 )); + _kcode = (block << 2) | ((c < 7) ? 0 : ((c > 8) ? 3 : c - 6)); _frequency = _fTbl[pos << 1] >> (7 - block); } @@ -172,7 +172,7 @@ void TownsPC98_FmSynthOperator::generateOutput(int32 phasebuf, int32 *feed, int3 if (lvlout < 832) { uint32 index = (lvlout << 3) + _sinTbl[(((int32)((_phase & 0xffff0000) - + phaseShift)) >> 16) & 0x3ff]; + + phaseShift)) >> 16) & 0x3ff]; *i = ((index < 6656) ? _tLvlTbl[index] : 0); } else { *i = 0; @@ -182,7 +182,7 @@ void TownsPC98_FmSynthOperator::generateOutput(int32 phasebuf, int32 *feed, int3 out += *o; } -void TownsPC98_FmSynthOperator::reset(){ +void TownsPC98_FmSynthOperator::reset() { keyOff(); _timer = 0; _keyScale2 = 0; @@ -227,10 +227,18 @@ public: void nextTick(int32 *buffer, uint32 bufferSize); - void setVolumeIntern(int volA, int volB) { _volumeA = volA; _volumeB = volB; } - void setVolumeChannelMasks(int channelMaskA, int channelMaskB) { _volMaskA = channelMaskA; _volMaskB = channelMaskB; } + void setVolumeIntern(int volA, int volB) { + _volumeA = volA; + _volumeB = volB; + } + void setVolumeChannelMasks(int channelMaskA, int channelMaskB) { + _volMaskA = channelMaskA; + _volMaskB = channelMaskB; + } - uint8 chanEnable() const { return _chanEnable; } + uint8 chanEnable() const { + return _chanEnable; + } private: void updateRegs(); @@ -280,7 +288,9 @@ private: class TownsPC98_FmSynthPercussionSource { public: TownsPC98_FmSynthPercussionSource(const uint32 timerbase); - ~TownsPC98_FmSynthPercussionSource() { delete[] _reg; } + ~TownsPC98_FmSynthPercussionSource() { + delete[] _reg; + } void init(const uint8 *instrData = 0); void reset(); @@ -288,8 +298,14 @@ public: void nextTick(int32 *buffer, uint32 bufferSize); - void setVolumeIntern(int volA, int volB) { _volumeA = volA; _volumeB = volB; } - void setVolumeChannelMasks(int channelMaskA, int channelMaskB) { _volMaskA = channelMaskA; _volMaskB = channelMaskB; } + void setVolumeIntern(int volA, int volB) { + _volumeA = volA; + _volumeB = volB; + } + void setVolumeChannelMasks(int channelMaskA, int channelMaskB) { + _volMaskA = channelMaskA; + _volMaskB = channelMaskB; + } private: struct RhtChannel { @@ -491,7 +507,7 @@ void TownsPC98_FmSynthSquareSineSource::nextTick(int32 *buffer, uint32 bufferSiz int32 finOut = 0; for (int ii = 0; ii < 3; ii++) { - int32 finOutTemp = ((_channels[ii].vol >> 4) & 1) ? _tleTable[_channels[ii].out ? _pReslt : 0] : _tlTable[_channels[ii].out ? (_channels[ii].vol & 0x0f) : 0]; +int32 finOutTemp = ((_channels[ii].vol >> 4) & 1) ? _tleTable[_channels[ii].out ? _pReslt : 0] : _tlTable[_channels[ii].out ? (_channels[ii].vol & 0x0f) : 0]; if ((1 << ii) & _volMaskA) finOutTemp = (finOutTemp * _volumeA) / Audio::Mixer::kMaxMixerVolume; @@ -597,8 +613,8 @@ void TownsPC98_FmSynthPercussionSource::writeReg(uint8 address, uint8 value) { if (!_ready) return; - uint8 h = address >> 4; - uint8 l = address & 15; + uint8 h = address >> 4; + uint8 l = address & 15; if (address > 15) *_reg[address] = value; @@ -697,14 +713,15 @@ void TownsPC98_FmSynthPercussionSource::recalcOuput(RhtChannel *ins) { } void TownsPC98_FmSynthPercussionSource::advanceInput(RhtChannel *ins) { - static const int8 adjustIndex[] = {-1, -1, -1, -1, 2, 5, 7, 9 }; + static const int8 adjustIndex[] = { -1, -1, -1, -1, 2, 5, 7, 9 }; - static const int16 stepTable[] = { 16, 17, 19, 21, 23, 25, 28, 31, 34, 37, 41, 45, 50, 55, + static const int16 stepTable[] = { + 16, 17, 19, 21, 23, 25, 28, 31, 34, 37, 41, 45, 50, 55, 60, 66, 73, 80, 88, 97, 107, 118, 130, 143, 157, 173, 190, 209, 230, 253, 279, 307, 337, 371, 408, 449, 494, 544, 598, 658, 724, 796, 876, 963, 1060, 1166, 1282, 1411, 1552 }; - uint8 cur = (int8) *ins->pos++; + uint8 cur = (int8)*ins->pos++; for (int i = 0; i < 2; i++) { int b = (2 * (cur & 7) + 1) * stepTable[ins->decState] / 8; @@ -772,7 +789,7 @@ bool TownsPC98_FmSynth::init() { } _mixer->playStream(Audio::Mixer::kPlainSoundType, - &_soundHandle, this, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO, true); + &_soundHandle, this, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO, true); _ready = true; @@ -861,7 +878,7 @@ void TownsPC98_FmSynth::writeReg(uint8 part, uint8 regAddress, uint8 value) { } _timers[0].smpPerCb = (int32) spc; - _timers[0].smpPerCbRem = (uint32) ((spc - (float)_timers[0].smpPerCb) * 1000000.0f); + _timers[0].smpPerCbRem = (uint32)((spc - (float)_timers[0].smpPerCb) * 1000000.0f); _timers[0].smpTillCb = _timers[0].smpPerCb; _timers[0].smpTillCbRem = _timers[0].smpPerCbRem; _timers[0].enabled = true; @@ -877,7 +894,7 @@ void TownsPC98_FmSynth::writeReg(uint8 part, uint8 regAddress, uint8 value) { } _timers[1].smpPerCb = (int32) spc; - _timers[1].smpPerCbRem = (uint32) ((spc - (float)_timers[1].smpPerCb) * 1000000.0f); + _timers[1].smpPerCbRem = (uint32)((spc - (float)_timers[1].smpPerCb) * 1000000.0f); _timers[1].smpTillCb = _timers[1].smpPerCb; _timers[1].smpTillCbRem = _timers[1].smpPerCbRem; _timers[1].enabled = true; @@ -1110,7 +1127,7 @@ void TownsPC98_FmSynth::generateTables() { delete[] _oprSinTbl; _oprSinTbl = new uint32[1024]; for (int i = 0; i < 1024; i++) { - double val = sin((double) (((i << 1) + 1) * PI / 1024.0)); + double val = sin((double)(((i << 1) + 1) * PI / 1024.0)); double d_dcb = log(1.0 / (double)ABS(val)) / log(2.0) * 256.0; int32 i_dcb = (int32)(2.0 * d_dcb); i_dcb = (i_dcb & 1) ? (i_dcb >> 1) + 1 : (i_dcb >> 1); @@ -1124,7 +1141,7 @@ void TownsPC98_FmSynth::generateTables() { int32 val_int = ((int32) val) >> 4; _oprLevelOut[i << 1] = (val_int & 1) ? ((val_int >> 1) + 1) << 2 : (val_int >> 1) << 2; _oprLevelOut[(i << 1) + 1] = -_oprLevelOut[i << 1]; - for (int ii = 1; ii < 13; ii++) { + for (int ii = 1; ii < 13; ++ii) { _oprLevelOut[(i << 1) + (ii << 9)] = _oprLevelOut[i << 1] >> ii; _oprLevelOut[(i << 1) + (ii << 9) + 1] = -_oprLevelOut[(i << 1) + (ii << 9)]; } @@ -1138,7 +1155,7 @@ void TownsPC98_FmSynth::generateTables() { delete[] _oprDetune; _oprDetune = new int32[256]; for (int i = 0; i < 128; i++) { - _oprDetune[i] = (int32) ((float)dtt[i] * _baserate * 64.0); + _oprDetune[i] = (int32)((float)dtt[i] * _baserate * 64.0); _oprDetune[i + 128] = -_oprDetune[i]; } @@ -1279,116 +1296,116 @@ const int TownsPC98_FmSynth::_ssgTables[] = { }; const uint8 TownsPC98_FmSynth::_percussionData[] = { - 0,24,1,192,1,216,2,128,4,88,23,64,27,152,1,128,29,24,2,128,31,152,0,128,136,128,128,128,0,136,97,103,153,139,34,163,72,195,27,69,1,154,137,35,8,51,169,122,164,75,133,203,81,146,168,121,185,68,202,8,33,237,49,177,12,133,140,17,160,42,161,10,0,137,176, 57, - 233,41,160,136,235,65,177,137,128,26,164,28,3,157,51,137,1,152,113,161,40,146,115,192,56,5,169,66,161,56,1,50,145,59,39,168,97,1,160,57,7,153,50,153,32,2,25,129,32,20,186,66,129,24,153,164,142,130,169,153,26,242,138,217,9,128,204,58,209,172,40, 176, 141, - 128,155,144,203,139,0,235,9,177,172,0,185,168,138,25,240,59,211,139,19,176,90,160,17,26,132,41,1,5,25,3,50,144,115,147,42,39,152,41,3,56,193,105,130,155,66,200,26,19,218,154,49,201,171,138,176,251,139,185,172,136,189,139,145,207,41,160,171,152, 186, 139, - 186,141,128,218,171,51,217,170,56,163,12,4,155,81,147,42,37,152,32,54,136,49,50,48,37,32,69,0,17,50,50,83,2,16,68,20,8,66,4,154,84,145,24,33,24,32,17,18,145,32,22,168,49,163,1,33,50,184,115,129,25,66,1,24,67,2,80,35,40,53,2,65,51,19,67,37,0,52,35,49, 37, - 34,49,37,17,52,17,35,35,35,34,32,49,33,152,34,145,24,24,128,138,128,184,9,177,171,168,185,155,152,172,155,186,172,185,172,155,186,173,153,202,187,185,202,170,171,202,186,169,170,170,171,139,154,171,153,154,169,10,168,154,128,168,154,0,153, 152, 136, 137, - 128,153,0,152,8,128,137,0,136,136,8,9,8,9,8,24,153,128,136,153,144,0,161,138,1,169,136,128,160,168,152,153,138,137,154,153,153,154,153,170,168,170,185,168,169,154,169,171,153,169,170,153,152,154,153,137,169,137,136,144,152,144,128,128,144,129,129, 0, 33, - 0,17,17,17,33,33,18,18,34,34,34,34,34,34,35,19,35,19,35,35,18,19,18,35,18,33,0,8,8,8,8,8,8,8,160,205,65,176,171,203,16,240,95,242,120,145,156,66,177,26,19,153,9,35,35,239,56,132,138,154,50,145,203,25,32,20,237,24,130,138,160,27,39,173,50,203,64,145, 139, - 18,168,48,146,171,65,18,176,12,52,128,25,5,57,240,104,161,25,129,18,188,114,160,26,36,200,154,18,1,128,186,73,162,173,32,184,25,144,137,234,8,154,32,160,158,18,187,81,2,235,41,36,144,154,17,67,128,33,160,114,146,26,37,33,232,41,130,41,178,29,50, 251, 24, - 1,153,138,160,76,179,155,11,0,38,252,41,146,41,178,27,193,43,39,170,136,17,129,8,49,233,48,129,11,6,26,130,136,128,64,1,248,105,145,9,16,144,140,5,25,168,16,186,48,5,171,217,57,134,171,8,34,188,20,203,41,6,155,161,89,164,140,2,136,51,202,41,131, 56, 144, - 8,97,144,146,13,69,200,42,130,25,152,57,6,220,88,177,26,148,9,168,8,67,192,156,65,145,137,10,4,154,18,157,67,160,154,1,50,188,82,170,82,185,49,220,97,144,10,8,16,145,9,136,18,202,51,184,141,114,179,139,24,19,8,250,121,160,40,160,10,18,152,168,42,35, 216, - 187,120,145,18,156,203,84,144,9,144,26,66,161,13,1,128,17,154,18,142,6,154,65,192,29,35,186,64,192,24,9,146,56,185,16,248,121,176,40,129,136,171,96,147,140,50,203,64,144,41,128,161,187,71,200,24,129,24,217,56,20,220,24,4,169,9,1,33,201,26,134,141,51,201, - 25,16,33,235,32,144,33,153,169,99,160,11,3,136,58,210,33,203,48,163,17,219,128,140,38,8,184,141,50,131,159,33,128,153,25,18,153,88,242,43,3,9,136,157,53,202,40,145,25,2,204,105,146,156,66,152,8,153,33,128,129,136,153,50,186,55,188,51,249,64,178, 27, 128, - 48,177,156,18,35,175,51,189,32,51,234,155,69,184,26,2,152,9,17,136,144,137,50,235,115,216,24,2,170,67,187,49,129,155,4,27,129,56,232,43,39,203,40,3,154,169,66,184,114,224,25,2,9,128,11,35,155,18,11,202,84,169,26,5,154,8,160,98,185,17,187,50, 23, 188, 33, - 1,139,4,154,90,147,12,3,43,2,170,171,103,193,28,132,137,8,129,24,170,50,201,42,35,202,169,52,201,33,218,40,39,203,0,40,147,29,163,139,83,185,1,4,159,34,160,12,21,155,40,129,137,58,151,13,2,136,144,16,153,40,17,131,207,51,144,140,4,154,17,146,170,73, 163, - 44,164,12,152,37,203,17,128,144,139,23,154,128,138,38,216,41,1,0,233,73,131,171,49,136,9,164,46,3,171,32,0,145,157,38,187,64,176,58,134,155,18,136,217,64,1,200,140,38,153,170,66,161,8,169,65,185,98,200,41,3,155,144,58,23,187,1,145,40,147,189,32, 68, 249, - 1,112,255,199,195,19,108,76,187,247,247,183,40,168,212,245,199,227,68,45,59,10,145,177,198,24,130,76,26,193,180,129,0,162,42,160,199,162,0,16,152,137,132,168,195,130,162,181,227,163,161,179,211,180,179,164,128,162,161,194,164,179,40,153,195,213,146, 178, - 147,176,50,186,161,196,151,58,16,28,162,160,131,122,155,33,241,146,128,40,26,128,154,36,170,89,59,9,24,144,77,161,8,177,112,139,33,232,148,24,41,61,9,26,162,32,30,58,153,32,59,73,59,11,79,137,57,9,49,30,24,153,131,25,106,61,153,73,28,56,27, 41, 137, 148, - 76,43,74,58,13,161,3,171,149,32,77,10,74,42,168,16,0,123,138,129,162,178,225,50,140,161,0,147,10,129,41,244,210,165,1,152,24,162,184,166,32,144,59,216,132,177,8,145,67,143,146,160,183,162,130,24,192,32,225,146,144,33,44,73,30,129,137,32,76, 152, 25, 161, - 2,154,32,177,132,232,2,136,210,128,149,177,32,58,27,168,225,133,8,44,107,136,25,136,17,26,58,46,16,11,145,17,144,79,136,144,136,145,152,33,31,162,130,200,82,153,74,137,147,26,0,13,133,170,149,16,192,0,178,0,128,152,182,150,9,16,9,137,33,59,63,10,152, 32, - 179,192,5,154,228,182,145,130,144,42,128,242,2,136,41,168,17,76,57,31,129,136,17,47,8,41,138,32,138,123,59,58,10,136,161,4,46,25,145,136,129,25,56,28,91,41,154,108,9,16,44,24,137,48,15,0,194,162,41,194,56,241,163,146,0,139,7,186,150,129,152,1,208,33,176, - 136,164,163,185,7,138,130,242,162,163,177,88,136,184,166,146,0,25,25,177,199,146,16,136,9,145,178,178,0,147,138,229,18,152,25,144,163,246,162,129,129,184,5,152,178,145,148,136,146,95,152,128,144,33,170,81,11,40,202,131,0,243,24,1,11,148,42, 24, 163, 140, - 120,9,76,58,153,145,56,30,72,46,42,9,8,57,91,76,59,26,160,129,41,76,10,57,192,163,129,16,225,2,27,40,200,48,91,226,40,145,43,177,177,182,196,145,33,184,165,17,192,163,194,129,211,128,162,197,129,0,136,211,146,8,162,144,0,167,160,1,176,150,137,1, 24, 243, - 0,129,145,25,123,169,130,168,132,41,63,42,136,137,120,26,136,8,24,89,29,58,177,193,147,1,26,162,176,167,180,8,49,28,29,178,162,88,43,42,57,43,61,8,29,129,128,128,123,137,24,243,16,136,16,46,0,169,149,128,1,60,153,72,154,90,25,25,25,8,91,73,12,16,137,144, - 72,11,8,167,128,129,9,138,166,193,147,162,123,137,145,1,162,26,1,219,147,129,210,147,243,1,243,16,144,145,160,131,200,4,59,75,57,218,2,178,77,24,60,11,147,10,50,141,64,27,185,122,161,41,128,90,136,24,46,16,139,16,24,28,124,9,41,8,26,121,10,42,40,139,129, - 0,201,135,137,56,176,176,35,215,145,1,26,145,144,160,135,138,1,177,146,146,161,65,242,136,164,177,1,1,186,151,208,148,129,10,32,241,145,163,178,17,168,136,151,168,2,148,185,133,176,130,129,154,163,215,0,146,136,40,211,161,131,171,81,144,170, 21, 184, 56, - 195,168,133,177,91,16,187,5,145,153,66,172,18,177,42,120,138,27,134,26,106,42,138,146,184,66,75,46,41,168,0,145,57,91,75,27,24,27,48,169,40,122,9,109,10,8,177,146,16,74,30,129,160,162,146,41,124,138,24,145,152,3,1,14,3,139,1,192,161,151,177,122,8, 10, 0, - 176,130,129,27,88,225,0,2,154,129,129,193,49,203,81,153,226,33,0,30,0,176,179,18,9,96,156,162,148,160,129,2,29,195,128,0,56,156,20,232,129,128,32,10,144,74,183,9,145,162,1,162,138,23,171,1,164,224,34,43,43,177,200,135,161,91,57,154,177,148, 145, 146, 58, - 108,136,170,35,208,177,34,128,44,129,155,151,243,16,1,154,72,193,144,18,11,122,160,153,5,192,24,130,184,132,226,0,128,153,131,181,136,65,154,128,17,170,39,28,59,144,168,80,25,47,24,26,144,32,47,41,153,161,148,8,92,9,9,129,144,33,26,47,24,137,108, 25, 10, - 17,10,73,75,47,24,184,48,8,45,57,138,136,150,10,48,139,136,35,203,121,8,27,179,161,106,0,29,16,176,179,3,185,19,227,41,145,168,61,197,177,20,10,57,42,250,147,196,16,41,138,24,195,208,135,137,0,145,160,2,210,146,195,177,132,136,153,167,210,146,162, 40, 8, - 138,148,227,145,17,137,40,169,179,130,242,2,196,9,146,145,169,167,146,130,137,136,51,220,17,163,28,74,10,76,40,140,5,137,43,18,12,107,137,40,8,201,50,0,143,3,138,161,134,138,104,169,16,162,160,121,25,28,129,152,32,56,14,16,184,146,3,46,25, 176, 129, 179, - 193,17,130,202,135,8,57,25,154,148,184,120,9,153,211,165,24,128,26,17,242,161,18,185,81,42,11,17,12,25,181,137,66,42,47,41,184,166,129,24,91,27,136,196,0,0,74,28,178,161,149,160,32,8,225,32,128,59,8,169,50,139,47,72,186,16,132,9,122,9,160,146,144,89,153, - 10,149,178,0,121,11,146,152,162,48,13,123,177,24,0,106,27,9,144,132,12,17,0,168,0,181,56,169,129,242,195,129,17,154,64,161,244,16,137,24,144,144,164,129,75,42,176,149,9,179,148,203,4,166,136,163,128,227,163,8,57,11,30,165,0,74,59,62,9,208,131,144,40, 76, - 26,27,196,129,1,25,43,49,174,67,153,136,106,152,41,25,28,2,43,44,104,45,59,8,43,128,144,120,25,12,17,152,9,130,155,151,145,74,40,13,48,192,58,90,43,43,177,146,49,31,75,24,217,131,0,76,26,152,149,161,24,74,154,193,166,145,32,27,161,164,176,135,152,24,193, - 162,146,164,58,227,193,148,161,128,18,234,130,180,145,2,200,1,163,186,98,184,129,149,153,49,42,186,151,242,129,1,43,8,177,212,165,8,40,137,24,8,144,90,9,25,48,44,46,24,138,40,144,108,58,27,128,181,128,80,29,42,152,162,130,25,106,136,11,148,8,144,128,136, - 112,139,80,153,24,136,129,46,0,60,129,208,1,3,13,57,168,144,1,242,17,9,26,2,185,27,55,140,73,137,179,16,192,3,145,143,33,9,171,135,160,17,137,10,151,168,3,178,44,17,208,144,167,0,40,155,16,167,152,18,144,26,160,199,1,136,91,136,160,178,150,161,1,10, 181, - 145,161,1,145,161,198,2,9,90,137,177,160,150,40,29,129,144,145,162,57,77,169,16,148,42,42,40,141,34,170,121,154,210,131,162,107,8,9,160,195,40,73,139,18,224,162,34,139,0,244,178,163,24,26,146,194,166,49,29,42,137,130,192,16,93,128,154,19,59, 11, 122, 11, - 146,177,120,42,26,43,164,152,17,60,63,137,128,48,10,58,92,9,59,91,75,139,32,25,25,61,74,28,177,40,130,74,29,73,168,130,128,48,14,8,77,9,25,26,179,211,32,78,26,41,152,161,180,89,59,9,153,166,160,3,26,57,106,154,88,184,40,1,27,58,73,143,131,169,3,161, 184, - 122,152,16,181,145,129,17,15,129,193,147,145,192,33,193,162,183,163,136,178,129,178,197,2,41,216,131,168,163,181,226,163,178,1,33,187,166,212,129,1,27,24,162,184,151,8,16,160,144,181,210,72,168,128,32,42,25,40,142,5,185,88,58,11,58,177,32,129,63,42, 136, - 186,53,29,75,58,144,144,129,77,128,11,144,133,29,40,152,24,161,129,80,155,60,3,12,89,8,60,152,152,49,136,47,57,224,129,16,41,90,139,162,147,170,51,169,27,17,95,26,26,160,5,139,48,76,10,228,146,1,136,44,161,147,209,130,137,73,224,1,162,195,32,210,177,180, - 179,148,145,154,132,242,146,1,152,32,192,1,144,155,7,177,168,5,138,178,148,152,150,136,89,152,9,41,196,145,40,28,16,8,10,178,167,24,1,44,123,137,136,145,194,48,27,74,26,192,179,135,136,88,27,10,177,163,164,128,73,24,31,8,0,192,149,144,129,9,106, 41, 200, - 161,151,41,138,0,24,226,162,49,42,11,90,136,136,152,17,145,10,63,40,11,56,245,162,16,26,73,11,144,135,137,58,106,10,25,8,57,137,28,33,129,156,113,10,10,161,18,8,153,77,3,217,0,1,242,128,193,18,128,75,60,178,154,37,45,58,29,144,1,184,66,41,29, 8, 145, 10, - 194,33,148,170,107,89,139,128,163,178,16,63,59,176,144,151,129,42,74,10,129,192,2,128,154,97,192,0,177,128,178,183,16,16,155,149,145,184,84,138,8,192,161,20,225,0,130,138,165,0,28,148,153,18,209,128,88,153,89,152,9,17,9,29,130,43,122,153,24, 32, 202, 49, - 24,43,106,154,130,193,27,51,29,28,133,138,65,11,123,25,10,40,152,44,130,26,43,148,45,73,140,33,8,153,88,128,61,144,42,59,225,128,18,155,50,75,186,20,202,120,144,42,92,176,162,165,25,2,169,152,135,185,19,152,8,146,160,123,195,137,132,209,0,16, 11, 2, 242, - 146,164,152,73,193,136,130,178,1,136,169,23,169,128,164,242,129,178,129,32,138,180,167,153,132,8,138,2,209,4,138,1,128,138,92,136,44,129,136,162,33,63,40,141,2,160,144,106,137,64,155,17,129,60,30,146,26,17,28,48,46,169,51,154,91,137,41,26,32,143,18, 138, - 1,32,28,123,177,9,181,195,56,57,14,145,161,17,17,31,41,152,145,194,194,20,153,41,9,243,129,180,0,128,45,16,43,170,135,144,16,25,42,137,242,163,194,16,0,57,14,130,194,178,16,33,30,8,59,211,163,160,5,137,44,10,17,170,3,120,9,44,146,136,131,140, 91, 9, 171, - 7,161,32,73,13,8,161,40,106,11,25,129,59,0,49,31,42,28,40,11,0,81,176,61,32,138,25,178,241,148,136,106,8,136,128,177,90,8,155,96,176,9,18,217,132,129,10,81,156,40,178,161,36,169,76,147,203,150,0,10,146,200,147,149,128,144,148,154,182,24,0,137,11,134,211, - 24,136,129,145,209,33,8,43,163,243,88,41,13,0,160,145,33,31,32,185,145,4,155,17,32,47,161,128,73,160,44,56,176,75,74,12,35,141,104,137,9,89,152,58,56,44,41,30,41,40,157,48,128,154,88,41,42,8,14,3,184,59,120,152,9,56,10,128,41,57,227,186,52,152,62, 8, 56, - 242,0,58,8,156,34,243,128,24,176,51,169,58,183,192,146,164,177,18,170,7,177,208,132,161,24,136,27,147,243,128,133,10,24,161,161,178,214,17,160,25,16,161,137,165,192,48,27,72,58,218,133,162,26,72,27,10,197,178,49,138,89,56,142,1,24,11,0,44,105, 10, 25, 0, - 194,9,3,47,8,138,147,18,28,48,202,147,199,146,25,161,0,145,194,163,57,11,146,248,130,32,57,63,154,16,48,14,128,144,209,133,26,56,154,182,162,195,18,152,44,194,180,168,5,24,137,138,35,192,232,66,176,161,24,41,26,244,129,163,160,75,129,226,147,40, 145, 61, - 13,130,177,17,137,112,170,130,0,136,75,152,177,241,34,0,59,156,51,186,178,91,132,137,137,122,1,45,28,50,172,57,108,8,26,136,32,152,46,144,131,171,4,152,18,141,148,1,216,32,9,60,169,66,152,128,72,90,201,1,17,201,136,3,195,26,73,133,200,176, 150, 146, 169, - 24,33,178,184,151,73,11,28,72,44,153,82,153,17,42,57,78,153,8,160,0,1,123,11,19,171,195,18,59,31,129,10,162,2,58,96,142,130,26,75,128,176,17,180,123,9,90,137,211,145,32,26,76,43,145,130,12,90,41,27,58,160,160,128,178,7,76,59,0,203,180,147,33,62,10,0,243, - 129,146,73,29,145,144,0,26,56,153,185,83,8,76,27,166,161,193,146,131,224,145,165,161,40,168,149,162,226,2,136,138,163,131,211,0,59,146,218,148,1,192,16,16,58,248,88,144,177,136,1,58,45,9,195,197,147,48,29,10,0,162,176,64,122,9,10,17,9,153,56, 75, 27, 31, - 72,136,9,129,129,61,45,59,10,161,18,122,43,59,41,169,34,155,130,131,219,120,162,27,49,208,160,131,156,66,12,145,50,240,16,136,12,162,40,129,130,15,129,162,146,180,83,139,58,217,129,177,4,0,169,197,163,144,242,131,168,179,179,17,197,145,178,164, 128, 160, - 211,2,244,163,145,162,129,212,177,163,17,208,163,195,180,57,24,170,182,164,129,0,60,60,169,149,162,177,122,26,24,136,136,133,43,27,178,56,77,24,128,240,0,2,44,46,8,128,193,146,64,27,42,16,193,25,0,192,148,11,52,47,153,147,243,0,24,73,28,144, 161, 150, 9, - 8,73,170,2,162,25,27,147,167,131,29,1,168,200,165,16,91,137,8,162,176,35,41,31,24,169,50,168,58,123,144,48,128,13,73,169,144,16,57,123,44,200,163,56,153,80,10,176,146,57,94,8,152,131,9,168,125,26,145,177,132,137,41,60,26,144,243,32,192,34,60, 43, 26, 16, - 249,164,16,58,61,11,130,243,146,2,42,44,27,128,165,137,49,45,28,16,43,8,211,48,28,152,105,9,9,163,161,169,35,107,42,232,164,130,168,72,42,168,210,148,144,136,129,3,217,194,50,27,192,41,210,147,40,76,226,1,161,1,155,132,145,147,171,67,173,210,132,161,106, - 137,56,169,209,131,64,13,129,9,194,17,57,61,169,17,128,40,31,16,10,162,57,61,75,139,40,242,17,58,59,138,179,144,50,105,140,179,243,57,40,26,9,243,130,24,29,57,128,210,129,25,59,91,137,162,178,72,27,181,168,19,129,8,184,231,147,178,32,28,184,198,148, 144, - 1,26,128,16,192,2,26,144,244,129,0,16,10,197,177,181,1,41,9,178,165,211,129,25,145,137,210,147,152,210,163,132,194,17,91,169,145,181,130,9,89,137,152,178,4,128,9,63,160,128,106,8,25,43,10,32,47,26,123,152,24,40,25,27,18,186,35,158,64,42,216,33,25,58, 58, - 45,184,147,29,72,46,9,0,178,146,58,77,26,25,209,165,128,145,17,153,128,129,148,240,129,1,40,31,0,152,242,163,16,59,44,24,243,146,128,1,26,26,179,213,145,130,176,131,40,25,145,219,179,167,8,33,59,14,176,166,16,136,74,128,176,128,149,8,8,209,148,152,0, 72, - 153,161,178,35,62,75,154,163,153,19,62,170,133,179,136,89,12,129,164,144,3,47,58,193,177,148,0,61,43,10,129,17,41,61,43,25,8,126,26,25,137,145,34,44,45,129,216,179,1,90,25,137,32,227,8,16,9,170,49,31,32,29,128,145,148,75,25,75,153,162,192,35,12, 80, 136, - 176,8,194,24,1,176,21,154,145,80,251,130,2,30,9,8,130,145,128,98,27,26,129,136,162,15,33,168,59,65,177,77,141,1,128,168,113,10,137,178,163,146,132,74,153,224,164,33,184,19,184,228,161,17,91,152,25,146,152,44,121,9,160,145,17,25,28,93,128,152,2,25,27,161, - 210,129,146,45,179,227,163,162,9,40,193,148,179,57,107,140,196,32,25,57,47,136,210,130,24,40,28,152,210,182,145,40,8,129,184,147,147,140,163,166,160,34,45,144,194,161,134,41,46,152,162,162,3,44,58,75,209,162,144,57,129,47,152,130,59,16,248,129,17,26, 57, - 9,29,167,2,60,42,138,136,209,130,90,42,42,176,146,178,120,28,8,160,145,16,33,31,1,8,160,129,128,242,164,32,152,177,146,213,196,128,40,26,160,163,180,146,108,60,144,144,136,147,137,40,90,161,3,17,219,243,33,184,130,60,136,243,178,179,132,26,8,168,212,147, - 16,57,42,31,145,145,160,32,43,184,66,45,180,33,140,226,1,91,152,16,144,193,162,48,77,25,137,153,17,178,78,0,0,16,14,90,152,153,19,129,13,123,137,129,160,1,73,44,9,129,0,153,120,10,9,162,195,32,139,28,151,161,2,128,26,45,193,146,48,29,146,153, 194, 5, 59, - 29,128,144,195,1,64,43,208,178,149,8,9,16,240,163,129,16,42,185,181,211,24,48,45,137,149,9,24,41,75,184,177,4,43,91,128,180,16,144,29,25,184,167,1,59,60,153,148,161,146,91,42,186,4,24,145,123,11,2,178,77,136,26,25,195,40,115,61,27,168,177,3,59,79,26, 25, - 144,1,48,13,56,154,248,1,16,9,129,8,2,178,31,130,153,162,20,15,33,170,56,40,29,28,128,152,149,144,56,120,11,162,212,129,144,145,59,180,243,147,145,144,16,152,48,241,0,161,176,1,134,10,129,200,166,144,128,121,26,24,177,178,196,48,75,138,41,180,195,26, 24, - 89,138,24,33,187,41,84,155,57,79,136,160,210,130,0,58,58,168,243,132,27,41,75,138,3,8,61,8,29,145,179,76,24,28,146,208,2,49,140,75,196,144,0,40,44,179,208,3,176,33,15,177,2,160,106,8,160,164,164,8,73,27,226,179,161,1,57,1,196,211,128,40,156,145,166, 178, - 131,29,128,145,162,165,40,27,216,146,135,144,40,160,194,177,145,20,139,200,151,178,17,136,40,25,205,130,17,11,17,129,156,38,26,25,137,179,163,11,79,16,12,146,147,143,89,25,136,136,25,48,26,46,129,40,29,42,29,8,145,2,56,27,62,8,25,212,161,48,43, 144, 129, - 29,145,144,41,106,10,107,43,184,131,1,36,61,13,138,2,194,1,16,27,75,186,181,151,8,1,161,138,211,129,2,59,248,129,16,0,144,63,152,150,136,24,25,128,30,161,128,17,24,225,146,10,16,0,9,227,183,129,40,60,26,162,194,181,24,90,9,24,0,176,161,193,194,35,12, 63, - 8,210,162,1,32,78,28,152,164,144,16,48,45,137,162,147,168,152,98,27,43,33,12,160,165,129,137,63,41,153,153,151,16,91,26,8,8,9,56,10,46,24,146,57,168,160,166,241,129,32,140,16,145,179,164,137,113,138,208,131,26,25,1,42,178,196,106,24,171,18,196,8, 18, 29, - 41,194,128,3,249,57,162,152,48,184,120,160,208,33,137,74,57,187,149,129,26,35,158,72,128,168,32,26,25,180,75,2,136,15,163,161,136,120,27,41,160,128,182,56,60,25,12,178,151,128,168,72,10,152,4,177,26,147,137,113,44,42,33,220,2,152,41,82,11, 210, 163, 184, - 133,162,10,196,128,3,234,40,149,152,161,1,44,129,194,4,225,16,58,168,24,194,146,146,154,49,21,218,33,152,248,129,194,147,0,28,1,195,162,20,140,42,25,160,198,1,33,136,142,3,25,24,141,16,177,208,112,0,138,41,160,130,45,60,32,170,73,24,75,59,161,176,49,159, - 97,26,168,149,145,32,28,25,184,211,129,179,74,73,8,153,136,193,151,160,32,48,143,9,147,181,145,32,60,9,187,133,166,144,32,152,25,136,161,150,168,145,81,10,42,0,169,182,148,136,58,41,187,182,211,131,16,137,25,243,144,129,2,9,8,202,7,25,185,21,144,136,153, - 65,184,137,56,151,10,153,49,16,145,14,56,176,11,192,19,89,91,44,168,147,2,8,147,63,27,1,136,229,129,73,26,136,26,137,81,170,147,77,72,12,42,42,192,24,104,91,26,27,65,177,27,32,41,60,14,136,17,170,150,129,24,58,11,16,251,162,19,57,31,0,152,129,145,17, 61, - 14,1,129,27,129,66,169,178,74,12,11,19,198,145,75,33,138,174,133,1,184,57,40,136,169,20,1,60,174,20,154,201,67,26,162,151,42,16,138,59,130,204,20,169,59,180,59,114,184,56,178,242,128,130,43,8,194,3,229,144,33,185,144,34,181,145,168,17,149,153,74,35, 220, - 129,128,1,88,59,75,225,136,130,168,17,144,12,151,8,25,179,8,1,240,16,8,25,145,211,41,130,138,115,169,160,163,168,84,154,74,0,170,144,211,149,2,30,128,137,9,149,1,144,58,60,57,153,178,150,17,29,27,74,25,195,152,56,15,1,25,26,152,149,80,153,57,73,140, 128, - 160,144,113,27,56,28,25,4,42,44,137,60,171,130,50,240,8,5,139,145,1,105,137,200,80,137,145,146,178,179,160,46,16,240,195,131,128,144,24,164,198,128,0,136,137,131,194,165,177,2,161,147,11,144,188,181,148,144,23,0,28,224,128,131,192,32,1,224,1,168,132,145, - 9,41,208,58,137,179,151,145,16,1,30,8,145,178,1,47,32,186,72,169,146,75,8,41,48,136,89,13,48,9,10,124,26,11,42,32,129,91,77,16,12,128,42,57,138,10,60,2,63,9,0,93,128,152,90,8,10,24,40,44,144,29,49,188,48,72,25,30,177,33,128,186,120,129,186,133, 152, 130, - 24,156,51,154,8,226,2,56,155,2,179,233,167,128,24,129,176,136,151,8,184,0,33,224,152,21,177,24,10,163,16,250,17,130,171,83,137,136,37,12,56,242,154,17,160,145,82,13,3,201,128,18,137,24,162,63,162,8,107,178,128,57,158,32,24,200,18,0,106,154,73,16, 248, 8, - 73,137,57,75,0,128,12,65,137,59,75,28,144,129,122,0,58,140,160,195,145,105,56,28,153,145,164,88,8,28,25,153,9,162,113,89,153,136,33,234,147,128,41,72,11,138,151,144,145,16,43,58,248,130,178,42,4,40,10,196,154,147,216,24,7,136,10,161,148,210,161, 98, 138, - 137,128,146,176,33,105,27,43,163,49,185,6,10,136,43,67,174,161,162,151,137,1,64,200,193,24,64,200,56,145,242,24,57,137,1,128,3,162,175,80,128,162,152,25,58,175,17,17,0,200,64,168,162,91,1,154,44,211,177,35,64,160,161,144,4,241,41,209,162,25,1,3,242, 176, - 134,153,42,41,136,135,154,2,130,46,41,161,153,180,145,34,26,46,18,242,137,146,129,25,128,11,151,161,40,179,27,122,168,59,137,181,50,172,36,56,15,9,129,137,128,75,2,58,12,52,141,8,24,58,153,157,122,145,9,1,80,27,184,32,74,219,50,57,168,153,180,48,28, 143, - 131,144,178,65,13,48,168,162,147,155,121,9,170,5,16,153,21,29,144,161,91,0,184,57,128,137,17,159,88,178,128,105,152,9,162,33,164,141,88,178,224,1,0,16,27,185,150,161,9,4,139,16,128,160,194,144,65,180,46,40,136,27,135,160,16,44,57,145,236,2,195,40,75,177, - 2,200,179,146,186,104,50,141,24,169,165,148,11,97,10,11,130,177,49,57,78,42,154,128,165,59,33,28,30,1,136,16,192,41,128,152,123,136,24,1,169,113,10,11,49,153,14,147,19,45,43,8,176,210,148,8,16,11,96,144,192,163,150,10,128,43,26,150,178,165,24,41,171, 18, - 27,215,1,8,128,136,40,35,208,11,161,193,18,73,154,133,155,165,164,10,49,154,8,199,0,2,168,64,192,0,40,162,43,202,180,150,10,106,24,185,145,131,184,113,43,24,162,187,73,146,42,81,171,121,58,155,151,16,43,32,31,9,160,146,17,136,94,10,24,145,25, 9, 130, 59, - 65,13,91,25,169,146,176,112,42,59,16,217,130,20,13,25,9,40,161,138,68,169,154,18,62,154,180,145,135,152,56,58,155,165,211,8,40,42,10,198,1,2,184,57,184,224,51,154,27,134,168,19,202,73,75,184,35,176,75,24,25,209,51,157,19,30,184,179,3,33,148,45, 232, 146, - 129,168,41,32,170,149,193,35,136,16,50,191,56,146,173,149,16,24,41,30,129,168,209,3,57,31,0,16,176,147,41,152,10,17,181,14,40,144,49,170,75,97,141,25,162,146,72,177,92,137,137,19,137,153,113,154,2,41,60,129,217,2,211,152,73,42,193,197,146,147, 10, 59, 0, - 192,196,132,41,160,25,88,169,16,40,241,1,153,81,28,10,147,161,209,88,75,9,161,162,180,16,43,57,235,33,56,156,129,144,2,135,31,128,145,136,163,56,59,154,57,167,160,105,137,0,138,163,3,41,47,185,211,131,41,41,60,139,182,146,16,16,43,242,144,145,129,16,179, - 183,1,26,9,147,240,131,160,91,74,152,184,166,178,33,140,9,4,162,233,34,136,129,144,163,60,142,144,149,128,33,73,13,161,194,131,0,26,56,142,128,163,128,1,233,56,209,41,145,194,147,179,149,64,30,8,128,216,18,24,43,43,32,153,25,74,109,137,153,48,8,137, 122, - 25,144,26,43,59,30,33,41,27,24,96,153,160,50,76,27,47,152,145,163,73,40,14,152,131,176,74,90,8,8,200,67,155,154,50,49,155,28,124,177,152,1,2,17,62,138,180,176,4,25,9,177,245,162,129,40,25,176,164,130,172,4,8,181,194,49,11,168,154,165,133,152,40,136, 226, - 179,19,26,185,16,167,194,16,25,57,243,136,147,1,31,25,184,132,160,33,62,138,129,130,41,121,137,153,145,26,17,107,136,179,1,61,60,26,162,168,148,64,31,25,32,168,152,64,31,137,8,129,33,62,24,137,8,16,59,47,153,33,162,91,59,41,170,145,5,43,60,41,13,178,134, - 57,153,12,194,227,8,2,128,57,208,162,19,216,32,178,25,128,160,48,194,195,37,155,10,33,251,163,146,16,136,12,166,195,160,148,129,176,147,178,150,160,72,162,162,193,162,60,200,145,5,144,25,122,216,129,161,130,0,10,73,1,241,2,9,168,33,13,161,165,24,64, 203, - 50,1,14,9,9,129,161,106,33,27,13,164,128,40,41,107,169,160,33,136,60,92,168,152,2,91,57,176,129,0,144,47,136,162,164,128,80,43,154,179,213,130,74,27,0,145,145,167,58,59,160,9,26,76,8,171,5,49,28,44,169,162,183,130,72,28,144,179,228,2,25,26,129, 186, 151, - 1,75,128,169,17,178,15,57,170,16,166,16,57,8,139,162,181,1,8,152,164,181,41,81,43,10,242,145,57,139,89,8,193,18,154,32,176,10,165,129,137,147,177,134,0,25,25,201,147,227,129,72,59,185,167,128,129,160,91,25,176,130,147,145,9,160,5,202,17,16, 186, 136, 37, - 177,56,76,42,169,186,48,9,145,57,24,128,41,169,134,137,145,147,28,41,168,131,228,32,27,9,60,129,178,64,60,45,25,9,24,152,49,31,136,57,42,0,25,12,181,18,153,57,96,169,177,132,153,123,9,152,129,177,17,74,43,24,169,128,121,137,25,1,139,96,42,10,146,178, 18, - 44,29,1,161,164,146,31,137,146,177,19,1,10,26,209,165,146,43,40,138,240,130,18,144,25,40,212,1,58,11,152,196,147,10,74,26,152,225,130,146,58,60,210,145,16,148,16,185,192,18,44,42,57,199,162,1,9,87,47,186,215,231,197,179,180,195,212,164,32,59,92, 126, 62, - 41,59,76,59,60,168,179,213,197,163,72,44,25,74,126,127,127,79,26,177,148,90,27,225,247,165,0,152,147,123,138,211,164,72,126,127,46,210,196,163,228,215,64,11,210,180,1,8,58,153,1,224,149,57,76,27,24,76,42,43,136,128,243,179,130,106,60,42,42,92,28,243,231, - 147,24,57,44,58,94,45,8,57,139,214,148,40,77,26,9,16,10,144,64,62,43,25,123,59,138,162,48,63,26,41,92,60,43,176,3,59,232,214,164,16,75,75,76,60,153,179,33,62,26,136,40,75,169,197,163,129,57,60,59,75,138,145,64,63,138,179,1,42,136,90,43,176,214,180,1, 25, - 152,195,129,129,106,76,60,137,145,178,2,25,10,228,130,57,59,44,41,154,165,105,76,44,144,16,76,26,41,76,26,152,1,58,26,9,193,165,16,92,26,41,77,59,76,76,60,26,136,161,130,152,195,163,211,146,0,57,11,211,130,8,25,40,62,153,162,17,109,60,153,146,40, 76, 60, - 26,160,179,211,163,32,60,42,153,179,194,199,130,24,58,43,58,27,128,161,195,129,226,196,147,90,59,75,44,136,128,145,160,148,123,59,42,26,41,26,57,27,192,215,147,57,59,27,161,145,213,130,106,76,43,9,144,162,129,177,181,130,136,194,146,40,10,129,25,210,146, - 178,197,196,179,196,130,8,41,9,144,178,130,209,182,17,92,43,176,147,144,212,130,136,0,177,130,73,62,10,161,130,91,75,59,43,57,46,25,41,77,10,177,164,16,26,136,210,197,179,130,128,57,77,43,25,75,10,227,179,180,179,146,128,57,185,183,163,145,0,8,8,10, 119, - 114,120,16,210,244,60,28,41,25,152,149,56,161,35,44,89,27,24,136,24,164,211,17,233,176,136,192,129,179,17,17,25,0,10,46,160,132,49,66,24,132,177,147,193,56,72,26,29,232,168,176,12,137,41,139,147,9,1,41,15,91,136,35,148,21,18,48,40,1,168,167,144,0,42,172, - 177,204,193,155,232,152,152,26,152,41,146,17,6,4,65,34,35,135,4,16,32,9,24,186,176,0,250,153,204,186,173,154,153,177,3,65,41,34,145,134,35,65,98,49,50,50,2,33,169,138,155,175,170,172,204,192,138,234,136,155,136,10,32,18,5,52,48,24,162,17,67,54,66,51, 34, - 131,184,174,234,153,10,9,40,0,152,251,168,142,154,9,16,33,49,33,128,154,170,156,34,54,54,33,68,0,1,136,201,137,26,88,48,35,99,8,152,189,189,187,155,171,16,24,130,145,188,175,203,144,49,115,67,67,50,19,2,1,0,0,130,131,1,136,206,216,188,203, 204, 187, 187, - 156,153,0,0,51,17,34,24,112,20,69,67,67,34,19,0,136,169,185,137,186,232,185,219,201,203,187,173,170,154,153,129,131,6,2,19,49,49,21,65,19,53,51,83,34,16,168,201,154,172,156,138,0,1,24,201,233,186,204,186,171,137,3,37,48,24,128,201,202,202,129,17, 48, 21, - 22,20,19,19,32,16,2,66,52,68,4,3,1,203,235,188,189,186,171,153,137,153,170,219,170,140,9,17,53,115,50,52,67,51,51,51,17,130,0,145,154,169,188,236,187,190,203,187,172,171,138,136,17,33,18,2,34,98,98,50,50,52,66,34,35,2,19,24,169,203,203,188,219, 169, 154, - 9,137,171,204,188,203,184,136,34,83,50,33,153,184,170,170,152,40,57,19,36,50,50,18,35,17,2,49,49,66,66,66,34,17,168,233,202,202,170,171,170,186,219,203,188,188,154,138,25,33,68,52,68,67,67,36,51,36,18,17,17,136,8,170,176,202,188,206,202,171,172,186, 169, - 153,8,25,144,128,1,34,68,52,68,51,52,34,49,18,34,2,144,136,155,140,187,186,186,154,154,185,185,153,9,9,0,24,0,128,144,168,169,170,154,154,153,9,8,16,8,0,144,19,35,68,51,52,67,51,66,34,50,33,1,144,185,186,172,204,187,188,173,172,186,172,186, 154, 138, 41, - 33,52,53,83,50,51,52,52,37,34,34,18,16,144,152,154,187,219,203,188,173,186,186,186,170,154,153,138,144,16,17,67,82,50,51,21,34,19,33,2,18,33,1,8,153,169,153,153,136,128,0,136,154,153,153,8,8,1,16,0,169,170,187,171,171,154,153,153,152,153,153,0,16,51, 83, - 66,50,67,50,51,67,51,52,35,18,136,186,219,187,189,186,171,187,173,187,188,187,203,138,9,16,33,50,52,53,67,67,147,8,128,128,128,128,128,128,128,128,0,240,255,55,232,23,220,0,148,1,9,18,148,10,189,32,163,62,160,5,137,12,149,42,153,144,34,42,8, 1, 138, 181, - 45,136,18,144,105,138,1,160,14,128,132,145,186,37,138,41,192,48,145,46,160,33,44,24,225,16,13,132,136,137,16,148,25,170,194,82,152,136,91,24,42,169,33,233,131,179,24,185,149,16,57,172,164,18,10,211,160,147,211,33,138,243,129,16,41,193,0,43, 132, 155, 73, - 58,145,244,145,43,35,9,171,16,110,25,8,28,74,162,128,26,27,82,45,136,153,18,8,136,8 + 0, 24, 1, 192, 1, 216, 2, 128, 4, 88, 23, 64, 27, 152, 1, 128, 29, 24, 2, 128, 31, 152, 0, 128, 136, 128, 128, 128, 0, 136, 97, 103, 153, 139, 34, 163, 72, 195, 27, 69, 1, 154, 137, 35, 8, 51, 169, 122, 164, 75, 133, 203, 81, 146, 168, 121, 185, 68, 202, 8, 33, 237, 49, 177, 12, 133, 140, 17, 160, 42, 161, 10, 0, 137, 176, 57, + 233, 41, 160, 136, 235, 65, 177, 137, 128, 26, 164, 28, 3, 157, 51, 137, 1, 152, 113, 161, 40, 146, 115, 192, 56, 5, 169, 66, 161, 56, 1, 50, 145, 59, 39, 168, 97, 1, 160, 57, 7, 153, 50, 153, 32, 2, 25, 129, 32, 20, 186, 66, 129, 24, 153, 164, 142, 130, 169, 153, 26, 242, 138, 217, 9, 128, 204, 58, 209, 172, 40, 176, 141, + 128, 155, 144, 203, 139, 0, 235, 9, 177, 172, 0, 185, 168, 138, 25, 240, 59, 211, 139, 19, 176, 90, 160, 17, 26, 132, 41, 1, 5, 25, 3, 50, 144, 115, 147, 42, 39, 152, 41, 3, 56, 193, 105, 130, 155, 66, 200, 26, 19, 218, 154, 49, 201, 171, 138, 176, 251, 139, 185, 172, 136, 189, 139, 145, 207, 41, 160, 171, 152, 186, 139, + 186, 141, 128, 218, 171, 51, 217, 170, 56, 163, 12, 4, 155, 81, 147, 42, 37, 152, 32, 54, 136, 49, 50, 48, 37, 32, 69, 0, 17, 50, 50, 83, 2, 16, 68, 20, 8, 66, 4, 154, 84, 145, 24, 33, 24, 32, 17, 18, 145, 32, 22, 168, 49, 163, 1, 33, 50, 184, 115, 129, 25, 66, 1, 24, 67, 2, 80, 35, 40, 53, 2, 65, 51, 19, 67, 37, 0, 52, 35, 49, 37, + 34, 49, 37, 17, 52, 17, 35, 35, 35, 34, 32, 49, 33, 152, 34, 145, 24, 24, 128, 138, 128, 184, 9, 177, 171, 168, 185, 155, 152, 172, 155, 186, 172, 185, 172, 155, 186, 173, 153, 202, 187, 185, 202, 170, 171, 202, 186, 169, 170, 170, 171, 139, 154, 171, 153, 154, 169, 10, 168, 154, 128, 168, 154, 0, 153, 152, 136, 137, + 128, 153, 0, 152, 8, 128, 137, 0, 136, 136, 8, 9, 8, 9, 8, 24, 153, 128, 136, 153, 144, 0, 161, 138, 1, 169, 136, 128, 160, 168, 152, 153, 138, 137, 154, 153, 153, 154, 153, 170, 168, 170, 185, 168, 169, 154, 169, 171, 153, 169, 170, 153, 152, 154, 153, 137, 169, 137, 136, 144, 152, 144, 128, 128, 144, 129, 129, 0, 33, + 0, 17, 17, 17, 33, 33, 18, 18, 34, 34, 34, 34, 34, 34, 35, 19, 35, 19, 35, 35, 18, 19, 18, 35, 18, 33, 0, 8, 8, 8, 8, 8, 8, 8, 160, 205, 65, 176, 171, 203, 16, 240, 95, 242, 120, 145, 156, 66, 177, 26, 19, 153, 9, 35, 35, 239, 56, 132, 138, 154, 50, 145, 203, 25, 32, 20, 237, 24, 130, 138, 160, 27, 39, 173, 50, 203, 64, 145, 139, + 18, 168, 48, 146, 171, 65, 18, 176, 12, 52, 128, 25, 5, 57, 240, 104, 161, 25, 129, 18, 188, 114, 160, 26, 36, 200, 154, 18, 1, 128, 186, 73, 162, 173, 32, 184, 25, 144, 137, 234, 8, 154, 32, 160, 158, 18, 187, 81, 2, 235, 41, 36, 144, 154, 17, 67, 128, 33, 160, 114, 146, 26, 37, 33, 232, 41, 130, 41, 178, 29, 50, 251, 24, + 1, 153, 138, 160, 76, 179, 155, 11, 0, 38, 252, 41, 146, 41, 178, 27, 193, 43, 39, 170, 136, 17, 129, 8, 49, 233, 48, 129, 11, 6, 26, 130, 136, 128, 64, 1, 248, 105, 145, 9, 16, 144, 140, 5, 25, 168, 16, 186, 48, 5, 171, 217, 57, 134, 171, 8, 34, 188, 20, 203, 41, 6, 155, 161, 89, 164, 140, 2, 136, 51, 202, 41, 131, 56, 144, + 8, 97, 144, 146, 13, 69, 200, 42, 130, 25, 152, 57, 6, 220, 88, 177, 26, 148, 9, 168, 8, 67, 192, 156, 65, 145, 137, 10, 4, 154, 18, 157, 67, 160, 154, 1, 50, 188, 82, 170, 82, 185, 49, 220, 97, 144, 10, 8, 16, 145, 9, 136, 18, 202, 51, 184, 141, 114, 179, 139, 24, 19, 8, 250, 121, 160, 40, 160, 10, 18, 152, 168, 42, 35, 216, + 187, 120, 145, 18, 156, 203, 84, 144, 9, 144, 26, 66, 161, 13, 1, 128, 17, 154, 18, 142, 6, 154, 65, 192, 29, 35, 186, 64, 192, 24, 9, 146, 56, 185, 16, 248, 121, 176, 40, 129, 136, 171, 96, 147, 140, 50, 203, 64, 144, 41, 128, 161, 187, 71, 200, 24, 129, 24, 217, 56, 20, 220, 24, 4, 169, 9, 1, 33, 201, 26, 134, 141, 51, 201, + 25, 16, 33, 235, 32, 144, 33, 153, 169, 99, 160, 11, 3, 136, 58, 210, 33, 203, 48, 163, 17, 219, 128, 140, 38, 8, 184, 141, 50, 131, 159, 33, 128, 153, 25, 18, 153, 88, 242, 43, 3, 9, 136, 157, 53, 202, 40, 145, 25, 2, 204, 105, 146, 156, 66, 152, 8, 153, 33, 128, 129, 136, 153, 50, 186, 55, 188, 51, 249, 64, 178, 27, 128, + 48, 177, 156, 18, 35, 175, 51, 189, 32, 51, 234, 155, 69, 184, 26, 2, 152, 9, 17, 136, 144, 137, 50, 235, 115, 216, 24, 2, 170, 67, 187, 49, 129, 155, 4, 27, 129, 56, 232, 43, 39, 203, 40, 3, 154, 169, 66, 184, 114, 224, 25, 2, 9, 128, 11, 35, 155, 18, 11, 202, 84, 169, 26, 5, 154, 8, 160, 98, 185, 17, 187, 50, 23, 188, 33, + 1, 139, 4, 154, 90, 147, 12, 3, 43, 2, 170, 171, 103, 193, 28, 132, 137, 8, 129, 24, 170, 50, 201, 42, 35, 202, 169, 52, 201, 33, 218, 40, 39, 203, 0, 40, 147, 29, 163, 139, 83, 185, 1, 4, 159, 34, 160, 12, 21, 155, 40, 129, 137, 58, 151, 13, 2, 136, 144, 16, 153, 40, 17, 131, 207, 51, 144, 140, 4, 154, 17, 146, 170, 73, 163, + 44, 164, 12, 152, 37, 203, 17, 128, 144, 139, 23, 154, 128, 138, 38, 216, 41, 1, 0, 233, 73, 131, 171, 49, 136, 9, 164, 46, 3, 171, 32, 0, 145, 157, 38, 187, 64, 176, 58, 134, 155, 18, 136, 217, 64, 1, 200, 140, 38, 153, 170, 66, 161, 8, 169, 65, 185, 98, 200, 41, 3, 155, 144, 58, 23, 187, 1, 145, 40, 147, 189, 32, 68, 249, + 1, 112, 255, 199, 195, 19, 108, 76, 187, 247, 247, 183, 40, 168, 212, 245, 199, 227, 68, 45, 59, 10, 145, 177, 198, 24, 130, 76, 26, 193, 180, 129, 0, 162, 42, 160, 199, 162, 0, 16, 152, 137, 132, 168, 195, 130, 162, 181, 227, 163, 161, 179, 211, 180, 179, 164, 128, 162, 161, 194, 164, 179, 40, 153, 195, 213, 146, 178, + 147, 176, 50, 186, 161, 196, 151, 58, 16, 28, 162, 160, 131, 122, 155, 33, 241, 146, 128, 40, 26, 128, 154, 36, 170, 89, 59, 9, 24, 144, 77, 161, 8, 177, 112, 139, 33, 232, 148, 24, 41, 61, 9, 26, 162, 32, 30, 58, 153, 32, 59, 73, 59, 11, 79, 137, 57, 9, 49, 30, 24, 153, 131, 25, 106, 61, 153, 73, 28, 56, 27, 41, 137, 148, + 76, 43, 74, 58, 13, 161, 3, 171, 149, 32, 77, 10, 74, 42, 168, 16, 0, 123, 138, 129, 162, 178, 225, 50, 140, 161, 0, 147, 10, 129, 41, 244, 210, 165, 1, 152, 24, 162, 184, 166, 32, 144, 59, 216, 132, 177, 8, 145, 67, 143, 146, 160, 183, 162, 130, 24, 192, 32, 225, 146, 144, 33, 44, 73, 30, 129, 137, 32, 76, 152, 25, 161, + 2, 154, 32, 177, 132, 232, 2, 136, 210, 128, 149, 177, 32, 58, 27, 168, 225, 133, 8, 44, 107, 136, 25, 136, 17, 26, 58, 46, 16, 11, 145, 17, 144, 79, 136, 144, 136, 145, 152, 33, 31, 162, 130, 200, 82, 153, 74, 137, 147, 26, 0, 13, 133, 170, 149, 16, 192, 0, 178, 0, 128, 152, 182, 150, 9, 16, 9, 137, 33, 59, 63, 10, 152, 32, + 179, 192, 5, 154, 228, 182, 145, 130, 144, 42, 128, 242, 2, 136, 41, 168, 17, 76, 57, 31, 129, 136, 17, 47, 8, 41, 138, 32, 138, 123, 59, 58, 10, 136, 161, 4, 46, 25, 145, 136, 129, 25, 56, 28, 91, 41, 154, 108, 9, 16, 44, 24, 137, 48, 15, 0, 194, 162, 41, 194, 56, 241, 163, 146, 0, 139, 7, 186, 150, 129, 152, 1, 208, 33, 176, + 136, 164, 163, 185, 7, 138, 130, 242, 162, 163, 177, 88, 136, 184, 166, 146, 0, 25, 25, 177, 199, 146, 16, 136, 9, 145, 178, 178, 0, 147, 138, 229, 18, 152, 25, 144, 163, 246, 162, 129, 129, 184, 5, 152, 178, 145, 148, 136, 146, 95, 152, 128, 144, 33, 170, 81, 11, 40, 202, 131, 0, 243, 24, 1, 11, 148, 42, 24, 163, 140, + 120, 9, 76, 58, 153, 145, 56, 30, 72, 46, 42, 9, 8, 57, 91, 76, 59, 26, 160, 129, 41, 76, 10, 57, 192, 163, 129, 16, 225, 2, 27, 40, 200, 48, 91, 226, 40, 145, 43, 177, 177, 182, 196, 145, 33, 184, 165, 17, 192, 163, 194, 129, 211, 128, 162, 197, 129, 0, 136, 211, 146, 8, 162, 144, 0, 167, 160, 1, 176, 150, 137, 1, 24, 243, + 0, 129, 145, 25, 123, 169, 130, 168, 132, 41, 63, 42, 136, 137, 120, 26, 136, 8, 24, 89, 29, 58, 177, 193, 147, 1, 26, 162, 176, 167, 180, 8, 49, 28, 29, 178, 162, 88, 43, 42, 57, 43, 61, 8, 29, 129, 128, 128, 123, 137, 24, 243, 16, 136, 16, 46, 0, 169, 149, 128, 1, 60, 153, 72, 154, 90, 25, 25, 25, 8, 91, 73, 12, 16, 137, 144, + 72, 11, 8, 167, 128, 129, 9, 138, 166, 193, 147, 162, 123, 137, 145, 1, 162, 26, 1, 219, 147, 129, 210, 147, 243, 1, 243, 16, 144, 145, 160, 131, 200, 4, 59, 75, 57, 218, 2, 178, 77, 24, 60, 11, 147, 10, 50, 141, 64, 27, 185, 122, 161, 41, 128, 90, 136, 24, 46, 16, 139, 16, 24, 28, 124, 9, 41, 8, 26, 121, 10, 42, 40, 139, 129, + 0, 201, 135, 137, 56, 176, 176, 35, 215, 145, 1, 26, 145, 144, 160, 135, 138, 1, 177, 146, 146, 161, 65, 242, 136, 164, 177, 1, 1, 186, 151, 208, 148, 129, 10, 32, 241, 145, 163, 178, 17, 168, 136, 151, 168, 2, 148, 185, 133, 176, 130, 129, 154, 163, 215, 0, 146, 136, 40, 211, 161, 131, 171, 81, 144, 170, 21, 184, 56, + 195, 168, 133, 177, 91, 16, 187, 5, 145, 153, 66, 172, 18, 177, 42, 120, 138, 27, 134, 26, 106, 42, 138, 146, 184, 66, 75, 46, 41, 168, 0, 145, 57, 91, 75, 27, 24, 27, 48, 169, 40, 122, 9, 109, 10, 8, 177, 146, 16, 74, 30, 129, 160, 162, 146, 41, 124, 138, 24, 145, 152, 3, 1, 14, 3, 139, 1, 192, 161, 151, 177, 122, 8, 10, 0, + 176, 130, 129, 27, 88, 225, 0, 2, 154, 129, 129, 193, 49, 203, 81, 153, 226, 33, 0, 30, 0, 176, 179, 18, 9, 96, 156, 162, 148, 160, 129, 2, 29, 195, 128, 0, 56, 156, 20, 232, 129, 128, 32, 10, 144, 74, 183, 9, 145, 162, 1, 162, 138, 23, 171, 1, 164, 224, 34, 43, 43, 177, 200, 135, 161, 91, 57, 154, 177, 148, 145, 146, 58, + 108, 136, 170, 35, 208, 177, 34, 128, 44, 129, 155, 151, 243, 16, 1, 154, 72, 193, 144, 18, 11, 122, 160, 153, 5, 192, 24, 130, 184, 132, 226, 0, 128, 153, 131, 181, 136, 65, 154, 128, 17, 170, 39, 28, 59, 144, 168, 80, 25, 47, 24, 26, 144, 32, 47, 41, 153, 161, 148, 8, 92, 9, 9, 129, 144, 33, 26, 47, 24, 137, 108, 25, 10, + 17, 10, 73, 75, 47, 24, 184, 48, 8, 45, 57, 138, 136, 150, 10, 48, 139, 136, 35, 203, 121, 8, 27, 179, 161, 106, 0, 29, 16, 176, 179, 3, 185, 19, 227, 41, 145, 168, 61, 197, 177, 20, 10, 57, 42, 250, 147, 196, 16, 41, 138, 24, 195, 208, 135, 137, 0, 145, 160, 2, 210, 146, 195, 177, 132, 136, 153, 167, 210, 146, 162, 40, 8, + 138, 148, 227, 145, 17, 137, 40, 169, 179, 130, 242, 2, 196, 9, 146, 145, 169, 167, 146, 130, 137, 136, 51, 220, 17, 163, 28, 74, 10, 76, 40, 140, 5, 137, 43, 18, 12, 107, 137, 40, 8, 201, 50, 0, 143, 3, 138, 161, 134, 138, 104, 169, 16, 162, 160, 121, 25, 28, 129, 152, 32, 56, 14, 16, 184, 146, 3, 46, 25, 176, 129, 179, + 193, 17, 130, 202, 135, 8, 57, 25, 154, 148, 184, 120, 9, 153, 211, 165, 24, 128, 26, 17, 242, 161, 18, 185, 81, 42, 11, 17, 12, 25, 181, 137, 66, 42, 47, 41, 184, 166, 129, 24, 91, 27, 136, 196, 0, 0, 74, 28, 178, 161, 149, 160, 32, 8, 225, 32, 128, 59, 8, 169, 50, 139, 47, 72, 186, 16, 132, 9, 122, 9, 160, 146, 144, 89, 153, + 10, 149, 178, 0, 121, 11, 146, 152, 162, 48, 13, 123, 177, 24, 0, 106, 27, 9, 144, 132, 12, 17, 0, 168, 0, 181, 56, 169, 129, 242, 195, 129, 17, 154, 64, 161, 244, 16, 137, 24, 144, 144, 164, 129, 75, 42, 176, 149, 9, 179, 148, 203, 4, 166, 136, 163, 128, 227, 163, 8, 57, 11, 30, 165, 0, 74, 59, 62, 9, 208, 131, 144, 40, 76, + 26, 27, 196, 129, 1, 25, 43, 49, 174, 67, 153, 136, 106, 152, 41, 25, 28, 2, 43, 44, 104, 45, 59, 8, 43, 128, 144, 120, 25, 12, 17, 152, 9, 130, 155, 151, 145, 74, 40, 13, 48, 192, 58, 90, 43, 43, 177, 146, 49, 31, 75, 24, 217, 131, 0, 76, 26, 152, 149, 161, 24, 74, 154, 193, 166, 145, 32, 27, 161, 164, 176, 135, 152, 24, 193, + 162, 146, 164, 58, 227, 193, 148, 161, 128, 18, 234, 130, 180, 145, 2, 200, 1, 163, 186, 98, 184, 129, 149, 153, 49, 42, 186, 151, 242, 129, 1, 43, 8, 177, 212, 165, 8, 40, 137, 24, 8, 144, 90, 9, 25, 48, 44, 46, 24, 138, 40, 144, 108, 58, 27, 128, 181, 128, 80, 29, 42, 152, 162, 130, 25, 106, 136, 11, 148, 8, 144, 128, 136, + 112, 139, 80, 153, 24, 136, 129, 46, 0, 60, 129, 208, 1, 3, 13, 57, 168, 144, 1, 242, 17, 9, 26, 2, 185, 27, 55, 140, 73, 137, 179, 16, 192, 3, 145, 143, 33, 9, 171, 135, 160, 17, 137, 10, 151, 168, 3, 178, 44, 17, 208, 144, 167, 0, 40, 155, 16, 167, 152, 18, 144, 26, 160, 199, 1, 136, 91, 136, 160, 178, 150, 161, 1, 10, 181, + 145, 161, 1, 145, 161, 198, 2, 9, 90, 137, 177, 160, 150, 40, 29, 129, 144, 145, 162, 57, 77, 169, 16, 148, 42, 42, 40, 141, 34, 170, 121, 154, 210, 131, 162, 107, 8, 9, 160, 195, 40, 73, 139, 18, 224, 162, 34, 139, 0, 244, 178, 163, 24, 26, 146, 194, 166, 49, 29, 42, 137, 130, 192, 16, 93, 128, 154, 19, 59, 11, 122, 11, + 146, 177, 120, 42, 26, 43, 164, 152, 17, 60, 63, 137, 128, 48, 10, 58, 92, 9, 59, 91, 75, 139, 32, 25, 25, 61, 74, 28, 177, 40, 130, 74, 29, 73, 168, 130, 128, 48, 14, 8, 77, 9, 25, 26, 179, 211, 32, 78, 26, 41, 152, 161, 180, 89, 59, 9, 153, 166, 160, 3, 26, 57, 106, 154, 88, 184, 40, 1, 27, 58, 73, 143, 131, 169, 3, 161, 184, + 122, 152, 16, 181, 145, 129, 17, 15, 129, 193, 147, 145, 192, 33, 193, 162, 183, 163, 136, 178, 129, 178, 197, 2, 41, 216, 131, 168, 163, 181, 226, 163, 178, 1, 33, 187, 166, 212, 129, 1, 27, 24, 162, 184, 151, 8, 16, 160, 144, 181, 210, 72, 168, 128, 32, 42, 25, 40, 142, 5, 185, 88, 58, 11, 58, 177, 32, 129, 63, 42, 136, + 186, 53, 29, 75, 58, 144, 144, 129, 77, 128, 11, 144, 133, 29, 40, 152, 24, 161, 129, 80, 155, 60, 3, 12, 89, 8, 60, 152, 152, 49, 136, 47, 57, 224, 129, 16, 41, 90, 139, 162, 147, 170, 51, 169, 27, 17, 95, 26, 26, 160, 5, 139, 48, 76, 10, 228, 146, 1, 136, 44, 161, 147, 209, 130, 137, 73, 224, 1, 162, 195, 32, 210, 177, 180, + 179, 148, 145, 154, 132, 242, 146, 1, 152, 32, 192, 1, 144, 155, 7, 177, 168, 5, 138, 178, 148, 152, 150, 136, 89, 152, 9, 41, 196, 145, 40, 28, 16, 8, 10, 178, 167, 24, 1, 44, 123, 137, 136, 145, 194, 48, 27, 74, 26, 192, 179, 135, 136, 88, 27, 10, 177, 163, 164, 128, 73, 24, 31, 8, 0, 192, 149, 144, 129, 9, 106, 41, 200, + 161, 151, 41, 138, 0, 24, 226, 162, 49, 42, 11, 90, 136, 136, 152, 17, 145, 10, 63, 40, 11, 56, 245, 162, 16, 26, 73, 11, 144, 135, 137, 58, 106, 10, 25, 8, 57, 137, 28, 33, 129, 156, 113, 10, 10, 161, 18, 8, 153, 77, 3, 217, 0, 1, 242, 128, 193, 18, 128, 75, 60, 178, 154, 37, 45, 58, 29, 144, 1, 184, 66, 41, 29, 8, 145, 10, + 194, 33, 148, 170, 107, 89, 139, 128, 163, 178, 16, 63, 59, 176, 144, 151, 129, 42, 74, 10, 129, 192, 2, 128, 154, 97, 192, 0, 177, 128, 178, 183, 16, 16, 155, 149, 145, 184, 84, 138, 8, 192, 161, 20, 225, 0, 130, 138, 165, 0, 28, 148, 153, 18, 209, 128, 88, 153, 89, 152, 9, 17, 9, 29, 130, 43, 122, 153, 24, 32, 202, 49, + 24, 43, 106, 154, 130, 193, 27, 51, 29, 28, 133, 138, 65, 11, 123, 25, 10, 40, 152, 44, 130, 26, 43, 148, 45, 73, 140, 33, 8, 153, 88, 128, 61, 144, 42, 59, 225, 128, 18, 155, 50, 75, 186, 20, 202, 120, 144, 42, 92, 176, 162, 165, 25, 2, 169, 152, 135, 185, 19, 152, 8, 146, 160, 123, 195, 137, 132, 209, 0, 16, 11, 2, 242, + 146, 164, 152, 73, 193, 136, 130, 178, 1, 136, 169, 23, 169, 128, 164, 242, 129, 178, 129, 32, 138, 180, 167, 153, 132, 8, 138, 2, 209, 4, 138, 1, 128, 138, 92, 136, 44, 129, 136, 162, 33, 63, 40, 141, 2, 160, 144, 106, 137, 64, 155, 17, 129, 60, 30, 146, 26, 17, 28, 48, 46, 169, 51, 154, 91, 137, 41, 26, 32, 143, 18, 138, + 1, 32, 28, 123, 177, 9, 181, 195, 56, 57, 14, 145, 161, 17, 17, 31, 41, 152, 145, 194, 194, 20, 153, 41, 9, 243, 129, 180, 0, 128, 45, 16, 43, 170, 135, 144, 16, 25, 42, 137, 242, 163, 194, 16, 0, 57, 14, 130, 194, 178, 16, 33, 30, 8, 59, 211, 163, 160, 5, 137, 44, 10, 17, 170, 3, 120, 9, 44, 146, 136, 131, 140, 91, 9, 171, + 7, 161, 32, 73, 13, 8, 161, 40, 106, 11, 25, 129, 59, 0, 49, 31, 42, 28, 40, 11, 0, 81, 176, 61, 32, 138, 25, 178, 241, 148, 136, 106, 8, 136, 128, 177, 90, 8, 155, 96, 176, 9, 18, 217, 132, 129, 10, 81, 156, 40, 178, 161, 36, 169, 76, 147, 203, 150, 0, 10, 146, 200, 147, 149, 128, 144, 148, 154, 182, 24, 0, 137, 11, 134, 211, + 24, 136, 129, 145, 209, 33, 8, 43, 163, 243, 88, 41, 13, 0, 160, 145, 33, 31, 32, 185, 145, 4, 155, 17, 32, 47, 161, 128, 73, 160, 44, 56, 176, 75, 74, 12, 35, 141, 104, 137, 9, 89, 152, 58, 56, 44, 41, 30, 41, 40, 157, 48, 128, 154, 88, 41, 42, 8, 14, 3, 184, 59, 120, 152, 9, 56, 10, 128, 41, 57, 227, 186, 52, 152, 62, 8, 56, + 242, 0, 58, 8, 156, 34, 243, 128, 24, 176, 51, 169, 58, 183, 192, 146, 164, 177, 18, 170, 7, 177, 208, 132, 161, 24, 136, 27, 147, 243, 128, 133, 10, 24, 161, 161, 178, 214, 17, 160, 25, 16, 161, 137, 165, 192, 48, 27, 72, 58, 218, 133, 162, 26, 72, 27, 10, 197, 178, 49, 138, 89, 56, 142, 1, 24, 11, 0, 44, 105, 10, 25, 0, + 194, 9, 3, 47, 8, 138, 147, 18, 28, 48, 202, 147, 199, 146, 25, 161, 0, 145, 194, 163, 57, 11, 146, 248, 130, 32, 57, 63, 154, 16, 48, 14, 128, 144, 209, 133, 26, 56, 154, 182, 162, 195, 18, 152, 44, 194, 180, 168, 5, 24, 137, 138, 35, 192, 232, 66, 176, 161, 24, 41, 26, 244, 129, 163, 160, 75, 129, 226, 147, 40, 145, 61, + 13, 130, 177, 17, 137, 112, 170, 130, 0, 136, 75, 152, 177, 241, 34, 0, 59, 156, 51, 186, 178, 91, 132, 137, 137, 122, 1, 45, 28, 50, 172, 57, 108, 8, 26, 136, 32, 152, 46, 144, 131, 171, 4, 152, 18, 141, 148, 1, 216, 32, 9, 60, 169, 66, 152, 128, 72, 90, 201, 1, 17, 201, 136, 3, 195, 26, 73, 133, 200, 176, 150, 146, 169, + 24, 33, 178, 184, 151, 73, 11, 28, 72, 44, 153, 82, 153, 17, 42, 57, 78, 153, 8, 160, 0, 1, 123, 11, 19, 171, 195, 18, 59, 31, 129, 10, 162, 2, 58, 96, 142, 130, 26, 75, 128, 176, 17, 180, 123, 9, 90, 137, 211, 145, 32, 26, 76, 43, 145, 130, 12, 90, 41, 27, 58, 160, 160, 128, 178, 7, 76, 59, 0, 203, 180, 147, 33, 62, 10, 0, 243, + 129, 146, 73, 29, 145, 144, 0, 26, 56, 153, 185, 83, 8, 76, 27, 166, 161, 193, 146, 131, 224, 145, 165, 161, 40, 168, 149, 162, 226, 2, 136, 138, 163, 131, 211, 0, 59, 146, 218, 148, 1, 192, 16, 16, 58, 248, 88, 144, 177, 136, 1, 58, 45, 9, 195, 197, 147, 48, 29, 10, 0, 162, 176, 64, 122, 9, 10, 17, 9, 153, 56, 75, 27, 31, + 72, 136, 9, 129, 129, 61, 45, 59, 10, 161, 18, 122, 43, 59, 41, 169, 34, 155, 130, 131, 219, 120, 162, 27, 49, 208, 160, 131, 156, 66, 12, 145, 50, 240, 16, 136, 12, 162, 40, 129, 130, 15, 129, 162, 146, 180, 83, 139, 58, 217, 129, 177, 4, 0, 169, 197, 163, 144, 242, 131, 168, 179, 179, 17, 197, 145, 178, 164, 128, 160, + 211, 2, 244, 163, 145, 162, 129, 212, 177, 163, 17, 208, 163, 195, 180, 57, 24, 170, 182, 164, 129, 0, 60, 60, 169, 149, 162, 177, 122, 26, 24, 136, 136, 133, 43, 27, 178, 56, 77, 24, 128, 240, 0, 2, 44, 46, 8, 128, 193, 146, 64, 27, 42, 16, 193, 25, 0, 192, 148, 11, 52, 47, 153, 147, 243, 0, 24, 73, 28, 144, 161, 150, 9, + 8, 73, 170, 2, 162, 25, 27, 147, 167, 131, 29, 1, 168, 200, 165, 16, 91, 137, 8, 162, 176, 35, 41, 31, 24, 169, 50, 168, 58, 123, 144, 48, 128, 13, 73, 169, 144, 16, 57, 123, 44, 200, 163, 56, 153, 80, 10, 176, 146, 57, 94, 8, 152, 131, 9, 168, 125, 26, 145, 177, 132, 137, 41, 60, 26, 144, 243, 32, 192, 34, 60, 43, 26, 16, + 249, 164, 16, 58, 61, 11, 130, 243, 146, 2, 42, 44, 27, 128, 165, 137, 49, 45, 28, 16, 43, 8, 211, 48, 28, 152, 105, 9, 9, 163, 161, 169, 35, 107, 42, 232, 164, 130, 168, 72, 42, 168, 210, 148, 144, 136, 129, 3, 217, 194, 50, 27, 192, 41, 210, 147, 40, 76, 226, 1, 161, 1, 155, 132, 145, 147, 171, 67, 173, 210, 132, 161, 106, + 137, 56, 169, 209, 131, 64, 13, 129, 9, 194, 17, 57, 61, 169, 17, 128, 40, 31, 16, 10, 162, 57, 61, 75, 139, 40, 242, 17, 58, 59, 138, 179, 144, 50, 105, 140, 179, 243, 57, 40, 26, 9, 243, 130, 24, 29, 57, 128, 210, 129, 25, 59, 91, 137, 162, 178, 72, 27, 181, 168, 19, 129, 8, 184, 231, 147, 178, 32, 28, 184, 198, 148, 144, + 1, 26, 128, 16, 192, 2, 26, 144, 244, 129, 0, 16, 10, 197, 177, 181, 1, 41, 9, 178, 165, 211, 129, 25, 145, 137, 210, 147, 152, 210, 163, 132, 194, 17, 91, 169, 145, 181, 130, 9, 89, 137, 152, 178, 4, 128, 9, 63, 160, 128, 106, 8, 25, 43, 10, 32, 47, 26, 123, 152, 24, 40, 25, 27, 18, 186, 35, 158, 64, 42, 216, 33, 25, 58, 58, + 45, 184, 147, 29, 72, 46, 9, 0, 178, 146, 58, 77, 26, 25, 209, 165, 128, 145, 17, 153, 128, 129, 148, 240, 129, 1, 40, 31, 0, 152, 242, 163, 16, 59, 44, 24, 243, 146, 128, 1, 26, 26, 179, 213, 145, 130, 176, 131, 40, 25, 145, 219, 179, 167, 8, 33, 59, 14, 176, 166, 16, 136, 74, 128, 176, 128, 149, 8, 8, 209, 148, 152, 0, 72, + 153, 161, 178, 35, 62, 75, 154, 163, 153, 19, 62, 170, 133, 179, 136, 89, 12, 129, 164, 144, 3, 47, 58, 193, 177, 148, 0, 61, 43, 10, 129, 17, 41, 61, 43, 25, 8, 126, 26, 25, 137, 145, 34, 44, 45, 129, 216, 179, 1, 90, 25, 137, 32, 227, 8, 16, 9, 170, 49, 31, 32, 29, 128, 145, 148, 75, 25, 75, 153, 162, 192, 35, 12, 80, 136, + 176, 8, 194, 24, 1, 176, 21, 154, 145, 80, 251, 130, 2, 30, 9, 8, 130, 145, 128, 98, 27, 26, 129, 136, 162, 15, 33, 168, 59, 65, 177, 77, 141, 1, 128, 168, 113, 10, 137, 178, 163, 146, 132, 74, 153, 224, 164, 33, 184, 19, 184, 228, 161, 17, 91, 152, 25, 146, 152, 44, 121, 9, 160, 145, 17, 25, 28, 93, 128, 152, 2, 25, 27, 161, + 210, 129, 146, 45, 179, 227, 163, 162, 9, 40, 193, 148, 179, 57, 107, 140, 196, 32, 25, 57, 47, 136, 210, 130, 24, 40, 28, 152, 210, 182, 145, 40, 8, 129, 184, 147, 147, 140, 163, 166, 160, 34, 45, 144, 194, 161, 134, 41, 46, 152, 162, 162, 3, 44, 58, 75, 209, 162, 144, 57, 129, 47, 152, 130, 59, 16, 248, 129, 17, 26, 57, + 9, 29, 167, 2, 60, 42, 138, 136, 209, 130, 90, 42, 42, 176, 146, 178, 120, 28, 8, 160, 145, 16, 33, 31, 1, 8, 160, 129, 128, 242, 164, 32, 152, 177, 146, 213, 196, 128, 40, 26, 160, 163, 180, 146, 108, 60, 144, 144, 136, 147, 137, 40, 90, 161, 3, 17, 219, 243, 33, 184, 130, 60, 136, 243, 178, 179, 132, 26, 8, 168, 212, 147, + 16, 57, 42, 31, 145, 145, 160, 32, 43, 184, 66, 45, 180, 33, 140, 226, 1, 91, 152, 16, 144, 193, 162, 48, 77, 25, 137, 153, 17, 178, 78, 0, 0, 16, 14, 90, 152, 153, 19, 129, 13, 123, 137, 129, 160, 1, 73, 44, 9, 129, 0, 153, 120, 10, 9, 162, 195, 32, 139, 28, 151, 161, 2, 128, 26, 45, 193, 146, 48, 29, 146, 153, 194, 5, 59, + 29, 128, 144, 195, 1, 64, 43, 208, 178, 149, 8, 9, 16, 240, 163, 129, 16, 42, 185, 181, 211, 24, 48, 45, 137, 149, 9, 24, 41, 75, 184, 177, 4, 43, 91, 128, 180, 16, 144, 29, 25, 184, 167, 1, 59, 60, 153, 148, 161, 146, 91, 42, 186, 4, 24, 145, 123, 11, 2, 178, 77, 136, 26, 25, 195, 40, 115, 61, 27, 168, 177, 3, 59, 79, 26, 25, + 144, 1, 48, 13, 56, 154, 248, 1, 16, 9, 129, 8, 2, 178, 31, 130, 153, 162, 20, 15, 33, 170, 56, 40, 29, 28, 128, 152, 149, 144, 56, 120, 11, 162, 212, 129, 144, 145, 59, 180, 243, 147, 145, 144, 16, 152, 48, 241, 0, 161, 176, 1, 134, 10, 129, 200, 166, 144, 128, 121, 26, 24, 177, 178, 196, 48, 75, 138, 41, 180, 195, 26, 24, + 89, 138, 24, 33, 187, 41, 84, 155, 57, 79, 136, 160, 210, 130, 0, 58, 58, 168, 243, 132, 27, 41, 75, 138, 3, 8, 61, 8, 29, 145, 179, 76, 24, 28, 146, 208, 2, 49, 140, 75, 196, 144, 0, 40, 44, 179, 208, 3, 176, 33, 15, 177, 2, 160, 106, 8, 160, 164, 164, 8, 73, 27, 226, 179, 161, 1, 57, 1, 196, 211, 128, 40, 156, 145, 166, 178, + 131, 29, 128, 145, 162, 165, 40, 27, 216, 146, 135, 144, 40, 160, 194, 177, 145, 20, 139, 200, 151, 178, 17, 136, 40, 25, 205, 130, 17, 11, 17, 129, 156, 38, 26, 25, 137, 179, 163, 11, 79, 16, 12, 146, 147, 143, 89, 25, 136, 136, 25, 48, 26, 46, 129, 40, 29, 42, 29, 8, 145, 2, 56, 27, 62, 8, 25, 212, 161, 48, 43, 144, 129, + 29, 145, 144, 41, 106, 10, 107, 43, 184, 131, 1, 36, 61, 13, 138, 2, 194, 1, 16, 27, 75, 186, 181, 151, 8, 1, 161, 138, 211, 129, 2, 59, 248, 129, 16, 0, 144, 63, 152, 150, 136, 24, 25, 128, 30, 161, 128, 17, 24, 225, 146, 10, 16, 0, 9, 227, 183, 129, 40, 60, 26, 162, 194, 181, 24, 90, 9, 24, 0, 176, 161, 193, 194, 35, 12, 63, + 8, 210, 162, 1, 32, 78, 28, 152, 164, 144, 16, 48, 45, 137, 162, 147, 168, 152, 98, 27, 43, 33, 12, 160, 165, 129, 137, 63, 41, 153, 153, 151, 16, 91, 26, 8, 8, 9, 56, 10, 46, 24, 146, 57, 168, 160, 166, 241, 129, 32, 140, 16, 145, 179, 164, 137, 113, 138, 208, 131, 26, 25, 1, 42, 178, 196, 106, 24, 171, 18, 196, 8, 18, 29, + 41, 194, 128, 3, 249, 57, 162, 152, 48, 184, 120, 160, 208, 33, 137, 74, 57, 187, 149, 129, 26, 35, 158, 72, 128, 168, 32, 26, 25, 180, 75, 2, 136, 15, 163, 161, 136, 120, 27, 41, 160, 128, 182, 56, 60, 25, 12, 178, 151, 128, 168, 72, 10, 152, 4, 177, 26, 147, 137, 113, 44, 42, 33, 220, 2, 152, 41, 82, 11, 210, 163, 184, + 133, 162, 10, 196, 128, 3, 234, 40, 149, 152, 161, 1, 44, 129, 194, 4, 225, 16, 58, 168, 24, 194, 146, 146, 154, 49, 21, 218, 33, 152, 248, 129, 194, 147, 0, 28, 1, 195, 162, 20, 140, 42, 25, 160, 198, 1, 33, 136, 142, 3, 25, 24, 141, 16, 177, 208, 112, 0, 138, 41, 160, 130, 45, 60, 32, 170, 73, 24, 75, 59, 161, 176, 49, 159, + 97, 26, 168, 149, 145, 32, 28, 25, 184, 211, 129, 179, 74, 73, 8, 153, 136, 193, 151, 160, 32, 48, 143, 9, 147, 181, 145, 32, 60, 9, 187, 133, 166, 144, 32, 152, 25, 136, 161, 150, 168, 145, 81, 10, 42, 0, 169, 182, 148, 136, 58, 41, 187, 182, 211, 131, 16, 137, 25, 243, 144, 129, 2, 9, 8, 202, 7, 25, 185, 21, 144, 136, 153, + 65, 184, 137, 56, 151, 10, 153, 49, 16, 145, 14, 56, 176, 11, 192, 19, 89, 91, 44, 168, 147, 2, 8, 147, 63, 27, 1, 136, 229, 129, 73, 26, 136, 26, 137, 81, 170, 147, 77, 72, 12, 42, 42, 192, 24, 104, 91, 26, 27, 65, 177, 27, 32, 41, 60, 14, 136, 17, 170, 150, 129, 24, 58, 11, 16, 251, 162, 19, 57, 31, 0, 152, 129, 145, 17, 61, + 14, 1, 129, 27, 129, 66, 169, 178, 74, 12, 11, 19, 198, 145, 75, 33, 138, 174, 133, 1, 184, 57, 40, 136, 169, 20, 1, 60, 174, 20, 154, 201, 67, 26, 162, 151, 42, 16, 138, 59, 130, 204, 20, 169, 59, 180, 59, 114, 184, 56, 178, 242, 128, 130, 43, 8, 194, 3, 229, 144, 33, 185, 144, 34, 181, 145, 168, 17, 149, 153, 74, 35, 220, + 129, 128, 1, 88, 59, 75, 225, 136, 130, 168, 17, 144, 12, 151, 8, 25, 179, 8, 1, 240, 16, 8, 25, 145, 211, 41, 130, 138, 115, 169, 160, 163, 168, 84, 154, 74, 0, 170, 144, 211, 149, 2, 30, 128, 137, 9, 149, 1, 144, 58, 60, 57, 153, 178, 150, 17, 29, 27, 74, 25, 195, 152, 56, 15, 1, 25, 26, 152, 149, 80, 153, 57, 73, 140, 128, + 160, 144, 113, 27, 56, 28, 25, 4, 42, 44, 137, 60, 171, 130, 50, 240, 8, 5, 139, 145, 1, 105, 137, 200, 80, 137, 145, 146, 178, 179, 160, 46, 16, 240, 195, 131, 128, 144, 24, 164, 198, 128, 0, 136, 137, 131, 194, 165, 177, 2, 161, 147, 11, 144, 188, 181, 148, 144, 23, 0, 28, 224, 128, 131, 192, 32, 1, 224, 1, 168, 132, 145, + 9, 41, 208, 58, 137, 179, 151, 145, 16, 1, 30, 8, 145, 178, 1, 47, 32, 186, 72, 169, 146, 75, 8, 41, 48, 136, 89, 13, 48, 9, 10, 124, 26, 11, 42, 32, 129, 91, 77, 16, 12, 128, 42, 57, 138, 10, 60, 2, 63, 9, 0, 93, 128, 152, 90, 8, 10, 24, 40, 44, 144, 29, 49, 188, 48, 72, 25, 30, 177, 33, 128, 186, 120, 129, 186, 133, 152, 130, + 24, 156, 51, 154, 8, 226, 2, 56, 155, 2, 179, 233, 167, 128, 24, 129, 176, 136, 151, 8, 184, 0, 33, 224, 152, 21, 177, 24, 10, 163, 16, 250, 17, 130, 171, 83, 137, 136, 37, 12, 56, 242, 154, 17, 160, 145, 82, 13, 3, 201, 128, 18, 137, 24, 162, 63, 162, 8, 107, 178, 128, 57, 158, 32, 24, 200, 18, 0, 106, 154, 73, 16, 248, 8, + 73, 137, 57, 75, 0, 128, 12, 65, 137, 59, 75, 28, 144, 129, 122, 0, 58, 140, 160, 195, 145, 105, 56, 28, 153, 145, 164, 88, 8, 28, 25, 153, 9, 162, 113, 89, 153, 136, 33, 234, 147, 128, 41, 72, 11, 138, 151, 144, 145, 16, 43, 58, 248, 130, 178, 42, 4, 40, 10, 196, 154, 147, 216, 24, 7, 136, 10, 161, 148, 210, 161, 98, 138, + 137, 128, 146, 176, 33, 105, 27, 43, 163, 49, 185, 6, 10, 136, 43, 67, 174, 161, 162, 151, 137, 1, 64, 200, 193, 24, 64, 200, 56, 145, 242, 24, 57, 137, 1, 128, 3, 162, 175, 80, 128, 162, 152, 25, 58, 175, 17, 17, 0, 200, 64, 168, 162, 91, 1, 154, 44, 211, 177, 35, 64, 160, 161, 144, 4, 241, 41, 209, 162, 25, 1, 3, 242, 176, + 134, 153, 42, 41, 136, 135, 154, 2, 130, 46, 41, 161, 153, 180, 145, 34, 26, 46, 18, 242, 137, 146, 129, 25, 128, 11, 151, 161, 40, 179, 27, 122, 168, 59, 137, 181, 50, 172, 36, 56, 15, 9, 129, 137, 128, 75, 2, 58, 12, 52, 141, 8, 24, 58, 153, 157, 122, 145, 9, 1, 80, 27, 184, 32, 74, 219, 50, 57, 168, 153, 180, 48, 28, 143, + 131, 144, 178, 65, 13, 48, 168, 162, 147, 155, 121, 9, 170, 5, 16, 153, 21, 29, 144, 161, 91, 0, 184, 57, 128, 137, 17, 159, 88, 178, 128, 105, 152, 9, 162, 33, 164, 141, 88, 178, 224, 1, 0, 16, 27, 185, 150, 161, 9, 4, 139, 16, 128, 160, 194, 144, 65, 180, 46, 40, 136, 27, 135, 160, 16, 44, 57, 145, 236, 2, 195, 40, 75, 177, + 2, 200, 179, 146, 186, 104, 50, 141, 24, 169, 165, 148, 11, 97, 10, 11, 130, 177, 49, 57, 78, 42, 154, 128, 165, 59, 33, 28, 30, 1, 136, 16, 192, 41, 128, 152, 123, 136, 24, 1, 169, 113, 10, 11, 49, 153, 14, 147, 19, 45, 43, 8, 176, 210, 148, 8, 16, 11, 96, 144, 192, 163, 150, 10, 128, 43, 26, 150, 178, 165, 24, 41, 171, 18, + 27, 215, 1, 8, 128, 136, 40, 35, 208, 11, 161, 193, 18, 73, 154, 133, 155, 165, 164, 10, 49, 154, 8, 199, 0, 2, 168, 64, 192, 0, 40, 162, 43, 202, 180, 150, 10, 106, 24, 185, 145, 131, 184, 113, 43, 24, 162, 187, 73, 146, 42, 81, 171, 121, 58, 155, 151, 16, 43, 32, 31, 9, 160, 146, 17, 136, 94, 10, 24, 145, 25, 9, 130, 59, + 65, 13, 91, 25, 169, 146, 176, 112, 42, 59, 16, 217, 130, 20, 13, 25, 9, 40, 161, 138, 68, 169, 154, 18, 62, 154, 180, 145, 135, 152, 56, 58, 155, 165, 211, 8, 40, 42, 10, 198, 1, 2, 184, 57, 184, 224, 51, 154, 27, 134, 168, 19, 202, 73, 75, 184, 35, 176, 75, 24, 25, 209, 51, 157, 19, 30, 184, 179, 3, 33, 148, 45, 232, 146, + 129, 168, 41, 32, 170, 149, 193, 35, 136, 16, 50, 191, 56, 146, 173, 149, 16, 24, 41, 30, 129, 168, 209, 3, 57, 31, 0, 16, 176, 147, 41, 152, 10, 17, 181, 14, 40, 144, 49, 170, 75, 97, 141, 25, 162, 146, 72, 177, 92, 137, 137, 19, 137, 153, 113, 154, 2, 41, 60, 129, 217, 2, 211, 152, 73, 42, 193, 197, 146, 147, 10, 59, 0, + 192, 196, 132, 41, 160, 25, 88, 169, 16, 40, 241, 1, 153, 81, 28, 10, 147, 161, 209, 88, 75, 9, 161, 162, 180, 16, 43, 57, 235, 33, 56, 156, 129, 144, 2, 135, 31, 128, 145, 136, 163, 56, 59, 154, 57, 167, 160, 105, 137, 0, 138, 163, 3, 41, 47, 185, 211, 131, 41, 41, 60, 139, 182, 146, 16, 16, 43, 242, 144, 145, 129, 16, 179, + 183, 1, 26, 9, 147, 240, 131, 160, 91, 74, 152, 184, 166, 178, 33, 140, 9, 4, 162, 233, 34, 136, 129, 144, 163, 60, 142, 144, 149, 128, 33, 73, 13, 161, 194, 131, 0, 26, 56, 142, 128, 163, 128, 1, 233, 56, 209, 41, 145, 194, 147, 179, 149, 64, 30, 8, 128, 216, 18, 24, 43, 43, 32, 153, 25, 74, 109, 137, 153, 48, 8, 137, 122, + 25, 144, 26, 43, 59, 30, 33, 41, 27, 24, 96, 153, 160, 50, 76, 27, 47, 152, 145, 163, 73, 40, 14, 152, 131, 176, 74, 90, 8, 8, 200, 67, 155, 154, 50, 49, 155, 28, 124, 177, 152, 1, 2, 17, 62, 138, 180, 176, 4, 25, 9, 177, 245, 162, 129, 40, 25, 176, 164, 130, 172, 4, 8, 181, 194, 49, 11, 168, 154, 165, 133, 152, 40, 136, 226, + 179, 19, 26, 185, 16, 167, 194, 16, 25, 57, 243, 136, 147, 1, 31, 25, 184, 132, 160, 33, 62, 138, 129, 130, 41, 121, 137, 153, 145, 26, 17, 107, 136, 179, 1, 61, 60, 26, 162, 168, 148, 64, 31, 25, 32, 168, 152, 64, 31, 137, 8, 129, 33, 62, 24, 137, 8, 16, 59, 47, 153, 33, 162, 91, 59, 41, 170, 145, 5, 43, 60, 41, 13, 178, 134, + 57, 153, 12, 194, 227, 8, 2, 128, 57, 208, 162, 19, 216, 32, 178, 25, 128, 160, 48, 194, 195, 37, 155, 10, 33, 251, 163, 146, 16, 136, 12, 166, 195, 160, 148, 129, 176, 147, 178, 150, 160, 72, 162, 162, 193, 162, 60, 200, 145, 5, 144, 25, 122, 216, 129, 161, 130, 0, 10, 73, 1, 241, 2, 9, 168, 33, 13, 161, 165, 24, 64, 203, + 50, 1, 14, 9, 9, 129, 161, 106, 33, 27, 13, 164, 128, 40, 41, 107, 169, 160, 33, 136, 60, 92, 168, 152, 2, 91, 57, 176, 129, 0, 144, 47, 136, 162, 164, 128, 80, 43, 154, 179, 213, 130, 74, 27, 0, 145, 145, 167, 58, 59, 160, 9, 26, 76, 8, 171, 5, 49, 28, 44, 169, 162, 183, 130, 72, 28, 144, 179, 228, 2, 25, 26, 129, 186, 151, + 1, 75, 128, 169, 17, 178, 15, 57, 170, 16, 166, 16, 57, 8, 139, 162, 181, 1, 8, 152, 164, 181, 41, 81, 43, 10, 242, 145, 57, 139, 89, 8, 193, 18, 154, 32, 176, 10, 165, 129, 137, 147, 177, 134, 0, 25, 25, 201, 147, 227, 129, 72, 59, 185, 167, 128, 129, 160, 91, 25, 176, 130, 147, 145, 9, 160, 5, 202, 17, 16, 186, 136, 37, + 177, 56, 76, 42, 169, 186, 48, 9, 145, 57, 24, 128, 41, 169, 134, 137, 145, 147, 28, 41, 168, 131, 228, 32, 27, 9, 60, 129, 178, 64, 60, 45, 25, 9, 24, 152, 49, 31, 136, 57, 42, 0, 25, 12, 181, 18, 153, 57, 96, 169, 177, 132, 153, 123, 9, 152, 129, 177, 17, 74, 43, 24, 169, 128, 121, 137, 25, 1, 139, 96, 42, 10, 146, 178, 18, + 44, 29, 1, 161, 164, 146, 31, 137, 146, 177, 19, 1, 10, 26, 209, 165, 146, 43, 40, 138, 240, 130, 18, 144, 25, 40, 212, 1, 58, 11, 152, 196, 147, 10, 74, 26, 152, 225, 130, 146, 58, 60, 210, 145, 16, 148, 16, 185, 192, 18, 44, 42, 57, 199, 162, 1, 9, 87, 47, 186, 215, 231, 197, 179, 180, 195, 212, 164, 32, 59, 92, 126, 62, + 41, 59, 76, 59, 60, 168, 179, 213, 197, 163, 72, 44, 25, 74, 126, 127, 127, 79, 26, 177, 148, 90, 27, 225, 247, 165, 0, 152, 147, 123, 138, 211, 164, 72, 126, 127, 46, 210, 196, 163, 228, 215, 64, 11, 210, 180, 1, 8, 58, 153, 1, 224, 149, 57, 76, 27, 24, 76, 42, 43, 136, 128, 243, 179, 130, 106, 60, 42, 42, 92, 28, 243, 231, + 147, 24, 57, 44, 58, 94, 45, 8, 57, 139, 214, 148, 40, 77, 26, 9, 16, 10, 144, 64, 62, 43, 25, 123, 59, 138, 162, 48, 63, 26, 41, 92, 60, 43, 176, 3, 59, 232, 214, 164, 16, 75, 75, 76, 60, 153, 179, 33, 62, 26, 136, 40, 75, 169, 197, 163, 129, 57, 60, 59, 75, 138, 145, 64, 63, 138, 179, 1, 42, 136, 90, 43, 176, 214, 180, 1, 25, + 152, 195, 129, 129, 106, 76, 60, 137, 145, 178, 2, 25, 10, 228, 130, 57, 59, 44, 41, 154, 165, 105, 76, 44, 144, 16, 76, 26, 41, 76, 26, 152, 1, 58, 26, 9, 193, 165, 16, 92, 26, 41, 77, 59, 76, 76, 60, 26, 136, 161, 130, 152, 195, 163, 211, 146, 0, 57, 11, 211, 130, 8, 25, 40, 62, 153, 162, 17, 109, 60, 153, 146, 40, 76, 60, + 26, 160, 179, 211, 163, 32, 60, 42, 153, 179, 194, 199, 130, 24, 58, 43, 58, 27, 128, 161, 195, 129, 226, 196, 147, 90, 59, 75, 44, 136, 128, 145, 160, 148, 123, 59, 42, 26, 41, 26, 57, 27, 192, 215, 147, 57, 59, 27, 161, 145, 213, 130, 106, 76, 43, 9, 144, 162, 129, 177, 181, 130, 136, 194, 146, 40, 10, 129, 25, 210, 146, + 178, 197, 196, 179, 196, 130, 8, 41, 9, 144, 178, 130, 209, 182, 17, 92, 43, 176, 147, 144, 212, 130, 136, 0, 177, 130, 73, 62, 10, 161, 130, 91, 75, 59, 43, 57, 46, 25, 41, 77, 10, 177, 164, 16, 26, 136, 210, 197, 179, 130, 128, 57, 77, 43, 25, 75, 10, 227, 179, 180, 179, 146, 128, 57, 185, 183, 163, 145, 0, 8, 8, 10, 119, + 114, 120, 16, 210, 244, 60, 28, 41, 25, 152, 149, 56, 161, 35, 44, 89, 27, 24, 136, 24, 164, 211, 17, 233, 176, 136, 192, 129, 179, 17, 17, 25, 0, 10, 46, 160, 132, 49, 66, 24, 132, 177, 147, 193, 56, 72, 26, 29, 232, 168, 176, 12, 137, 41, 139, 147, 9, 1, 41, 15, 91, 136, 35, 148, 21, 18, 48, 40, 1, 168, 167, 144, 0, 42, 172, + 177, 204, 193, 155, 232, 152, 152, 26, 152, 41, 146, 17, 6, 4, 65, 34, 35, 135, 4, 16, 32, 9, 24, 186, 176, 0, 250, 153, 204, 186, 173, 154, 153, 177, 3, 65, 41, 34, 145, 134, 35, 65, 98, 49, 50, 50, 2, 33, 169, 138, 155, 175, 170, 172, 204, 192, 138, 234, 136, 155, 136, 10, 32, 18, 5, 52, 48, 24, 162, 17, 67, 54, 66, 51, 34, + 131, 184, 174, 234, 153, 10, 9, 40, 0, 152, 251, 168, 142, 154, 9, 16, 33, 49, 33, 128, 154, 170, 156, 34, 54, 54, 33, 68, 0, 1, 136, 201, 137, 26, 88, 48, 35, 99, 8, 152, 189, 189, 187, 155, 171, 16, 24, 130, 145, 188, 175, 203, 144, 49, 115, 67, 67, 50, 19, 2, 1, 0, 0, 130, 131, 1, 136, 206, 216, 188, 203, 204, 187, 187, + 156, 153, 0, 0, 51, 17, 34, 24, 112, 20, 69, 67, 67, 34, 19, 0, 136, 169, 185, 137, 186, 232, 185, 219, 201, 203, 187, 173, 170, 154, 153, 129, 131, 6, 2, 19, 49, 49, 21, 65, 19, 53, 51, 83, 34, 16, 168, 201, 154, 172, 156, 138, 0, 1, 24, 201, 233, 186, 204, 186, 171, 137, 3, 37, 48, 24, 128, 201, 202, 202, 129, 17, 48, 21, + 22, 20, 19, 19, 32, 16, 2, 66, 52, 68, 4, 3, 1, 203, 235, 188, 189, 186, 171, 153, 137, 153, 170, 219, 170, 140, 9, 17, 53, 115, 50, 52, 67, 51, 51, 51, 17, 130, 0, 145, 154, 169, 188, 236, 187, 190, 203, 187, 172, 171, 138, 136, 17, 33, 18, 2, 34, 98, 98, 50, 50, 52, 66, 34, 35, 2, 19, 24, 169, 203, 203, 188, 219, 169, 154, + 9, 137, 171, 204, 188, 203, 184, 136, 34, 83, 50, 33, 153, 184, 170, 170, 152, 40, 57, 19, 36, 50, 50, 18, 35, 17, 2, 49, 49, 66, 66, 66, 34, 17, 168, 233, 202, 202, 170, 171, 170, 186, 219, 203, 188, 188, 154, 138, 25, 33, 68, 52, 68, 67, 67, 36, 51, 36, 18, 17, 17, 136, 8, 170, 176, 202, 188, 206, 202, 171, 172, 186, 169, + 153, 8, 25, 144, 128, 1, 34, 68, 52, 68, 51, 52, 34, 49, 18, 34, 2, 144, 136, 155, 140, 187, 186, 186, 154, 154, 185, 185, 153, 9, 9, 0, 24, 0, 128, 144, 168, 169, 170, 154, 154, 153, 9, 8, 16, 8, 0, 144, 19, 35, 68, 51, 52, 67, 51, 66, 34, 50, 33, 1, 144, 185, 186, 172, 204, 187, 188, 173, 172, 186, 172, 186, 154, 138, 41, + 33, 52, 53, 83, 50, 51, 52, 52, 37, 34, 34, 18, 16, 144, 152, 154, 187, 219, 203, 188, 173, 186, 186, 186, 170, 154, 153, 138, 144, 16, 17, 67, 82, 50, 51, 21, 34, 19, 33, 2, 18, 33, 1, 8, 153, 169, 153, 153, 136, 128, 0, 136, 154, 153, 153, 8, 8, 1, 16, 0, 169, 170, 187, 171, 171, 154, 153, 153, 152, 153, 153, 0, 16, 51, 83, + 66, 50, 67, 50, 51, 67, 51, 52, 35, 18, 136, 186, 219, 187, 189, 186, 171, 187, 173, 187, 188, 187, 203, 138, 9, 16, 33, 50, 52, 53, 67, 67, 147, 8, 128, 128, 128, 128, 128, 128, 128, 128, 0, 240, 255, 55, 232, 23, 220, 0, 148, 1, 9, 18, 148, 10, 189, 32, 163, 62, 160, 5, 137, 12, 149, 42, 153, 144, 34, 42, 8, 1, 138, 181, + 45, 136, 18, 144, 105, 138, 1, 160, 14, 128, 132, 145, 186, 37, 138, 41, 192, 48, 145, 46, 160, 33, 44, 24, 225, 16, 13, 132, 136, 137, 16, 148, 25, 170, 194, 82, 152, 136, 91, 24, 42, 169, 33, 233, 131, 179, 24, 185, 149, 16, 57, 172, 164, 18, 10, 211, 160, 147, 211, 33, 138, 243, 129, 16, 41, 193, 0, 43, 132, 155, 73, + 58, 145, 244, 145, 43, 35, 9, 171, 16, 110, 25, 8, 28, 74, 162, 128, 26, 27, 82, 45, 136, 153, 18, 8, 136, 8 }; diff --git a/sound/softsynth/fmtowns_pc98/towns_pc98_fmsynth.h b/sound/softsynth/fmtowns_pc98/towns_pc98_fmsynth.h index fbe85f5b24..3a40d6aed4 100644 --- a/sound/softsynth/fmtowns_pc98/towns_pc98_fmsynth.h +++ b/sound/softsynth/fmtowns_pc98/towns_pc98_fmsynth.h @@ -44,8 +44,8 @@ enum EnvelopeState { class TownsPC98_FmSynthOperator { public: TownsPC98_FmSynthOperator(const uint32 timerbase, const uint8 *rateTable, - const uint8 *shiftTable, const uint8 *attackDecayTable, const uint32 *frqTable, - const uint32 *sineTable, const int32 *tlevelOut, const int32 *detuneTable); + const uint8 *shiftTable, const uint8 *attackDecayTable, const uint32 *frqTable, + const uint32 *sineTable, const int32 *tlevelOut, const int32 *detuneTable); ~TownsPC98_FmSynthOperator() {} void keyOn(); @@ -55,17 +55,40 @@ public: void recalculateRates(); void generateOutput(int32 phasebuf, int32 *feedbuf, int32 &out); - void feedbackLevel(int32 level) {_feedbackLevel = level ? level + 6 : 0; } - void detune(int value) { _detn = &_detnTbl[value << 5]; } - void multiple(uint32 value) { _multiple = value ? (value << 1) : 1; } - void attackRate(uint32 value) { _specifiedAttackRate = value; } + void feedbackLevel(int32 level) { + _feedbackLevel = level ? level + 6 : 0; + } + void detune(int value) { + _detn = &_detnTbl[value << 5]; + } + void multiple(uint32 value) { + _multiple = value ? (value << 1) : 1; + } + void attackRate(uint32 value) { + _specifiedAttackRate = value; + } bool scaleRate(uint8 value); - void decayRate(uint32 value) { _specifiedDecayRate = value; recalculateRates(); } - void sustainRate(uint32 value) { _specifiedSustainRate = value; recalculateRates(); } - void sustainLevel(uint32 value) { _sustainLevel = (value == 0x0f) ? 0x3e0 : value << 5; } - void releaseRate(uint32 value) { _specifiedReleaseRate = value; recalculateRates(); } - void totalLevel(uint32 value) { _totalLevel = value << 3; } - void ampModulation(bool enable) { _ampMod = enable; } + void decayRate(uint32 value) { + _specifiedDecayRate = value; + recalculateRates(); + } + void sustainRate(uint32 value) { + _specifiedSustainRate = value; + recalculateRates(); + } + void sustainLevel(uint32 value) { + _sustainLevel = (value == 0x0f) ? 0x3e0 : value << 5; + } + void releaseRate(uint32 value) { + _specifiedReleaseRate = value; + recalculateRates(); + } + void totalLevel(uint32 value) { + _totalLevel = value << 3; + } + void ampModulation(bool enable) { + _ampMod = enable; + } void reset(); protected: @@ -126,16 +149,24 @@ public: // AudioStream interface int readBuffer(int16 *buffer, const int numSamples); - bool isStereo() const { return true; } - bool endOfData() const { return false; } - int getRate() const { return _mixer->getOutputRate(); } + bool isStereo() const { + return true; + } + bool endOfData() const { + return false; + } + int getRate() const { + return _mixer->getOutputRate(); + } protected: // Implement this in your inherited class if your driver generates // additional output that has to be inserted into the buffer. virtual void nextTickEx(int32 *buffer, uint32 bufferSize) {} - void toggleRegProtection(bool prot) { _regProtectionFlag = prot; } + void toggleRegProtection(bool prot) { + _regProtectionFlag = prot; + } uint8 readSSGStatus(); virtual void timerCallbackA() = 0; @@ -169,8 +200,12 @@ private: delete opr[i]; } - void ampModSensitivity(uint32 value) { ampModSvty = (1 << (3 - value)) - (((value >> 1) & 1) | (value & 1)); } - void frqModSensitivity(uint32 value) { frqModSvty = value << 5; } + void ampModSensitivity(uint32 value) { + ampModSvty = (1 << (3 - value)) - (((value >> 1) & 1) | (value & 1)); + } + void frqModSensitivity(uint32 value) { + frqModSvty = value << 5; + } uint16 frqTemp; bool enableLeft; -- cgit v1.2.3 From 7f1f4c8b07973782a0a56ff530e11cfb631a6a75 Mon Sep 17 00:00:00 2001 From: Johannes Schickel Date: Mon, 2 Aug 2010 19:36:49 +0000 Subject: TOWNS/PC98: Replaced some tabs with spaces. svn-id: r51654 --- sound/softsynth/fmtowns_pc98/towns_audio.cpp | 4 +-- sound/softsynth/fmtowns_pc98/towns_euphony.cpp | 4 +-- sound/softsynth/fmtowns_pc98/towns_pc98_driver.cpp | 42 +++++++++++----------- .../softsynth/fmtowns_pc98/towns_pc98_fmsynth.cpp | 16 ++++----- 4 files changed, 33 insertions(+), 33 deletions(-) (limited to 'sound/softsynth') diff --git a/sound/softsynth/fmtowns_pc98/towns_audio.cpp b/sound/softsynth/fmtowns_pc98/towns_audio.cpp index 1207cb121f..d3484ce548 100644 --- a/sound/softsynth/fmtowns_pc98/towns_audio.cpp +++ b/sound/softsynth/fmtowns_pc98/towns_audio.cpp @@ -779,12 +779,12 @@ int TownsAudioInterface::fmKeyOn(int chan, int note, int velo) { v |= 4; for (uint8 reg = 0x80 + chan; reg < 0x90; reg += 4) - writeReg(part, reg, _fmSaveReg[part][reg] | 0x0f); + writeReg(part, reg, _fmSaveReg[part][reg] | 0x0f); writeReg(0, 0x28, v); for (uint8 reg = 0x80 + chan; reg < 0x90; reg += 4) - writeReg(part, reg, _fmSaveReg[part][reg]); + writeReg(part, reg, _fmSaveReg[part][reg]); bufferedWriteReg(0, 0x28, v | 0xf0); diff --git a/sound/softsynth/fmtowns_pc98/towns_euphony.cpp b/sound/softsynth/fmtowns_pc98/towns_euphony.cpp index db25846b47..4fe645e2fc 100644 --- a/sound/softsynth/fmtowns_pc98/towns_euphony.cpp +++ b/sound/softsynth/fmtowns_pc98/towns_euphony.cpp @@ -109,7 +109,7 @@ void TownsEuphonyDriver::reset() { if (_tempoControlMode == 1) { //if (///) - // return; + // return; setTempoIntern(_defaultTempo); } else { setTempoIntern(_defaultTempo); @@ -415,7 +415,7 @@ void TownsEuphonyDriver::updateCheckEot() { } bool TownsEuphonyDriver::parseNext() { -#define OPC(x) &TownsEuphonyDriver::evt##x +#define OPC(x) &TownsEuphonyDriver::evt##x static const EuphonyOpcode opcodes[] = { OPC(NotImpl), OPC(SetupNote), diff --git a/sound/softsynth/fmtowns_pc98/towns_pc98_driver.cpp b/sound/softsynth/fmtowns_pc98/towns_pc98_driver.cpp index 2853f616a3..82d0bd0438 100644 --- a/sound/softsynth/fmtowns_pc98/towns_pc98_driver.cpp +++ b/sound/softsynth/fmtowns_pc98/towns_pc98_driver.cpp @@ -34,13 +34,13 @@ public: 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_RECALCFREQ = 0x01, + CHS_KEYOFF = 0x02, + CHS_SSGOFF = 0x04, + CHS_VBROFF = 0x08, + CHS_ALLOFF = 0x0f, + CHS_PROTECT = 0x40, + CHS_EOT = 0x80 } ChannelState; virtual void loadData(uint8 *data); @@ -197,7 +197,7 @@ TownsPC98_MusicChannel::~TownsPC98_MusicChannel() { } void TownsPC98_MusicChannel::init() { -#define Control(x) &TownsPC98_MusicChannel::control_##x +#define Control(x) &TownsPC98_MusicChannel::control_##x static const ControlEventFunc ctrlEvents[] = { Control(f0_setPatch), Control(f1_presetOutputLevel), @@ -589,7 +589,7 @@ TownsPC98_MusicChannelSSG::TownsPC98_MusicChannelSSG(TownsPC98_AudioDriver *driv void TownsPC98_MusicChannelSSG::init() { _algorithm = 0x80; -#define Control(x) &TownsPC98_MusicChannelSSG::control_##x +#define Control(x) &TownsPC98_MusicChannelSSG::control_##x static const ControlEventFunc ctrlEventsSSG[] = { Control(f0_setPatch), Control(f1_setTotalLevel), @@ -936,7 +936,7 @@ TownsPC98_MusicChannelPCM::TownsPC98_MusicChannelPCM(TownsPC98_AudioDriver *driv void TownsPC98_MusicChannelPCM::init() { _algorithm = 0x80; -#define Control(x) &TownsPC98_MusicChannelPCM::control_##x +#define Control(x) &TownsPC98_MusicChannelPCM::control_##x static const ControlEventFunc ctrlEventsPCM[] = { Control(dummy), Control(f1_prcStart), @@ -1328,7 +1328,7 @@ void TownsPC98_AudioDriver::startSoundEffect() { } const uint8 TownsPC98_AudioDriver::_drvTables[] = { - // channel presets + // channel presets 0x00, 0x80, 0x00, 0x00, 0x00, 0x01, 0x01, 0x80, 0x01, 0x01, 0x00, 0x02, 0x02, 0x80, 0x02, 0x02, 0x00, 0x04, @@ -1336,29 +1336,29 @@ const uint8 TownsPC98_AudioDriver::_drvTables[] = { 0x01, 0x80, 0x04, 0x05, 0x01, 0x10, 0x02, 0x80, 0x05, 0x06, 0x01, 0x20, - // control event size - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x04, 0x05, + // control event size + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x04, 0x05, 0x02, 0x06, 0x02, 0x00, 0x00, 0x02, 0x00, 0x02, - // fmt level presets - 0x54, 0x50, 0x4C, 0x48, 0x44, 0x40, 0x3C, 0x38, + // fmt level presets + 0x54, 0x50, 0x4C, 0x48, 0x44, 0x40, 0x3C, 0x38, 0x34, 0x30, 0x2C, 0x28, 0x24, 0x20, 0x1C, 0x18, - 0x14, 0x10, 0x0C, 0x08, 0x04, 0x90, 0x90, 0x90, + 0x14, 0x10, 0x0C, 0x08, 0x04, 0x90, 0x90, 0x90, - // carriers - 0x08, 0x08, 0x08, 0x08, 0x0C, 0x0E, 0x0E, 0x0F, + // carriers + 0x08, 0x08, 0x08, 0x08, 0x0C, 0x0E, 0x0E, 0x0F, - // pc98 level presets + // pc98 level presets 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 + // 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 + // 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, diff --git a/sound/softsynth/fmtowns_pc98/towns_pc98_fmsynth.cpp b/sound/softsynth/fmtowns_pc98/towns_pc98_fmsynth.cpp index c7cd83560d..65014f6201 100644 --- a/sound/softsynth/fmtowns_pc98/towns_pc98_fmsynth.cpp +++ b/sound/softsynth/fmtowns_pc98/towns_pc98_fmsynth.cpp @@ -32,7 +32,7 @@ TownsPC98_FmSynthOperator::TownsPC98_FmSynthOperator(const uint32 timerbase, con _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), - _phase(0), _state(kEnvReady),_ playing(false), _timer(0), _keyScale1(0), + _phase(0), _state(kEnvReady), _playing(false), _timer(0), _keyScale1(0), _keyScale2(0), _currentLevel(1023), _ampMod(false), _tickCount(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; @@ -1261,7 +1261,7 @@ void TownsPC98_FmSynth::nextTick(int32 *buffer, uint32 bufferSize) { } const uint32 TownsPC98_FmSynth::_adtStat[] = { - 0x00010001, 0x00010001, 0x00010001, 0x01010001, + 0x00010001, 0x00010001, 0x00010001, 0x01010001, 0x00010101, 0x00010101, 0x00010101, 0x01010101, 0x01010101, 0x01010101, 0x01010102, 0x01010102, 0x01020102, 0x01020102, 0x01020202, 0x01020202, @@ -1275,14 +1275,14 @@ const uint32 TownsPC98_FmSynth::_adtStat[] = { const uint8 TownsPC98_FmSynth::_detSrc[] = { 0x02, 0x02, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0x04, 0x04, 0x04, 0x05, 0x05, 0x06, 0x06, 0x07, - 0x08, 0x08, 0x08, 0x08, 0x01, 0x01, 0x01, 0x01, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, + 0x08, 0x08, 0x08, 0x08, 0x01, 0x01, 0x01, 0x01, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0x04, 0x04, 0x04, 0x05, 0x05, 0x06, 0x06, 0x07, - 0x08, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, - 0x10, 0x10, 0x10, 0x10, 0x02, 0x02, 0x02, 0x02, + 0x08, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, + 0x10, 0x10, 0x10, 0x10, 0x02, 0x02, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0x04, 0x04, 0x04, 0x05, - 0x05, 0x06, 0x06, 0x07, 0x08, 0x08, 0x09, 0x0a, - 0x0b, 0x0c, 0x0d, 0x0e, 0x10, 0x11, 0x13, 0x14, + 0x05, 0x06, 0x06, 0x07, 0x08, 0x08, 0x09, 0x0a, + 0x0b, 0x0c, 0x0d, 0x0e, 0x10, 0x11, 0x13, 0x14, 0x16, 0x16, 0x16, 0x16 }; -- cgit v1.2.3 From 20d6173ee060d73202945dce9a142943491b085c Mon Sep 17 00:00:00 2001 From: Florian Kagerer Date: Mon, 2 Aug 2010 20:17:05 +0000 Subject: TOWNS AUDIO: fix typo svn-id: r51655 --- sound/softsynth/fmtowns_pc98/towns_audio.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound/softsynth') diff --git a/sound/softsynth/fmtowns_pc98/towns_audio.cpp b/sound/softsynth/fmtowns_pc98/towns_audio.cpp index d3484ce548..b3d37dbcd6 100644 --- a/sound/softsynth/fmtowns_pc98/towns_audio.cpp +++ b/sound/softsynth/fmtowns_pc98/towns_audio.cpp @@ -572,7 +572,7 @@ int TownsAudioInterface::intf_pcmPlayEffect(va_list &args) { TownsAudio_WaveTable w; w.readHeader(data); - if (!w.size < (w.loopStart + w.loopLen)) + if (w.size < (w.loopStart + w.loopLen)) return 13; if (!w.size) -- cgit v1.2.3 From 39846310d79e75faf55482a239ec5ca8eaf34c2b Mon Sep 17 00:00:00 2001 From: Max Horn Date: Tue, 3 Aug 2010 00:02:46 +0000 Subject: SOUND: Constify waveform table; slightly simplify code svn-id: r51671 --- sound/softsynth/sid.cpp | 13 ++++--------- sound/softsynth/sid.h | 13 ++++--------- sound/softsynth/wave6581.cpp | 15 +++++---------- 3 files changed, 13 insertions(+), 28 deletions(-) (limited to 'sound/softsynth') diff --git a/sound/softsynth/sid.cpp b/sound/softsynth/sid.cpp index d600ac28f5..e925f4a447 100644 --- a/sound/softsynth/sid.cpp +++ b/sound/softsynth/sid.cpp @@ -46,11 +46,6 @@ const int SID::FIXP_MASK = 0xffff; WaveformGenerator::WaveformGenerator() { sync_source = this; - wave__ST = wave6581__ST; - wave_P_T = wave6581_P_T; - wave_PS_ = wave6581_PS_; - wave_PST = wave6581_PST; - reset(); } @@ -226,19 +221,19 @@ RESID_INLINE reg12 WaveformGenerator::outputN___() { // Combined waveforms: RESID_INLINE reg12 WaveformGenerator::output__ST() { - return wave__ST[output__S_()] << 4; + return wave6581__ST[output__S_()] << 4; } RESID_INLINE reg12 WaveformGenerator::output_P_T() { - return (wave_P_T[output___T() >> 1] << 4) & output_P__(); + return (wave6581_P_T[output___T() >> 1] << 4) & output_P__(); } RESID_INLINE reg12 WaveformGenerator::output_PS_() { - return (wave_PS_[output__S_()] << 4) & output_P__(); + return (wave6581_PS_[output__S_()] << 4) & output_P__(); } RESID_INLINE reg12 WaveformGenerator::output_PST() { - return (wave_PST[output__S_()] << 4) & output_P__(); + return (wave6581_PST[output__S_()] << 4) & output_P__(); } // Combined waveforms including noise: diff --git a/sound/softsynth/sid.h b/sound/softsynth/sid.h index d57ec73bad..c78f538441 100644 --- a/sound/softsynth/sid.h +++ b/sound/softsynth/sid.h @@ -118,15 +118,10 @@ protected: reg12 outputNPST(); // Sample data for combinations of waveforms. - static reg8 wave6581__ST[]; - static reg8 wave6581_P_T[]; - static reg8 wave6581_PS_[]; - static reg8 wave6581_PST[]; - - reg8* wave__ST; - reg8* wave_P_T; - reg8* wave_PS_; - reg8* wave_PST; + static const reg8 wave6581__ST[]; + static const reg8 wave6581_P_T[]; + static const reg8 wave6581_PS_[]; + static const reg8 wave6581_PST[]; friend class Voice; friend class SID; diff --git a/sound/softsynth/wave6581.cpp b/sound/softsynth/wave6581.cpp index 29998dcd0a..d1ddad1623 100644 --- a/sound/softsynth/wave6581.cpp +++ b/sound/softsynth/wave6581.cpp @@ -32,11 +32,9 @@ #include "sid.h" -namespace Resid -{ +namespace Resid { -reg8 WaveformGenerator::wave6581__ST[] = -{ +const reg8 WaveformGenerator::wave6581__ST[] = { /* 0x000: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x008: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x010: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -551,8 +549,7 @@ reg8 WaveformGenerator::wave6581__ST[] = /* 0xff8: */ 0x3e, 0x3e, 0x3f, 0x3f, 0x7f, 0x7f, 0x7f, 0x7f, }; -reg8 WaveformGenerator::wave6581_P_T[] = -{ +const reg8 WaveformGenerator::wave6581_P_T[] = { /* 0x000: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x008: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x010: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -1067,8 +1064,7 @@ reg8 WaveformGenerator::wave6581_P_T[] = /* 0xff8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; -reg8 WaveformGenerator::wave6581_PS_[] = -{ +const reg8 WaveformGenerator::wave6581_PS_[] = { /* 0x000: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x008: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x010: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -1583,8 +1579,7 @@ reg8 WaveformGenerator::wave6581_PS_[] = /* 0xff8: */ 0x7e, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, }; -reg8 WaveformGenerator::wave6581_PST[] = -{ +const reg8 WaveformGenerator::wave6581_PST[] = { /* 0x000: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x008: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x010: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -- cgit v1.2.3 From 8e08c432da73e014c7759f2f18019ddc3870771c Mon Sep 17 00:00:00 2001 From: Florian Kagerer Date: Tue, 3 Aug 2010 13:12:42 +0000 Subject: FMTOWNS AUDIO: minor layout change svn-id: r51691 --- sound/softsynth/fmtowns_pc98/towns_audio.cpp | 4 +- sound/softsynth/fmtowns_pc98/towns_audio.h | 2 +- .../softsynth/fmtowns_pc98/towns_pc98_fmsynth.cpp | 99 ++++++++++++++++++++ sound/softsynth/fmtowns_pc98/towns_pc98_fmsynth.h | 102 +-------------------- 4 files changed, 105 insertions(+), 102 deletions(-) (limited to 'sound/softsynth') diff --git a/sound/softsynth/fmtowns_pc98/towns_audio.cpp b/sound/softsynth/fmtowns_pc98/towns_audio.cpp index b3d37dbcd6..3d3427fcfb 100644 --- a/sound/softsynth/fmtowns_pc98/towns_audio.cpp +++ b/sound/softsynth/fmtowns_pc98/towns_audio.cpp @@ -129,7 +129,7 @@ TownsAudioInterface::TownsAudioInterface(Audio::Mixer *mixer, TownsAudioInterfac INTCB(notImpl), INTCB(writeReg), INTCB(notImpl), - INTCB(bufferedWriteReg), + INTCB(writeRegBuffer), // 20 INTCB(readRegBuffer), INTCB(setTimerA), @@ -399,7 +399,7 @@ int TownsAudioInterface::intf_writeReg(va_list &args) { return 0; } -int TownsAudioInterface::intf_bufferedWriteReg(va_list &args) { +int TownsAudioInterface::intf_writeRegBuffer(va_list &args) { int part = va_arg(args, int) ? 1 : 0; int reg = va_arg(args, int); int val = va_arg(args, int); diff --git a/sound/softsynth/fmtowns_pc98/towns_audio.h b/sound/softsynth/fmtowns_pc98/towns_audio.h index 22784699bc..93a9198fe4 100644 --- a/sound/softsynth/fmtowns_pc98/towns_audio.h +++ b/sound/softsynth/fmtowns_pc98/towns_audio.h @@ -65,7 +65,7 @@ private: int intf_setLevel(va_list &args); int intf_chanOff(va_list &args); int intf_writeReg(va_list &args); - int intf_bufferedWriteReg(va_list &args); + int intf_writeRegBuffer(va_list &args); int intf_readRegBuffer(va_list &args); int intf_setTimerA(va_list &args); int intf_setTimerB(va_list &args); diff --git a/sound/softsynth/fmtowns_pc98/towns_pc98_fmsynth.cpp b/sound/softsynth/fmtowns_pc98/towns_pc98_fmsynth.cpp index 65014f6201..7a91cb81b9 100644 --- a/sound/softsynth/fmtowns_pc98/towns_pc98_fmsynth.cpp +++ b/sound/softsynth/fmtowns_pc98/towns_pc98_fmsynth.cpp @@ -26,6 +26,96 @@ #include "sound/softsynth/fmtowns_pc98/towns_pc98_fmsynth.h" #include "common/endian.h" +class TownsPC98_FmSynthOperator { +public: + TownsPC98_FmSynthOperator(const uint32 timerbase, const uint8 *rateTable, + const uint8 *shiftTable, const uint8 *attackDecayTable, const uint32 *frqTable, + const uint32 *sineTable, const int32 *tlevelOut, const int32 *detuneTable); + ~TownsPC98_FmSynthOperator() {} + + void keyOn(); + void keyOff(); + void frequency(int freq); + void updatePhaseIncrement(); + void recalculateRates(); + void generateOutput(int32 phasebuf, int32 *feedbuf, int32 &out); + + void feedbackLevel(int32 level) { + _feedbackLevel = level ? level + 6 : 0; + } + void detune(int value) { + _detn = &_detnTbl[value << 5]; + } + void multiple(uint32 value) { + _multiple = value ? (value << 1) : 1; + } + void attackRate(uint32 value) { + _specifiedAttackRate = value; + } + bool scaleRate(uint8 value); + void decayRate(uint32 value) { + _specifiedDecayRate = value; + recalculateRates(); + } + void sustainRate(uint32 value) { + _specifiedSustainRate = value; + recalculateRates(); + } + void sustainLevel(uint32 value) { + _sustainLevel = (value == 0x0f) ? 0x3e0 : value << 5; + } + void releaseRate(uint32 value) { + _specifiedReleaseRate = value; + recalculateRates(); + } + void totalLevel(uint32 value) { + _totalLevel = value << 3; + } + void ampModulation(bool enable) { + _ampMod = enable; + } + void reset(); + +protected: + EnvelopeState _state; + bool _playing; + uint32 _feedbackLevel; + uint32 _multiple; + uint32 _totalLevel; + uint8 _keyScale1; + uint8 _keyScale2; + uint32 _specifiedAttackRate; + uint32 _specifiedDecayRate; + uint32 _specifiedSustainRate; + uint32 _specifiedReleaseRate; + uint32 _tickCount; + uint32 _sustainLevel; + + bool _ampMod; + uint32 _frequency; + uint8 _kcode; + uint32 _phase; + uint32 _phaseIncrement; + const int32 *_detn; + + const uint8 *_rateTbl; + const uint8 *_rshiftTbl; + const uint8 *_adTbl; + const uint32 *_fTbl; + const uint32 *_sinTbl; + const int32 *_tLvlTbl; + const int32 *_detnTbl; + + const uint32 _tickLength; + uint32 _timer; + int32 _currentLevel; + + struct EvpState { + uint8 rate; + uint8 shift; + } fs_a, fs_d, fs_s, fs_r; +}; + TownsPC98_FmSynthOperator::TownsPC98_FmSynthOperator(const uint32 timerbase, const uint8 *rateTable, const uint8 *shiftTable, const uint8 *attackDecayTable, const uint32 *frqTable, const uint32 *sineTable, const int32 *tlevelOut, const int32 *detuneTable) : @@ -1409,3 +1499,12 @@ const uint8 TownsPC98_FmSynth::_percussionData[] = { 45, 136, 18, 144, 105, 138, 1, 160, 14, 128, 132, 145, 186, 37, 138, 41, 192, 48, 145, 46, 160, 33, 44, 24, 225, 16, 13, 132, 136, 137, 16, 148, 25, 170, 194, 82, 152, 136, 91, 24, 42, 169, 33, 233, 131, 179, 24, 185, 149, 16, 57, 172, 164, 18, 10, 211, 160, 147, 211, 33, 138, 243, 129, 16, 41, 193, 0, 43, 132, 155, 73, 58, 145, 244, 145, 43, 35, 9, 171, 16, 110, 25, 8, 28, 74, 162, 128, 26, 27, 82, 45, 136, 153, 18, 8, 136, 8 }; + +TownsPC98_FmSynth::ChanInternal::ChanInternal() { + memset(this, 0, sizeof(ChanInternal)); +} + +TownsPC98_FmSynth::ChanInternal::~ChanInternal() { + for (uint i = 0; i < ARRAYSIZE(opr); ++i) + delete opr[i]; +} diff --git a/sound/softsynth/fmtowns_pc98/towns_pc98_fmsynth.h b/sound/softsynth/fmtowns_pc98/towns_pc98_fmsynth.h index 3a40d6aed4..34ee2ce7b8 100644 --- a/sound/softsynth/fmtowns_pc98/towns_pc98_fmsynth.h +++ b/sound/softsynth/fmtowns_pc98/towns_pc98_fmsynth.h @@ -30,6 +30,7 @@ #include "sound/mixer.h" #include "common/list.h" +class TownsPC98_FmSynthOperator; class TownsPC98_FmSynthSquareSineSource; class TownsPC98_FmSynthPercussionSource; @@ -41,96 +42,6 @@ enum EnvelopeState { kEnvReleasing }; -class TownsPC98_FmSynthOperator { -public: - TownsPC98_FmSynthOperator(const uint32 timerbase, const uint8 *rateTable, - const uint8 *shiftTable, const uint8 *attackDecayTable, const uint32 *frqTable, - const uint32 *sineTable, const int32 *tlevelOut, const int32 *detuneTable); - ~TownsPC98_FmSynthOperator() {} - - void keyOn(); - void keyOff(); - void frequency(int freq); - void updatePhaseIncrement(); - void recalculateRates(); - void generateOutput(int32 phasebuf, int32 *feedbuf, int32 &out); - - void feedbackLevel(int32 level) { - _feedbackLevel = level ? level + 6 : 0; - } - void detune(int value) { - _detn = &_detnTbl[value << 5]; - } - void multiple(uint32 value) { - _multiple = value ? (value << 1) : 1; - } - void attackRate(uint32 value) { - _specifiedAttackRate = value; - } - bool scaleRate(uint8 value); - void decayRate(uint32 value) { - _specifiedDecayRate = value; - recalculateRates(); - } - void sustainRate(uint32 value) { - _specifiedSustainRate = value; - recalculateRates(); - } - void sustainLevel(uint32 value) { - _sustainLevel = (value == 0x0f) ? 0x3e0 : value << 5; - } - void releaseRate(uint32 value) { - _specifiedReleaseRate = value; - recalculateRates(); - } - void totalLevel(uint32 value) { - _totalLevel = value << 3; - } - void ampModulation(bool enable) { - _ampMod = enable; - } - void reset(); - -protected: - EnvelopeState _state; - bool _playing; - uint32 _feedbackLevel; - uint32 _multiple; - uint32 _totalLevel; - uint8 _keyScale1; - uint8 _keyScale2; - uint32 _specifiedAttackRate; - uint32 _specifiedDecayRate; - uint32 _specifiedSustainRate; - uint32 _specifiedReleaseRate; - uint32 _tickCount; - uint32 _sustainLevel; - - bool _ampMod; - uint32 _frequency; - uint8 _kcode; - uint32 _phase; - uint32 _phaseIncrement; - const int32 *_detn; - - const uint8 *_rateTbl; - const uint8 *_rshiftTbl; - const uint8 *_adTbl; - const uint32 *_fTbl; - const uint32 *_sinTbl; - const int32 *_tLvlTbl; - const int32 *_detnTbl; - - const uint32 _tickLength; - uint32 _timer; - int32 _currentLevel; - - struct EvpState { - uint8 rate; - uint8 shift; - } fs_a, fs_d, fs_s, fs_r; -}; - class TownsPC98_FmSynth : public Audio::AudioStream { public: enum EmuType { @@ -191,14 +102,8 @@ private: void generateOutput(int32 &leftSample, int32 &rightSample, int32 *del, int32 *feed); struct ChanInternal { - ChanInternal() { - memset(this, 0, sizeof(ChanInternal)); - } - - ~ChanInternal() { - for (uint i = 0; i < ARRAYSIZE(opr); ++i) - delete opr[i]; - } + ChanInternal(); + ~ChanInternal(); void ampModSensitivity(uint32 value) { ampModSvty = (1 << (3 - value)) - (((value >> 1) & 1) | (value & 1)); @@ -217,7 +122,6 @@ private: uint32 ampModSvty; uint32 frqModSvty; - TownsPC98_FmSynthOperator *opr[4]; }; -- cgit v1.2.3 From 5962b0bbe27b8d32dbbad1e8c3d36906dc391dd2 Mon Sep 17 00:00:00 2001 From: Florian Kagerer Date: Tue, 3 Aug 2010 14:58:01 +0000 Subject: KYRA/TOWNS: implement music/sfx volume control via GUI/GMM svn-id: r51695 --- sound/softsynth/fmtowns_pc98/towns_audio.cpp | 25 +++++++++++++++++++++- sound/softsynth/fmtowns_pc98/towns_audio.h | 10 +++++++++ sound/softsynth/fmtowns_pc98/towns_euphony.cpp | 21 +++++++++++++++++- sound/softsynth/fmtowns_pc98/towns_euphony.h | 5 ++++- .../softsynth/fmtowns_pc98/towns_pc98_fmsynth.cpp | 8 +++---- 5 files changed, 62 insertions(+), 7 deletions(-) (limited to 'sound/softsynth') diff --git a/sound/softsynth/fmtowns_pc98/towns_audio.cpp b/sound/softsynth/fmtowns_pc98/towns_audio.cpp index 3d3427fcfb..683f574f65 100644 --- a/sound/softsynth/fmtowns_pc98/towns_audio.cpp +++ b/sound/softsynth/fmtowns_pc98/towns_audio.cpp @@ -101,7 +101,8 @@ private: TownsAudioInterface::TownsAudioInterface(Audio::Mixer *mixer, TownsAudioInterfacePluginDriver *driver) : TownsPC98_FmSynth(mixer, kTypeTowns), _fmInstruments(0), _pcmInstruments(0), _pcmChan(0), _waveTables(0), _waveTablesTotalDataSize(0), - _baserate(55125.0f / (float)mixer->getOutputRate()), _tickLength(0), _timer(0), _drv(driver), _ready(false) { + _baserate(55125.0f / (float)mixer->getOutputRate()), _tickLength(0), _timer(0), _drv(driver), + _musicVolume(256), _sfxVolume(256), _pcmSfxChanMask(0), _ready(false) { #define INTCB(x) &TownsAudioInterface::intf_##x static const TownsAudioIntfCallback intfCb[] = { @@ -247,6 +248,8 @@ bool TownsAudioInterface::init() { _timer = 0; + setVolumeChannelMasks(-1, 0); + callback(0); _ready = true; @@ -269,6 +272,22 @@ int TownsAudioInterface::callback(int command, ...) { return res; } +void TownsAudioInterface::setMusicVolume(int volume) { + _musicVolume = CLIP(volume, 0, Audio::Mixer::kMaxMixerVolume); + setVolumeIntern(_musicVolume, _sfxVolume); +} + +void TownsAudioInterface::setSoundEffectVolume(int volume) { + _sfxVolume = CLIP(volume, 0, Audio::Mixer::kMaxMixerVolume); + setVolumeIntern(_musicVolume, _sfxVolume); +} + +void TownsAudioInterface::setSoundEffectChanMask(uint32 mask) { + _pcmSfxChanMask = mask >> 6; + mask &= 0x3f; + setVolumeChannelMasks(~mask, mask); +} + void TownsAudioInterface::nextTickEx(int32 *buffer, uint32 bufferSize) { if (!_ready) return; @@ -302,6 +321,10 @@ void TownsAudioInterface::nextTickEx(int32 *buffer, uint32 bufferSize) { for (int ii = 0; ii < 8; ii++) { if (_pcmChanOut & _chanFlags[ii]) { int32 o = _pcmChan[ii].data[_pcmChan[ii].pos >> 11] * _pcmChan[ii].velo; + if ((1 << ii) & (~_pcmSfxChanMask)) + o = (o * _musicVolume) / Audio::Mixer::kMaxMixerVolume; + if ((1 << ii) & _pcmSfxChanMask) + o = (o * _sfxVolume) / Audio::Mixer::kMaxMixerVolume; if (_pcmChan[ii].panLeft) finOutL += ((o * _pcmChan[ii].panLeft) >> 3); if (_pcmChan[ii].panRight) diff --git a/sound/softsynth/fmtowns_pc98/towns_audio.h b/sound/softsynth/fmtowns_pc98/towns_audio.h index 93a9198fe4..707c9e6bd4 100644 --- a/sound/softsynth/fmtowns_pc98/towns_audio.h +++ b/sound/softsynth/fmtowns_pc98/towns_audio.h @@ -46,6 +46,12 @@ public: int callback(int command, ...); + 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 8 bits are pcm channels. + void setSoundEffectChanMask(uint32 mask); + private: void nextTickEx(int32 *buffer, uint32 bufferSize); @@ -148,6 +154,10 @@ private: uint32 _tickLength; uint32 _timer; + uint16 _musicVolume; + uint16 _sfxVolume; + uint32 _pcmSfxChanMask; + TownsAudioInterfacePluginDriver *_drv; bool _ready; diff --git a/sound/softsynth/fmtowns_pc98/towns_euphony.cpp b/sound/softsynth/fmtowns_pc98/towns_euphony.cpp index 4fe645e2fc..13120df17a 100644 --- a/sound/softsynth/fmtowns_pc98/towns_euphony.cpp +++ b/sound/softsynth/fmtowns_pc98/towns_euphony.cpp @@ -130,8 +130,19 @@ void TownsEuphonyDriver::unloadWaveTable(int id) { _intf->callback(35, id); } -void TownsEuphonyDriver::reserveSfxChannels(int num) { +void TownsEuphonyDriver::reserveSoundEffectChannels(int num) { _intf->callback(33, num); + uint32 volMask = 0; + + if (num > 8) + return; + + for (uint32 v = 1 << 13; num; num--) { + volMask |= v; + v >>= 1; + } + + _intf->setSoundEffectChanMask(volMask); } int TownsEuphonyDriver::setMusicTempo(int tempo) { @@ -289,6 +300,14 @@ void TownsEuphonyDriver::timerCallback(int timerId) { } } +void TownsEuphonyDriver::setMusicVolume(int volume) { + _intf->setMusicVolume(volume); +} + +void TownsEuphonyDriver::setSoundEffectVolume(int volume) { + _intf->setSoundEffectVolume(volume); +} + void TownsEuphonyDriver::resetTables() { memset(_tEnable, 0xff, 32); memset(_tMode, 0xff, 16); diff --git a/sound/softsynth/fmtowns_pc98/towns_euphony.h b/sound/softsynth/fmtowns_pc98/towns_euphony.h index c869b612a3..47cfdcb2b9 100644 --- a/sound/softsynth/fmtowns_pc98/towns_euphony.h +++ b/sound/softsynth/fmtowns_pc98/towns_euphony.h @@ -39,7 +39,7 @@ public: void loadInstrument(int chanType, int id, const uint8 *data); void loadWaveTable(const uint8 *data); void unloadWaveTable(int id); - void reserveSfxChannels(int num); + void reserveSoundEffectChannels(int num); int setMusicTempo(int tempo); int startMusicTrack(const uint8 *data, int trackSize, int startTick); @@ -66,6 +66,9 @@ public: void timerCallback(int timerId); + void setMusicVolume(int volume); + void setSoundEffectVolume(int volume); + TownsAudioInterface *intf() { return _intf; } diff --git a/sound/softsynth/fmtowns_pc98/towns_pc98_fmsynth.cpp b/sound/softsynth/fmtowns_pc98/towns_pc98_fmsynth.cpp index 7a91cb81b9..507c8e159a 100644 --- a/sound/softsynth/fmtowns_pc98/towns_pc98_fmsynth.cpp +++ b/sound/softsynth/fmtowns_pc98/towns_pc98_fmsynth.cpp @@ -1157,12 +1157,12 @@ uint8 TownsPC98_FmSynth::readSSGStatus() { void TownsPC98_FmSynth::setVolumeIntern(int volA, int volB) { Common::StackLock lock(_mutex); - _volumeA = volA; - _volumeB = volB; + _volumeA = CLIP(volA, 0, Audio::Mixer::kMaxMixerVolume); + _volumeB = CLIP(volB, 0, Audio::Mixer::kMaxMixerVolume); if (_ssg) - _ssg->setVolumeIntern(volA, volB); + _ssg->setVolumeIntern(_volumeA, _volumeB); if (_prc) - _prc->setVolumeIntern(volA, volB); + _prc->setVolumeIntern(_volumeA, _volumeB); } void TownsPC98_FmSynth::setVolumeChannelMasks(int channelMaskA, int channelMaskB) { -- cgit v1.2.3 From 3fc3a59139b52828fa06f8f3e22f068c004fd469 Mon Sep 17 00:00:00 2001 From: Florian Kagerer Date: Tue, 3 Aug 2010 18:19:25 +0000 Subject: KYRA/TOWNS: replace some music stops with fadeouts (based on original code) svn-id: r51708 --- sound/softsynth/fmtowns_pc98/towns_audio.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'sound/softsynth') diff --git a/sound/softsynth/fmtowns_pc98/towns_audio.cpp b/sound/softsynth/fmtowns_pc98/towns_audio.cpp index 683f574f65..ea5797baec 100644 --- a/sound/softsynth/fmtowns_pc98/towns_audio.cpp +++ b/sound/softsynth/fmtowns_pc98/towns_audio.cpp @@ -101,8 +101,8 @@ private: TownsAudioInterface::TownsAudioInterface(Audio::Mixer *mixer, TownsAudioInterfacePluginDriver *driver) : TownsPC98_FmSynth(mixer, kTypeTowns), _fmInstruments(0), _pcmInstruments(0), _pcmChan(0), _waveTables(0), _waveTablesTotalDataSize(0), - _baserate(55125.0f / (float)mixer->getOutputRate()), _tickLength(0), _timer(0), _drv(driver), - _musicVolume(256), _sfxVolume(256), _pcmSfxChanMask(0), _ready(false) { + _baserate(55125.0f / (float)mixer->getOutputRate()), _tickLength(0), _timer(0), _drv(driver), _pcmSfxChanMask(0), + _musicVolume(Audio::Mixer::kMaxMixerVolume), _sfxVolume(Audio::Mixer::kMaxMixerVolume), _ready(false) { #define INTCB(x) &TownsAudioInterface::intf_##x static const TownsAudioIntfCallback intfCb[] = { @@ -257,6 +257,9 @@ bool TownsAudioInterface::init() { } int TownsAudioInterface::callback(int command, ...) { + if (!_ready) + return 1; + va_list args; va_start(args, command); -- cgit v1.2.3 From 449927abcf3c7c5b7346b6483375f19150ebc3bd Mon Sep 17 00:00:00 2001 From: Florian Kagerer Date: Tue, 3 Aug 2010 19:06:27 +0000 Subject: FMTOWNS AUDIO: fix typo svn-id: r51709 --- sound/softsynth/fmtowns_pc98/towns_audio.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound/softsynth') diff --git a/sound/softsynth/fmtowns_pc98/towns_audio.cpp b/sound/softsynth/fmtowns_pc98/towns_audio.cpp index ea5797baec..773c5a8067 100644 --- a/sound/softsynth/fmtowns_pc98/towns_audio.cpp +++ b/sound/softsynth/fmtowns_pc98/towns_audio.cpp @@ -1303,7 +1303,7 @@ void TownsAudioInterface::pcmCalcPhaseStep(TownsAudio_PcmChannel *p, TownsAudio_ uint32 s = 0; if (diff < 0) { - diff -= 1; + diff *= -1; bl = diff % 12; diff /= 12; s = (r >> diff); -- cgit v1.2.3 From e5ffc7847cb70f792b4658aa032959949e849669 Mon Sep 17 00:00:00 2001 From: Florian Kagerer Date: Wed, 4 Aug 2010 16:53:09 +0000 Subject: AUDIO: Implement volume and balance control for the AudioCD manager (needed for music fading in Kyra 1 FM-Towns and probably other FM-Towns games). This addition applies to emulated CD audio only for now. I haven't found a way to implement this for real CDs yet. SDL doesn't seem to support this (but it might be just me? If anyone knows more about this, just tell me). svn-id: r51741 --- sound/softsynth/fmtowns_pc98/towns_audio.cpp | 90 +++++++++++++++++++++----- sound/softsynth/fmtowns_pc98/towns_audio.h | 3 + sound/softsynth/fmtowns_pc98/towns_euphony.cpp | 8 +-- sound/softsynth/fmtowns_pc98/towns_euphony.h | 4 +- 4 files changed, 81 insertions(+), 24 deletions(-) (limited to 'sound/softsynth') diff --git a/sound/softsynth/fmtowns_pc98/towns_audio.cpp b/sound/softsynth/fmtowns_pc98/towns_audio.cpp index 773c5a8067..42b9be804e 100644 --- a/sound/softsynth/fmtowns_pc98/towns_audio.cpp +++ b/sound/softsynth/fmtowns_pc98/towns_audio.cpp @@ -24,6 +24,7 @@ */ #include "sound/softsynth/fmtowns_pc98/towns_audio.h" +#include "sound/audiocd.h" #include "common/endian.h" @@ -101,8 +102,9 @@ private: TownsAudioInterface::TownsAudioInterface(Audio::Mixer *mixer, TownsAudioInterfacePluginDriver *driver) : TownsPC98_FmSynth(mixer, kTypeTowns), _fmInstruments(0), _pcmInstruments(0), _pcmChan(0), _waveTables(0), _waveTablesTotalDataSize(0), - _baserate(55125.0f / (float)mixer->getOutputRate()), _tickLength(0), _timer(0), _drv(driver), _pcmSfxChanMask(0), - _musicVolume(Audio::Mixer::kMaxMixerVolume), _sfxVolume(Audio::Mixer::kMaxMixerVolume), _ready(false) { + _baserate(55125.0f / (float)mixer->getOutputRate()), _tickLength(0), _timer(0), _drv(driver), + _pcmSfxChanMask(0), _musicVolume(Audio::Mixer::kMaxMixerVolume), _sfxVolume(Audio::Mixer::kMaxMixerVolume), + _cdaVolFlags(0), _ready(false) { #define INTCB(x) &TownsAudioInterface::intf_##x static const TownsAudioIntfCallback intfCb[] = { @@ -147,7 +149,7 @@ TownsAudioInterface::TownsAudioInterface(Audio::Mixer *mixer, TownsAudioInterfac INTCB(notImpl), INTCB(notImpl), // 32 - INTCB(notImpl), + INTCB(loadSamples), INTCB(reserveEffectChannels), INTCB(loadWaveTable), INTCB(unloadWaveTable), @@ -268,7 +270,6 @@ int TownsAudioInterface::callback(int command, ...) { return 4; } - Common::StackLock lock(_mutex); int res = (this->*_intfOpcodes[command])(args); va_end(args); @@ -350,11 +351,9 @@ void TownsAudioInterface::timerCallbackA() { void TownsAudioInterface::timerCallbackB() { Common::StackLock lock(_mutex); - if (_ready) { - if (_drv) - _drv->timerCallback(1); - for (int i = 0; i < 8; i++) - pcmUpdateEnvelopeGenerator(i); + if (_drv && _ready) { + _drv->timerCallback(1); + callback(80); } } @@ -489,6 +488,29 @@ int TownsAudioInterface::intf_enableTimerB(va_list &args) { return 0; } +int TownsAudioInterface::intf_loadSamples(va_list &args) { + uint32 dest = va_arg(args, uint32); + int size = va_arg(args, int); + uint8 *src = va_arg(args, uint8*); + + if (dest >= 65536 || size == 0 || size > 65536) + return 3; + if (size + dest > 65536) + return 5; + + int dwIndex = _numWaveTables - 1; + for (uint32 t = _waveTablesTotalDataSize; dwIndex && (dest < t); dwIndex--) + t -= _waveTables[dwIndex].size; + + TownsAudio_WaveTable *s = &_waveTables[dwIndex]; + _waveTablesTotalDataSize -= s->size; + s->size = size; + s->readData(src); + _waveTablesTotalDataSize += s->size; + + return 0; +} + int TownsAudioInterface::intf_reserveEffectChannels(va_list &args) { int numChan = va_arg(args, int); if (numChan > 8) @@ -541,9 +563,9 @@ int TownsAudioInterface::intf_loadWaveTable(va_list &args) { TownsAudio_WaveTable *s = &_waveTables[_numWaveTables++]; s->readHeader(data); - s->readData(data + 32); - - _waveTablesTotalDataSize += w.size; + + _waveTablesTotalDataSize += s->size; + callback(32, _waveTablesTotalDataSize, s->size, data + 32); return 0; } @@ -698,9 +720,44 @@ int TownsAudioInterface::intf_pcmUpdateEnvelopeGenerator(va_list &args) { } int TownsAudioInterface::intf_cdaSetVolume(va_list &args) { - /*int unk = va_arg(args, int); - int volume1 = va_arg(args, int); - int volume2 = va_arg(args, int);*/ + int mode = va_arg(args, int); + int left = va_arg(args, int); + int right = va_arg(args, int); + + // calculate mixer balance value + int8 balance = right - left; + + if (left & 0xff80 || right & 0xff80) + return 3; + + static const uint8 flags[] = { 0x0C, 0x30, 0x40, 0x80 }; + + //int a = (mode & 0x40) ? 4 : 0; + int b = mode & 3; + left = (left & 0x7e) >> 1; + right = (right & 0x7e) >> 1; + + if (mode & 0x40) + _cdaVolFlags |= flags[b]; + else + _cdaVolFlags &= ~flags[b]; + + if (mode > 1) { + // Unknown purpose / TODO + + } else if (mode == 1) { + // FM Towns seems to support volumes of 0 - 63 for each channel. + // We recalculate sane values for out 0 to 255 volume range. + + int vl = (int)(((float)left * 255.0f) / 63.0f); + int vr = (int)(((float)right * 255.0f) / 63.0f); + AudioCD.setVolume((vl + vr) >> 1); + AudioCD.setBalance(balance); + + } else { + // Unknown purpose / TODO + } + return 0; } @@ -1402,8 +1459,7 @@ void TownsAudio_PcmChannel::clear() { panLeft = panRight = 0; - envTotalLevel = envAttackRate = envDecayRate = envSustainLevel = - envSustainRate = envReleaseRate = 0; + envTotalLevel = envAttackRate = envDecayRate = envSustainLevel = envSustainRate = envReleaseRate = 0; envStep = envCurrentLevel = 0; envState = kEnvReady; diff --git a/sound/softsynth/fmtowns_pc98/towns_audio.h b/sound/softsynth/fmtowns_pc98/towns_audio.h index 707c9e6bd4..212c00c40f 100644 --- a/sound/softsynth/fmtowns_pc98/towns_audio.h +++ b/sound/softsynth/fmtowns_pc98/towns_audio.h @@ -77,6 +77,7 @@ private: int intf_setTimerB(va_list &args); int intf_enableTimerA(va_list &args); int intf_enableTimerB(va_list &args); + int intf_loadSamples(va_list &args); int intf_reserveEffectChannels(va_list &args); int intf_loadWaveTable(va_list &args); int intf_unloadWaveTable(va_list &args); @@ -148,6 +149,8 @@ private: void pcmCalcPhaseStep(TownsAudio_PcmChannel *p, TownsAudio_WaveTable *w); void cdaReset(); + + uint8 _cdaVolFlags; const float _baserate; uint32 _timerBase; diff --git a/sound/softsynth/fmtowns_pc98/towns_euphony.cpp b/sound/softsynth/fmtowns_pc98/towns_euphony.cpp index 13120df17a..e23d5bcb36 100644 --- a/sound/softsynth/fmtowns_pc98/towns_euphony.cpp +++ b/sound/softsynth/fmtowns_pc98/towns_euphony.cpp @@ -66,8 +66,6 @@ bool TownsEuphonyDriver::init() { reset(); - cdaSetVolume(1, 118, 118); - return true; } @@ -194,7 +192,7 @@ bool TownsEuphonyDriver::soundEffectIsPlaying(int chan) { return _intf->callback(40, chan) ? true : false; } -void TownsEuphonyDriver::chanStereo(int chan, int mode) { +void TownsEuphonyDriver::chanPanPos(int chan, int mode) { _intf->callback(3, chan, mode); } @@ -206,8 +204,8 @@ void TownsEuphonyDriver::chanVolume(int chan, int vol) { _intf->callback(8, chan, vol); } -void TownsEuphonyDriver::cdaSetVolume(int a, int vol1, int vol2) { - _intf->callback(67, a, vol1, vol2); +void TownsEuphonyDriver::cdaSetVolume(int mode, int volLeft, int volRight) { + _intf->callback(67, mode, volLeft, volRight); } int TownsEuphonyDriver::chanEnable(int tableEntry, int val) { diff --git a/sound/softsynth/fmtowns_pc98/towns_euphony.h b/sound/softsynth/fmtowns_pc98/towns_euphony.h index 47cfdcb2b9..2026a299c1 100644 --- a/sound/softsynth/fmtowns_pc98/towns_euphony.h +++ b/sound/softsynth/fmtowns_pc98/towns_euphony.h @@ -50,11 +50,11 @@ public: void stopSoundEffect(int chan); bool soundEffectIsPlaying(int chan); - void chanStereo(int chan, int mode); + void chanPanPos(int chan, int mode); void chanPitch(int chan, int pitch); void chanVolume(int chan, int vol); - void cdaSetVolume(int a, int vol1, int vol2); + void cdaSetVolume(int mode, int volLeft, int volRight); int chanEnable(int tableEntry, int val); int chanMode(int tableEntry, int val); -- cgit v1.2.3 From 054c586bcc74de047536b5d4f2fdc4540dce24f3 Mon Sep 17 00:00:00 2001 From: Florian Kagerer Date: Sun, 8 Aug 2010 17:34:32 +0000 Subject: KYRA/TOWNS: some minor sound improvements (some cleanup to internal driver volume control, minor frequency change for fm-towns) svn-id: r51930 --- sound/softsynth/fmtowns_pc98/towns_audio.cpp | 104 ++++++++++++--------- sound/softsynth/fmtowns_pc98/towns_audio.h | 16 ++-- sound/softsynth/fmtowns_pc98/towns_euphony.cpp | 20 ++-- sound/softsynth/fmtowns_pc98/towns_euphony.h | 12 ++- .../softsynth/fmtowns_pc98/towns_pc98_fmsynth.cpp | 49 +++++----- sound/softsynth/fmtowns_pc98/towns_pc98_fmsynth.h | 1 + 6 files changed, 115 insertions(+), 87 deletions(-) (limited to 'sound/softsynth') diff --git a/sound/softsynth/fmtowns_pc98/towns_audio.cpp b/sound/softsynth/fmtowns_pc98/towns_audio.cpp index 42b9be804e..c9ba03ea27 100644 --- a/sound/softsynth/fmtowns_pc98/towns_audio.cpp +++ b/sound/softsynth/fmtowns_pc98/towns_audio.cpp @@ -104,7 +104,7 @@ TownsAudioInterface::TownsAudioInterface(Audio::Mixer *mixer, TownsAudioInterfac _fmInstruments(0), _pcmInstruments(0), _pcmChan(0), _waveTables(0), _waveTablesTotalDataSize(0), _baserate(55125.0f / (float)mixer->getOutputRate()), _tickLength(0), _timer(0), _drv(driver), _pcmSfxChanMask(0), _musicVolume(Audio::Mixer::kMaxMixerVolume), _sfxVolume(Audio::Mixer::kMaxMixerVolume), - _cdaVolFlags(0), _ready(false) { + _outputVolumeFlags(0), _outputMuteFlags(0), _ready(false) { #define INTCB(x) &TownsAudioInterface::intf_##x static const TownsAudioIntfCallback intfCb[] = { @@ -192,11 +192,11 @@ TownsAudioInterface::TownsAudioInterface(Audio::Mixer *mixer, TownsAudioInterfac INTCB(notImpl), INTCB(notImpl), INTCB(notImpl), - INTCB(cdaSetVolume), + INTCB(setOutputVolume), // 68 - INTCB(cdaReset), - INTCB(notImpl), + INTCB(resetOutputVolume), INTCB(notImpl), + INTCB(updateOutputVolume), INTCB(notImpl), // 72 INTCB(notImpl), @@ -218,6 +218,8 @@ TownsAudioInterface::TownsAudioInterface(Audio::Mixer *mixer, TownsAudioInterfac _intfOpcodes = intfCb; memset(_fmSaveReg, 0, sizeof(_fmSaveReg)); + memset(_outputLevel, 0, sizeof(_outputLevel)); + _timerBase = (uint32)(_baserate * 1000000.0f); _tickLength = 2 * _timerBase; } @@ -286,7 +288,7 @@ void TownsAudioInterface::setSoundEffectVolume(int volume) { setVolumeIntern(_musicVolume, _sfxVolume); } -void TownsAudioInterface::setSoundEffectChanMask(uint32 mask) { +void TownsAudioInterface::setSoundEffectChanMask(int mask) { _pcmSfxChanMask = mask >> 6; mask &= 0x3f; setVolumeChannelMasks(~mask, mask); @@ -298,8 +300,8 @@ void TownsAudioInterface::nextTickEx(int32 *buffer, uint32 bufferSize) { for (uint32 i = 0; i < bufferSize; i++) { _timer += _tickLength; - while (_timer > 0x5B8D80) { - _timer -= 0x5B8D80; + while (_timer > 0x514767) { + _timer -= 0x514767; for (int ii = 0; ii < 8; ii++) { if ((_pcmChanKeyPlaying & _chanFlags[ii]) || (_pcmChanEffectPlaying & _chanFlags[ii])) { @@ -361,7 +363,7 @@ int TownsAudioInterface::intf_reset(va_list &args) { Common::StackLock lock(_mutex); fmReset(); pcmReset(); - cdaReset(); + callback(68); return 0; } @@ -708,56 +710,59 @@ int TownsAudioInterface::intf_fmReset(va_list &args) { return 0; } -int TownsAudioInterface::intf_cdaReset(va_list &args) { - cdaReset(); - return 0; -} - -int TownsAudioInterface::intf_pcmUpdateEnvelopeGenerator(va_list &args) { - for (int i = 0; i < 8; i++) - pcmUpdateEnvelopeGenerator(i); - return 0; -} - -int TownsAudioInterface::intf_cdaSetVolume(va_list &args) { - int mode = va_arg(args, int); +int TownsAudioInterface::intf_setOutputVolume(va_list &args) { + int chanType = va_arg(args, int); int left = va_arg(args, int); int right = va_arg(args, int); - // calculate mixer balance value - int8 balance = right - left; - if (left & 0xff80 || right & 0xff80) return 3; static const uint8 flags[] = { 0x0C, 0x30, 0x40, 0x80 }; - //int a = (mode & 0x40) ? 4 : 0; - int b = mode & 3; + uint8 chan = (chanType & 0x40) ? 8 : 12; + + chanType &= 3; left = (left & 0x7e) >> 1; right = (right & 0x7e) >> 1; - if (mode & 0x40) - _cdaVolFlags |= flags[b]; + if (chan) + _outputVolumeFlags |= flags[chanType]; else - _cdaVolFlags &= ~flags[b]; + _outputVolumeFlags &= ~flags[chanType]; - if (mode > 1) { - // Unknown purpose / TODO + if (chanType > 1) { + _outputLevel[chan + chanType] = left; + } else { + if (chanType == 0) + chan -= 8; + _outputLevel[chan] = left; + _outputLevel[chan + 1] = right; + } - } else if (mode == 1) { - // FM Towns seems to support volumes of 0 - 63 for each channel. - // We recalculate sane values for out 0 to 255 volume range. + updateOutputVolume(); - int vl = (int)(((float)left * 255.0f) / 63.0f); - int vr = (int)(((float)right * 255.0f) / 63.0f); - AudioCD.setVolume((vl + vr) >> 1); - AudioCD.setBalance(balance); + return 0; +} - } else { - // Unknown purpose / TODO - } +int TownsAudioInterface::intf_resetOutputVolume(va_list &args) { + memset(_outputLevel, 0, sizeof(_outputLevel)); + _outputMuteFlags = 0; + _outputVolumeFlags = 0; + updateOutputVolume(); + return 0; +} +int TownsAudioInterface::intf_updateOutputVolume(va_list &args) { + int flags = va_arg(args, int); + _outputMuteFlags = flags & 3; + updateOutputVolume(); + return 0; +} + +int TownsAudioInterface::intf_pcmUpdateEnvelopeGenerator(va_list &args) { + for (int i = 0; i < 8; i++) + pcmUpdateEnvelopeGenerator(i); return 0; } @@ -1382,8 +1387,19 @@ void TownsAudioInterface::pcmCalcPhaseStep(TownsAudio_PcmChannel *p, TownsAudio_ p->step = (s * p->stepPitch) >> 14; } -void TownsAudioInterface::cdaReset() { - +void TownsAudioInterface::updateOutputVolume() { + // FM Towns seems to support volumes of 0 - 63 for each channel. + // We recalculate sane values for our 0 to 255 volume range and + // balance values for our -128 to 127 volume range + + // CD-AUDIO + int vl = (int)(((float)_outputLevel[12] * 127.0f) / 63.0f); + int vr = (int)(((float)_outputLevel[13] * 127.0f) / 63.0f); + int8 balance = vr - vl; + vl = (int)(((float)_outputLevel[12] * 255.0f) / 63.0f); + vr = (int)(((float)_outputLevel[13] * 255.0f) / 63.0f); + AudioCD.setVolume((vl + vr) >> 1); + AudioCD.setBalance(balance); } const uint8 TownsAudioInterface::_chanFlags[] = { @@ -1457,7 +1473,7 @@ void TownsAudio_PcmChannel::clear() { stepNote = 0x4000; stepPitch = 0x4000; - panLeft = panRight = 0; + panLeft = panRight = 7; envTotalLevel = envAttackRate = envDecayRate = envSustainLevel = envSustainRate = envReleaseRate = 0; envStep = envCurrentLevel = 0; diff --git a/sound/softsynth/fmtowns_pc98/towns_audio.h b/sound/softsynth/fmtowns_pc98/towns_audio.h index 212c00c40f..950c016b4e 100644 --- a/sound/softsynth/fmtowns_pc98/towns_audio.h +++ b/sound/softsynth/fmtowns_pc98/towns_audio.h @@ -50,7 +50,7 @@ public: 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 8 bits are pcm channels. - void setSoundEffectChanMask(uint32 mask); + void setSoundEffectChanMask(int mask); private: void nextTickEx(int32 *buffer, uint32 bufferSize); @@ -92,8 +92,9 @@ private: int intf_fmSetPitch(va_list &args); int intf_fmSetLevel(va_list &args); int intf_fmReset(va_list &args); - int intf_cdaSetVolume(va_list &args); - int intf_cdaReset(va_list &args); + int intf_setOutputVolume(va_list &args); + int intf_resetOutputVolume(va_list &args); + int intf_updateOutputVolume(va_list &args); int intf_pcmUpdateEnvelopeGenerator(va_list &args); int intf_notImpl(va_list &args); @@ -148,9 +149,10 @@ private: void pcmCalcPhaseStep(TownsAudio_PcmChannel *p, TownsAudio_WaveTable *w); - void cdaReset(); - - uint8 _cdaVolFlags; + void updateOutputVolume(); + uint8 _outputVolumeFlags; + uint8 _outputLevel[16]; + uint8 _outputMuteFlags; const float _baserate; uint32 _timerBase; @@ -159,7 +161,7 @@ private: uint16 _musicVolume; uint16 _sfxVolume; - uint32 _pcmSfxChanMask; + int _pcmSfxChanMask; TownsAudioInterfacePluginDriver *_drv; bool _ready; diff --git a/sound/softsynth/fmtowns_pc98/towns_euphony.cpp b/sound/softsynth/fmtowns_pc98/towns_euphony.cpp index e23d5bcb36..0c0c203cc9 100644 --- a/sound/softsynth/fmtowns_pc98/towns_euphony.cpp +++ b/sound/softsynth/fmtowns_pc98/towns_euphony.cpp @@ -180,6 +180,10 @@ void TownsEuphonyDriver::stopParser() { } } +void TownsEuphonyDriver::continueParsing() { + _suspendParsing = false; +} + void TownsEuphonyDriver::playSoundEffect(int chan, int note, int velo, const uint8 *data) { _intf->callback(37, chan, note, velo, data); } @@ -204,7 +208,7 @@ void TownsEuphonyDriver::chanVolume(int chan, int vol) { _intf->callback(8, chan, vol); } -void TownsEuphonyDriver::cdaSetVolume(int mode, int volLeft, int volRight) { +void TownsEuphonyDriver::setOutputVolume(int mode, int volLeft, int volRight) { _intf->callback(67, mode, volLeft, volRight); } @@ -230,7 +234,7 @@ int TownsEuphonyDriver::chanOrdr(int tableEntry, int val) { return 0; } -int TownsEuphonyDriver::chanLevel(int tableEntry, int val) { +int TownsEuphonyDriver::chanVolumeShift(int tableEntry, int val) { if (tableEntry > 31) return 3; if (val <= 40) @@ -238,7 +242,7 @@ int TownsEuphonyDriver::chanLevel(int tableEntry, int val) { return 0; } -int TownsEuphonyDriver::chanTranspose(int tableEntry, int val) { +int TownsEuphonyDriver::chanNoteShift(int tableEntry, int val) { if (tableEntry > 31) return 3; if (val <= 40) @@ -660,8 +664,8 @@ bool TownsEuphonyDriver::evtSetupNote() { uint8 velo = _musicPos[5]; sendEvent(mode, evt); - sendEvent(mode, prepTranspose(note)); - sendEvent(mode, prepVelo(velo)); + sendEvent(mode, applyNoteShift(note)); + sendEvent(mode, applyVolumeShift(velo)); jumpNextLoop(); if (_musicPos[0] == 0xfe || _musicPos[0] == 0xfd) @@ -700,7 +704,7 @@ bool TownsEuphonyDriver::evtPolyphonicAftertouch() { uint8 mode = _tMode[_musicPos[1]]; sendEvent(mode, evt); - sendEvent(mode, prepTranspose(_musicPos[4])); + sendEvent(mode, applyNoteShift(_musicPos[4])); sendEvent(mode, _musicPos[5]); return false; @@ -768,7 +772,7 @@ bool TownsEuphonyDriver::evtModeOrdrChange() { return false; } -uint8 TownsEuphonyDriver::prepTranspose(uint8 in) { +uint8 TownsEuphonyDriver::applyNoteShift(uint8 in) { int out = _tTranspose[_musicPos[1]]; if (!out) return in; @@ -783,7 +787,7 @@ uint8 TownsEuphonyDriver::prepTranspose(uint8 in) { return out & 0xff; } -uint8 TownsEuphonyDriver::prepVelo(uint8 in) { +uint8 TownsEuphonyDriver::applyVolumeShift(uint8 in) { int out = _tLevel[_musicPos[1]]; out += (in & 0x7f); out = CLIP(out, 1, 127); diff --git a/sound/softsynth/fmtowns_pc98/towns_euphony.h b/sound/softsynth/fmtowns_pc98/towns_euphony.h index 2026a299c1..fa1f8ba496 100644 --- a/sound/softsynth/fmtowns_pc98/towns_euphony.h +++ b/sound/softsynth/fmtowns_pc98/towns_euphony.h @@ -45,6 +45,8 @@ public: int startMusicTrack(const uint8 *data, int trackSize, int startTick); void setMusicLoop(bool loop); void stopParser(); + bool parserIsPlaying() {return _playing; } + void continueParsing(); void playSoundEffect(int chan, int note, int velo, const uint8 *data); void stopSoundEffect(int chan); @@ -54,13 +56,13 @@ public: void chanPitch(int chan, int pitch); void chanVolume(int chan, int vol); - void cdaSetVolume(int mode, int volLeft, int volRight); + void setOutputVolume(int chanType, int volLeft, int volRight); int chanEnable(int tableEntry, int val); int chanMode(int tableEntry, int val); int chanOrdr(int tableEntry, int val); - int chanLevel(int tableEntry, int val); - int chanTranspose(int tableEntry, int val); + int chanVolumeShift(int tableEntry, int val); + int chanNoteShift(int tableEntry, int val); int assignChannel(int chan, int tableEntry); @@ -112,8 +114,8 @@ private: return false; } - uint8 prepTranspose(uint8 in); - uint8 prepVelo(uint8 in); + uint8 applyNoteShift(uint8 in); + uint8 applyVolumeShift(uint8 in); void sendNoteOff(); void sendNoteOn(); diff --git a/sound/softsynth/fmtowns_pc98/towns_pc98_fmsynth.cpp b/sound/softsynth/fmtowns_pc98/towns_pc98_fmsynth.cpp index 507c8e159a..241b9bde50 100644 --- a/sound/softsynth/fmtowns_pc98/towns_pc98_fmsynth.cpp +++ b/sound/softsynth/fmtowns_pc98/towns_pc98_fmsynth.cpp @@ -28,7 +28,7 @@ class TownsPC98_FmSynthOperator { public: - TownsPC98_FmSynthOperator(const uint32 timerbase, const uint8 *rateTable, + TownsPC98_FmSynthOperator(const uint32 timerbase, const uint32 rtt, const uint8 *rateTable, const uint8 *shiftTable, const uint8 *attackDecayTable, const uint32 *frqTable, const uint32 *sineTable, const int32 *tlevelOut, const int32 *detuneTable); ~TownsPC98_FmSynthOperator() {} @@ -108,6 +108,7 @@ protected: const uint32 _tickLength; uint32 _timer; + const uint32 _rtt; int32 _currentLevel; struct EvpState { @@ -116,10 +117,10 @@ protected: } fs_a, fs_d, fs_s, fs_r; }; -TownsPC98_FmSynthOperator::TownsPC98_FmSynthOperator(const uint32 timerbase, const uint8 *rateTable, - const uint8 *shiftTable, const uint8 *attackDecayTable, const uint32 *frqTable, - const uint32 *sineTable, const int32 *tlevelOut, const int32 *detuneTable) : - _rateTbl(rateTable), _rshiftTbl(shiftTable), _adTbl(attackDecayTable), _fTbl(frqTable), +TownsPC98_FmSynthOperator::TownsPC98_FmSynthOperator(const uint32 timerbase, const uint32 rtt, + const uint8 *rateTable, const uint8 *shiftTable, const uint8 *attackDecayTable, + 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), _phase(0), _state(kEnvReady), _playing(false), _timer(0), _keyScale1(0), @@ -190,8 +191,8 @@ void TownsPC98_FmSynthOperator::generateOutput(int32 phasebuf, int32 *feed, int3 return; _timer += _tickLength; - while (_timer > 0x5B8D80) { - _timer -= 0x5B8D80; + while (_timer > _rtt) { + _timer -= _rtt; ++_tickCount; int32 levelIncrement = 0; @@ -308,7 +309,7 @@ bool TownsPC98_FmSynthOperator::scaleRate(uint8 value) { class TownsPC98_FmSynthSquareSineSource { public: - TownsPC98_FmSynthSquareSineSource(const uint32 timerbase); + TownsPC98_FmSynthSquareSineSource(const uint32 timerbase, const uint32 rtt); ~TownsPC98_FmSynthSquareSineSource(); void init(const int *rsTable, const int *rseTable); @@ -351,6 +352,7 @@ private: const uint32 _tickLength; uint32 _timer; + const uint32 _rtt; struct Channel { int tick; @@ -377,7 +379,7 @@ private: class TownsPC98_FmSynthPercussionSource { public: - TownsPC98_FmSynthPercussionSource(const uint32 timerbase); + TownsPC98_FmSynthPercussionSource(const uint32 timerbase, const uint32 rtt); ~TownsPC98_FmSynthPercussionSource() { delete[] _reg; } @@ -429,6 +431,7 @@ private: const uint32 _tickLength; uint32 _timer; + const uint32 _rtt; uint8 **_reg; @@ -440,8 +443,8 @@ private: bool _ready; }; -TownsPC98_FmSynthSquareSineSource::TownsPC98_FmSynthSquareSineSource(const uint32 timerbase) : _tlTable(0), - _tleTable(0), _updateRequest(-1), _tickLength(timerbase * 27), _ready(0), _reg(0), _rand(1), _outN(1), +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), _volMaskA(0), _volMaskB(0), _volumeA(Audio::Mixer::kMaxMixerVolume), _volumeB(Audio::Mixer::kMaxMixerVolume) { @@ -558,8 +561,8 @@ void TownsPC98_FmSynthSquareSineSource::nextTick(int32 *buffer, uint32 bufferSiz for (uint32 i = 0; i < bufferSize; i++) { _timer += _tickLength; - while (_timer > 0x5B8D80) { - _timer -= 0x5B8D80; + while (_timer > _rtt) { + _timer -= _rtt; if (++_nTick >= (_noiseGenerator & 0x1f)) { if ((_rand + 1) & 2) @@ -597,7 +600,7 @@ void TownsPC98_FmSynthSquareSineSource::nextTick(int32 *buffer, uint32 bufferSiz int32 finOut = 0; for (int ii = 0; ii < 3; ii++) { -int32 finOutTemp = ((_channels[ii].vol >> 4) & 1) ? _tleTable[_channels[ii].out ? _pReslt : 0] : _tlTable[_channels[ii].out ? (_channels[ii].vol & 0x0f) : 0]; + int32 finOutTemp = ((_channels[ii].vol >> 4) & 1) ? _tleTable[_channels[ii].out ? _pReslt : 0] : _tlTable[_channels[ii].out ? (_channels[ii].vol & 0x0f) : 0]; if ((1 << ii) & _volMaskA) finOutTemp = (finOutTemp * _volumeA) / Audio::Mixer::kMaxMixerVolume; @@ -624,8 +627,8 @@ void TownsPC98_FmSynthSquareSineSource::updateRegs() { _updateRequest = -1; } -TownsPC98_FmSynthPercussionSource::TownsPC98_FmSynthPercussionSource(const uint32 timerbase) : - _tickLength(timerbase * 2), _timer(0), _ready(false), _volMaskA(0), _volMaskB(0), _volumeA(Audio::Mixer::kMaxMixerVolume), _volumeB(Audio::Mixer::kMaxMixerVolume) { +TownsPC98_FmSynthPercussionSource::TownsPC98_FmSynthPercussionSource(const uint32 timerbase, const uint32 rtt) : + _rtt(rtt), _tickLength(timerbase * 2), _timer(0), _ready(false), _volMaskA(0), _volMaskB(0), _volumeA(Audio::Mixer::kMaxMixerVolume), _volumeB(Audio::Mixer::kMaxMixerVolume) { memset(_rhChan, 0, sizeof(RhtChannel) * 6); _reg = new uint8 *[40]; @@ -758,8 +761,8 @@ void TownsPC98_FmSynthPercussionSource::nextTick(int32 *buffer, uint32 bufferSiz for (uint32 i = 0; i < bufferSize; i++) { _timer += _tickLength; - while (_timer > 0x5B8D80) { - _timer -= 0x5B8D80; + while (_timer > _rtt) { + _timer -= _rtt; for (int ii = 0; ii < 6; ii++) { RhtChannel *s = &_rhChan[ii]; @@ -826,7 +829,7 @@ TownsPC98_FmSynth::TownsPC98_FmSynth(Audio::Mixer *mixer, EmuType type) : _chanInternal(0), _ssg(0), _prc(0), _numChan(type == kType26 ? 3 : 6), _numSSG(type == kTypeTowns ? 0 : 3), _hasPercussion(type == kType86 ? true : false), _oprRates(0), _oprRateshift(0), _oprAttackDecay(0), _oprFrq(0), _oprSinTbl(0), _oprLevelOut(0), _oprDetune(0), - _baserate(55125.0f / (float)mixer->getOutputRate()), + _rtt(type == kTypeTowns ? 0x514767 : 0x5B8D80), _baserate(55125.0f / (float)mixer->getOutputRate()), _volMaskA(0), _volMaskB(0), _volumeA(255), _volumeB(255), _regProtectionFlag(false), _ready(false) { @@ -834,7 +837,7 @@ TownsPC98_FmSynth::TownsPC98_FmSynth(Audio::Mixer *mixer, EmuType type) : memset(&_timers[1], 0, sizeof(ChipTimer)); _timers[0].cb = &TownsPC98_FmSynth::timerCallbackA; _timers[1].cb = &TownsPC98_FmSynth::timerCallbackB; - _timerbase = (uint32)(_baserate * 1000000.0f); + _timerbase = (uint32)(_baserate * 1000000.0f); } TownsPC98_FmSynth::~TownsPC98_FmSynth() { @@ -865,16 +868,16 @@ bool TownsPC98_FmSynth::init() { for (int i = 0; i < _numChan; i++) { memset(&_chanInternal[i], 0, sizeof(ChanInternal)); for (int j = 0; j < 4; ++j) - _chanInternal[i].opr[j] = new TownsPC98_FmSynthOperator(_timerbase, _oprRates, _oprRateshift, _oprAttackDecay, _oprFrq, _oprSinTbl, _oprLevelOut, _oprDetune); + _chanInternal[i].opr[j] = new TownsPC98_FmSynthOperator(_timerbase, _rtt, _oprRates, _oprRateshift, _oprAttackDecay, _oprFrq, _oprSinTbl, _oprLevelOut, _oprDetune); } if (_numSSG) { - _ssg = new TownsPC98_FmSynthSquareSineSource(_timerbase); + _ssg = new TownsPC98_FmSynthSquareSineSource(_timerbase, _rtt); _ssg->init(&_ssgTables[0], &_ssgTables[16]); } if (_hasPercussion) { - _prc = new TownsPC98_FmSynthPercussionSource(_timerbase); + _prc = new TownsPC98_FmSynthPercussionSource(_timerbase, _rtt); _prc->init(_percussionData); } diff --git a/sound/softsynth/fmtowns_pc98/towns_pc98_fmsynth.h b/sound/softsynth/fmtowns_pc98/towns_pc98_fmsynth.h index 34ee2ce7b8..3072503610 100644 --- a/sound/softsynth/fmtowns_pc98/towns_pc98_fmsynth.h +++ b/sound/softsynth/fmtowns_pc98/towns_pc98_fmsynth.h @@ -160,6 +160,7 @@ private: const float _baserate; uint32 _timerbase; + uint32 _rtt; Audio::Mixer *_mixer; Audio::SoundHandle _soundHandle; -- cgit v1.2.3