diff options
Diffstat (limited to 'sound')
-rw-r--r-- | sound/decoders/flac.cpp | 4 | ||||
-rw-r--r-- | sound/decoders/mac_snd.cpp | 2 | ||||
-rw-r--r-- | sound/decoders/mp3.cpp | 2 | ||||
-rw-r--r-- | sound/fmopl.cpp | 6 | ||||
-rw-r--r-- | sound/mididrv.cpp | 21 | ||||
-rw-r--r-- | sound/mididrv.h | 10 | ||||
-rw-r--r-- | sound/mixer.cpp | 4 | ||||
-rw-r--r-- | sound/mods/tfmx.cpp | 38 | ||||
-rw-r--r-- | sound/module.mk | 1 | ||||
-rw-r--r-- | sound/softsynth/cms.cpp | 372 | ||||
-rw-r--r-- | sound/softsynth/cms.h | 92 | ||||
-rw-r--r-- | sound/softsynth/fmtowns_pc98/towns_audio.cpp | 44 | ||||
-rw-r--r-- | sound/softsynth/fmtowns_pc98/towns_audio.h | 1 | ||||
-rw-r--r-- | sound/softsynth/fmtowns_pc98/towns_euphony.cpp | 8 | ||||
-rw-r--r-- | sound/softsynth/fmtowns_pc98/towns_pc98_driver.cpp | 36 | ||||
-rw-r--r-- | sound/softsynth/fmtowns_pc98/towns_pc98_driver.h | 6 | ||||
-rw-r--r-- | sound/softsynth/fmtowns_pc98/towns_pc98_fmsynth.cpp | 52 | ||||
-rw-r--r-- | sound/softsynth/fmtowns_pc98/towns_pc98_fmsynth.h | 19 | ||||
-rw-r--r-- | sound/softsynth/opl/mame.cpp | 6 |
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; */ |