aboutsummaryrefslogtreecommitdiff
path: root/sound
diff options
context:
space:
mode:
authorJohannes Schickel2010-10-13 03:57:44 +0000
committerJohannes Schickel2010-10-13 03:57:44 +0000
commit75e8452b6e6a2bf4fb2f588aa00b428a60d873b5 (patch)
treef29541d55309487a94bd1d38e8b53bb3dde9aec6 /sound
parent48ee83b88957dab86bc763e9ef21a70179fa8679 (diff)
parente9f50882ea5b6beeefa994040be9d3bab6a1f107 (diff)
downloadscummvm-rg350-75e8452b6e6a2bf4fb2f588aa00b428a60d873b5.tar.gz
scummvm-rg350-75e8452b6e6a2bf4fb2f588aa00b428a60d873b5.tar.bz2
scummvm-rg350-75e8452b6e6a2bf4fb2f588aa00b428a60d873b5.zip
OPENGL: Merged from trunk, from rev 52105 to 53396.
This includes an rather hacky attempt to merge all the recent gp2x backend changes into the branch. I suppose the gp2x backend and probably all new backends, i.e. gph, dingux etc., might not compile anymore. Since I have no way of testing those it would be nice if porters could look into getting those up to speed in this branch. svn-id: r53399
Diffstat (limited to 'sound')
-rw-r--r--sound/decoders/flac.cpp4
-rw-r--r--sound/decoders/mac_snd.cpp2
-rw-r--r--sound/decoders/mp3.cpp2
-rw-r--r--sound/fmopl.cpp6
-rw-r--r--sound/mididrv.cpp21
-rw-r--r--sound/mididrv.h10
-rw-r--r--sound/mixer.cpp4
-rw-r--r--sound/mods/tfmx.cpp38
-rw-r--r--sound/module.mk1
-rw-r--r--sound/softsynth/cms.cpp372
-rw-r--r--sound/softsynth/cms.h92
-rw-r--r--sound/softsynth/fmtowns_pc98/towns_audio.cpp44
-rw-r--r--sound/softsynth/fmtowns_pc98/towns_audio.h1
-rw-r--r--sound/softsynth/fmtowns_pc98/towns_euphony.cpp8
-rw-r--r--sound/softsynth/fmtowns_pc98/towns_pc98_driver.cpp36
-rw-r--r--sound/softsynth/fmtowns_pc98/towns_pc98_driver.h6
-rw-r--r--sound/softsynth/fmtowns_pc98/towns_pc98_fmsynth.cpp52
-rw-r--r--sound/softsynth/fmtowns_pc98/towns_pc98_fmsynth.h19
-rw-r--r--sound/softsynth/opl/mame.cpp6
19 files changed, 661 insertions, 63 deletions
diff --git a/sound/decoders/flac.cpp b/sound/decoders/flac.cpp
index 2a92735616..560b83e1ee 100644
--- a/sound/decoders/flac.cpp
+++ b/sound/decoders/flac.cpp
@@ -139,7 +139,7 @@ public:
bool seek(const Timestamp &where);
Timestamp getLength() const { return _length; }
- bool isStreamDecoderReady() const { return getStreamDecoderState() == FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC ; }
+ bool isStreamDecoderReady() const { return getStreamDecoderState() == FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC; }
protected:
uint getChannels() const { return MIN<uint>(_streaminfo.channels, MAX_OUTPUT_CHANNELS); }
@@ -552,7 +552,7 @@ void FLACStream::convertBuffersGeneric(SampleType* bufDestination, const FLAC__i
for (; numSamples > 0; numSamples -= numChannels) {
for (uint i = 0; i < numChannels; ++i)
- *bufDestination++ = static_cast<SampleType>(*(inChannels[i]++) >> kPower) ;
+ *bufDestination++ = static_cast<SampleType>(*(inChannels[i]++) >> kPower);
}
} else {
for (; numSamples > 0; numSamples -= numChannels) {
diff --git a/sound/decoders/mac_snd.cpp b/sound/decoders/mac_snd.cpp
index d6894f1144..48f6886bf4 100644
--- a/sound/decoders/mac_snd.cpp
+++ b/sound/decoders/mac_snd.cpp
@@ -69,7 +69,7 @@ SeekableAudioStream *makeMacSndStream(Common::SeekableReadStream *stream,
// We really should never get this as long as we have sampled data only
if (stream->readUint16BE() != 1) {
warning("makeMacSndStream(): Unsupported command count");
- return 0;
+ return 0;
}
uint16 command = stream->readUint16BE();
diff --git a/sound/decoders/mp3.cpp b/sound/decoders/mp3.cpp
index e54d646b0a..e06b82a9e2 100644
--- a/sound/decoders/mp3.cpp
+++ b/sound/decoders/mp3.cpp
@@ -232,6 +232,8 @@ bool MP3Stream::seek(const Timestamp &where) {
while (mad_timer_compare(destination, _totalTime) > 0 && _state != MP3_STATE_EOS)
readHeader();
+ decodeMP3Data();
+
return (_state != MP3_STATE_EOS);
}
diff --git a/sound/fmopl.cpp b/sound/fmopl.cpp
index 16dc3986d6..ee54a79a46 100644
--- a/sound/fmopl.cpp
+++ b/sound/fmopl.cpp
@@ -42,7 +42,7 @@ enum OplEmulator {
OPL::OPL() {
if (_hasInstance)
- error("There are multiple OPL output instances running.");
+ error("There are multiple OPL output instances running");
_hasInstance = true;
}
@@ -91,7 +91,7 @@ Config::DriverId Config::detect(OplType type) {
} else {
// Else we will output a warning and just
// return that no valid driver is found.
- warning("Your selected OPL driver \"%s\" does not support type %d emulation, which is requested by your game.", _drivers[drv].description, type);
+ warning("Your selected OPL driver \"%s\" does not support type %d emulation, which is requested by your game", _drivers[drv].description, type);
return -1;
}
}
@@ -138,7 +138,7 @@ OPL *Config::create(DriverId driver, OplType type) {
if (type == kOpl2)
return new MAME::OPL();
else
- warning("MAME OPL emulator only supports OPL2 emulation.");
+ warning("MAME OPL emulator only supports OPL2 emulation");
return 0;
#ifndef DISABLE_DOSBOX_OPL
diff --git a/sound/mididrv.cpp b/sound/mididrv.cpp
index eb8bafee01..aa9f8797ba 100644
--- a/sound/mididrv.cpp
+++ b/sound/mididrv.cpp
@@ -58,7 +58,7 @@ const byte MidiDriver::_gmToMt32[128] = {
static const uint32 GUIOMapping[] = {
MT_PCSPK, Common::GUIO_MIDIPCSPK,
- /*MDT_CMS, Common::GUIO_MIDICMS,*/
+ MT_CMS, Common::GUIO_MIDICMS,
MT_PCJR, Common::GUIO_MIDIPCJR,
MT_ADLIB, Common::GUIO_MIDIADLIB,
MT_C64, Common::GUIO_MIDIC64,
@@ -162,7 +162,7 @@ MidiDriver::DeviceHandle MidiDriver::detectDevice(int flags) {
case MT_AMIGA:
if (flags & MDT_AMIGA)
return hdl;
- break;
+ break;
case MT_APPLEIIGS:
if (flags & MDT_APPLEIIGS)
@@ -247,10 +247,10 @@ MidiDriver::DeviceHandle MidiDriver::detectDevice(int flags) {
tp = MT_PC98;
else if (flags & MDT_ADLIB)
tp = MT_ADLIB;
- else if (flags & MDT_PCSPK)
- tp = MT_PCSPK;
else if (flags & MDT_PCJR)
tp = MT_PCJR;
+ else if (flags & MDT_PCSPK)
+ tp = MT_PCSPK;
else if (flags & MDT_C64)
tp = MT_C64;
else if (flags & MDT_AMIGA)
@@ -306,3 +306,16 @@ MidiDriver::DeviceHandle MidiDriver::getDeviceHandle(const Common::String &ident
return 0;
}
+
+void MidiDriver::sendMT32Reset() {
+ static const byte resetSysEx[] = { 0x41, 0x10, 0x16, 0x12, 0x7F, 0x00, 0x00, 0x01, 0x00 };
+ sysEx(resetSysEx, sizeof(resetSysEx));
+ g_system->delayMillis(100);
+}
+
+void MidiDriver::sendGMReset() {
+ static const byte resetSysEx[] = { 0x7E, 0x7F, 0x09, 0x01 };
+ sysEx(resetSysEx, sizeof(resetSysEx));
+ g_system->delayMillis(100);
+}
+
diff --git a/sound/mididrv.h b/sound/mididrv.h
index 7ba1fe19f7..9e649cba3d 100644
--- a/sound/mididrv.h
+++ b/sound/mididrv.h
@@ -216,6 +216,16 @@ public:
}
/**
+ * Send a Roland MT-32 reset sysEx to the midi device.
+ */
+ void sendMT32Reset();
+
+ /**
+ * Send a General MIDI reset sysEx to the midi device.
+ */
+ void sendGMReset();
+
+ /**
* Transmit a sysEx to the midi device.
*
* The given msg MUST NOT contain the usual SysEx frame, i.e.
diff --git a/sound/mixer.cpp b/sound/mixer.cpp
index 3d8b55683f..cb3cc2a0f3 100644
--- a/sound/mixer.cpp
+++ b/sound/mixer.cpp
@@ -246,6 +246,10 @@ void MixerImpl::playStream(
}
}
+#ifdef AUDIO_REVERSE_STEREO
+ reverseStereo = !reverseStereo;
+#endif
+
// Create the channel
Channel *chan = new Channel(this, type, stream, autofreeStream, reverseStereo, id, permanent);
chan->setVolume(volume);
diff --git a/sound/mods/tfmx.cpp b/sound/mods/tfmx.cpp
index ad468033c5..b65a998e82 100644
--- a/sound/mods/tfmx.cpp
+++ b/sound/mods/tfmx.cpp
@@ -36,17 +36,22 @@
// couple debug-functions
namespace {
- void displayPatternstep(const void *const vptr);
- void displayMacroStep(const void *const vptr);
- const uint16 noteIntervalls[64] = {
+#if 0
+void displayPatternstep(const void * const vptr);
+void displayMacroStep(const void * const vptr);
+#endif
+
+static const uint16 noteIntervalls[64] = {
1710, 1614, 1524, 1438, 1357, 1281, 1209, 1141, 1077, 1017, 960, 908,
856, 810, 764, 720, 680, 642, 606, 571, 539, 509, 480, 454,
428, 404, 381, 360, 340, 320, 303, 286, 270, 254, 240, 227,
214, 202, 191, 180, 170, 160, 151, 143, 135, 127, 120, 113,
214, 202, 191, 180, 170, 160, 151, 143, 135, 127, 120, 113,
- 214, 202, 191, 180 };
-}
+ 214, 202, 191, 180
+};
+
+} // End of anonymous namespace
namespace Audio {
@@ -101,7 +106,7 @@ void Tfmx::interrupt() {
// externally queued macros
if (channel.customMacro) {
- const byte *const noteCmd = (const byte *)&channel.customMacro;
+ const byte * const noteCmd = (const byte *)&channel.customMacro;
channel.sfxLocked = false;
noteCommand(noteCmd[0], noteCmd[1], (noteCmd[2] & 0xF0) | (uint8)i, noteCmd[3]);
channel.customMacro = 0;
@@ -1096,10 +1101,11 @@ int Tfmx::doSfx(uint16 sfxIndex, bool unlockChannel) {
} // End of namespace Audio
// some debugging functions
+#if 0
namespace {
-#if !defined(NDEBUG) && 0
-void displayMacroStep(const void *const vptr) {
- const char *tableMacros[] = {
+
+void displayMacroStep(const void * const vptr) {
+ static const char *tableMacros[] = {
"DMAoff+Resetxx/xx/xx flag/addset/vol ",
"DMAon (start sample at selected begin) ",
"SetBegin xxxxxx sample-startadress",
@@ -1144,15 +1150,15 @@ void displayMacroStep(const void *const vptr) {
"SID stop xx.... flag (1=clear all)"
};
- const byte *const macroData = (const byte *const)vptr;
+ const byte *const macroData = (const byte * const)vptr;
if (macroData[0] < ARRAYSIZE(tableMacros))
debug("%s %02X%02X%02X", tableMacros[macroData[0]], macroData[1], macroData[2], macroData[3]);
else
debug("Unkown Macro #%02X %02X%02X%02X", macroData[0], macroData[1], macroData[2], macroData[3]);
}
-void displayPatternstep(const void *const vptr) {
- const char *tablePatterns[] = {
+void displayPatternstep(const void * const vptr) {
+ static const char *tablePatterns[] = {
"End --Next track step--",
"Loop[count / step.w]",
"Cont[patternno./ step.w]",
@@ -1171,7 +1177,7 @@ void displayPatternstep(const void *const vptr) {
"NOP!-no operation-------"
};
- const byte *const patData = (const byte *const)vptr;
+ const byte * const patData = (const byte * const)vptr;
const byte command = patData[0];
if (command < 0xF0) { // Playnote
const byte flags = command >> 6; // 0-1 means note+detune, 2 means wait, 3 means portamento?
@@ -1180,10 +1186,8 @@ void displayPatternstep(const void *const vptr) {
} else
debug("%s %02X%02X%02X",tablePatterns[command & 0xF], patData[1], patData[2], patData[3]);
}
-#else
-void displayMacroStep(const void *const vptr, int chan, int index) {}
-void displayPatternstep(const void *const vptr) {}
+
+} // End of anonymous namespace
#endif
-} // End of namespace
#endif // #if defined(SOUND_MODS_TFMX_H)
diff --git a/sound/module.mk b/sound/module.mk
index 116884cf57..6cfa165a95 100644
--- a/sound/module.mk
+++ b/sound/module.mk
@@ -32,6 +32,7 @@ MODULE_OBJS := \
mods/soundfx.o \
mods/tfmx.o \
softsynth/adlib.o \
+ softsynth/cms.o \
softsynth/opl/dbopl.o \
softsynth/opl/dosbox.o \
softsynth/opl/mame.o \
diff --git a/sound/softsynth/cms.cpp b/sound/softsynth/cms.cpp
new file mode 100644
index 0000000000..88f04a1ab9
--- /dev/null
+++ b/sound/softsynth/cms.cpp
@@ -0,0 +1,372 @@
+/* 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/cms.h"
+#include "sound/null.h"
+
+#include "common/textconsole.h"
+#include "common/translation.h"
+#include "common/debug.h"
+
+// CMS/Gameblaster Emulation taken from DosBox
+
+#define LEFT 0x00
+#define RIGHT 0x01
+
+static const byte envelope[8][64] = {
+ /* zero amplitude */
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ /* maximum amplitude */
+ {15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+ 15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+ 15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+ 15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15, },
+ /* single decay */
+ {15,14,13,12,11,10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ /* repetitive decay */
+ {15,14,13,12,11,10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0,
+ 15,14,13,12,11,10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0,
+ 15,14,13,12,11,10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0,
+ 15,14,13,12,11,10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 },
+ /* single triangular */
+ { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,
+ 15,14,13,12,11,10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ /* repetitive triangular */
+ { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,
+ 15,14,13,12,11,10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0,
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,
+ 15,14,13,12,11,10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 },
+ /* single attack */
+ { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ /* repetitive attack */
+ { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15 }
+};
+
+static const int amplitude_lookup[16] = {
+ 0*32767/16, 1*32767/16, 2*32767/16, 3*32767/16,
+ 4*32767/16, 5*32767/16, 6*32767/16, 7*32767/16,
+ 8*32767/16, 9*32767/16, 10*32767/16, 11*32767/16,
+ 12*32767/16, 13*32767/16, 14*32767/16, 15*32767/16
+};
+
+void CMSEmulator::portWrite(int port, int val) {
+ switch (port) {
+ case 0x220:
+ portWriteIntern(0, 1, val);
+ break;
+
+ case 0x221:
+ _saa1099[0].selected_reg = val & 0x1f;
+ if (_saa1099[0].selected_reg == 0x18 || _saa1099[0].selected_reg == 0x19) {
+ /* clock the envelope channels */
+ if (_saa1099[0].env_clock[0]) envelope(0, 0);
+ if (_saa1099[0].env_clock[1]) envelope(0, 1);
+ }
+ break;
+
+ case 0x222:
+ portWriteIntern(1, 1, val);
+ break;
+
+ case 0x223:
+ _saa1099[1].selected_reg = val & 0x1f;
+ if (_saa1099[1].selected_reg == 0x18 || _saa1099[1].selected_reg == 0x19) {
+ /* clock the envelope channels */
+ if (_saa1099[1].env_clock[0]) envelope(1, 0);
+ if (_saa1099[1].env_clock[1]) envelope(1, 1);
+ }
+ break;
+
+ default:
+ warning("CMSEmulator got port: 0x%X", port);
+ break;
+ }
+}
+
+void CMSEmulator::readBuffer(int16 *buffer, const int numSamples) {
+ update(0, &buffer[0], numSamples);
+ update(1, &buffer[0], numSamples);
+}
+
+void CMSEmulator::envelope(int chip, int ch) {
+ SAA1099 *saa = &_saa1099[chip];
+ if (saa->env_enable[ch]) {
+ int step, mode, mask;
+ mode = saa->env_mode[ch];
+ /* step from 0..63 and then loop in steps 32..63 */
+ step = saa->env_step[ch] = ((saa->env_step[ch] + 1) & 0x3f) | (saa->env_step[ch] & 0x20);
+
+ mask = 15;
+ if (saa->env_bits[ch])
+ mask &= ~1; /* 3 bit resolution, mask LSB */
+
+ saa->channels[ch*3+0].envelope[ LEFT] =
+ saa->channels[ch*3+1].envelope[ LEFT] =
+ saa->channels[ch*3+2].envelope[ LEFT] = ::envelope[mode][step] & mask;
+ if (saa->env_reverse_right[ch] & 0x01) {
+ saa->channels[ch*3+0].envelope[RIGHT] =
+ saa->channels[ch*3+1].envelope[RIGHT] =
+ saa->channels[ch*3+2].envelope[RIGHT] = (15 - ::envelope[mode][step]) & mask;
+ } else {
+ saa->channels[ch*3+0].envelope[RIGHT] =
+ saa->channels[ch*3+1].envelope[RIGHT] =
+ saa->channels[ch*3+2].envelope[RIGHT] = ::envelope[mode][step] & mask;
+ }
+ } else {
+ /* envelope mode off, set all envelope factors to 16 */
+ saa->channels[ch*3+0].envelope[ LEFT] =
+ saa->channels[ch*3+1].envelope[ LEFT] =
+ saa->channels[ch*3+2].envelope[ LEFT] =
+ saa->channels[ch*3+0].envelope[RIGHT] =
+ saa->channels[ch*3+1].envelope[RIGHT] =
+ saa->channels[ch*3+2].envelope[RIGHT] = 16;
+ }
+}
+
+void CMSEmulator::update(int chip, int16 *buffer, int length) {
+ struct SAA1099 *saa = &_saa1099[chip];
+ int j, ch;
+
+ /* if the channels are disabled we're done */
+ if (!saa->all_ch_enable) {
+ /* init output data */
+ if (chip == 0) {
+ memset(buffer, 0, sizeof(int16)*length*2);
+ }
+ return;
+ }
+
+ if (chip == 0) {
+ memset(buffer, 0, sizeof(int16)*length*2);
+ }
+
+ for (ch = 0; ch < 2; ch++) {
+ switch (saa->noise_params[ch]) {
+ case 0: saa->noise[ch].freq = 31250.0 * 2; break;
+ case 1: saa->noise[ch].freq = 15625.0 * 2; break;
+ case 2: saa->noise[ch].freq = 7812.5 * 2; break;
+ case 3: saa->noise[ch].freq = saa->channels[ch * 3].freq; break;
+ }
+ }
+
+ /* fill all data needed */
+ for (j = 0; j < length; ++j) {
+ int output_l = 0, output_r = 0;
+
+ /* for each channel */
+ for (ch = 0; ch < 6; ch++) {
+ if (saa->channels[ch].freq == 0.0)
+ saa->channels[ch].freq = (double)((2 * 15625) << saa->channels[ch].octave) /
+ (511.0 - (double)saa->channels[ch].frequency);
+
+ /* check the actual position in the square wave */
+ saa->channels[ch].counter -= saa->channels[ch].freq;
+ while (saa->channels[ch].counter < 0) {
+ /* calculate new frequency now after the half wave is updated */
+ saa->channels[ch].freq = (double)((2 * 15625) << saa->channels[ch].octave) /
+ (511.0 - (double)saa->channels[ch].frequency);
+
+ saa->channels[ch].counter += _sampleRate;
+ saa->channels[ch].level ^= 1;
+
+ /* eventually clock the envelope counters */
+ if (ch == 1 && saa->env_clock[0] == 0)
+ envelope(chip, 0);
+ if (ch == 4 && saa->env_clock[1] == 0)
+ envelope(chip, 1);
+ }
+
+ /* if the noise is enabled */
+ if (saa->channels[ch].noise_enable) {
+ /* if the noise level is high (noise 0: chan 0-2, noise 1: chan 3-5) */
+ if (saa->noise[ch/3].level & 1) {
+ /* subtract to avoid overflows, also use only half amplitude */
+ output_l -= saa->channels[ch].amplitude[ LEFT] * saa->channels[ch].envelope[ LEFT] / 16 / 2;
+ output_r -= saa->channels[ch].amplitude[RIGHT] * saa->channels[ch].envelope[RIGHT] / 16 / 2;
+ }
+ }
+
+ /* if the square wave is enabled */
+ if (saa->channels[ch].freq_enable) {
+ /* if the channel level is high */
+ if (saa->channels[ch].level & 1) {
+ output_l += saa->channels[ch].amplitude[ LEFT] * saa->channels[ch].envelope[ LEFT] / 16;
+ output_r += saa->channels[ch].amplitude[RIGHT] * saa->channels[ch].envelope[RIGHT] / 16;
+ }
+ }
+ }
+
+ for (ch = 0; ch < 2; ch++) {
+ /* check the actual position in noise generator */
+ saa->noise[ch].counter -= saa->noise[ch].freq;
+ while (saa->noise[ch].counter < 0) {
+ saa->noise[ch].counter += _sampleRate;
+ if (((saa->noise[ch].level & 0x4000) == 0) == ((saa->noise[ch].level & 0x0040) == 0) )
+ saa->noise[ch].level = (saa->noise[ch].level << 1) | 1;
+ else
+ saa->noise[ch].level <<= 1;
+ }
+ }
+ /* write sound data to the buffer */
+ buffer[j*2] += output_l / 6;
+ buffer[j*2+1] += output_r / 6;
+ }
+}
+
+void CMSEmulator::portWriteIntern(int chip, int offset, int data) {
+ SAA1099 *saa = &_saa1099[chip];
+ int reg = saa->selected_reg;
+ int ch;
+
+ switch (reg) {
+ /* channel i amplitude */
+ case 0x00:
+ case 0x01:
+ case 0x02:
+ case 0x03:
+ case 0x04:
+ case 0x05:
+ ch = reg & 7;
+ saa->channels[ch].amplitude[LEFT] = amplitude_lookup[data & 0x0f];
+ saa->channels[ch].amplitude[RIGHT] = amplitude_lookup[(data >> 4) & 0x0f];
+ break;
+
+ /* channel i frequency */
+ case 0x08:
+ case 0x09:
+ case 0x0a:
+ case 0x0b:
+ case 0x0c:
+ case 0x0d:
+ ch = reg & 7;
+ saa->channels[ch].frequency = data & 0xff;
+ break;
+
+ /* channel i octave */
+ case 0x10:
+ case 0x11:
+ case 0x12:
+ ch = (reg - 0x10) << 1;
+ saa->channels[ch + 0].octave = data & 0x07;
+ saa->channels[ch + 1].octave = (data >> 4) & 0x07;
+ break;
+
+ /* channel i frequency enable */
+ case 0x14:
+ saa->channels[0].freq_enable = data & 0x01;
+ saa->channels[1].freq_enable = data & 0x02;
+ saa->channels[2].freq_enable = data & 0x04;
+ saa->channels[3].freq_enable = data & 0x08;
+ saa->channels[4].freq_enable = data & 0x10;
+ saa->channels[5].freq_enable = data & 0x20;
+ break;
+
+ /* channel i noise enable */
+ case 0x15:
+ saa->channels[0].noise_enable = data & 0x01;
+ saa->channels[1].noise_enable = data & 0x02;
+ saa->channels[2].noise_enable = data & 0x04;
+ saa->channels[3].noise_enable = data & 0x08;
+ saa->channels[4].noise_enable = data & 0x10;
+ saa->channels[5].noise_enable = data & 0x20;
+ break;
+
+ /* noise generators parameters */
+ case 0x16:
+ saa->noise_params[0] = data & 0x03;
+ saa->noise_params[1] = (data >> 4) & 0x03;
+ break;
+
+ /* envelope generators parameters */
+ case 0x18:
+ case 0x19:
+ ch = reg - 0x18;
+ saa->env_reverse_right[ch] = data & 0x01;
+ saa->env_mode[ch] = (data >> 1) & 0x07;
+ saa->env_bits[ch] = data & 0x10;
+ saa->env_clock[ch] = data & 0x20;
+ saa->env_enable[ch] = data & 0x80;
+ /* reset the envelope */
+ saa->env_step[ch] = 0;
+ break;
+
+ /* channels enable & reset generators */
+ case 0x1c:
+ saa->all_ch_enable = data & 0x01;
+ saa->sync_state = data & 0x02;
+ if (data & 0x02) {
+ int i;
+ /* Synch & Reset generators */
+ for (i = 0; i < 6; i++) {
+ saa->channels[i].level = 0;
+ saa->channels[i].counter = 0.0;
+ }
+ }
+ break;
+
+ default:
+ // The CMS allows all registers to be written, so we just output some debug
+ // message here
+ debug(5, "CMS Unkown write to reg %x with %x",reg, data);
+ }
+}
+
+class CMSMusicPlugin : public NullMusicPlugin {
+public:
+ const char *getName() const {
+ return _s("Creative Music System Emulator");
+ }
+
+ const char *getId() const {
+ return "cms";
+ }
+
+ MusicDevices getDevices() const;
+};
+
+MusicDevices CMSMusicPlugin::getDevices() const {
+ MusicDevices devices;
+ devices.push_back(MusicDevice(this, "", MT_CMS));
+ return devices;
+}
+
+//#if PLUGIN_ENABLED_DYNAMIC(CMS)
+ //REGISTER_PLUGIN_DYNAMIC(CMS, PLUGIN_TYPE_MUSIC, CMSMusicPlugin);
+//#else
+ REGISTER_PLUGIN_STATIC(CMS, PLUGIN_TYPE_MUSIC, CMSMusicPlugin);
+//#endif
diff --git a/sound/softsynth/cms.h b/sound/softsynth/cms.h
new file mode 100644
index 0000000000..d5bb7f0a42
--- /dev/null
+++ b/sound/softsynth/cms.h
@@ -0,0 +1,92 @@
+/* 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 SOUND_SOFTSYNTH_CMS_H
+#define SOUND_SOFTSYNTH_CMS_H
+
+#include "common/scummsys.h"
+
+/* this structure defines a channel */
+struct saa1099_channel {
+ int frequency; /* frequency (0x00..0xff) */
+ int freq_enable; /* frequency enable */
+ int noise_enable; /* noise enable */
+ int octave; /* octave (0x00..0x07) */
+ int amplitude[2]; /* amplitude (0x00..0x0f) */
+ int envelope[2]; /* envelope (0x00..0x0f or 0x10 == off) */
+
+ /* vars to simulate the square wave */
+ double counter;
+ double freq;
+ int level;
+};
+
+/* this structure defines a noise channel */
+struct saa1099_noise {
+ /* vars to simulate the noise generator output */
+ double counter;
+ double freq;
+ int level; /* noise polynomal shifter */
+};
+
+/* this structure defines a SAA1099 chip */
+struct SAA1099 {
+ int stream; /* our stream */
+ int noise_params[2]; /* noise generators parameters */
+ int env_enable[2]; /* envelope generators enable */
+ int env_reverse_right[2]; /* envelope reversed for right channel */
+ int env_mode[2]; /* envelope generators mode */
+ int env_bits[2]; /* non zero = 3 bits resolution */
+ int env_clock[2]; /* envelope clock mode (non-zero external) */
+ int env_step[2]; /* current envelope step */
+ int all_ch_enable; /* all channels enable */
+ int sync_state; /* sync all channels */
+ int selected_reg; /* selected register */
+ struct saa1099_channel channels[6]; /* channels */
+ struct saa1099_noise noise[2]; /* noise generators */
+};
+
+class CMSEmulator {
+public:
+ CMSEmulator(uint32 sampleRate) {
+ _sampleRate = sampleRate;
+ memset(_saa1099, 0, sizeof(SAA1099)*2);
+ }
+
+ ~CMSEmulator() { }
+
+ void portWrite(int port, int val);
+ void readBuffer(int16 *buffer, const int numSamples);
+private:
+ uint32 _sampleRate;
+
+ SAA1099 _saa1099[2];
+
+ void envelope(int chip, int ch);
+ void update(int chip, int16 *buffer, int length);
+ void portWriteIntern(int chip, int offset, int data);
+};
+
+
+#endif
diff --git a/sound/softsynth/fmtowns_pc98/towns_audio.cpp b/sound/softsynth/fmtowns_pc98/towns_audio.cpp
index e74991a55f..e6da237881 100644
--- a/sound/softsynth/fmtowns_pc98/towns_audio.cpp
+++ b/sound/softsynth/fmtowns_pc98/towns_audio.cpp
@@ -103,7 +103,8 @@ 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),
- _outputVolumeFlags(0), _outputMuteFlags(0), _ready(false) {
+ _outputVolumeFlags(0), _outputMuteFlags(0), _pcmChanOut(0), _pcmChanReserved(0), _pcmChanKeyPressed(0),
+ _pcmChanEffectPlaying(0), _pcmChanKeyPlaying(0), _ready(false) {
#define INTCB(x) &TownsAudioInterface::intf_##x
static const TownsAudioIntfCallback intfCb[] = {
@@ -199,7 +200,7 @@ TownsAudioInterface::TownsAudioInterface(Audio::Mixer *mixer, TownsAudioInterfac
INTCB(notImpl),
// 72
INTCB(notImpl),
- INTCB(notImpl),
+ INTCB(cdaToggle),
INTCB(notImpl),
INTCB(notImpl),
// 76
@@ -224,6 +225,10 @@ TownsAudioInterface::TownsAudioInterface(Audio::Mixer *mixer, TownsAudioInterfac
}
TownsAudioInterface::~TownsAudioInterface() {
+ reset();
+ _ready = false;
+ deinit();
+
delete[] _fmSaveReg[0];
delete[] _fmSaveReg[1];
delete[] _fmInstruments;
@@ -236,9 +241,6 @@ bool TownsAudioInterface::init() {
if (_ready)
return true;
- if (!_drv)
- return false;
-
if (!TownsPC98_FmSynth::init())
return false;
@@ -253,9 +255,9 @@ bool TownsAudioInterface::init() {
setVolumeChannelMasks(-1, 0);
+ _ready = true;
callback(0);
- _ready = true;
return true;
}
@@ -352,8 +354,9 @@ void TownsAudioInterface::timerCallbackA() {
void TownsAudioInterface::timerCallbackB() {
Common::StackLock lock(_mutex);
- if (_drv && _ready) {
- _drv->timerCallback(1);
+ if (_ready) {
+ if (_drv)
+ _drv->timerCallback(1);
callback(80);
}
}
@@ -491,7 +494,7 @@ int TownsAudioInterface::intf_enableTimerB(va_list &args) {
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*);
+ uint8 *src = va_arg(args, uint8*);
if (dest >= 65536 || size == 0 || size > 65536)
return 3;
@@ -563,7 +566,7 @@ int TownsAudioInterface::intf_loadWaveTable(va_list &args) {
TownsAudio_WaveTable *s = &_waveTables[_numWaveTables++];
s->readHeader(data);
-
+
_waveTablesTotalDataSize += s->size;
callback(32, _waveTablesTotalDataSize, s->size, data + 32);
@@ -658,7 +661,7 @@ int TownsAudioInterface::intf_pcmEffectPlaying(va_list &args) {
if (chan < 0x40 || chan > 0x47)
return 1;
chan -= 0x40;
- return (_pcmChanEffectPlaying & _chanFlags[chan]) ? true : false;
+ return (_pcmChanEffectPlaying & _chanFlags[chan]) ? 1 : 0;
}
int TownsAudioInterface::intf_fmKeyOn(va_list &args) {
@@ -719,11 +722,11 @@ int TownsAudioInterface::intf_setOutputVolume(va_list &args) {
static const uint8 flags[] = { 0x0C, 0x30, 0x40, 0x80 };
uint8 chan = (chanType & 0x40) ? 8 : 12;
-
+
chanType &= 3;
left = (left & 0x7e) >> 1;
right = (right & 0x7e) >> 1;
-
+
if (chan)
_outputVolumeFlags |= flags[chanType];
else
@@ -758,6 +761,12 @@ int TownsAudioInterface::intf_updateOutputVolume(va_list &args) {
return 0;
}
+int TownsAudioInterface::intf_cdaToggle(va_list &args) {
+ //int mode = va_arg(args, int);
+ //_unkMask = mode ? 0x7f : 0x3f;
+ return 0;
+}
+
int TownsAudioInterface::intf_pcmUpdateEnvelopeGenerator(va_list &args) {
for (int i = 0; i < 8; i++)
pcmUpdateEnvelopeGenerator(i);
@@ -1389,10 +1398,13 @@ 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 volume = (int)(((float)MAX(_outputLevel[12], _outputLevel[13]) * 255.0f) / 63.0f);
- int balance = (int)((float)((_outputLevel[13] - _outputLevel[12]) * 127.0f) / (float)MAX(_outputLevel[12], _outputLevel[13]));
+ uint32 maxVol = MAX(_outputLevel[12], _outputLevel[13]);
+
+ int volume = (int)(((float)(maxVol * 255) / 63.0f));
+ int balance = maxVol ? (int)( ( ((int)_outputLevel[13] - _outputLevel[12]) * 127) / (float)maxVol) : 0;
+
g_system->getAudioCDManager()->setVolume(volume);
g_system->getAudioCDManager()->setBalance(balance);
}
diff --git a/sound/softsynth/fmtowns_pc98/towns_audio.h b/sound/softsynth/fmtowns_pc98/towns_audio.h
index 950c016b4e..95fb1ded59 100644
--- a/sound/softsynth/fmtowns_pc98/towns_audio.h
+++ b/sound/softsynth/fmtowns_pc98/towns_audio.h
@@ -95,6 +95,7 @@ private:
int intf_setOutputVolume(va_list &args);
int intf_resetOutputVolume(va_list &args);
int intf_updateOutputVolume(va_list &args);
+ int intf_cdaToggle(va_list &args);
int intf_pcmUpdateEnvelopeGenerator(va_list &args);
int intf_notImpl(va_list &args);
diff --git a/sound/softsynth/fmtowns_pc98/towns_euphony.cpp b/sound/softsynth/fmtowns_pc98/towns_euphony.cpp
index 0c0c203cc9..7b52b4594f 100644
--- a/sound/softsynth/fmtowns_pc98/towns_euphony.cpp
+++ b/sound/softsynth/fmtowns_pc98/towns_euphony.cpp
@@ -131,7 +131,7 @@ void TownsEuphonyDriver::unloadWaveTable(int id) {
void TownsEuphonyDriver::reserveSoundEffectChannels(int num) {
_intf->callback(33, num);
uint32 volMask = 0;
-
+
if (num > 8)
return;
@@ -139,7 +139,7 @@ void TownsEuphonyDriver::reserveSoundEffectChannels(int num) {
volMask |= v;
v >>= 1;
}
-
+
_intf->setSoundEffectChanMask(volMask);
}
@@ -560,10 +560,10 @@ uint8 TownsEuphonyDriver::appendEvent(uint8 evt, uint8 chan) {
void TownsEuphonyDriver::sendEvent(uint8 mode, uint8 command) {
if (mode == 0) {
- warning("TownsEuphonyDriver: Mode 0 not implemented.");
+ // warning("TownsEuphonyDriver: Mode 0 not implemented");
} else if (mode == 0x10) {
- warning("TownsEuphonyDriver: Mode 0x10 not implemented.");
+ warning("TownsEuphonyDriver: Mode 0x10 not implemented");
} else if (mode == 0xff) {
if (command >= 0xf0) {
diff --git a/sound/softsynth/fmtowns_pc98/towns_pc98_driver.cpp b/sound/softsynth/fmtowns_pc98/towns_pc98_driver.cpp
index 82d0bd0438..8047616dbf 100644
--- a/sound/softsynth/fmtowns_pc98/towns_pc98_driver.cpp
+++ b/sound/softsynth/fmtowns_pc98/towns_pc98_driver.cpp
@@ -160,6 +160,7 @@ public:
void reset();
};
+#ifndef DISABLE_PC98_RHYTHM_CHANNEL
class TownsPC98_MusicChannelPCM : public TownsPC98_MusicChannel {
public:
TownsPC98_MusicChannelPCM(TownsPC98_AudioDriver *driver, uint8 regOffs,
@@ -178,6 +179,7 @@ private:
typedef bool (TownsPC98_MusicChannelPCM::*ControlEventFunc)(uint8 para);
const ControlEventFunc *controlEvents;
};
+#endif
TownsPC98_MusicChannel::TownsPC98_MusicChannel(TownsPC98_AudioDriver *driver, uint8 regOffs, uint8 flgs, uint8 num,
uint8 key, uint8 prt, uint8 id) : _drv(driver), _regOffset(regOffs), _flags(flgs), _chanNum(num), _keyNum(key),
@@ -312,7 +314,7 @@ void TownsPC98_MusicChannel::processEvents() {
void TownsPC98_MusicChannel::processFrequency() {
if (_flags & CHS_RECALCFREQ) {
- _frequency = (((const uint16 *)_drv->_opnFreqTable)[_frqBlockMSB & 0x0f] + _frqLSB) | (((_frqBlockMSB & 0x70) >> 1) << 8);
+ _frequency = (READ_LE_UINT16(&_drv->_opnFreqTable[(_frqBlockMSB & 0x0f) << 1]) + _frqLSB) | (((_frqBlockMSB & 0x70) >> 1) << 8);
_drv->writeReg(_part, _regOffset + 0xa4, (_frequency >> 8));
_drv->writeReg(_part, _regOffset + 0xa0, (_frequency & 0xff));
@@ -709,7 +711,7 @@ void TownsPC98_MusicChannelSSG::processFrequency() {
if (_flags & CHS_RECALCFREQ) {
_block = _frqBlockMSB >> 4;
- _frequency = ((const uint16 *)_drv->_opnFreqTableSSG)[_frqBlockMSB & 0x0f] + _frqLSB;
+ _frequency = READ_LE_UINT16(&_drv->_opnFreqTableSSG[(_frqBlockMSB & 0x0f) << 1]) + _frqLSB;
uint16 f = _frequency >> _block;
_drv->writeReg(_part, _regOffset << 1, f & 0xff);
@@ -928,6 +930,7 @@ void TownsPC98_SfxChannel::reset() {
_drv->_ssgPatches[i + 12] = src[i + 12];
}
+#ifndef DISABLE_PC98_RHYTHM_CHANNEL
TownsPC98_MusicChannelPCM::TownsPC98_MusicChannelPCM(TownsPC98_AudioDriver *driver, uint8 regOffs,
uint8 flgs, uint8 num, uint8 key, uint8 prt, uint8 id) :
TownsPC98_MusicChannel(driver, regOffs, flgs, num, key, prt, id), controlEvents(0) {
@@ -1016,9 +1019,13 @@ bool TownsPC98_MusicChannelPCM::control_ff_endOfTrack(uint8 para) {
return false;
}
}
+#endif // DISABLE_PC98_RHYTHM_CHANNEL
TownsPC98_AudioDriver::TownsPC98_AudioDriver(Audio::Mixer *mixer, EmuType type) : TownsPC98_FmSynth(mixer, type),
- _channels(0), _ssgChannels(0), _sfxChannels(0), _rhythmChannel(0),
+ _channels(0), _ssgChannels(0), _sfxChannels(0),
+#ifndef DISABLE_PC98_RHYTHM_CHANNEL
+ _rhythmChannel(0),
+#endif
_trackPtr(0), _sfxData(0), _sfxOffs(0), _ssgPatches(0),
_patches(0), _sfxBuffer(0), _musicBuffer(0),
@@ -1027,7 +1034,13 @@ TownsPC98_AudioDriver::TownsPC98_AudioDriver(Audio::Mixer *mixer, EmuType type)
_updateChannelsFlag(type == kType26 ? 0x07 : 0x3F), _finishedChannelsFlag(0),
_updateSSGFlag(type == kTypeTowns ? 0x00 : 0x07), _finishedSSGFlag(0),
- _updateRhythmFlag(type == kType86 ? 0x01 : 0x00), _finishedRhythmFlag(0),
+ _updateRhythmFlag(type == kType86 ?
+#ifndef DISABLE_PC98_RHYTHM_CHANNEL
+ 0x01
+#else
+ 0x00
+#endif
+ : 0x00), _finishedRhythmFlag(0),
_updateSfxFlag(0), _finishedSfxFlag(0),
_musicTickCounter(0),
@@ -1041,6 +1054,8 @@ TownsPC98_AudioDriver::TownsPC98_AudioDriver(Audio::Mixer *mixer, EmuType type)
TownsPC98_AudioDriver::~TownsPC98_AudioDriver() {
reset();
+ _ready = false;
+ deinit();
if (_channels) {
for (int i = 0; i < _numChan; i++)
@@ -1059,8 +1074,9 @@ TownsPC98_AudioDriver::~TownsPC98_AudioDriver() {
delete _sfxChannels[i];
delete[] _sfxChannels;
}
-
+#ifndef DISABLE_PC98_RHYTHM_CHANNEL
delete _rhythmChannel;
+#endif
delete[] _ssgPatches;
}
@@ -1104,10 +1120,12 @@ bool TownsPC98_AudioDriver::init() {
}
}
+#ifndef DISABLE_PC98_RHYTHM_CHANNEL
if (_hasPercussion) {
_rhythmChannel = new TownsPC98_MusicChannelPCM(this, 0, 0, 0, 0, 0, 1);
_rhythmChannel->init();
}
+#endif
setMusicTempo(84);
setSfxTempo(654);
@@ -1149,7 +1167,9 @@ void TownsPC98_AudioDriver::loadMusicData(uint8 *data, bool loadPaused) {
}
if (_hasPercussion) {
+#ifndef DISABLE_PC98_RHYTHM_CHANNEL
_rhythmChannel->loadData(data + READ_LE_UINT16(src_a));
+#endif
src_a += 2;
}
@@ -1209,8 +1229,10 @@ void TownsPC98_AudioDriver::reset() {
memcpy(_ssgPatches, _drvTables + 156, 256);
}
+#ifndef DISABLE_PC98_RHYTHM_CHANNEL
if (_rhythmChannel)
_rhythmChannel->reset();
+#endif
}
void TownsPC98_AudioDriver::fadeStep() {
@@ -1230,10 +1252,12 @@ void TownsPC98_AudioDriver::fadeStep() {
if (!_fading) {
_fading = 19;
+#ifndef DISABLE_PC98_RHYTHM_CHANNEL
if (_hasPercussion) {
if (_updateRhythmFlag & _rhythmChannel->_idFlag)
_rhythmChannel->reset();
}
+#endif
} else {
if (!--_fading)
reset();
@@ -1260,9 +1284,11 @@ void TownsPC98_AudioDriver::timerCallbackB() {
}
}
+#ifndef DISABLE_PC98_RHYTHM_CHANNEL
if (_hasPercussion)
if (_updateRhythmFlag & _rhythmChannel->_idFlag)
_rhythmChannel->processEvents();
+#endif
}
toggleRegProtection(false);
diff --git a/sound/softsynth/fmtowns_pc98/towns_pc98_driver.h b/sound/softsynth/fmtowns_pc98/towns_pc98_driver.h
index 18daee1e72..00fcf7c5d5 100644
--- a/sound/softsynth/fmtowns_pc98/towns_pc98_driver.h
+++ b/sound/softsynth/fmtowns_pc98/towns_pc98_driver.h
@@ -31,13 +31,17 @@
class TownsPC98_MusicChannel;
class TownsPC98_MusicChannelSSG;
class TownsPC98_SfxChannel;
+#ifndef DISABLE_PC98_RHYTHM_CHANNEL
class TownsPC98_MusicChannelPCM;
+#endif
class TownsPC98_AudioDriver : public TownsPC98_FmSynth {
friend class TownsPC98_MusicChannel;
friend class TownsPC98_MusicChannelSSG;
friend class TownsPC98_SfxChannel;
+#ifndef DISABLE_PC98_RHYTHM_CHANNEL
friend class TownsPC98_MusicChannelPCM;
+#endif
public:
TownsPC98_AudioDriver(Audio::Mixer *mixer, EmuType type);
~TownsPC98_AudioDriver();
@@ -84,7 +88,9 @@ protected:
TownsPC98_MusicChannel **_channels;
TownsPC98_MusicChannelSSG **_ssgChannels;
TownsPC98_SfxChannel **_sfxChannels;
+#ifndef DISABLE_PC98_RHYTHM_CHANNEL
TownsPC98_MusicChannelPCM *_rhythmChannel;
+#endif
const uint8 *_opnCarrier;
const uint8 *_opnFreqTable;
diff --git a/sound/softsynth/fmtowns_pc98/towns_pc98_fmsynth.cpp b/sound/softsynth/fmtowns_pc98/towns_pc98_fmsynth.cpp
index 241b9bde50..e779812c42 100644
--- a/sound/softsynth/fmtowns_pc98/towns_pc98_fmsynth.cpp
+++ b/sound/softsynth/fmtowns_pc98/towns_pc98_fmsynth.cpp
@@ -377,6 +377,7 @@ private:
bool _ready;
};
+#ifndef DISABLE_PC98_RHYTHM_CHANNEL
class TownsPC98_FmSynthPercussionSource {
public:
TownsPC98_FmSynthPercussionSource(const uint32 timerbase, const uint32 rtt);
@@ -442,6 +443,7 @@ private:
bool _ready;
};
+#endif // DISABLE_PC98_RHYTHM_CHANNEL
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),
@@ -627,6 +629,7 @@ void TownsPC98_FmSynthSquareSineSource::updateRegs() {
_updateRequest = -1;
}
+#ifndef DISABLE_PC98_RHYTHM_CHANNEL
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) {
@@ -823,11 +826,16 @@ void TownsPC98_FmSynthPercussionSource::advanceInput(RhtChannel *ins) {
cur >>= 4;
}
}
+#endif // DISABLE_PC98_RHYTHM_CHANNEL
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),
+ _chanInternal(0), _ssg(0),
+#ifndef DISABLE_PC98_RHYTHM_CHANNEL
+ _prc(0),
+#endif
+ _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),
_rtt(type == kTypeTowns ? 0x514767 : 0x5B8D80), _baserate(55125.0f / (float)mixer->getOutputRate()),
_volMaskA(0), _volMaskB(0), _volumeA(255), _volumeB(255),
@@ -835,16 +843,19 @@ TownsPC98_FmSynth::TownsPC98_FmSynth(Audio::Mixer *mixer, EmuType type) :
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);
+
+ _timers[0].cb = _timers[1].cb = &TownsPC98_FmSynth::idleTimerCallback;
+ _timerbase = (uint32)(_baserate * 1000000.0f);
}
TownsPC98_FmSynth::~TownsPC98_FmSynth() {
- Common::StackLock lock(_mutex);
- _mixer->stopHandle(_soundHandle);
+ if (_ready)
+ deinit();
+
delete _ssg;
+#ifndef DISABLE_PC98_RHYTHM_CHANNEL
delete _prc;
+#endif
delete[] _chanInternal;
delete[] _oprRates;
@@ -876,10 +887,15 @@ bool TownsPC98_FmSynth::init() {
_ssg->init(&_ssgTables[0], &_ssgTables[16]);
}
+#ifndef DISABLE_PC98_RHYTHM_CHANNEL
if (_hasPercussion) {
_prc = new TownsPC98_FmSynthPercussionSource(_timerbase, _rtt);
_prc->init(_percussionData);
}
+#endif
+
+ _timers[0].cb = &TownsPC98_FmSynth::timerCallbackA;
+ _timers[1].cb = &TownsPC98_FmSynth::timerCallbackB;
_mixer->playStream(Audio::Mixer::kPlainSoundType,
&_soundHandle, this, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO, true);
@@ -890,6 +906,7 @@ bool TownsPC98_FmSynth::init() {
}
void TownsPC98_FmSynth::reset() {
+ Common::StackLock lock(_mutex);
for (int i = 0; i < _numChan; i++) {
for (int ii = 0; ii < 4; ii++)
_chanInternal[i].opr[ii]->reset();
@@ -905,8 +922,10 @@ void TownsPC98_FmSynth::reset() {
if (_ssg)
_ssg->reset();
+#ifndef DISABLE_PC98_RHYTHM_CHANNEL
if (_prc)
_prc->reset();
+#endif
}
void TownsPC98_FmSynth::writeReg(uint8 part, uint8 regAddress, uint8 value) {
@@ -940,9 +959,11 @@ void TownsPC98_FmSynth::writeReg(uint8 part, uint8 regAddress, uint8 value) {
_ssg->writeReg(l, value);
break;
case 0x10:
+#ifndef DISABLE_PC98_RHYTHM_CHANNEL
// pcm rhythm channel
if (_prc)
_prc->writeReg(l, value);
+#endif
break;
case 0x20:
if (l == 8) {
@@ -1103,7 +1124,7 @@ int TownsPC98_FmSynth::readBuffer(int16 *buffer, const int numSamples) {
memset(tmp, 0, sizeof(int32) * numSamples);
int32 samplesLeft = numSamples >> 1;
- while (samplesLeft) {
+ while (_ready && samplesLeft) {
int32 render = samplesLeft;
for (int i = 0; i < 2; i++) {
@@ -1134,8 +1155,10 @@ int TownsPC98_FmSynth::readBuffer(int16 *buffer, const int numSamples) {
if (_ssg)
_ssg->nextTick(tmp, render);
+#ifndef DISABLE_PC98_RHYTHM_CHANNEL
if (_prc)
_prc->nextTick(tmp, render);
+#endif
nextTickEx(tmp, render);
@@ -1154,6 +1177,13 @@ int TownsPC98_FmSynth::readBuffer(int16 *buffer, const int numSamples) {
return numSamples;
}
+void TownsPC98_FmSynth::deinit() {
+ _ready = false;
+ _mixer->stopHandle(_soundHandle);
+ Common::StackLock lock(_mutex);
+ _timers[0].cb = _timers[1].cb = &TownsPC98_FmSynth::idleTimerCallback;
+}
+
uint8 TownsPC98_FmSynth::readSSGStatus() {
return _ssg->chanEnable();
}
@@ -1164,8 +1194,10 @@ void TownsPC98_FmSynth::setVolumeIntern(int volA, int volB) {
_volumeB = CLIP<uint16>(volB, 0, Audio::Mixer::kMaxMixerVolume);
if (_ssg)
_ssg->setVolumeIntern(_volumeA, _volumeB);
+#ifndef DISABLE_PC98_RHYTHM_CHANNEL
if (_prc)
_prc->setVolumeIntern(_volumeA, _volumeB);
+#endif
}
void TownsPC98_FmSynth::setVolumeChannelMasks(int channelMaskA, int channelMaskB) {
@@ -1174,8 +1206,10 @@ void TownsPC98_FmSynth::setVolumeChannelMasks(int channelMaskA, int channelMaskB
_volMaskB = channelMaskB;
if (_ssg)
_ssg->setVolumeChannelMasks(_volMaskA >> _numChan, _volMaskB >> _numChan);
+#ifndef DISABLE_PC98_RHYTHM_CHANNEL
if (_prc)
_prc->setVolumeChannelMasks(_volMaskA >> (_numChan + _numSSG), _volMaskB >> (_numChan + _numSSG));
+#endif
}
void TownsPC98_FmSynth::generateTables() {
@@ -1388,6 +1422,7 @@ const int TownsPC98_FmSynth::_ssgTables[] = {
0x000575, 0x000463, 0x00039D, 0x0002FA, 0x000242, 0x0001B6, 0x00014C, 0x0000FB
};
+#ifndef DISABLE_PC98_RHYTHM_CHANNEL
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,
@@ -1502,6 +1537,7 @@ 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
};
+#endif // DISABLE_PC98_RHYTHM_CHANNEL
TownsPC98_FmSynth::ChanInternal::ChanInternal() {
memset(this, 0, sizeof(ChanInternal));
diff --git a/sound/softsynth/fmtowns_pc98/towns_pc98_fmsynth.h b/sound/softsynth/fmtowns_pc98/towns_pc98_fmsynth.h
index 3072503610..ddd249b1b8 100644
--- a/sound/softsynth/fmtowns_pc98/towns_pc98_fmsynth.h
+++ b/sound/softsynth/fmtowns_pc98/towns_pc98_fmsynth.h
@@ -30,9 +30,21 @@
#include "sound/mixer.h"
#include "common/list.h"
+#ifdef __DS__
+/* This disables the rhythm channel when emulating the PC-98 type 86 sound card.
+ * The only purpose is code size reduction for certain backends.
+ * At the moment the only games which make use of the rhythm channel are the
+ * (very rare) PC-98 versions of Legend of Kyrandia 2 and Lands of Lore. Music will
+ * still be okay, just missing a couple of rhythm instruments.
+ */
+#define DISABLE_PC98_RHYTHM_CHANNEL
+#endif
+
class TownsPC98_FmSynthOperator;
class TownsPC98_FmSynthSquareSineSource;
+#ifndef DISABLE_PC98_RHYTHM_CHANNEL
class TownsPC98_FmSynthPercussionSource;
+#endif
enum EnvelopeState {
kEnvReady,
@@ -71,6 +83,8 @@ public:
}
protected:
+ void deinit();
+
// 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) {}
@@ -126,7 +140,9 @@ private:
};
TownsPC98_FmSynthSquareSineSource *_ssg;
+#ifndef DISABLE_PC98_RHYTHM_CHANNEL
TownsPC98_FmSynthPercussionSource *_prc;
+#endif
ChanInternal *_chanInternal;
uint8 *_oprRates;
@@ -140,6 +156,7 @@ private:
bool _regProtectionFlag;
typedef void (TownsPC98_FmSynth::*ChipTimerProc)();
+ void idleTimerCallback() {}
struct ChipTimer {
bool enabled;
@@ -165,7 +182,9 @@ private:
Audio::Mixer *_mixer;
Audio::SoundHandle _soundHandle;
+#ifndef DISABLE_PC98_RHYTHM_CHANNEL
static const uint8 _percussionData[];
+#endif
static const uint32 _adtStat[];
static const uint8 _detSrc[];
static const int _ssgTables[];
diff --git a/sound/softsynth/opl/mame.cpp b/sound/softsynth/opl/mame.cpp
index f6da659918..c875080e8f 100644
--- a/sound/softsynth/opl/mame.cpp
+++ b/sound/softsynth/opl/mame.cpp
@@ -694,7 +694,7 @@ static int OPLOpenTable(void) {
return 0;
}
/* make total level table */
- for (t = 0; t < EG_ENT - 1 ; t++) {
+ for (t = 0; t < EG_ENT - 1; t++) {
rate = ((1 << TL_BITS) - 1) / pow(10.0, EG_STEP * t / 20); /* dB -> voltage */
TL_TABLE[ t] = (int)rate;
TL_TABLE[TL_MAX + t] = -TL_TABLE[t];
@@ -1082,10 +1082,10 @@ void OPLResetChip(FM_OPL *OPL) {
for (i = 0xff; i >= 0x20; i--)
OPLWriteReg(OPL,i,0);
/* reset OPerator parameter */
- for (c = 0; c < OPL->max_ch ;c++ ) {
+ for (c = 0; c < OPL->max_ch; c++) {
OPL_CH *CH = &OPL->P_CH[c];
/* OPL->P_CH[c].PAN = OPN_CENTER; */
- for (s = 0; s < 2; s++ ) {
+ for (s = 0; s < 2; s++) {
/* wave table */
CH->SLOT[s].wavetable = &SIN_TABLE[0];
/* CH->SLOT[s].evm = ENV_MOD_RR; */