aboutsummaryrefslogtreecommitdiff
path: root/sound
diff options
context:
space:
mode:
authorMax Horn2011-02-09 01:09:01 +0000
committerMax Horn2011-02-09 01:09:01 +0000
commit42ab839dd6c8a1570b232101eb97f4e54de57935 (patch)
tree3b763d8913a87482b793e0348c88b9a5f40eecc9 /sound
parent386203a3d6ce1abf457c9110d695408ec5f01b85 (diff)
downloadscummvm-rg350-42ab839dd6c8a1570b232101eb97f4e54de57935.tar.gz
scummvm-rg350-42ab839dd6c8a1570b232101eb97f4e54de57935.tar.bz2
scummvm-rg350-42ab839dd6c8a1570b232101eb97f4e54de57935.zip
AUDIO: Rename sound/ dir to audio/
svn-id: r55850
Diffstat (limited to 'sound')
-rw-r--r--sound/audiostream.cpp407
-rw-r--r--sound/audiostream.h371
-rw-r--r--sound/decoders/adpcm.cpp851
-rw-r--r--sound/decoders/adpcm.h90
-rw-r--r--sound/decoders/aiff.cpp186
-rw-r--r--sound/decoders/aiff.h71
-rw-r--r--sound/decoders/flac.cpp745
-rw-r--r--sound/decoders/flac.h75
-rw-r--r--sound/decoders/iff_sound.cpp130
-rw-r--r--sound/decoders/iff_sound.h47
-rw-r--r--sound/decoders/mac_snd.cpp116
-rw-r--r--sound/decoders/mac_snd.h58
-rw-r--r--sound/decoders/mp3.cpp375
-rw-r--r--sound/decoders/mp3.h76
-rw-r--r--sound/decoders/raw.cpp356
-rw-r--r--sound/decoders/raw.h153
-rw-r--r--sound/decoders/vag.cpp150
-rw-r--r--sound/decoders/vag.h60
-rw-r--r--sound/decoders/voc.cpp403
-rw-r--r--sound/decoders/voc.h107
-rw-r--r--sound/decoders/vorbis.cpp262
-rw-r--r--sound/decoders/vorbis.h75
-rw-r--r--sound/decoders/wave.cpp194
-rw-r--r--sound/decoders/wave.h84
-rw-r--r--sound/fmopl.cpp197
-rw-r--r--sound/fmopl.h179
-rw-r--r--sound/mididrv.cpp326
-rw-r--r--sound/mididrv.h288
-rw-r--r--sound/midiparser.cpp467
-rw-r--r--sound/midiparser.h404
-rw-r--r--sound/midiparser_smf.cpp384
-rw-r--r--sound/midiparser_xmidi.cpp375
-rw-r--r--sound/mixer.cpp556
-rw-r--r--sound/mixer.h265
-rw-r--r--sound/mixer_intern.h135
-rw-r--r--sound/mods/infogrames.cpp470
-rw-r--r--sound/mods/infogrames.h148
-rw-r--r--sound/mods/maxtrax.cpp1040
-rw-r--r--sound/mods/maxtrax.h225
-rw-r--r--sound/mods/module.cpp252
-rw-r--r--sound/mods/module.h90
-rw-r--r--sound/mods/paula.cpp212
-rw-r--r--sound/mods/paula.h210
-rw-r--r--sound/mods/protracker.cpp466
-rw-r--r--sound/mods/protracker.h57
-rw-r--r--sound/mods/rjp1.cpp582
-rw-r--r--sound/mods/rjp1.h50
-rw-r--r--sound/mods/soundfx.cpp275
-rw-r--r--sound/mods/soundfx.h53
-rw-r--r--sound/mods/tfmx.cpp1193
-rw-r--r--sound/mods/tfmx.h284
-rw-r--r--sound/module.mk61
-rw-r--r--sound/mpu401.cpp145
-rw-r--r--sound/mpu401.h92
-rw-r--r--sound/musicplugin.cpp64
-rw-r--r--sound/musicplugin.h125
-rw-r--r--sound/null.cpp62
-rw-r--r--sound/null.h56
-rw-r--r--sound/rate.cpp358
-rw-r--r--sound/rate.h90
-rw-r--r--sound/rate_arm.cpp465
-rw-r--r--sound/rate_arm_asm.s687
-rw-r--r--sound/softsynth/adlib.cpp1617
-rw-r--r--sound/softsynth/appleiigs.cpp57
-rw-r--r--sound/softsynth/cms.cpp376
-rw-r--r--sound/softsynth/cms.h92
-rw-r--r--sound/softsynth/emumidi.h116
-rw-r--r--sound/softsynth/fluidsynth.cpp254
-rw-r--r--sound/softsynth/fmtowns_pc98/towns_audio.cpp1583
-rw-r--r--sound/softsynth/fmtowns_pc98/towns_audio.h179
-rw-r--r--sound/softsynth/fmtowns_pc98/towns_euphony.cpp905
-rw-r--r--sound/softsynth/fmtowns_pc98/towns_euphony.h187
-rw-r--r--sound/softsynth/fmtowns_pc98/towns_pc98_driver.cpp1428
-rw-r--r--sound/softsynth/fmtowns_pc98/towns_pc98_driver.h135
-rw-r--r--sound/softsynth/fmtowns_pc98/towns_pc98_fmsynth.cpp1548
-rw-r--r--sound/softsynth/fmtowns_pc98/towns_pc98_fmsynth.h196
-rw-r--r--sound/softsynth/mt32.cpp573
-rw-r--r--sound/softsynth/mt32/freeverb.cpp310
-rw-r--r--sound/softsynth/mt32/freeverb.h244
-rw-r--r--sound/softsynth/mt32/i386.cpp849
-rw-r--r--sound/softsynth/mt32/i386.h49
-rw-r--r--sound/softsynth/mt32/module.mk14
-rw-r--r--sound/softsynth/mt32/mt32_file.cpp70
-rw-r--r--sound/softsynth/mt32/mt32_file.h52
-rw-r--r--sound/softsynth/mt32/mt32emu.h70
-rw-r--r--sound/softsynth/mt32/part.cpp633
-rw-r--r--sound/softsynth/mt32/part.h113
-rw-r--r--sound/softsynth/mt32/partial.cpp968
-rw-r--r--sound/softsynth/mt32/partial.h148
-rw-r--r--sound/softsynth/mt32/partialManager.cpp272
-rw-r--r--sound/softsynth/mt32/partialManager.h56
-rw-r--r--sound/softsynth/mt32/structures.h284
-rw-r--r--sound/softsynth/mt32/synth.cpp1198
-rw-r--r--sound/softsynth/mt32/synth.h300
-rw-r--r--sound/softsynth/mt32/tables.cpp757
-rw-r--r--sound/softsynth/mt32/tables.h116
-rw-r--r--sound/softsynth/opl/dbopl.cpp1536
-rw-r--r--sound/softsynth/opl/dbopl.h283
-rw-r--r--sound/softsynth/opl/dosbox.cpp335
-rw-r--r--sound/softsynth/opl/dosbox.h110
-rw-r--r--sound/softsynth/opl/mame.cpp1234
-rw-r--r--sound/softsynth/opl/mame.h202
-rw-r--r--sound/softsynth/pcspk.cpp187
-rw-r--r--sound/softsynth/pcspk.h88
-rw-r--r--sound/softsynth/sid.cpp1456
-rw-r--r--sound/softsynth/sid.h348
-rw-r--r--sound/softsynth/wave6581.cpp2098
-rw-r--r--sound/softsynth/ym2612.cpp789
-rw-r--r--sound/softsynth/ym2612.h179
-rw-r--r--sound/timestamp.cpp212
-rw-r--r--sound/timestamp.h251
111 files changed, 0 insertions, 41887 deletions
diff --git a/sound/audiostream.cpp b/sound/audiostream.cpp
deleted file mode 100644
index b3efb2cefe..0000000000
--- a/sound/audiostream.cpp
+++ /dev/null
@@ -1,407 +0,0 @@
-/* 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 "common/debug.h"
-#include "common/endian.h"
-#include "common/file.h"
-#include "common/queue.h"
-#include "common/util.h"
-
-#include "sound/audiostream.h"
-#include "sound/decoders/flac.h"
-#include "sound/mixer.h"
-#include "sound/decoders/mp3.h"
-#include "sound/decoders/raw.h"
-#include "sound/decoders/vorbis.h"
-
-
-namespace Audio {
-
-struct StreamFileFormat {
- /** Decodername */
- const char *decoderName;
- const char *fileExtension;
- /**
- * Pointer to a function which tries to open a file of type StreamFormat.
- * Return NULL in case of an error (invalid/nonexisting file).
- */
- SeekableAudioStream *(*openStreamFile)(Common::SeekableReadStream *stream, DisposeAfterUse::Flag disposeAfterUse);
-};
-
-static const StreamFileFormat STREAM_FILEFORMATS[] = {
- /* decoderName, fileExt, openStreamFuntion */
-#ifdef USE_FLAC
- { "FLAC", ".flac", makeFLACStream },
- { "FLAC", ".fla", makeFLACStream },
-#endif
-#ifdef USE_VORBIS
- { "Ogg Vorbis", ".ogg", makeVorbisStream },
-#endif
-#ifdef USE_MAD
- { "MPEG Layer 3", ".mp3", makeMP3Stream },
-#endif
-
- { NULL, NULL, NULL } // Terminator
-};
-
-SeekableAudioStream *SeekableAudioStream::openStreamFile(const Common::String &basename) {
- SeekableAudioStream *stream = NULL;
- Common::File *fileHandle = new Common::File();
-
- for (int i = 0; i < ARRAYSIZE(STREAM_FILEFORMATS)-1 && stream == NULL; ++i) {
- Common::String filename = basename + STREAM_FILEFORMATS[i].fileExtension;
- fileHandle->open(filename);
- if (fileHandle->isOpen()) {
- // Create the stream object
- stream = STREAM_FILEFORMATS[i].openStreamFile(fileHandle, DisposeAfterUse::YES);
- fileHandle = 0;
- break;
- }
- }
-
- delete fileHandle;
-
- if (stream == NULL)
- debug(1, "SeekableAudioStream::openStreamFile: Could not open compressed AudioFile %s", basename.c_str());
-
- return stream;
-}
-
-#pragma mark -
-#pragma mark --- LoopingAudioStream ---
-#pragma mark -
-
-LoopingAudioStream::LoopingAudioStream(RewindableAudioStream *stream, uint loops, DisposeAfterUse::Flag disposeAfterUse)
- : _parent(stream), _disposeAfterUse(disposeAfterUse), _loops(loops), _completeIterations(0) {
- assert(stream);
-
- if (!stream->rewind()) {
- // TODO: Properly indicate error
- _loops = _completeIterations = 1;
- }
-}
-
-LoopingAudioStream::~LoopingAudioStream() {
- if (_disposeAfterUse == DisposeAfterUse::YES)
- delete _parent;
-}
-
-int LoopingAudioStream::readBuffer(int16 *buffer, const int numSamples) {
- if ((_loops && _completeIterations == _loops) || !numSamples)
- return 0;
-
- int samplesRead = _parent->readBuffer(buffer, numSamples);
-
- if (_parent->endOfStream()) {
- ++_completeIterations;
- if (_completeIterations == _loops)
- return samplesRead;
-
- const int remainingSamples = numSamples - samplesRead;
-
- if (!_parent->rewind()) {
- // TODO: Properly indicate error
- _loops = _completeIterations = 1;
- return samplesRead;
- }
-
- return samplesRead + readBuffer(buffer + samplesRead, remainingSamples);
- }
-
- return samplesRead;
-}
-
-bool LoopingAudioStream::endOfData() const {
- return (_loops != 0 && (_completeIterations == _loops));
-}
-
-AudioStream *makeLoopingAudioStream(RewindableAudioStream *stream, uint loops) {
- if (loops != 1)
- return new LoopingAudioStream(stream, loops);
- else
- return stream;
-}
-
-AudioStream *makeLoopingAudioStream(SeekableAudioStream *stream, Timestamp start, Timestamp end, uint loops) {
- if (!start.totalNumberOfFrames() && (!end.totalNumberOfFrames() || end == stream->getLength())) {
- return makeLoopingAudioStream(stream, loops);
- } else {
- if (!end.totalNumberOfFrames())
- end = stream->getLength();
-
- if (start >= end) {
- warning("makeLoopingAudioStream: start (%d) >= end (%d)", start.msecs(), end.msecs());
- delete stream;
- return 0;
- }
-
- return makeLoopingAudioStream(new SubSeekableAudioStream(stream, start, end), loops);
- }
-}
-
-#pragma mark -
-#pragma mark --- SubLoopingAudioStream ---
-#pragma mark -
-
-SubLoopingAudioStream::SubLoopingAudioStream(SeekableAudioStream *stream,
- uint loops,
- const Timestamp loopStart,
- const Timestamp loopEnd,
- DisposeAfterUse::Flag disposeAfterUse)
- : _parent(stream), _disposeAfterUse(disposeAfterUse), _loops(loops),
- _pos(0, getRate() * (isStereo() ? 2 : 1)),
- _loopStart(convertTimeToStreamPos(loopStart, getRate(), isStereo())),
- _loopEnd(convertTimeToStreamPos(loopEnd, getRate(), isStereo())),
- _done(false) {
- assert(loopStart < loopEnd);
-
- if (!_parent->rewind())
- _done = true;
-}
-
-SubLoopingAudioStream::~SubLoopingAudioStream() {
- if (_disposeAfterUse == DisposeAfterUse::YES)
- delete _parent;
-}
-
-int SubLoopingAudioStream::readBuffer(int16 *buffer, const int numSamples) {
- if (_done)
- return 0;
-
- int framesLeft = MIN(_loopEnd.frameDiff(_pos), numSamples);
- int framesRead = _parent->readBuffer(buffer, framesLeft);
- _pos = _pos.addFrames(framesRead);
-
- if (framesRead < framesLeft && _parent->endOfData()) {
- // TODO: Proper error indication.
- _done = true;
- return framesRead;
- } else if (_pos == _loopEnd) {
- if (_loops != 0) {
- --_loops;
- if (!_loops) {
- _done = true;
- return framesRead;
- }
- }
-
- if (!_parent->seek(_loopStart)) {
- // TODO: Proper error indication.
- _done = true;
- return framesRead;
- }
-
- _pos = _loopStart;
- framesLeft = numSamples - framesLeft;
- return framesRead + readBuffer(buffer + framesRead, framesLeft);
- } else {
- return framesRead;
- }
-}
-
-#pragma mark -
-#pragma mark --- SubSeekableAudioStream ---
-#pragma mark -
-
-SubSeekableAudioStream::SubSeekableAudioStream(SeekableAudioStream *parent, const Timestamp start, const Timestamp end, DisposeAfterUse::Flag disposeAfterUse)
- : _parent(parent), _disposeAfterUse(disposeAfterUse),
- _start(convertTimeToStreamPos(start, getRate(), isStereo())),
- _pos(0, getRate() * (isStereo() ? 2 : 1)),
- _length(convertTimeToStreamPos(end - start, getRate(), isStereo())) {
-
- assert(_length.totalNumberOfFrames() % (isStereo() ? 2 : 1) == 0);
- _parent->seek(_start);
-}
-
-SubSeekableAudioStream::~SubSeekableAudioStream() {
- if (_disposeAfterUse)
- delete _parent;
-}
-
-int SubSeekableAudioStream::readBuffer(int16 *buffer, const int numSamples) {
- int framesLeft = MIN(_length.frameDiff(_pos), numSamples);
- int framesRead = _parent->readBuffer(buffer, framesLeft);
- _pos = _pos.addFrames(framesRead);
- return framesRead;
-}
-
-bool SubSeekableAudioStream::seek(const Timestamp &where) {
- _pos = convertTimeToStreamPos(where, getRate(), isStereo());
- if (_pos > _length) {
- _pos = _length;
- return false;
- }
-
- if (_parent->seek(_pos + _start)) {
- return true;
- } else {
- _pos = _length;
- return false;
- }
-}
-
-#pragma mark -
-#pragma mark --- Queueing audio stream ---
-#pragma mark -
-
-
-void QueuingAudioStream::queueBuffer(byte *data, uint32 size, DisposeAfterUse::Flag disposeAfterUse, byte flags) {
- AudioStream *stream = makeRawStream(data, size, getRate(), flags, disposeAfterUse);
- queueAudioStream(stream, DisposeAfterUse::YES);
-}
-
-
-class QueuingAudioStreamImpl : public QueuingAudioStream {
-private:
- /**
- * We queue a number of (pointers to) audio stream objects.
- * In addition, we need to remember for each stream whether
- * to dispose it after all data has been read from it.
- * Hence, we don't store pointers to stream objects directly,
- * but rather StreamHolder structs.
- */
- struct StreamHolder {
- AudioStream *_stream;
- DisposeAfterUse::Flag _disposeAfterUse;
- StreamHolder(AudioStream *stream, DisposeAfterUse::Flag disposeAfterUse)
- : _stream(stream),
- _disposeAfterUse(disposeAfterUse) {}
- };
-
- /**
- * The sampling rate of this audio stream.
- */
- const int _rate;
-
- /**
- * Whether this audio stream is mono (=false) or stereo (=true).
- */
- const int _stereo;
-
- /**
- * This flag is set by the finish() method only. See there for more details.
- */
- bool _finished;
-
- /**
- * A mutex to avoid access problems (causing e.g. corruption of
- * the linked list) in thread aware environments.
- */
- Common::Mutex _mutex;
-
- /**
- * The queue of audio streams.
- */
- Common::Queue<StreamHolder> _queue;
-
-public:
- QueuingAudioStreamImpl(int rate, bool stereo)
- : _rate(rate), _stereo(stereo), _finished(false) {}
- ~QueuingAudioStreamImpl();
-
- // Implement the AudioStream API
- virtual int readBuffer(int16 *buffer, const int numSamples);
- virtual bool isStereo() const { return _stereo; }
- virtual int getRate() const { return _rate; }
- virtual bool endOfData() const {
- //Common::StackLock lock(_mutex);
- return _queue.empty();
- }
- virtual bool endOfStream() const { return _finished && _queue.empty(); }
-
- // Implement the QueuingAudioStream API
- virtual void queueAudioStream(AudioStream *stream, DisposeAfterUse::Flag disposeAfterUse);
- virtual void finish() { _finished = true; }
-
- uint32 numQueuedStreams() const {
- //Common::StackLock lock(_mutex);
- return _queue.size();
- }
-};
-
-QueuingAudioStreamImpl::~QueuingAudioStreamImpl() {
- while (!_queue.empty()) {
- StreamHolder tmp = _queue.pop();
- if (tmp._disposeAfterUse == DisposeAfterUse::YES)
- delete tmp._stream;
- }
-}
-
-void QueuingAudioStreamImpl::queueAudioStream(AudioStream *stream, DisposeAfterUse::Flag disposeAfterUse) {
- assert(!_finished);
- if ((stream->getRate() != getRate()) || (stream->isStereo() != isStereo()))
- error("QueuingAudioStreamImpl::queueAudioStream: stream has mismatched parameters");
-
- Common::StackLock lock(_mutex);
- _queue.push(StreamHolder(stream, disposeAfterUse));
-}
-
-int QueuingAudioStreamImpl::readBuffer(int16 *buffer, const int numSamples) {
- Common::StackLock lock(_mutex);
- int samplesDecoded = 0;
-
- while (samplesDecoded < numSamples && !_queue.empty()) {
- AudioStream *stream = _queue.front()._stream;
- samplesDecoded += stream->readBuffer(buffer + samplesDecoded, numSamples - samplesDecoded);
-
- if (stream->endOfData()) {
- StreamHolder tmp = _queue.pop();
- if (tmp._disposeAfterUse == DisposeAfterUse::YES)
- delete stream;
- }
- }
-
- return samplesDecoded;
-}
-
-QueuingAudioStream *makeQueuingAudioStream(int rate, bool stereo) {
- return new QueuingAudioStreamImpl(rate, stereo);
-}
-
-Timestamp convertTimeToStreamPos(const Timestamp &where, int rate, bool isStereo) {
- Timestamp result(where.convertToFramerate(rate * (isStereo ? 2 : 1)));
-
- // When the Stream is a stereo stream, we have to assure
- // that the sample position is an even number.
- if (isStereo && (result.totalNumberOfFrames() & 1))
- result = result.addFrames(-1); // We cut off one sample here.
-
- // Since Timestamp allows sub-frame-precision it might lead to odd behaviors
- // when we would just return result.
- //
- // An example is when converting the timestamp 500ms to a 11025 Hz based
- // stream. It would have an internal frame counter of 5512.5. Now when
- // doing calculations at frame precision, this might lead to unexpected
- // results: The frame difference between a timestamp 1000ms and the above
- // mentioned timestamp (both with 11025 as framerate) would be 5512,
- // instead of 5513, which is what a frame-precision based code would expect.
- //
- // By creating a new Timestamp with the given parameters, we create a
- // Timestamp with frame-precision, which just drops a sub-frame-precision
- // information (i.e. rounds down).
- return Timestamp(result.secs(), result.numberOfFrames(), result.framerate());
-}
-
-} // End of namespace Audio
diff --git a/sound/audiostream.h b/sound/audiostream.h
deleted file mode 100644
index b2c012841d..0000000000
--- a/sound/audiostream.h
+++ /dev/null
@@ -1,371 +0,0 @@
-/* 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_AUDIOSTREAM_H
-#define SOUND_AUDIOSTREAM_H
-
-#include "common/util.h"
-#include "common/scummsys.h"
-#include "common/types.h"
-
-#include "sound/timestamp.h"
-
-namespace Audio {
-
-class SeekableAudioStream;
-
-/**
- * Generic audio input stream. Subclasses of this are used to feed arbitrary
- * sampled audio data into ScummVM's audio mixer.
- */
-class AudioStream {
-public:
- virtual ~AudioStream() {}
-
- /**
- * Fill the given buffer with up to numSamples samples. Returns the actual
- * number of samples read, or -1 if a critical error occurred (note: you
- * *must* check if this value is less than what you requested, this can
- * happen when the stream is fully used up).
- *
- * Data has to be in native endianess, 16 bit per sample, signed. For stereo
- * stream, buffer will be filled with interleaved left and right channel
- * samples, starting with a left sample. Furthermore, the samples in the
- * left and right are summed up. So if you request 4 samples from a stereo
- * stream, you will get a total of two left channel and two right channel
- * samples.
- */
- virtual int readBuffer(int16 *buffer, const int numSamples) = 0;
-
- /** Is this a stereo stream? */
- virtual bool isStereo() const = 0;
-
- /** Sample rate of the stream. */
- virtual int getRate() const = 0;
-
- /**
- * End of data reached? If this returns true, it means that at this
- * time there is no data available in the stream. However there may be
- * more data in the future.
- * This is used by e.g. a rate converter to decide whether to keep on
- * converting data or stop.
- */
- virtual bool endOfData() const = 0;
-
- /**
- * End of stream reached? If this returns true, it means that all data
- * in this stream is used up and no additional data will appear in it
- * in the future.
- * This is used by the mixer to decide whether a given stream shall be
- * removed from the list of active streams (and thus be destroyed).
- * By default this maps to endOfData()
- */
- virtual bool endOfStream() const { return endOfData(); }
-};
-
-/**
- * A rewindable audio stream. This allows for reseting the AudioStream
- * to its initial state. Note that rewinding itself is not required to
- * be working when the stream is being played by Mixer!
- */
-class RewindableAudioStream : public AudioStream {
-public:
- /**
- * Rewinds the stream to its start.
- *
- * @return true on success, false otherwise.
- */
- virtual bool rewind() = 0;
-};
-
-/**
- * A looping audio stream. This object does nothing besides using
- * a RewindableAudioStream to play a stream in a loop.
- */
-class LoopingAudioStream : public AudioStream {
-public:
- /**
- * Creates a looping audio stream object.
- *
- * Note that on creation of the LoopingAudioStream object
- * the underlying stream will be rewound.
- *
- * @see makeLoopingAudioStream
- *
- * @param stream Stream to loop
- * @param loops How often to loop (0 = infinite)
- * @param disposeAfterUse Destroy the stream after the LoopingAudioStream has finished playback.
- */
- LoopingAudioStream(RewindableAudioStream *stream, uint loops, DisposeAfterUse::Flag disposeAfterUse = DisposeAfterUse::YES);
- ~LoopingAudioStream();
-
- int readBuffer(int16 *buffer, const int numSamples);
- bool endOfData() const;
-
- bool isStereo() const { return _parent->isStereo(); }
- int getRate() const { return _parent->getRate(); }
-
- /**
- * Returns number of loops the stream has played.
- *
- * @param numLoops number of loops to play, 0 - infinite
- */
- uint getCompleteIterations() const { return _completeIterations; }
-private:
- RewindableAudioStream *_parent;
- DisposeAfterUse::Flag _disposeAfterUse;
-
- uint _loops;
- uint _completeIterations;
-};
-
-/**
- * Wrapper functionality to efficiently create a stream, which might be looped.
- *
- * Note that this function does not return a LoopingAudioStream, because it does
- * not create one when the loop count is "1". This allows to keep the runtime
- * overhead down, when the code does not require any functionality only offered
- * by LoopingAudioStream.
- *
- * @param stream Stream to loop (will be automatically destroyed, when the looping is done)
- * @param loops How often to loop (0 = infinite)
- * @return A new AudioStream, which offers the desired functionality.
- */
-AudioStream *makeLoopingAudioStream(RewindableAudioStream *stream, uint loops);
-
-/**
- * A seekable audio stream. Subclasses of this class implement an
- * interface for seeking. The seeking itself is not required to be
- * working while the stream is being played by Mixer!
- */
-class SeekableAudioStream : public RewindableAudioStream {
-public:
- /**
- * Tries to load a file by trying all available formats.
- * In case of an error, the file handle will be closed, but deleting
- * it is still the responsibility of the caller.
- *
- * @param basename a filename without an extension
- * @return an SeekableAudioStream ready to use in case of success;
- * NULL in case of an error (e.g. invalid/nonexisting file)
- */
- static SeekableAudioStream *openStreamFile(const Common::String &basename);
-
- /**
- * Seeks to a given offset in the stream.
- *
- * @param where offset in milliseconds
- * @return true on success, false on failure.
- */
- bool seek(uint32 where) {
- return seek(Timestamp(where, getRate()));
- }
-
- /**
- * Seeks to a given offset in the stream.
- *
- * @param where offset as timestamp
- * @return true on success, false on failure.
- */
- virtual bool seek(const Timestamp &where) = 0;
-
- /**
- * Returns the length of the stream.
- *
- * @return length as Timestamp.
- */
- virtual Timestamp getLength() const = 0;
-
- virtual bool rewind() { return seek(0); }
-};
-
-/**
- * Wrapper functionality to efficiently create a stream, which might be looped
- * in a certain interval.
- *
- * This automatically starts the stream at time "start"!
- *
- * Note that this function does not return a LoopingAudioStream, because it does
- * not create one when the loop count is "1". This allows to keep the runtime
- * overhead down, when the code does not require any functionality only offered
- * by LoopingAudioStream.
- *
- * @param stream Stream to loop (will be automatically destroyed, when the looping is done)
- * @param start Starttime of the stream interval to be looped
- * @param end End of the stream interval to be looped (a zero time, means till end)
- * @param loops How often to loop (0 = infinite)
- * @return A new AudioStream, which offers the desired functionality.
- */
-AudioStream *makeLoopingAudioStream(SeekableAudioStream *stream, Timestamp start, Timestamp end, uint loops);
-
-/**
- * A looping audio stream, which features looping of a nested part of the
- * stream.
- *
- * NOTE:
- * Currently this implementation stops after the nested loop finished
- * playback.
- *
- * IMPORTANT:
- * This might be merged with SubSeekableAudioStream for playback purposes.
- * (After extending it to accept a start time).
- */
-class SubLoopingAudioStream : public AudioStream {
-public:
- /**
- * Constructor for a SubLoopingAudioStream.
- *
- * Note that on creation of the SubLoopingAudioStream object
- * the underlying stream will be rewound.
- *
- * @param stream Stream to loop
- * @param loops How often the stream should be looped (0 means infinite)
- * @param loopStart Start of the loop (this must be smaller than loopEnd)
- * @param loopEnd End of the loop (thus must be greater than loopStart)
- * @param disposeAfterUse Whether the stream should be disposed, when the
- * SubLoopingAudioStream is destroyed.
- */
- SubLoopingAudioStream(SeekableAudioStream *stream, uint loops,
- const Timestamp loopStart,
- const Timestamp loopEnd,
- DisposeAfterUse::Flag disposeAfterUse = DisposeAfterUse::YES);
- ~SubLoopingAudioStream();
-
- int readBuffer(int16 *buffer, const int numSamples);
- bool endOfData() const { return _done; }
-
- bool isStereo() const { return _parent->isStereo(); }
- int getRate() const { return _parent->getRate(); }
-private:
- SeekableAudioStream *_parent;
- DisposeAfterUse::Flag _disposeAfterUse;
-
- uint _loops;
- Timestamp _pos;
- Timestamp _loopStart, _loopEnd;
-
- bool _done;
-};
-
-
-/**
- * A SubSeekableAudioStream provides access to a SeekableAudioStream
- * just in the range [start, end).
- * The same caveats apply to SubSeekableAudioStream as do to SeekableAudioStream.
- *
- * Manipulating the parent stream directly /will/ mess up a substream.
- */
-class SubSeekableAudioStream : public SeekableAudioStream {
-public:
- /**
- * Creates a new SubSeekableAudioStream.
- *
- * @param parent parent stream object.
- * @param start Start time.
- * @param end End time.
- * @param disposeAfterUse Whether the parent stream object should be destroyed on destruction of the SubSeekableAudioStream.
- */
- SubSeekableAudioStream(SeekableAudioStream *parent, const Timestamp start, const Timestamp end, DisposeAfterUse::Flag disposeAfterUse = DisposeAfterUse::YES);
- ~SubSeekableAudioStream();
-
- int readBuffer(int16 *buffer, const int numSamples);
-
- bool isStereo() const { return _parent->isStereo(); }
-
- int getRate() const { return _parent->getRate(); }
-
- bool endOfData() const { return (_pos >= _length) || _parent->endOfStream(); }
-
- bool seek(const Timestamp &where);
-
- Timestamp getLength() const { return _length; }
-private:
- SeekableAudioStream *_parent;
- DisposeAfterUse::Flag _disposeAfterUse;
-
- const Timestamp _start;
- const Timestamp _length;
- Timestamp _pos;
-};
-
-class QueuingAudioStream : public Audio::AudioStream {
-public:
-
- /**
- * Queue an audio stream for playback. This stream plays all queued
- * streams, in the order they were queued. If disposeAfterUse is set to
- * DisposeAfterUse::YES, then the queued stream is deleted after all data
- * contained in it has been played.
- */
- virtual void queueAudioStream(Audio::AudioStream *audStream,
- DisposeAfterUse::Flag disposeAfterUse = DisposeAfterUse::YES) = 0;
-
- /**
- * Queue a block of raw audio data for playback. This stream plays all
- * queued block, in the order they were queued. If disposeAfterUse is set
- * to DisposeAfterUse::YES, then the queued block is released using free()
- * after all data contained in it has been played.
- *
- * @note Make sure to allocate the data block with malloc(), not with new[].
- *
- * @param data pointer to the audio data block
- * @param size length of the audio data block
- * @param disposeAfterUse if equal to DisposeAfterUse::YES, the block is released using free() after use.
- * @param flags a bit-ORed combination of RawFlags describing the audio data format
- */
- void queueBuffer(byte *data, uint32 size, DisposeAfterUse::Flag disposeAfterUse, byte flags);
-
- /**
- * Mark this stream as finished. That is, signal that no further data
- * will be queued to it. Only after this has been done can this
- * stream ever 'end'.
- */
- virtual void finish() = 0;
-
- /**
- * Return the number of streams still queued for playback (including
- * the currently playing stream).
- */
- virtual uint32 numQueuedStreams() const = 0;
-};
-
-/**
- * Factory function for an QueuingAudioStream.
- */
-QueuingAudioStream *makeQueuingAudioStream(int rate, bool stereo);
-
-/**
- * Converts a point in time to a precise sample offset
- * with the given parameters.
- *
- * @param where Point in time.
- * @param rate Rate of the stream.
- * @param isStereo Is the stream a stereo stream?
- */
-Timestamp convertTimeToStreamPos(const Timestamp &where, int rate, bool isStereo);
-
-} // End of namespace Audio
-
-#endif
diff --git a/sound/decoders/adpcm.cpp b/sound/decoders/adpcm.cpp
deleted file mode 100644
index 4b5e6a5b84..0000000000
--- a/sound/decoders/adpcm.cpp
+++ /dev/null
@@ -1,851 +0,0 @@
-/* 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 "common/endian.h"
-
-#include "sound/decoders/adpcm.h"
-#include "sound/audiostream.h"
-
-
-namespace Audio {
-
-class ADPCMStream : public RewindableAudioStream {
-protected:
- Common::SeekableReadStream *_stream;
- const DisposeAfterUse::Flag _disposeAfterUse;
- const int32 _startpos;
- const int32 _endpos;
- const int _channels;
- const uint32 _blockAlign;
- uint32 _blockPos[2];
- const int _rate;
-
- struct {
- // OKI/IMA
- struct {
- int32 last;
- int32 stepIndex;
- } ima_ch[2];
- } _status;
-
- virtual void reset();
- int16 stepAdjust(byte);
-
-public:
- ADPCMStream(Common::SeekableReadStream *stream, DisposeAfterUse::Flag disposeAfterUse, uint32 size, int rate, int channels, uint32 blockAlign);
- ~ADPCMStream();
-
- virtual bool endOfData() const { return (_stream->eos() || _stream->pos() >= _endpos); }
- virtual bool isStereo() const { return _channels == 2; }
- virtual int getRate() const { return _rate; }
-
- virtual bool rewind();
-};
-
-// Routines to convert 12 bit linear samples to the
-// Dialogic or Oki ADPCM coding format aka VOX.
-// See also <http://www.comptek.ru/telephony/tnotes/tt1-13.html>
-//
-// IMA ADPCM support is based on
-// <http://wiki.multimedia.cx/index.php?title=IMA_ADPCM>
-//
-// In addition, also MS IMA ADPCM is supported. See
-// <http://wiki.multimedia.cx/index.php?title=Microsoft_IMA_ADPCM>.
-
-ADPCMStream::ADPCMStream(Common::SeekableReadStream *stream, DisposeAfterUse::Flag disposeAfterUse, uint32 size, int rate, int channels, uint32 blockAlign)
- : _stream(stream),
- _disposeAfterUse(disposeAfterUse),
- _startpos(stream->pos()),
- _endpos(_startpos + size),
- _channels(channels),
- _blockAlign(blockAlign),
- _rate(rate) {
-
- reset();
-}
-
-ADPCMStream::~ADPCMStream() {
- if (_disposeAfterUse == DisposeAfterUse::YES)
- delete _stream;
-}
-
-void ADPCMStream::reset() {
- memset(&_status, 0, sizeof(_status));
- _blockPos[0] = _blockPos[1] = _blockAlign; // To make sure first header is read
-}
-
-bool ADPCMStream::rewind() {
- // TODO: Error checking.
- reset();
- _stream->seek(_startpos);
- return true;
-}
-
-
-#pragma mark -
-
-
-class Oki_ADPCMStream : public ADPCMStream {
-public:
- Oki_ADPCMStream(Common::SeekableReadStream *stream, DisposeAfterUse::Flag disposeAfterUse, uint32 size, int rate, int channels, uint32 blockAlign)
- : ADPCMStream(stream, disposeAfterUse, size, rate, channels, blockAlign) {}
-
- virtual int readBuffer(int16 *buffer, const int numSamples);
-
-protected:
- int16 decodeOKI(byte);
-};
-
-int Oki_ADPCMStream::readBuffer(int16 *buffer, const int numSamples) {
- int samples;
- byte data;
-
- assert(numSamples % 2 == 0);
-
- for (samples = 0; samples < numSamples && !_stream->eos() && _stream->pos() < _endpos; samples += 2) {
- data = _stream->readByte();
- buffer[samples] = decodeOKI((data >> 4) & 0x0f);
- buffer[samples + 1] = decodeOKI(data & 0x0f);
- }
- return samples;
-}
-
-static const int16 okiStepSize[49] = {
- 16, 17, 19, 21, 23, 25, 28, 31,
- 34, 37, 41, 45, 50, 55, 60, 66,
- 73, 80, 88, 97, 107, 118, 130, 143,
- 157, 173, 190, 209, 230, 253, 279, 307,
- 337, 371, 408, 449, 494, 544, 598, 658,
- 724, 796, 876, 963, 1060, 1166, 1282, 1411,
- 1552
-};
-
-// Decode Linear to ADPCM
-int16 Oki_ADPCMStream::decodeOKI(byte code) {
- int16 diff, E, samp;
-
- E = (2 * (code & 0x7) + 1) * okiStepSize[_status.ima_ch[0].stepIndex] / 8;
- diff = (code & 0x08) ? -E : E;
- samp = _status.ima_ch[0].last + diff;
- // Clip the values to +/- 2^11 (supposed to be 12 bits)
- samp = CLIP<int16>(samp, -2048, 2047);
-
- _status.ima_ch[0].last = samp;
- _status.ima_ch[0].stepIndex += stepAdjust(code);
- _status.ima_ch[0].stepIndex = CLIP<int32>(_status.ima_ch[0].stepIndex, 0, ARRAYSIZE(okiStepSize) - 1);
-
- // * 16 effectively converts 12-bit input to 16-bit output
- return samp * 16;
-}
-
-
-#pragma mark -
-
-
-class Ima_ADPCMStream : public ADPCMStream {
-protected:
- int16 decodeIMA(byte code, int channel = 0); // Default to using the left channel/using one channel
-
-public:
- Ima_ADPCMStream(Common::SeekableReadStream *stream, DisposeAfterUse::Flag disposeAfterUse, uint32 size, int rate, int channels, uint32 blockAlign)
- : ADPCMStream(stream, disposeAfterUse, size, rate, channels, blockAlign) {
- memset(&_status, 0, sizeof(_status));
- }
-
- virtual int readBuffer(int16 *buffer, const int numSamples);
-};
-
-int Ima_ADPCMStream::readBuffer(int16 *buffer, const int numSamples) {
- int samples;
- byte data;
-
- assert(numSamples % 2 == 0);
-
- for (samples = 0; samples < numSamples && !_stream->eos() && _stream->pos() < _endpos; samples += 2) {
- data = _stream->readByte();
- buffer[samples] = decodeIMA((data >> 4) & 0x0f);
- buffer[samples + 1] = decodeIMA(data & 0x0f, _channels == 2 ? 1 : 0);
- }
- return samples;
-}
-
-#pragma mark -
-
-
-class Apple_ADPCMStream : public Ima_ADPCMStream {
-protected:
- // Apple QuickTime IMA ADPCM
- int32 _streamPos[2];
- int16 _buffer[2][2];
- uint8 _chunkPos[2];
-
- void reset() {
- Ima_ADPCMStream::reset();
- _chunkPos[0] = 0;
- _chunkPos[1] = 0;
- _streamPos[0] = 0;
- _streamPos[1] = _blockAlign;
- }
-
-public:
- Apple_ADPCMStream(Common::SeekableReadStream *stream, DisposeAfterUse::Flag disposeAfterUse, uint32 size, int rate, int channels, uint32 blockAlign)
- : Ima_ADPCMStream(stream, disposeAfterUse, size, rate, channels, blockAlign) {
- _chunkPos[0] = 0;
- _chunkPos[1] = 0;
- _streamPos[0] = 0;
- _streamPos[1] = _blockAlign;
- }
-
- virtual int readBuffer(int16 *buffer, const int numSamples);
-
-};
-
-int Apple_ADPCMStream::readBuffer(int16 *buffer, const int numSamples) {
- // Need to write at least one samples per channel
- assert((numSamples % _channels) == 0);
-
- // Current sample positions
- int samples[2] = { 0, 0};
-
- // Number of samples per channel
- int chanSamples = numSamples / _channels;
-
- for (int i = 0; i < _channels; i++) {
- _stream->seek(_streamPos[i]);
-
- while ((samples[i] < chanSamples) &&
- // Last byte read and a new one needed
- !((_stream->eos() || (_stream->pos() >= _endpos)) && (_chunkPos[i] == 0))) {
-
- if (_blockPos[i] == _blockAlign) {
- // 2 byte header per block
- uint16 temp = _stream->readUint16BE();
-
- // First 9 bits are the upper bits of the predictor
- _status.ima_ch[i].last = (int16) (temp & 0xFF80);
- // Lower 7 bits are the step index
- _status.ima_ch[i].stepIndex = temp & 0x007F;
-
- // Clip the step index
- _status.ima_ch[i].stepIndex = CLIP<int32>(_status.ima_ch[i].stepIndex, 0, 88);
-
- _blockPos[i] = 2;
- }
-
- if (_chunkPos[i] == 0) {
- // Decode data
- byte data = _stream->readByte();
- _buffer[i][0] = decodeIMA(data & 0x0F, i);
- _buffer[i][1] = decodeIMA(data >> 4, i);
- }
-
- // The original is interleaved block-wise, we want it sample-wise
- buffer[_channels * samples[i] + i] = _buffer[i][_chunkPos[i]];
-
- if (++_chunkPos[i] > 1) {
- // We're about to decode the next byte, so advance the block position
- _chunkPos[i] = 0;
- _blockPos[i]++;
- }
-
- samples[i]++;
-
- if (_channels == 2)
- if (_blockPos[i] == _blockAlign)
- // We're at the end of the block.
- // Since the channels are interleaved, skip the next block
- _stream->skip(MIN<uint32>(_blockAlign, _endpos - _stream->pos()));
-
- _streamPos[i] = _stream->pos();
- }
- }
-
- return samples[0] + samples[1];
-}
-
-#pragma mark -
-
-
-class MSIma_ADPCMStream : public Ima_ADPCMStream {
-public:
- MSIma_ADPCMStream(Common::SeekableReadStream *stream, DisposeAfterUse::Flag disposeAfterUse, uint32 size, int rate, int channels, uint32 blockAlign, bool invertSamples = false)
- : Ima_ADPCMStream(stream, disposeAfterUse, size, rate, channels, blockAlign), _invertSamples(invertSamples) {
- if (blockAlign == 0)
- error("ADPCMStream(): blockAlign isn't specified for MS IMA ADPCM");
- }
-
- virtual int readBuffer(int16 *buffer, const int numSamples) {
- if (_channels == 1)
- return readBufferMSIMA1(buffer, numSamples);
- else
- return readBufferMSIMA2(buffer, numSamples);
- }
-
- int readBufferMSIMA1(int16 *buffer, const int numSamples);
- int readBufferMSIMA2(int16 *buffer, const int numSamples);
-
-private:
- bool _invertSamples; // Some implementations invert the way samples are decoded
-};
-
-int MSIma_ADPCMStream::readBufferMSIMA1(int16 *buffer, const int numSamples) {
- int samples = 0;
- byte data;
-
- assert(numSamples % 2 == 0);
-
- while (samples < numSamples && !_stream->eos() && _stream->pos() < _endpos) {
- if (_blockPos[0] == _blockAlign) {
- // read block header
- _status.ima_ch[0].last = _stream->readSint16LE();
- _status.ima_ch[0].stepIndex = _stream->readSint16LE();
- _blockPos[0] = 4;
- }
-
- for (; samples < numSamples && _blockPos[0] < _blockAlign && !_stream->eos() && _stream->pos() < _endpos; samples += 2) {
- data = _stream->readByte();
- _blockPos[0]++;
- buffer[samples] = decodeIMA(_invertSamples ? (data >> 4) & 0x0f : data & 0x0f);
- buffer[samples + 1] = decodeIMA(_invertSamples ? data & 0x0f : (data >> 4) & 0x0f);
- }
- }
- return samples;
-}
-
-
-// Microsoft as usual tries to implement it differently. This method
-// is used for stereo data.
-int MSIma_ADPCMStream::readBufferMSIMA2(int16 *buffer, const int numSamples) {
- int samples;
- uint32 data;
- int nibble;
- byte k;
-
- // TODO: Currently this implementation only supports
- // reading a multiple of 16 samples at once. We might
- // consider changing that so it could read an arbitrary
- // sample pair count.
- assert(numSamples % 16 == 0);
-
- for (samples = 0; samples < numSamples && !_stream->eos() && _stream->pos() < _endpos;) {
- for (int channel = 0; channel < 2; channel++) {
- data = _stream->readUint32LE();
-
- for (nibble = 0; nibble < 8; nibble++) {
- k = ((data & 0xf0000000) >> 28);
- buffer[samples + channel + nibble * 2] = decodeIMA(k);
- data <<= 4;
- }
- }
- samples += 16;
- }
- return samples;
-}
-
-
-#pragma mark -
-
-
-static const int MSADPCMAdaptCoeff1[] = {
- 256, 512, 0, 192, 240, 460, 392
-};
-
-static const int MSADPCMAdaptCoeff2[] = {
- 0, -256, 0, 64, 0, -208, -232
-};
-
-static const int MSADPCMAdaptationTable[] = {
- 230, 230, 230, 230, 307, 409, 512, 614,
- 768, 614, 512, 409, 307, 230, 230, 230
-};
-
-
-class MS_ADPCMStream : public ADPCMStream {
-protected:
- struct ADPCMChannelStatus {
- byte predictor;
- int16 delta;
- int16 coeff1;
- int16 coeff2;
- int16 sample1;
- int16 sample2;
- };
-
- struct {
- // MS ADPCM
- ADPCMChannelStatus ch[2];
- } _status;
-
- void reset() {
- ADPCMStream::reset();
- memset(&_status, 0, sizeof(_status));
- }
-
-public:
- MS_ADPCMStream(Common::SeekableReadStream *stream, DisposeAfterUse::Flag disposeAfterUse, uint32 size, int rate, int channels, uint32 blockAlign)
- : ADPCMStream(stream, disposeAfterUse, size, rate, channels, blockAlign) {
- if (blockAlign == 0)
- error("MS_ADPCMStream(): blockAlign isn't specified for MS ADPCM");
- memset(&_status, 0, sizeof(_status));
- }
-
- virtual int readBuffer(int16 *buffer, const int numSamples);
-
-protected:
- int16 decodeMS(ADPCMChannelStatus *c, byte);
-};
-
-int16 MS_ADPCMStream::decodeMS(ADPCMChannelStatus *c, byte code) {
- int32 predictor;
-
- predictor = (((c->sample1) * (c->coeff1)) + ((c->sample2) * (c->coeff2))) / 256;
- predictor += (signed)((code & 0x08) ? (code - 0x10) : (code)) * c->delta;
-
- predictor = CLIP<int32>(predictor, -32768, 32767);
-
- c->sample2 = c->sample1;
- c->sample1 = predictor;
- c->delta = (MSADPCMAdaptationTable[(int)code] * c->delta) >> 8;
-
- if (c->delta < 16)
- c->delta = 16;
-
- return (int16)predictor;
-}
-
-int MS_ADPCMStream::readBuffer(int16 *buffer, const int numSamples) {
- int samples;
- byte data;
- int i = 0;
-
- samples = 0;
-
- while (samples < numSamples && !_stream->eos() && _stream->pos() < _endpos) {
- if (_blockPos[0] == _blockAlign) {
- // read block header
- for (i = 0; i < _channels; i++) {
- _status.ch[i].predictor = CLIP(_stream->readByte(), (byte)0, (byte)6);
- _status.ch[i].coeff1 = MSADPCMAdaptCoeff1[_status.ch[i].predictor];
- _status.ch[i].coeff2 = MSADPCMAdaptCoeff2[_status.ch[i].predictor];
- }
-
- for (i = 0; i < _channels; i++)
- _status.ch[i].delta = _stream->readSint16LE();
-
- for (i = 0; i < _channels; i++)
- _status.ch[i].sample1 = _stream->readSint16LE();
-
- for (i = 0; i < _channels; i++)
- buffer[samples++] = _status.ch[i].sample2 = _stream->readSint16LE();
-
- for (i = 0; i < _channels; i++)
- buffer[samples++] = _status.ch[i].sample1;
-
- _blockPos[0] = _channels * 7;
- }
-
- for (; samples < numSamples && _blockPos[0] < _blockAlign && !_stream->eos() && _stream->pos() < _endpos; samples += 2) {
- data = _stream->readByte();
- _blockPos[0]++;
- buffer[samples] = decodeMS(&_status.ch[0], (data >> 4) & 0x0f);
- buffer[samples + 1] = decodeMS(&_status.ch[_channels - 1], data & 0x0f);
- }
- }
-
- return samples;
-}
-
-
-
-#pragma mark -
-
-
-class Tinsel_ADPCMStream : public ADPCMStream {
-protected:
- struct {
- // Tinsel
- double predictor;
- double K0, K1;
- double d0, d1;
- } _status;
-
- void reset() {
- ADPCMStream::reset();
- memset(&_status, 0, sizeof(_status));
- }
-
- int16 decodeTinsel(int16, double);
- void readBufferTinselHeader();
-
-public:
- Tinsel_ADPCMStream(Common::SeekableReadStream *stream, DisposeAfterUse::Flag disposeAfterUse, uint32 size, int rate, int channels, uint32 blockAlign)
- : ADPCMStream(stream, disposeAfterUse, size, rate, channels, blockAlign) {
-
- if (blockAlign == 0)
- error("Tinsel_ADPCMStream(): blockAlign isn't specified");
-
- if (channels != 1)
- error("Tinsel_ADPCMStream(): Tinsel ADPCM only supports mono");
-
- memset(&_status, 0, sizeof(_status));
- }
-
-};
-
-static const double TinselFilterTable[4][2] = {
- {0, 0 },
- {0.9375, 0},
- {1.796875, -0.8125},
- {1.53125, -0.859375}
-};
-
-void Tinsel_ADPCMStream::readBufferTinselHeader() {
- uint8 start = _stream->readByte();
- uint8 filterVal = (start & 0xC0) >> 6;
-
- if ((start & 0x20) != 0) {
- //Lower 6 bit are negative
-
- // Negate
- start = ~(start | 0xC0) + 1;
-
- _status.predictor = 1 << start;
- } else {
- // Lower 6 bit are positive
-
- // Truncate
- start &= 0x1F;
-
- _status.predictor = ((double) 1.0) / (1 << start);
- }
-
- _status.K0 = TinselFilterTable[filterVal][0];
- _status.K1 = TinselFilterTable[filterVal][1];
-}
-
-int16 Tinsel_ADPCMStream::decodeTinsel(int16 code, double eVal) {
- double sample;
-
- sample = (double) code;
- sample *= eVal * _status.predictor;
- sample += (_status.d0 * _status.K0) + (_status.d1 * _status.K1);
-
- _status.d1 = _status.d0;
- _status.d0 = sample;
-
- return (int16) CLIP<double>(sample, -32768.0, 32767.0);
-}
-
-class Tinsel4_ADPCMStream : public Tinsel_ADPCMStream {
-public:
- Tinsel4_ADPCMStream(Common::SeekableReadStream *stream, DisposeAfterUse::Flag disposeAfterUse, uint32 size, int rate, int channels, uint32 blockAlign)
- : Tinsel_ADPCMStream(stream, disposeAfterUse, size, rate, channels, blockAlign) {}
-
- virtual int readBuffer(int16 *buffer, const int numSamples);
-};
-
-int Tinsel4_ADPCMStream::readBuffer(int16 *buffer, const int numSamples) {
- int samples;
- uint16 data;
- const double eVal = 1.142822265;
-
- samples = 0;
-
- assert(numSamples % 2 == 0);
-
- while (samples < numSamples && !_stream->eos() && _stream->pos() < _endpos) {
- if (_blockPos[0] == _blockAlign) {
- readBufferTinselHeader();
- _blockPos[0] = 0;
- }
-
- for (; samples < numSamples && _blockPos[0] < _blockAlign && !_stream->eos() && _stream->pos() < _endpos; samples += 2, _blockPos[0]++) {
- // Read 1 byte = 8 bits = two 4 bit blocks
- data = _stream->readByte();
- buffer[samples] = decodeTinsel((data << 8) & 0xF000, eVal);
- buffer[samples+1] = decodeTinsel((data << 12) & 0xF000, eVal);
- }
- }
-
- return samples;
-}
-
-class Tinsel6_ADPCMStream : public Tinsel_ADPCMStream {
-protected:
- uint8 _chunkPos;
- uint16 _chunkData;
-
- void reset() {
- ADPCMStream::reset();
- _chunkPos = 0;
- _chunkData = 0;
- }
-
-public:
- Tinsel6_ADPCMStream(Common::SeekableReadStream *stream, DisposeAfterUse::Flag disposeAfterUse, uint32 size, int rate, int channels, uint32 blockAlign)
- : Tinsel_ADPCMStream(stream, disposeAfterUse, size, rate, channels, blockAlign) {
- _chunkPos = 0;
- _chunkData = 0;
- }
-
- virtual int readBuffer(int16 *buffer, const int numSamples);
-};
-
-int Tinsel6_ADPCMStream::readBuffer(int16 *buffer, const int numSamples) {
- int samples;
- const double eVal = 1.032226562;
-
- samples = 0;
-
- while (samples < numSamples && !_stream->eos() && _stream->pos() < _endpos) {
- if (_blockPos[0] == _blockAlign) {
- readBufferTinselHeader();
- _blockPos[0] = 0;
- _chunkPos = 0;
- }
-
- for (; samples < numSamples && _blockPos[0] < _blockAlign && !_stream->eos() && _stream->pos() < _endpos; samples++, _chunkPos = (_chunkPos + 1) % 4) {
-
- switch (_chunkPos) {
- case 0:
- _chunkData = _stream->readByte();
- buffer[samples] = decodeTinsel((_chunkData << 8) & 0xFC00, eVal);
- break;
- case 1:
- _chunkData = (_chunkData << 8) | (_stream->readByte());
- buffer[samples] = decodeTinsel((_chunkData << 6) & 0xFC00, eVal);
- _blockPos[0]++;
- break;
- case 2:
- _chunkData = (_chunkData << 8) | (_stream->readByte());
- buffer[samples] = decodeTinsel((_chunkData << 4) & 0xFC00, eVal);
- _blockPos[0]++;
- break;
- case 3:
- _chunkData = (_chunkData << 8);
- buffer[samples] = decodeTinsel((_chunkData << 2) & 0xFC00, eVal);
- _blockPos[0]++;
- break;
- }
-
- }
-
- }
-
- return samples;
-}
-
-class Tinsel8_ADPCMStream : public Tinsel_ADPCMStream {
-public:
- Tinsel8_ADPCMStream(Common::SeekableReadStream *stream, DisposeAfterUse::Flag disposeAfterUse, uint32 size, int rate, int channels, uint32 blockAlign)
- : Tinsel_ADPCMStream(stream, disposeAfterUse, size, rate, channels, blockAlign) {}
-
- virtual int readBuffer(int16 *buffer, const int numSamples);
-};
-
-int Tinsel8_ADPCMStream::readBuffer(int16 *buffer, const int numSamples) {
- int samples;
- byte data;
- const double eVal = 1.007843258;
-
- samples = 0;
-
- while (samples < numSamples && !_stream->eos() && _stream->pos() < _endpos) {
- if (_blockPos[0] == _blockAlign) {
- readBufferTinselHeader();
- _blockPos[0] = 0;
- }
-
- for (; samples < numSamples && _blockPos[0] < _blockAlign && !_stream->eos() && _stream->pos() < _endpos; samples++, _blockPos[0]++) {
- // Read 1 byte = 8 bits = one 8 bit block
- data = _stream->readByte();
- buffer[samples] = decodeTinsel(data << 8, eVal);
- }
- }
-
- return samples;
-}
-
-
-#pragma mark -
-
-// Duck DK3 IMA ADPCM Decoder
-// Based on FFmpeg's decoder and http://wiki.multimedia.cx/index.php?title=Duck_DK3_IMA_ADPCM
-
-class DK3_ADPCMStream : public Ima_ADPCMStream {
-protected:
-
- void reset() {
- Ima_ADPCMStream::reset();
- _topNibble = false;
- }
-
-public:
- DK3_ADPCMStream(Common::SeekableReadStream *stream, DisposeAfterUse::Flag disposeAfterUse, uint32 size, int rate, int channels, uint32 blockAlign)
- : Ima_ADPCMStream(stream, disposeAfterUse, size, rate, channels, blockAlign) {
-
- // DK3 only works as a stereo stream
- assert(channels == 2);
- _topNibble = false;
- }
-
- virtual int readBuffer(int16 *buffer, const int numSamples);
-
-private:
- byte _nibble, _lastByte;
- bool _topNibble;
-};
-
-#define DK3_READ_NIBBLE() \
-do { \
- if (_topNibble) { \
- _nibble = _lastByte >> 4; \
- _topNibble = false; \
- } else { \
- if (_stream->pos() >= _endpos) \
- break; \
- if ((_stream->pos() % _blockAlign) == 0) \
- continue; \
- _lastByte = _stream->readByte(); \
- _nibble = _lastByte & 0xf; \
- _topNibble = true; \
- } \
-} while (0)
-
-
-int DK3_ADPCMStream::readBuffer(int16 *buffer, const int numSamples) {
- int samples = 0;
-
- assert((numSamples % 4) == 0);
-
- while (samples < numSamples && !_stream->eos() && _stream->pos() < _endpos) {
- if ((_stream->pos() % _blockAlign) == 0) {
- _stream->readUint16LE(); // Unknown
- uint16 rate = _stream->readUint16LE(); // Copy of rate
- _stream->skip(6); // Unknown
- // Get predictor for both sum/diff channels
- _status.ima_ch[0].last = _stream->readSint16LE();
- _status.ima_ch[1].last = _stream->readSint16LE();
- // Get index for both sum/diff channels
- _status.ima_ch[0].stepIndex = _stream->readByte();
- _status.ima_ch[1].stepIndex = _stream->readByte();
-
- if (_stream->eos())
- break;
-
- // Sanity check
- assert(rate == getRate());
- }
-
- DK3_READ_NIBBLE();
- decodeIMA(_nibble, 0);
-
- DK3_READ_NIBBLE();
- decodeIMA(_nibble, 1);
-
- buffer[samples++] = _status.ima_ch[0].last + _status.ima_ch[1].last;
- buffer[samples++] = _status.ima_ch[0].last - _status.ima_ch[1].last;
-
- DK3_READ_NIBBLE();
- decodeIMA(_nibble, 0);
-
- buffer[samples++] = _status.ima_ch[0].last + _status.ima_ch[1].last;
- buffer[samples++] = _status.ima_ch[0].last - _status.ima_ch[1].last;
- }
-
- return samples;
-}
-
-
-#pragma mark -
-
-
-// adjust the step for use on the next sample.
-int16 ADPCMStream::stepAdjust(byte code) {
- static const int16 adjusts[] = {-1, -1, -1, -1, 2, 4, 6, 8};
-
- return adjusts[code & 0x07];
-}
-
-static const uint16 imaStepTable[89] = {
- 7, 8, 9, 10, 11, 12, 13, 14,
- 16, 17, 19, 21, 23, 25, 28, 31,
- 34, 37, 41, 45, 50, 55, 60, 66,
- 73, 80, 88, 97, 107, 118, 130, 143,
- 157, 173, 190, 209, 230, 253, 279, 307,
- 337, 371, 408, 449, 494, 544, 598, 658,
- 724, 796, 876, 963, 1060, 1166, 1282, 1411,
- 1552, 1707, 1878, 2066, 2272, 2499, 2749, 3024,
- 3327, 3660, 4026, 4428, 4871, 5358, 5894, 6484,
- 7132, 7845, 8630, 9493,10442,11487,12635,13899,
- 15289,16818,18500,20350,22385,24623,27086,29794,
- 32767
-};
-
-int16 Ima_ADPCMStream::decodeIMA(byte code, int channel) {
- int32 E = (2 * (code & 0x7) + 1) * imaStepTable[_status.ima_ch[channel].stepIndex] / 8;
- int32 diff = (code & 0x08) ? -E : E;
- int32 samp = CLIP<int32>(_status.ima_ch[channel].last + diff, -32768, 32767);
-
- _status.ima_ch[channel].last = samp;
- _status.ima_ch[channel].stepIndex += stepAdjust(code);
- _status.ima_ch[channel].stepIndex = CLIP<int32>(_status.ima_ch[channel].stepIndex, 0, ARRAYSIZE(imaStepTable) - 1);
-
- return samp;
-}
-
-RewindableAudioStream *makeADPCMStream(Common::SeekableReadStream *stream, DisposeAfterUse::Flag disposeAfterUse, uint32 size, typesADPCM type, int rate, int channels, uint32 blockAlign) {
- // If size is 0, report the entire size of the stream
- if (!size)
- size = stream->size();
-
- switch (type) {
- case kADPCMOki:
- return new Oki_ADPCMStream(stream, disposeAfterUse, size, rate, channels, blockAlign);
- case kADPCMMSIma:
- return new MSIma_ADPCMStream(stream, disposeAfterUse, size, rate, channels, blockAlign);
- case kADPCMMSImaLastExpress:
- return new MSIma_ADPCMStream(stream, disposeAfterUse, size, rate, channels, blockAlign, true);
- case kADPCMMS:
- return new MS_ADPCMStream(stream, disposeAfterUse, size, rate, channels, blockAlign);
- case kADPCMTinsel4:
- return new Tinsel4_ADPCMStream(stream, disposeAfterUse, size, rate, channels, blockAlign);
- case kADPCMTinsel6:
- return new Tinsel6_ADPCMStream(stream, disposeAfterUse, size, rate, channels, blockAlign);
- case kADPCMTinsel8:
- return new Tinsel8_ADPCMStream(stream, disposeAfterUse, size, rate, channels, blockAlign);
- case kADPCMIma:
- return new Ima_ADPCMStream(stream, disposeAfterUse, size, rate, channels, blockAlign);
- case kADPCMApple:
- return new Apple_ADPCMStream(stream, disposeAfterUse, size, rate, channels, blockAlign);
- case kADPCMDK3:
- return new DK3_ADPCMStream(stream, disposeAfterUse, size, rate, channels, blockAlign);
- default:
- error("Unsupported ADPCM encoding");
- break;
- }
-}
-
-} // End of namespace Audio
diff --git a/sound/decoders/adpcm.h b/sound/decoders/adpcm.h
deleted file mode 100644
index 38ec870a27..0000000000
--- a/sound/decoders/adpcm.h
+++ /dev/null
@@ -1,90 +0,0 @@
-/* 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$
- *
- */
-
-/**
- * @file
- * Sound decoder used in engines:
- * - agos
- * - lastexpress
- * - mohawk
- * - saga
- * - scumm
- * - tinsel
- */
-
-#ifndef SOUND_ADPCM_H
-#define SOUND_ADPCM_H
-
-#include "common/scummsys.h"
-#include "common/stream.h"
-
-
-namespace Audio {
-
-class AudioStream;
-class RewindableAudioStream;
-
-// There are several types of ADPCM encoding, only some are supported here
-// For all the different encodings, refer to:
-// http://wiki.multimedia.cx/index.php?title=Category:ADPCM_Audio_Codecs
-// Usually, if the audio stream we're trying to play has the FourCC header
-// string intact, it's easy to discern which encoding is used
-enum typesADPCM {
- kADPCMOki, // Dialogic/Oki ADPCM (aka VOX)
- kADPCMMSIma, // Microsoft IMA ADPCM
- kADPCMMSImaLastExpress, // Microsoft IMA ADPCM (with inverted samples)
- kADPCMMS, // Microsoft ADPCM
- kADPCMTinsel4, // 4-bit ADPCM used by the Tinsel engine
- kADPCMTinsel6, // 6-bit ADPCM used by the Tinsel engine
- kADPCMTinsel8, // 8-bit ADPCM used by the Tinsel engine
- kADPCMIma, // Standard IMA ADPCM
- kADPCMApple, // Apple QuickTime IMA ADPCM
- kADPCMDK3 // Duck DK3 IMA ADPCM
-};
-
-/**
- * Takes an input stream containing ADPCM compressed sound data and creates
- * an RewindableAudioStream from that.
- *
- * @param stream the SeekableReadStream from which to read the ADPCM data
- * @param disposeAfterUse whether to delete the stream after use
- * @param size how many bytes to read from the stream (0 = all)
- * @param type the compression type used
- * @param rate the sampling rate
- * @param channels the number of channels
- * @param blockAlign block alignment ???
- * @return a new RewindableAudioStream, or NULL, if an error occurred
- */
-RewindableAudioStream *makeADPCMStream(
- Common::SeekableReadStream *stream,
- DisposeAfterUse::Flag disposeAfterUse,
- uint32 size, typesADPCM type,
- int rate = 22050,
- int channels = 2,
- uint32 blockAlign = 0);
-
-} // End of namespace Audio
-
-#endif
diff --git a/sound/decoders/aiff.cpp b/sound/decoders/aiff.cpp
deleted file mode 100644
index ce8c6ad32c..0000000000
--- a/sound/decoders/aiff.cpp
+++ /dev/null
@@ -1,186 +0,0 @@
-/* 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$
- *
- */
-
-/*
- * The code in this file is based on information found at
- * http://www.borg.com/~jglatt/tech/aiff.htm
- *
- * We currently only implement uncompressed AIFF. If we ever need AIFF-C, SoX
- * (http://sox.sourceforge.net) may be a good place to start from.
- */
-
-#include "common/endian.h"
-#include "common/util.h"
-#include "common/stream.h"
-
-#include "sound/decoders/aiff.h"
-#include "sound/audiostream.h"
-#include "sound/mixer.h"
-#include "sound/decoders/raw.h"
-
-namespace Audio {
-
-uint32 readExtended(Common::SeekableReadStream &stream) {
- // The sample rate is stored as an "80 bit IEEE Standard 754 floating
- // point number (Standard Apple Numeric Environment [SANE] data type
- // Extended).
-
- byte buf[10];
- uint32 mantissa;
- uint32 last = 0;
- byte exp;
-
- stream.read(buf, 10);
- mantissa = READ_BE_UINT32(buf + 2);
- exp = 30 - buf[1];
-
- while (exp--) {
- last = mantissa;
- mantissa >>= 1;
- }
-
- if (last & 0x00000001)
- mantissa++;
-
- return mantissa;
-}
-
-bool loadAIFFFromStream(Common::SeekableReadStream &stream, int &size, int &rate, byte &flags) {
- byte buf[4];
-
- stream.read(buf, 4);
- if (memcmp(buf, "FORM", 4) != 0) {
- warning("loadAIFFFromStream: No 'FORM' header");
- return false;
- }
-
- stream.readUint32BE();
-
- // This could be AIFC, but we don't handle that case.
-
- stream.read(buf, 4);
- if (memcmp(buf, "AIFF", 4) != 0) {
- warning("loadAIFFFromStream: No 'AIFF' header");
- return false;
- }
-
- // From here on, we only care about the COMM and SSND chunks, which are
- // the only required chunks.
-
- bool foundCOMM = false;
- bool foundSSND = false;
-
- uint16 numChannels = 0, bitsPerSample = 0;
- uint32 numSampleFrames = 0, offset = 0, blockSize = 0, soundOffset = 0;
-
- while (!(foundCOMM && foundSSND) && !stream.err() && !stream.eos()) {
- uint32 length, pos;
-
- stream.read(buf, 4);
- length = stream.readUint32BE();
- pos = stream.pos();
-
- if (memcmp(buf, "COMM", 4) == 0) {
- foundCOMM = true;
- numChannels = stream.readUint16BE();
- numSampleFrames = stream.readUint32BE();
- bitsPerSample = stream.readUint16BE();
- rate = readExtended(stream);
- size = numSampleFrames * numChannels * (bitsPerSample / 8);
- } else if (memcmp(buf, "SSND", 4) == 0) {
- foundSSND = true;
- offset = stream.readUint32BE();
- blockSize = stream.readUint32BE();
- soundOffset = stream.pos();
- }
-
- stream.seek(pos + length);
- }
-
- if (!foundCOMM) {
- warning("loadAIFFFromStream: Cound not find 'COMM' chunk");
- return false;
- }
-
- if (!foundSSND) {
- warning("loadAIFFFromStream: Cound not find 'SSND' chunk");
- return false;
- }
-
- // We only implement a subset of the AIFF standard.
-
- if (numChannels < 1 || numChannels > 2) {
- warning("loadAIFFFromStream: Only 1 or 2 channels are supported, not %d", numChannels);
- return false;
- }
-
- if (bitsPerSample != 8 && bitsPerSample != 16) {
- warning("loadAIFFFromStream: Only 8 or 16 bits per sample are supported, not %d", bitsPerSample);
- return false;
- }
-
- if (offset != 0 || blockSize != 0) {
- warning("loadAIFFFromStream: Block-aligned data is not supported");
- return false;
- }
-
- // Samples are always signed, and big endian.
-
- flags = 0;
- if (bitsPerSample == 16)
- flags |= Audio::FLAG_16BITS;
- if (numChannels == 2)
- flags |= Audio::FLAG_STEREO;
-
- stream.seek(soundOffset);
-
- // Stream now points at the sample data
-
- return true;
-}
-
-SeekableAudioStream *makeAIFFStream(Common::SeekableReadStream *stream,
- DisposeAfterUse::Flag disposeAfterUse) {
- int size, rate;
- byte *data, flags;
-
- if (!loadAIFFFromStream(*stream, size, rate, flags)) {
- if (disposeAfterUse == DisposeAfterUse::YES)
- delete stream;
- return 0;
- }
-
- data = (byte *)malloc(size);
- assert(data);
- stream->read(data, size);
-
- if (disposeAfterUse == DisposeAfterUse::YES)
- delete stream;
-
- // Since we allocated our own buffer for the data, we must specify DisposeAfterUse::YES.
- return makeRawStream(data, size, rate, flags);
-}
-
-} // End of namespace Audio
diff --git a/sound/decoders/aiff.h b/sound/decoders/aiff.h
deleted file mode 100644
index 06c56ecd38..0000000000
--- a/sound/decoders/aiff.h
+++ /dev/null
@@ -1,71 +0,0 @@
-/* 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$
- *
- */
-
-/**
- * @file
- * Sound decoder used in engines:
- * - saga
- * - sci
- * - sword1
- */
-
-#ifndef SOUND_AIFF_H
-#define SOUND_AIFF_H
-
-#include "common/scummsys.h"
-#include "common/types.h"
-
-namespace Common { class SeekableReadStream; }
-
-namespace Audio {
-
-class SeekableAudioStream;
-
-/**
- * Try to load an AIFF from the given seekable stream. Returns true if
- * successful. In that case, the stream's seek position will be set to the
- * start of the audio data, and size, rate and flags contain information
- * necessary for playback. Currently this function only supports uncompressed
- * raw PCM data as well as IMA ADPCM.
- */
-extern bool loadAIFFFromStream(Common::SeekableReadStream &stream, int &size, int &rate, byte &flags);
-
-/**
- * Try to load an AIFF from the given seekable stream and create an AudioStream
- * from that data.
- *
- * This function uses loadAIFFFromStream() internally.
- *
- * @param stream the SeekableReadStream from which to read the AIFF data
- * @param disposeAfterUse whether to delete the stream after use
- * @return a new SeekableAudioStream, or NULL, if an error occurred
- */
-SeekableAudioStream *makeAIFFStream(
- Common::SeekableReadStream *stream,
- DisposeAfterUse::Flag disposeAfterUse);
-
-} // End of namespace Audio
-
-#endif
diff --git a/sound/decoders/flac.cpp b/sound/decoders/flac.cpp
deleted file mode 100644
index 080141f224..0000000000
--- a/sound/decoders/flac.cpp
+++ /dev/null
@@ -1,745 +0,0 @@
-/* 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$
- *
- */
-
-// Disable symbol overrides for FILE as that is used in FLAC headers
-#define FORBIDDEN_SYMBOL_EXCEPTION_FILE
-
-#include "sound/decoders/flac.h"
-
-#ifdef USE_FLAC
-
-#include "common/debug.h"
-#include "common/stream.h"
-#include "common/util.h"
-
-#include "sound/audiostream.h"
-
-#define FLAC__NO_DLL // that MS-magic gave me headaches - just link the library you like
-#include <FLAC/export.h>
-
-
-// check if we have FLAC >= 1.1.3; LEGACY_FLAC code can be removed once FLAC-1.1.3 propagates everywhere
-#if !defined(FLAC_API_VERSION_CURRENT) || FLAC_API_VERSION_CURRENT < 8
-#define LEGACY_FLAC
-#else
-#undef LEGACY_FLAC
-#endif
-
-
-#ifdef LEGACY_FLAC
-
-// Before FLAC 1.1.3, we needed to use the stream decoder API.
-#include <FLAC/seekable_stream_decoder.h>
-typedef uint FLAC_size_t;
-
-#else
-
-// With FLAC 1.1.3, the stream decoder API was merged into the regular
-// stream API. In order to stay compatible with older FLAC versions, we
-// simply add some typedefs and #ifdefs to map between the old and new API.
-// We use the typedefs (instead of only #defines) in order to somewhat
-// improve the readability of the code.
-
-#include <FLAC/stream_decoder.h>
-typedef size_t FLAC_size_t;
-// Add aliases for the old names
-typedef FLAC__StreamDecoderState FLAC__SeekableStreamDecoderState;
-typedef FLAC__StreamDecoderReadStatus FLAC__SeekableStreamDecoderReadStatus;
-typedef FLAC__StreamDecoderSeekStatus FLAC__SeekableStreamDecoderSeekStatus;
-typedef FLAC__StreamDecoderTellStatus FLAC__SeekableStreamDecoderTellStatus;
-typedef FLAC__StreamDecoderLengthStatus FLAC__SeekableStreamDecoderLengthStatus;
-typedef FLAC__StreamDecoder FLAC__SeekableStreamDecoder;
-
-#endif
-
-
-namespace Audio {
-
-#pragma mark -
-#pragma mark --- FLAC stream ---
-#pragma mark -
-
-static const uint MAX_OUTPUT_CHANNELS = 2;
-
-
-class FLACStream : public SeekableAudioStream {
-protected:
- Common::SeekableReadStream *_inStream;
- bool _disposeAfterUse;
-
- ::FLAC__SeekableStreamDecoder *_decoder;
-
- /** Header of the stream */
- FLAC__StreamMetadata_StreamInfo _streaminfo;
-
- /** index + 1(!) of the last sample to be played */
- FLAC__uint64 _lastSample;
-
- /** total play time */
- Timestamp _length;
-
- /** true if the last sample was decoded from the FLAC-API - there might still be data in the buffer */
- bool _lastSampleWritten;
-
- typedef int16 SampleType;
- enum { BUFTYPE_BITS = 16 };
-
- enum {
- // Maximal buffer size. According to the FLAC format specification, the block size is
- // a 16 bit value (in fact it seems the maximal block size is 32768, but we play it safe).
- BUFFER_SIZE = 65536
- };
-
- struct {
- SampleType bufData[BUFFER_SIZE];
- SampleType *bufReadPos;
- uint bufFill;
- } _sampleCache;
-
- SampleType *_outBuffer;
- uint _requestedSamples;
-
- typedef void (*PFCONVERTBUFFERS)(SampleType*, const FLAC__int32*[], uint, const uint, const uint8);
- PFCONVERTBUFFERS _methodConvertBuffers;
-
-
-public:
- FLACStream(Common::SeekableReadStream *inStream, bool dispose);
- virtual ~FLACStream();
-
- int readBuffer(int16 *buffer, const int numSamples);
-
- bool isStereo() const { return _streaminfo.channels >= 2; }
- int getRate() const { return _streaminfo.sample_rate; }
- bool endOfData() const {
- // End of data is reached if there either is no valid stream data available,
- // or if we reached the last sample and completely emptied the sample cache.
- return _streaminfo.channels == 0 || (_lastSampleWritten && _sampleCache.bufFill == 0);
- }
-
- bool seek(const Timestamp &where);
- Timestamp getLength() const { return _length; }
-
- bool isStreamDecoderReady() const { return getStreamDecoderState() == FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC; }
-protected:
- uint getChannels() const { return MIN<uint>(_streaminfo.channels, MAX_OUTPUT_CHANNELS); }
-
- bool allocateBuffer(uint minSamples);
-
- inline FLAC__StreamDecoderState getStreamDecoderState() const;
-
- inline bool processSingleBlock();
- inline bool processUntilEndOfMetadata();
- bool seekAbsolute(FLAC__uint64 sample);
-
- inline ::FLAC__SeekableStreamDecoderReadStatus callbackRead(FLAC__byte buffer[], FLAC_size_t *bytes);
- inline ::FLAC__SeekableStreamDecoderSeekStatus callbackSeek(FLAC__uint64 absoluteByteOffset);
- inline ::FLAC__SeekableStreamDecoderTellStatus callbackTell(FLAC__uint64 *absoluteByteOffset);
- inline ::FLAC__SeekableStreamDecoderLengthStatus callbackLength(FLAC__uint64 *streamLength);
- inline bool callbackEOF();
- inline ::FLAC__StreamDecoderWriteStatus callbackWrite(const ::FLAC__Frame *frame, const FLAC__int32 * const buffer[]);
- inline void callbackMetadata(const ::FLAC__StreamMetadata *metadata);
- inline void callbackError(::FLAC__StreamDecoderErrorStatus status);
-
-private:
- static ::FLAC__SeekableStreamDecoderReadStatus callWrapRead(const ::FLAC__SeekableStreamDecoder *decoder, FLAC__byte buffer[], FLAC_size_t *bytes, void *clientData);
- static ::FLAC__SeekableStreamDecoderSeekStatus callWrapSeek(const ::FLAC__SeekableStreamDecoder *decoder, FLAC__uint64 absoluteByteOffset, void *clientData);
- static ::FLAC__SeekableStreamDecoderTellStatus callWrapTell(const ::FLAC__SeekableStreamDecoder *decoder, FLAC__uint64 *absoluteByteOffset, void *clientData);
- static ::FLAC__SeekableStreamDecoderLengthStatus callWrapLength(const ::FLAC__SeekableStreamDecoder *decoder, FLAC__uint64 *streamLength, void *clientData);
- static FLAC__bool callWrapEOF(const ::FLAC__SeekableStreamDecoder *decoder, void *clientData);
- static ::FLAC__StreamDecoderWriteStatus callWrapWrite(const ::FLAC__SeekableStreamDecoder *decoder, const ::FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *clientData);
- static void callWrapMetadata(const ::FLAC__SeekableStreamDecoder *decoder, const ::FLAC__StreamMetadata *metadata, void *clientData);
- static void callWrapError(const ::FLAC__SeekableStreamDecoder *decoder, ::FLAC__StreamDecoderErrorStatus status, void *clientData);
-
- void setBestConvertBufferMethod();
- static void convertBuffersGeneric(SampleType* bufDestination, const FLAC__int32 *inChannels[], uint numSamples, const uint numChannels, const uint8 numBits);
- static void convertBuffersStereoNS(SampleType* bufDestination, const FLAC__int32 *inChannels[], uint numSamples, const uint numChannels, const uint8 numBits);
- static void convertBuffersStereo8Bit(SampleType* bufDestination, const FLAC__int32 *inChannels[], uint numSamples, const uint numChannels, const uint8 numBits);
- static void convertBuffersMonoNS(SampleType* bufDestination, const FLAC__int32 *inChannels[], uint numSamples, const uint numChannels, const uint8 numBits);
- static void convertBuffersMono8Bit(SampleType* bufDestination, const FLAC__int32 *inChannels[], uint numSamples, const uint numChannels, const uint8 numBits);
-};
-
-FLACStream::FLACStream(Common::SeekableReadStream *inStream, bool dispose)
-#ifdef LEGACY_FLAC
- : _decoder(::FLAC__seekable_stream_decoder_new()),
-#else
- : _decoder(::FLAC__stream_decoder_new()),
-#endif
- _inStream(inStream),
- _disposeAfterUse(dispose),
- _length(0, 1000), _lastSample(0),
- _outBuffer(NULL), _requestedSamples(0), _lastSampleWritten(false),
- _methodConvertBuffers(&FLACStream::convertBuffersGeneric)
-{
- assert(_inStream);
- memset(&_streaminfo, 0, sizeof(_streaminfo));
-
- _sampleCache.bufReadPos = NULL;
- _sampleCache.bufFill = 0;
-
- _methodConvertBuffers = &FLACStream::convertBuffersGeneric;
-
- bool success;
-#ifdef LEGACY_FLAC
- ::FLAC__seekable_stream_decoder_set_read_callback(_decoder, &FLACStream::callWrapRead);
- ::FLAC__seekable_stream_decoder_set_seek_callback(_decoder, &FLACStream::callWrapSeek);
- ::FLAC__seekable_stream_decoder_set_tell_callback(_decoder, &FLACStream::callWrapTell);
- ::FLAC__seekable_stream_decoder_set_length_callback(_decoder, &FLACStream::callWrapLength);
- ::FLAC__seekable_stream_decoder_set_eof_callback(_decoder, &FLACStream::callWrapEOF);
- ::FLAC__seekable_stream_decoder_set_write_callback(_decoder, &FLACStream::callWrapWrite);
- ::FLAC__seekable_stream_decoder_set_metadata_callback(_decoder, &FLACStream::callWrapMetadata);
- ::FLAC__seekable_stream_decoder_set_error_callback(_decoder, &FLACStream::callWrapError);
- ::FLAC__seekable_stream_decoder_set_client_data(_decoder, (void*)this);
-
- success = (::FLAC__seekable_stream_decoder_init(_decoder) == FLAC__SEEKABLE_STREAM_DECODER_OK);
-#else
- success = (::FLAC__stream_decoder_init_stream(
- _decoder,
- &FLACStream::callWrapRead,
- &FLACStream::callWrapSeek,
- &FLACStream::callWrapTell,
- &FLACStream::callWrapLength,
- &FLACStream::callWrapEOF,
- &FLACStream::callWrapWrite,
- &FLACStream::callWrapMetadata,
- &FLACStream::callWrapError,
- (void*)this
- ) == FLAC__STREAM_DECODER_INIT_STATUS_OK);
-#endif
- if (success) {
- if (processUntilEndOfMetadata() && _streaminfo.channels > 0) {
- _lastSample = _streaminfo.total_samples + 1;
- _length = Timestamp(0, _lastSample - 1, getRate());
- return; // no error occurred
- }
- }
-
- warning("FLACStream: could not create audio stream");
-}
-
-FLACStream::~FLACStream() {
- if (_decoder != NULL) {
-#ifdef LEGACY_FLAC
- (void) ::FLAC__seekable_stream_decoder_finish(_decoder);
- ::FLAC__seekable_stream_decoder_delete(_decoder);
-#else
- (void) ::FLAC__stream_decoder_finish(_decoder);
- ::FLAC__stream_decoder_delete(_decoder);
-#endif
- }
- if (_disposeAfterUse)
- delete _inStream;
-}
-
-inline FLAC__StreamDecoderState FLACStream::getStreamDecoderState() const {
- assert(_decoder != NULL);
-#ifdef LEGACY_FLAC
- return ::FLAC__seekable_stream_decoder_get_stream_decoder_state(_decoder);
-#else
- return ::FLAC__stream_decoder_get_state(_decoder);
-#endif
-}
-
-inline bool FLACStream::processSingleBlock() {
- assert(_decoder != NULL);
-#ifdef LEGACY_FLAC
- return 0 != ::FLAC__seekable_stream_decoder_process_single(_decoder);
-#else
- return 0 != ::FLAC__stream_decoder_process_single(_decoder);
-#endif
-}
-
-inline bool FLACStream::processUntilEndOfMetadata() {
- assert(_decoder != NULL);
-#ifdef LEGACY_FLAC
- return 0 != ::FLAC__seekable_stream_decoder_process_until_end_of_metadata(_decoder);
-#else
- return 0 != ::FLAC__stream_decoder_process_until_end_of_metadata(_decoder);
-#endif
-}
-
-bool FLACStream::seekAbsolute(FLAC__uint64 sample) {
- assert(_decoder != NULL);
-#ifdef LEGACY_FLAC
- const bool result = (0 != ::FLAC__seekable_stream_decoder_seek_absolute(_decoder, sample));
-#else
- const bool result = (0 != ::FLAC__stream_decoder_seek_absolute(_decoder, sample));
-#endif
- if (result) {
- _lastSampleWritten = (_lastSample != 0 && sample >= _lastSample); // only set if we are SURE
- }
- return result;
-}
-
-bool FLACStream::seek(const Timestamp &where) {
- _sampleCache.bufFill = 0;
- _sampleCache.bufReadPos = NULL;
- // FLAC uses the sample pair number, thus we always use "false" for the isStereo parameter
- // of the convertTimeToStreamPos helper.
- return seekAbsolute((FLAC__uint64)convertTimeToStreamPos(where, getRate(), false).totalNumberOfFrames());
-}
-
-int FLACStream::readBuffer(int16 *buffer, const int numSamples) {
- const uint numChannels = getChannels();
-
- if (numChannels == 0) {
- warning("FLACStream: Stream not successfully initialised, cant playback");
- return -1; // streaminfo wasnt read!
- }
-
- assert(numSamples % numChannels == 0); // must be multiple of channels!
- assert(buffer != NULL);
- assert(_outBuffer == NULL);
- assert(_requestedSamples == 0);
-
- _outBuffer = buffer;
- _requestedSamples = numSamples;
-
- // If there is still data in our buffer from the last time around,
- // copy that first.
- if (_sampleCache.bufFill > 0) {
- assert(_sampleCache.bufReadPos >= _sampleCache.bufData);
- assert(_sampleCache.bufFill % numChannels == 0);
-
- const uint copySamples = MIN((uint)numSamples, _sampleCache.bufFill);
- memcpy(buffer, _sampleCache.bufReadPos, copySamples*sizeof(buffer[0]));
-
- _outBuffer = buffer + copySamples;
- _requestedSamples = numSamples - copySamples;
- _sampleCache.bufReadPos += copySamples;
- _sampleCache.bufFill -= copySamples;
- }
-
- bool decoderOk = true;
-
- FLAC__StreamDecoderState state = getStreamDecoderState();
-
- // Keep poking FLAC to process more samples until we completely satisfied the request
- // respectively until we run out of data.
- while (!_lastSampleWritten && _requestedSamples > 0 && state == FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC) {
- assert(_sampleCache.bufFill == 0);
- assert(_requestedSamples % numChannels == 0);
- processSingleBlock();
- state = getStreamDecoderState();
-
- if (state == FLAC__STREAM_DECODER_END_OF_STREAM)
- _lastSampleWritten = true;
- }
-
- // Error handling
- switch (state) {
- case FLAC__STREAM_DECODER_END_OF_STREAM:
- _lastSampleWritten = true;
- break;
- case FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC:
- break;
- default:
- decoderOk = false;
- warning("FLACStream: An error occurred while decoding. DecoderState is: %s",
- FLAC__StreamDecoderStateString[getStreamDecoderState()]);
- }
-
- // Compute how many samples we actually produced
- const int samples = (int)(_outBuffer - buffer);
- assert(samples % numChannels == 0);
-
- _outBuffer = NULL; // basically unnecessary, only for the purpose of the asserts
- _requestedSamples = 0; // basically unnecessary, only for the purpose of the asserts
-
- return decoderOk ? samples : -1;
-}
-
-inline ::FLAC__SeekableStreamDecoderReadStatus FLACStream::callbackRead(FLAC__byte buffer[], FLAC_size_t *bytes) {
- if (*bytes == 0) {
-#ifdef LEGACY_FLAC
- return FLAC__SEEKABLE_STREAM_DECODER_READ_STATUS_ERROR; /* abort to avoid a deadlock */
-#else
- return FLAC__STREAM_DECODER_READ_STATUS_ABORT; /* abort to avoid a deadlock */
-#endif
- }
-
- const uint32 bytesRead = _inStream->read(buffer, *bytes);
-
- if (bytesRead == 0) {
-#ifdef LEGACY_FLAC
- return _inStream->eos() ? FLAC__SEEKABLE_STREAM_DECODER_READ_STATUS_OK : FLAC__SEEKABLE_STREAM_DECODER_READ_STATUS_ERROR;
-#else
- return _inStream->eos() ? FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM : FLAC__STREAM_DECODER_READ_STATUS_ABORT;
-#endif
- }
-
- *bytes = static_cast<uint>(bytesRead);
-#ifdef LEGACY_FLAC
- return FLAC__SEEKABLE_STREAM_DECODER_READ_STATUS_OK;
-#else
- return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
-#endif
-}
-
-void FLACStream::setBestConvertBufferMethod() {
- PFCONVERTBUFFERS tempMethod = &FLACStream::convertBuffersGeneric;
-
- const uint numChannels = getChannels();
- const uint8 numBits = (uint8)_streaminfo.bits_per_sample;
-
- assert(numChannels >= 1);
- assert(numBits >= 4 && numBits <=32);
-
- if (numChannels == 1) {
- if (numBits == 8)
- tempMethod = &FLACStream::convertBuffersMono8Bit;
- if (numBits == BUFTYPE_BITS)
- tempMethod = &FLACStream::convertBuffersMonoNS;
- } else if (numChannels == 2) {
- if (numBits == 8)
- tempMethod = &FLACStream::convertBuffersStereo8Bit;
- if (numBits == BUFTYPE_BITS)
- tempMethod = &FLACStream::convertBuffersStereoNS;
- } /* else ... */
-
- _methodConvertBuffers = tempMethod;
-}
-
-// 1 channel, no scaling
-void FLACStream::convertBuffersMonoNS(SampleType* bufDestination, const FLAC__int32 *inChannels[], uint numSamples, const uint numChannels, const uint8 numBits) {
- assert(numChannels == 1);
- assert(numBits == BUFTYPE_BITS);
-
- FLAC__int32 const* inChannel1 = inChannels[0];
-
- while (numSamples >= 4) {
- bufDestination[0] = static_cast<SampleType>(inChannel1[0]);
- bufDestination[1] = static_cast<SampleType>(inChannel1[1]);
- bufDestination[2] = static_cast<SampleType>(inChannel1[2]);
- bufDestination[3] = static_cast<SampleType>(inChannel1[3]);
- bufDestination += 4;
- inChannel1 += 4;
- numSamples -= 4;
- }
-
- for (; numSamples > 0; --numSamples) {
- *bufDestination++ = static_cast<SampleType>(*inChannel1++);
- }
-
- inChannels[0] = inChannel1;
- assert(numSamples == 0); // dint copy too many samples
-}
-
-// 1 channel, scaling from 8Bit
-void FLACStream::convertBuffersMono8Bit(SampleType* bufDestination, const FLAC__int32 *inChannels[], uint numSamples, const uint numChannels, const uint8 numBits) {
- assert(numChannels == 1);
- assert(numBits == 8);
- assert(8 < BUFTYPE_BITS);
-
- FLAC__int32 const* inChannel1 = inChannels[0];
-
- while (numSamples >= 4) {
- bufDestination[0] = static_cast<SampleType>(inChannel1[0]) << (BUFTYPE_BITS - 8);
- bufDestination[1] = static_cast<SampleType>(inChannel1[1]) << (BUFTYPE_BITS - 8);
- bufDestination[2] = static_cast<SampleType>(inChannel1[2]) << (BUFTYPE_BITS - 8);
- bufDestination[3] = static_cast<SampleType>(inChannel1[3]) << (BUFTYPE_BITS - 8);
- bufDestination += 4;
- inChannel1 += 4;
- numSamples -= 4;
- }
-
- for (; numSamples > 0; --numSamples) {
- *bufDestination++ = static_cast<SampleType>(*inChannel1++) << (BUFTYPE_BITS - 8);
- }
-
- inChannels[0] = inChannel1;
- assert(numSamples == 0); // dint copy too many samples
-}
-
-// 2 channels, no scaling
-void FLACStream::convertBuffersStereoNS(SampleType* bufDestination, const FLAC__int32 *inChannels[], uint numSamples, const uint numChannels, const uint8 numBits) {
- assert(numChannels == 2);
- assert(numBits == BUFTYPE_BITS);
- assert(numSamples % 2 == 0); // must be integral multiply of channels
-
-
- FLAC__int32 const* inChannel1 = inChannels[0]; // Left Channel
- FLAC__int32 const* inChannel2 = inChannels[1]; // Right Channel
-
- while (numSamples >= 2*2) {
- bufDestination[0] = static_cast<SampleType>(inChannel1[0]);
- bufDestination[1] = static_cast<SampleType>(inChannel2[0]);
- bufDestination[2] = static_cast<SampleType>(inChannel1[1]);
- bufDestination[3] = static_cast<SampleType>(inChannel2[1]);
- bufDestination += 2 * 2;
- inChannel1 += 2;
- inChannel2 += 2;
- numSamples -= 2 * 2;
- }
-
- while (numSamples > 0) {
- bufDestination[0] = static_cast<SampleType>(*inChannel1++);
- bufDestination[1] = static_cast<SampleType>(*inChannel2++);
- bufDestination += 2;
- numSamples -= 2;
- }
-
- inChannels[0] = inChannel1;
- inChannels[1] = inChannel2;
- assert(numSamples == 0); // dint copy too many samples
-}
-
-// 2 channels, scaling from 8Bit
-void FLACStream::convertBuffersStereo8Bit(SampleType* bufDestination, const FLAC__int32 *inChannels[], uint numSamples, const uint numChannels, const uint8 numBits) {
- assert(numChannels == 2);
- assert(numBits == 8);
- assert(numSamples % 2 == 0); // must be integral multiply of channels
- assert(8 < BUFTYPE_BITS);
-
- FLAC__int32 const* inChannel1 = inChannels[0]; // Left Channel
- FLAC__int32 const* inChannel2 = inChannels[1]; // Right Channel
-
- while (numSamples >= 2*2) {
- bufDestination[0] = static_cast<SampleType>(inChannel1[0]) << (BUFTYPE_BITS - 8);
- bufDestination[1] = static_cast<SampleType>(inChannel2[0]) << (BUFTYPE_BITS - 8);
- bufDestination[2] = static_cast<SampleType>(inChannel1[1]) << (BUFTYPE_BITS - 8);
- bufDestination[3] = static_cast<SampleType>(inChannel2[1]) << (BUFTYPE_BITS - 8);
- bufDestination += 2 * 2;
- inChannel1 += 2;
- inChannel2 += 2;
- numSamples -= 2 * 2;
- }
-
- while (numSamples > 0) {
- bufDestination[0] = static_cast<SampleType>(*inChannel1++) << (BUFTYPE_BITS - 8);
- bufDestination[1] = static_cast<SampleType>(*inChannel2++) << (BUFTYPE_BITS - 8);
- bufDestination += 2;
- numSamples -= 2;
- }
-
- inChannels[0] = inChannel1;
- inChannels[1] = inChannel2;
- assert(numSamples == 0); // dint copy too many samples
-}
-
-// all Purpose-conversion - slowest of em all
-void FLACStream::convertBuffersGeneric(SampleType* bufDestination, const FLAC__int32 *inChannels[], uint numSamples, const uint numChannels, const uint8 numBits) {
- assert(numSamples % numChannels == 0); // must be integral multiply of channels
-
- if (numBits < BUFTYPE_BITS) {
- const uint8 kPower = (uint8)(BUFTYPE_BITS - numBits);
-
- for (; numSamples > 0; numSamples -= numChannels) {
- for (uint i = 0; i < numChannels; ++i)
- *bufDestination++ = static_cast<SampleType>(*(inChannels[i]++)) << kPower;
- }
- } else if (numBits > BUFTYPE_BITS) {
- const uint8 kPower = (uint8)(numBits - BUFTYPE_BITS);
-
- for (; numSamples > 0; numSamples -= numChannels) {
- for (uint i = 0; i < numChannels; ++i)
- *bufDestination++ = static_cast<SampleType>(*(inChannels[i]++) >> kPower);
- }
- } else {
- for (; numSamples > 0; numSamples -= numChannels) {
- for (uint i = 0; i < numChannels; ++i)
- *bufDestination++ = static_cast<SampleType>(*(inChannels[i]++));
- }
- }
-
- assert(numSamples == 0); // dint copy too many samples
-}
-
-inline ::FLAC__StreamDecoderWriteStatus FLACStream::callbackWrite(const ::FLAC__Frame *frame, const FLAC__int32 * const buffer[]) {
- assert(frame->header.channels == _streaminfo.channels);
- assert(frame->header.sample_rate == _streaminfo.sample_rate);
- assert(frame->header.bits_per_sample == _streaminfo.bits_per_sample);
- assert(frame->header.number_type == FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER || _streaminfo.min_blocksize == _streaminfo.max_blocksize);
-
- // We require that either the sample cache is empty, or that no samples were requested
- assert(_sampleCache.bufFill == 0 || _requestedSamples == 0);
-
- uint numSamples = frame->header.blocksize;
- const uint numChannels = getChannels();
- const uint8 numBits = (uint8)_streaminfo.bits_per_sample;
-
- assert(_requestedSamples % numChannels == 0); // must be integral multiply of channels
-
- const FLAC__uint64 firstSampleNumber = (frame->header.number_type == FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER) ?
- frame->header.number.sample_number : (static_cast<FLAC__uint64>(frame->header.number.frame_number)) * _streaminfo.max_blocksize;
-
- // Check whether we are about to reach beyond the last sample we are supposed to play.
- if (_lastSample != 0 && firstSampleNumber + numSamples >= _lastSample) {
- numSamples = (uint)(firstSampleNumber >= _lastSample ? 0 : _lastSample - firstSampleNumber);
- _lastSampleWritten = true;
- }
-
- // The value in _requestedSamples counts raw samples, so if there are more than one
- // channel, we have to multiply the number of available sample "pairs" by numChannels
- numSamples *= numChannels;
-
- const FLAC__int32 *inChannels[MAX_OUTPUT_CHANNELS];
- for (uint i = 0; i < numChannels; ++i)
- inChannels[i] = buffer[i];
-
- // write the incoming samples directly into the buffer provided to us by the mixer
- if (_requestedSamples > 0) {
- assert(_requestedSamples % numChannels == 0);
- assert(_outBuffer != NULL);
-
- // Copy & convert the available samples (limited both by how many we have available, and
- // by how many are actually needed).
- const uint copySamples = MIN(_requestedSamples, numSamples);
- (*_methodConvertBuffers)(_outBuffer, inChannels, copySamples, numChannels, numBits);
-
- _requestedSamples -= copySamples;
- numSamples -= copySamples;
- _outBuffer += copySamples;
- }
-
- // Write all remaining samples (i.e. those which didn't fit into the mixer buffer)
- // into the sample cache.
- if (_sampleCache.bufFill == 0)
- _sampleCache.bufReadPos = _sampleCache.bufData;
- const uint cacheSpace = (_sampleCache.bufData + BUFFER_SIZE) - (_sampleCache.bufReadPos + _sampleCache.bufFill);
- assert(numSamples <= cacheSpace);
- (*_methodConvertBuffers)(_sampleCache.bufReadPos + _sampleCache.bufFill, inChannels, numSamples, numChannels, numBits);
-
- _sampleCache.bufFill += numSamples;
-
- return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
-}
-
-inline ::FLAC__SeekableStreamDecoderSeekStatus FLACStream::callbackSeek(FLAC__uint64 absoluteByteOffset) {
- _inStream->seek(absoluteByteOffset, SEEK_SET);
- const bool result = (absoluteByteOffset == (FLAC__uint64)_inStream->pos());
-
-#ifdef LEGACY_FLAC
- return result ? FLAC__SEEKABLE_STREAM_DECODER_SEEK_STATUS_OK : FLAC__SEEKABLE_STREAM_DECODER_SEEK_STATUS_ERROR;
-#else
- return result ? FLAC__STREAM_DECODER_SEEK_STATUS_OK : FLAC__STREAM_DECODER_SEEK_STATUS_ERROR;
-#endif
-}
-
-inline ::FLAC__SeekableStreamDecoderTellStatus FLACStream::callbackTell(FLAC__uint64 *absoluteByteOffset) {
- *absoluteByteOffset = static_cast<FLAC__uint64>(_inStream->pos());
-#ifdef LEGACY_FLAC
- return FLAC__SEEKABLE_STREAM_DECODER_TELL_STATUS_OK;
-#else
- return FLAC__STREAM_DECODER_TELL_STATUS_OK;
-#endif
-}
-
-inline ::FLAC__SeekableStreamDecoderLengthStatus FLACStream::callbackLength(FLAC__uint64 *streamLength) {
- *streamLength = static_cast<FLAC__uint64>(_inStream->size());
-#ifdef LEGACY_FLAC
- return FLAC__SEEKABLE_STREAM_DECODER_LENGTH_STATUS_OK;
-#else
- return FLAC__STREAM_DECODER_LENGTH_STATUS_OK;
-#endif
-}
-
-inline bool FLACStream::callbackEOF() {
- return _inStream->eos();
-}
-
-
-inline void FLACStream::callbackMetadata(const ::FLAC__StreamMetadata *metadata) {
- assert(_decoder != NULL);
- assert(metadata->type == FLAC__METADATA_TYPE_STREAMINFO); // others arent really interesting
-
- _streaminfo = metadata->data.stream_info;
- setBestConvertBufferMethod(); // should be set after getting stream-information. FLAC always parses the info first
-}
-inline void FLACStream::callbackError(::FLAC__StreamDecoderErrorStatus status) {
- // some of these are non-critical-Errors
- debug(1, "FLACStream: An error occurred while decoding. DecoderState is: %s",
- FLAC__StreamDecoderErrorStatusString[status]);
-}
-
-/* Static Callback Wrappers */
-::FLAC__SeekableStreamDecoderReadStatus FLACStream::callWrapRead(const ::FLAC__SeekableStreamDecoder *decoder, FLAC__byte buffer[], FLAC_size_t *bytes, void *clientData) {
- FLACStream *instance = (FLACStream *)clientData;
- assert(0 != instance);
- return instance->callbackRead(buffer, bytes);
-}
-
-::FLAC__SeekableStreamDecoderSeekStatus FLACStream::callWrapSeek(const ::FLAC__SeekableStreamDecoder *decoder, FLAC__uint64 absoluteByteOffset, void *clientData) {
- FLACStream *instance = (FLACStream *)clientData;
- assert(0 != instance);
- return instance->callbackSeek(absoluteByteOffset);
-}
-
-::FLAC__SeekableStreamDecoderTellStatus FLACStream::callWrapTell(const ::FLAC__SeekableStreamDecoder *decoder, FLAC__uint64 *absoluteByteOffset, void *clientData) {
- FLACStream *instance = (FLACStream *)clientData;
- assert(0 != instance);
- return instance->callbackTell(absoluteByteOffset);
-}
-
-::FLAC__SeekableStreamDecoderLengthStatus FLACStream::callWrapLength(const ::FLAC__SeekableStreamDecoder *decoder, FLAC__uint64 *streamLength, void *clientData) {
- FLACStream *instance = (FLACStream *)clientData;
- assert(0 != instance);
- return instance->callbackLength(streamLength);
-}
-
-FLAC__bool FLACStream::callWrapEOF(const ::FLAC__SeekableStreamDecoder *decoder, void *clientData) {
- FLACStream *instance = (FLACStream *)clientData;
- assert(0 != instance);
- return instance->callbackEOF();
-}
-
-::FLAC__StreamDecoderWriteStatus FLACStream::callWrapWrite(const ::FLAC__SeekableStreamDecoder *decoder, const ::FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *clientData) {
- FLACStream *instance = (FLACStream *)clientData;
- assert(0 != instance);
- return instance->callbackWrite(frame, buffer);
-}
-
-void FLACStream::callWrapMetadata(const ::FLAC__SeekableStreamDecoder *decoder, const ::FLAC__StreamMetadata *metadata, void *clientData) {
- FLACStream *instance = (FLACStream *)clientData;
- assert(0 != instance);
- instance->callbackMetadata(metadata);
-}
-
-void FLACStream::callWrapError(const ::FLAC__SeekableStreamDecoder *decoder, ::FLAC__StreamDecoderErrorStatus status, void *clientData) {
- FLACStream *instance = (FLACStream *)clientData;
- assert(0 != instance);
- instance->callbackError(status);
-}
-
-
-#pragma mark -
-#pragma mark --- FLAC factory functions ---
-#pragma mark -
-
-SeekableAudioStream *makeFLACStream(
- Common::SeekableReadStream *stream,
- DisposeAfterUse::Flag disposeAfterUse) {
- SeekableAudioStream *s = new FLACStream(stream, disposeAfterUse);
- if (s && s->endOfData()) {
- delete s;
- return 0;
- } else {
- return s;
- }
-}
-
-} // End of namespace Audio
-
-#endif // #ifdef USE_FLAC
diff --git a/sound/decoders/flac.h b/sound/decoders/flac.h
deleted file mode 100644
index 17f95ec1fb..0000000000
--- a/sound/decoders/flac.h
+++ /dev/null
@@ -1,75 +0,0 @@
-/* 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$
- *
- */
-
-/**
- * @file
- * Sound decoder used in engines:
- * - agos
- * - draci
- * - kyra
- * - m4
- * - queen
- * - saga
- * - sci
- * - scumm
- * - sword1
- * - sword2
- * - touche
- * - tucker
- */
-
-#ifndef SOUND_FLAC_H
-#define SOUND_FLAC_H
-
-#include "common/scummsys.h"
-#include "common/types.h"
-
-#ifdef USE_FLAC
-
-namespace Common {
- class SeekableReadStream;
-}
-
-namespace Audio {
-
-class AudioStream;
-class SeekableAudioStream;
-
-/**
- * Create a new SeekableAudioStream from the FLAC data in the given stream.
- * Allows for seeking (which is why we require a SeekableReadStream).
- *
- * @param stream the SeekableReadStream from which to read the FLAC data
- * @param disposeAfterUse whether to delete the stream after use
- * @return a new SeekableAudioStream, or NULL, if an error occurred
- */
-SeekableAudioStream *makeFLACStream(
- Common::SeekableReadStream *stream,
- DisposeAfterUse::Flag disposeAfterUse);
-
-} // End of namespace Audio
-
-#endif // #ifdef USE_FLAC
-#endif // #ifndef SOUND_FLAC_H
diff --git a/sound/decoders/iff_sound.cpp b/sound/decoders/iff_sound.cpp
deleted file mode 100644
index 148de5b621..0000000000
--- a/sound/decoders/iff_sound.cpp
+++ /dev/null
@@ -1,130 +0,0 @@
-/* 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/decoders/iff_sound.h"
-#include "sound/audiostream.h"
-#include "sound/mixer.h"
-#include "sound/decoders/raw.h"
-#include "common/iff_container.h"
-#include "common/func.h"
-
-namespace Audio {
-
-struct Voice8Header {
- uint32 oneShotHiSamples;
- uint32 repeatHiSamples;
- uint32 samplesPerHiCycle;
- uint16 samplesPerSec;
- byte octaves;
- byte compression;
- uint32 volume;
-
- Voice8Header() {
- memset(this, 0, sizeof(Voice8Header));
- }
-
- void load(Common::ReadStream &stream);
-};
-
-void Voice8Header::load(Common::ReadStream &stream) {
- oneShotHiSamples = stream.readUint32BE();
- repeatHiSamples = stream.readUint32BE();
- samplesPerHiCycle = stream.readUint32BE();
- samplesPerSec = stream.readUint16BE();
- octaves = stream.readByte();
- compression = stream.readByte();
- volume = stream.readUint32BE();
-}
-
-
-
-struct A8SVXLoader {
- Voice8Header _header;
- int8 *_data;
- uint32 _dataSize;
-
- void load(Common::ReadStream &input) {
- Common::IFFParser parser(&input);
- Common::Functor1Mem< Common::IFFChunk&, bool, A8SVXLoader > c(this, &A8SVXLoader::callback);
- parser.parse(c);
- }
-
- bool callback(Common::IFFChunk &chunk) {
- switch (chunk._type) {
- case ID_VHDR:
- _header.load(*chunk._stream);
- break;
-
- case ID_BODY:
- _dataSize = chunk._size;
- _data = (int8*)malloc(_dataSize);
- assert(_data);
- loadData(chunk._stream);
- return true;
- }
-
- return false;
- }
-
- void loadData(Common::ReadStream *stream) {
- switch (_header.compression) {
- case 0:
- stream->read(_data, _dataSize);
- break;
-
- case 1:
- // implement other formats here
- error("compressed IFF audio is not supported");
- break;
- }
-
- }
-};
-
-
-AudioStream *make8SVXStream(Common::ReadStream &input, bool loop) {
- A8SVXLoader loader;
- loader.load(input);
-
- SeekableAudioStream *stream = Audio::makeRawStream((byte *)loader._data, loader._dataSize, loader._header.samplesPerSec, 0);
-
- uint32 loopStart = 0, loopEnd = 0;
- if (loop) {
- // the standard way to loop 8SVX audio implies use of the oneShotHiSamples and
- // repeatHiSamples fields
- loopStart = 0;
- loopEnd = loader._header.oneShotHiSamples + loader._header.repeatHiSamples;
-
- if (loopStart != loopEnd) {
- return new SubLoopingAudioStream(stream, 0,
- Timestamp(0, loopStart, loader._header.samplesPerSec),
- Timestamp(0, loopEnd, loader._header.samplesPerSec));
- }
- }
-
- return stream;
-}
-
-}
diff --git a/sound/decoders/iff_sound.h b/sound/decoders/iff_sound.h
deleted file mode 100644
index 4e53059380..0000000000
--- a/sound/decoders/iff_sound.h
+++ /dev/null
@@ -1,47 +0,0 @@
-/* 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$
- *
- */
-
-/**
- * @file
- * Sound decoder used in engines:
- * - parallaction
- */
-
-#ifndef SOUND_IFF_H
-#define SOUND_IFF_H
-
-namespace Common {
- class ReadStream;
-}
-
-namespace Audio {
-
-class AudioStream;
-
-AudioStream *make8SVXStream(Common::ReadStream &stream, bool loop);
-
-}
-
-#endif
diff --git a/sound/decoders/mac_snd.cpp b/sound/decoders/mac_snd.cpp
deleted file mode 100644
index 48f6886bf4..0000000000
--- a/sound/decoders/mac_snd.cpp
+++ /dev/null
@@ -1,116 +0,0 @@
-/* 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$
- *
- */
-
-/*
- * The code in this file is based on information found at
- * http://developer.apple.com/legacy/mac/library/documentation/mac/Sound/Sound-60.html#HEADING60-15
- *
- * We implement both type 1 and type 2 snd resources, but only those that are sampled
- */
-
-#include "common/util.h"
-#include "common/stream.h"
-
-#include "sound/decoders/mac_snd.h"
-#include "sound/audiostream.h"
-#include "sound/decoders/raw.h"
-
-namespace Audio {
-
-SeekableAudioStream *makeMacSndStream(Common::SeekableReadStream *stream,
- DisposeAfterUse::Flag disposeAfterUse) {
-
- uint16 sndType = stream->readUint16BE();
-
- if (sndType == 1) {
- // "normal" snd resources
- if (stream->readUint16BE() != 1) {
- warning("makeMacSndStream(): Unsupported data type count");
- return 0;
- }
-
- if (stream->readUint16BE() != 5) {
- // 5 == sampled
- warning("makeMacSndStream(): Unsupported data type");
- return 0;
- }
-
- stream->readUint32BE(); // initialization option
- } else if (sndType == 2) {
- // old HyperCard snd resources
- stream->readUint16BE(); // reference count (unused)
- } else {
- warning("makeMacSndStream(): Unknown format type %d", sndType);
- return 0;
- }
-
- // 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;
- }
-
- uint16 command = stream->readUint16BE();
-
- // 0x8050 - soundCmd (with dataOffsetFlag set): install a sampled sound as a voice
- // 0x8051 - bufferCmd (with dataOffsetFlag set): play a sample sound
- if (command != 0x8050 && command != 0x8051) {
- warning("makeMacSndStream(): Unsupported command %04x", command);
- return 0;
- }
-
- stream->readUint16BE(); // 0
- uint32 soundHeaderOffset = stream->readUint32BE();
-
- stream->seek(soundHeaderOffset);
-
- uint32 soundDataOffset = stream->readUint32BE();
- uint32 size = stream->readUint32BE();
- uint16 rate = stream->readUint32BE() >> 16; // Really fixed point, but we only support integer rates
- stream->readUint32BE(); // loop start
- stream->readUint32BE(); // loop end
- byte encoding = stream->readByte();
- stream->readByte(); // base frequency
-
- if (encoding != 0) {
- // 0 == PCM
- warning("makeMacSndStream(): Unsupported compression %d", encoding);
- return 0;
- }
-
- stream->skip(soundDataOffset);
-
- byte *data = (byte *)malloc(size);
- assert(data);
- stream->read(data, size);
-
- if (disposeAfterUse == DisposeAfterUse::YES)
- delete stream;
-
- // Since we allocated our own buffer for the data, we must specify DisposeAfterUse::YES.
- return makeRawStream(data, size, rate, Audio::FLAG_UNSIGNED);
-}
-
-} // End of namespace Audio
diff --git a/sound/decoders/mac_snd.h b/sound/decoders/mac_snd.h
deleted file mode 100644
index 198a61333e..0000000000
--- a/sound/decoders/mac_snd.h
+++ /dev/null
@@ -1,58 +0,0 @@
-/* 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$
- *
- */
-
-/**
- * @file
- * Sound decoder used in engines:
- * - sci
- */
-
-#ifndef SOUND_MAC_SND_H
-#define SOUND_MAC_SND_H
-
-#include "common/scummsys.h"
-#include "common/types.h"
-
-namespace Common { class SeekableReadStream; }
-
-namespace Audio {
-
-class SeekableAudioStream;
-
-/**
- * Try to load a Mac snd resource from the given seekable stream and create a SeekableAudioStream
- * from that data.
- *
- * @param stream the SeekableReadStream from which to read the snd data
- * @param disposeAfterUse whether to delete the stream after use
- * @return a new SeekableAudioStream, or NULL, if an error occurred
- */
-SeekableAudioStream *makeMacSndStream(
- Common::SeekableReadStream *stream,
- DisposeAfterUse::Flag disposeAfterUse);
-
-} // End of namespace Audio
-
-#endif
diff --git a/sound/decoders/mp3.cpp b/sound/decoders/mp3.cpp
deleted file mode 100644
index e06b82a9e2..0000000000
--- a/sound/decoders/mp3.cpp
+++ /dev/null
@@ -1,375 +0,0 @@
-/* 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/decoders/mp3.h"
-
-#ifdef USE_MAD
-
-#include "common/debug.h"
-#include "common/stream.h"
-#include "common/util.h"
-
-#include "sound/audiostream.h"
-
-#include <mad.h>
-
-#if defined(__PSP__)
- #include "backends/platform/psp/mp3.h"
-#endif
-namespace Audio {
-
-
-#pragma mark -
-#pragma mark --- MP3 (MAD) stream ---
-#pragma mark -
-
-
-class MP3Stream : public SeekableAudioStream {
-protected:
- enum State {
- MP3_STATE_INIT, // Need to init the decoder
- MP3_STATE_READY, // ready for processing data
- MP3_STATE_EOS // end of data reached (may need to loop)
- };
-
- Common::SeekableReadStream *_inStream;
- DisposeAfterUse::Flag _disposeAfterUse;
-
- uint _posInFrame;
- State _state;
-
- Timestamp _length;
- mad_timer_t _totalTime;
-
- mad_stream _stream;
- mad_frame _frame;
- mad_synth _synth;
-
- enum {
- BUFFER_SIZE = 5 * 8192
- };
-
- // This buffer contains a slab of input data
- byte _buf[BUFFER_SIZE + MAD_BUFFER_GUARD];
-
-public:
- MP3Stream(Common::SeekableReadStream *inStream,
- DisposeAfterUse::Flag dispose);
- ~MP3Stream();
-
- int readBuffer(int16 *buffer, const int numSamples);
-
- bool endOfData() const { return _state == MP3_STATE_EOS; }
- bool isStereo() const { return MAD_NCHANNELS(&_frame.header) == 2; }
- int getRate() const { return _frame.header.samplerate; }
-
- bool seek(const Timestamp &where);
- Timestamp getLength() const { return _length; }
-protected:
- void decodeMP3Data();
- void readMP3Data();
-
- void initStream();
- void readHeader();
- void deinitStream();
-};
-
-MP3Stream::MP3Stream(Common::SeekableReadStream *inStream, DisposeAfterUse::Flag dispose) :
- _inStream(inStream),
- _disposeAfterUse(dispose),
- _posInFrame(0),
- _state(MP3_STATE_INIT),
- _length(0, 1000),
- _totalTime(mad_timer_zero) {
-
- // The MAD_BUFFER_GUARD must always contain zeros (the reason
- // for this is that the Layer III Huffman decoder of libMAD
- // may read a few bytes beyond the end of the input buffer).
- memset(_buf + BUFFER_SIZE, 0, MAD_BUFFER_GUARD);
-
- // Calculate the length of the stream
- initStream();
-
- while (_state != MP3_STATE_EOS)
- readHeader();
-
- // To rule out any invalid sample rate to be encountered here, say in case the
- // MP3 stream is invalid, we just check the MAD error code here.
- // We need to assure this, since else we might trigger an assertion in Timestamp
- // (When getRate() returns 0 or a negative number to be precise).
- // Note that we allow "MAD_ERROR_BUFLEN" as error code here, since according
- // to mad.h it is also set on EOF.
- if ((_stream.error == MAD_ERROR_NONE || _stream.error == MAD_ERROR_BUFLEN) && getRate() > 0)
- _length = Timestamp(mad_timer_count(_totalTime, MAD_UNITS_MILLISECONDS), getRate());
-
- deinitStream();
-
- // Reinit stream
- _state = MP3_STATE_INIT;
-
- // Decode the first chunk of data. This is necessary so that _frame
- // is setup and isStereo() and getRate() return correct results.
- decodeMP3Data();
-}
-
-MP3Stream::~MP3Stream() {
- deinitStream();
-
- if (_disposeAfterUse == DisposeAfterUse::YES)
- delete _inStream;
-}
-
-void MP3Stream::decodeMP3Data() {
- do {
- if (_state == MP3_STATE_INIT)
- initStream();
-
- if (_state == MP3_STATE_EOS)
- return;
-
- // If necessary, load more data into the stream decoder
- if (_stream.error == MAD_ERROR_BUFLEN)
- readMP3Data();
-
- while (_state == MP3_STATE_READY) {
- _stream.error = MAD_ERROR_NONE;
-
- // Decode the next frame
- if (mad_frame_decode(&_frame, &_stream) == -1) {
- if (_stream.error == MAD_ERROR_BUFLEN) {
- break; // Read more data
- } else if (MAD_RECOVERABLE(_stream.error)) {
- // Note: we will occasionally see MAD_ERROR_BADDATAPTR errors here.
- // These are normal and expected (caused by our frame skipping (i.e. "seeking")
- // code above).
- debug(6, "MP3Stream: Recoverable error in mad_frame_decode (%s)", mad_stream_errorstr(&_stream));
- continue;
- } else {
- warning("MP3Stream: Unrecoverable error in mad_frame_decode (%s)", mad_stream_errorstr(&_stream));
- break;
- }
- }
-
- // Synthesize PCM data
- mad_synth_frame(&_synth, &_frame);
- _posInFrame = 0;
- break;
- }
- } while (_state != MP3_STATE_EOS && _stream.error == MAD_ERROR_BUFLEN);
-
- if (_stream.error != MAD_ERROR_NONE)
- _state = MP3_STATE_EOS;
-}
-
-void MP3Stream::readMP3Data() {
- uint32 remaining = 0;
-
- // Give up immediately if we already used up all data in the stream
- if (_inStream->eos()) {
- _state = MP3_STATE_EOS;
- return;
- }
-
- if (_stream.next_frame) {
- // If there is still data in the MAD stream, we need to preserve it.
- // Note that we use memmove, as we are reusing the same buffer,
- // and hence the data regions we copy from and to may overlap.
- remaining = _stream.bufend - _stream.next_frame;
- assert(remaining < BUFFER_SIZE); // Paranoia check
- memmove(_buf, _stream.next_frame, remaining);
- }
-
- // Try to read the next block
- uint32 size = _inStream->read(_buf + remaining, BUFFER_SIZE - remaining);
- if (size <= 0) {
- _state = MP3_STATE_EOS;
- return;
- }
-
- // Feed the data we just read into the stream decoder
- _stream.error = MAD_ERROR_NONE;
- mad_stream_buffer(&_stream, _buf, size + remaining);
-}
-
-bool MP3Stream::seek(const Timestamp &where) {
- if (where == _length) {
- _state = MP3_STATE_EOS;
- return true;
- } else if (where > _length) {
- return false;
- }
-
- const uint32 time = where.msecs();
-
- mad_timer_t destination;
- mad_timer_set(&destination, time / 1000, time % 1000, 1000);
-
- if (_state != MP3_STATE_READY || mad_timer_compare(destination, _totalTime) < 0)
- initStream();
-
- while (mad_timer_compare(destination, _totalTime) > 0 && _state != MP3_STATE_EOS)
- readHeader();
-
- decodeMP3Data();
-
- return (_state != MP3_STATE_EOS);
-}
-
-void MP3Stream::initStream() {
- if (_state != MP3_STATE_INIT)
- deinitStream();
-
- // Init MAD
- mad_stream_init(&_stream);
- mad_frame_init(&_frame);
- mad_synth_init(&_synth);
-
- // Reset the stream data
- _inStream->seek(0, SEEK_SET);
- _totalTime = mad_timer_zero;
- _posInFrame = 0;
-
- // Update state
- _state = MP3_STATE_READY;
-
- // Read the first few sample bytes
- readMP3Data();
-}
-
-void MP3Stream::readHeader() {
- if (_state != MP3_STATE_READY)
- return;
-
- // If necessary, load more data into the stream decoder
- if (_stream.error == MAD_ERROR_BUFLEN)
- readMP3Data();
-
- while (_state != MP3_STATE_EOS) {
- _stream.error = MAD_ERROR_NONE;
-
- // Decode the next header. Note: mad_frame_decode would do this for us, too.
- // However, for seeking we don't want to decode the full frame (else it would
- // be far too slow). Hence we perform this explicitly in a separate step.
- if (mad_header_decode(&_frame.header, &_stream) == -1) {
- if (_stream.error == MAD_ERROR_BUFLEN) {
- readMP3Data(); // Read more data
- continue;
- } else if (MAD_RECOVERABLE(_stream.error)) {
- debug(6, "MP3Stream: Recoverable error in mad_header_decode (%s)", mad_stream_errorstr(&_stream));
- continue;
- } else {
- warning("MP3Stream: Unrecoverable error in mad_header_decode (%s)", mad_stream_errorstr(&_stream));
- break;
- }
- }
-
- // Sum up the total playback time so far
- mad_timer_add(&_totalTime, _frame.header.duration);
- break;
- }
-
- if (_stream.error != MAD_ERROR_NONE)
- _state = MP3_STATE_EOS;
-}
-
-void MP3Stream::deinitStream() {
- if (_state == MP3_STATE_INIT)
- return;
-
- // Deinit MAD
- mad_synth_finish(&_synth);
- mad_frame_finish(&_frame);
- mad_stream_finish(&_stream);
-
- _state = MP3_STATE_EOS;
-}
-
-static inline int scale_sample(mad_fixed_t sample) {
- // round
- sample += (1L << (MAD_F_FRACBITS - 16));
-
- // clip
- if (sample > MAD_F_ONE - 1)
- sample = MAD_F_ONE - 1;
- else if (sample < -MAD_F_ONE)
- sample = -MAD_F_ONE;
-
- // quantize and scale to not saturate when mixing a lot of channels
- return sample >> (MAD_F_FRACBITS + 1 - 16);
-}
-
-int MP3Stream::readBuffer(int16 *buffer, const int numSamples) {
- int samples = 0;
- // Keep going as long as we have input available
- while (samples < numSamples && _state != MP3_STATE_EOS) {
- const int len = MIN(numSamples, samples + (int)(_synth.pcm.length - _posInFrame) * MAD_NCHANNELS(&_frame.header));
- while (samples < len) {
- *buffer++ = (int16)scale_sample(_synth.pcm.samples[0][_posInFrame]);
- samples++;
- if (MAD_NCHANNELS(&_frame.header) == 2) {
- *buffer++ = (int16)scale_sample(_synth.pcm.samples[1][_posInFrame]);
- samples++;
- }
- _posInFrame++;
- }
- if (_posInFrame >= _synth.pcm.length) {
- // We used up all PCM data in the current frame -- read & decode more
- decodeMP3Data();
- }
- }
- return samples;
-}
-
-
-#pragma mark -
-#pragma mark --- MP3 factory functions ---
-#pragma mark -
-
-SeekableAudioStream *makeMP3Stream(
- Common::SeekableReadStream *stream,
- DisposeAfterUse::Flag disposeAfterUse) {
-
-#if defined(__PSP__)
- SeekableAudioStream *s = 0;
-
- if (Mp3PspStream::isOkToCreateStream())
- s = new Mp3PspStream(stream, disposeAfterUse);
-
- if (!s) // go to regular MAD mp3 stream if ME fails
- s = new MP3Stream(stream, disposeAfterUse);
-#else
- SeekableAudioStream *s = new MP3Stream(stream, disposeAfterUse);
-#endif
- if (s && s->endOfData()) {
- delete s;
- return 0;
- } else {
- return s;
- }
-}
-
-} // End of namespace Audio
-
-#endif // #ifdef USE_MAD
diff --git a/sound/decoders/mp3.h b/sound/decoders/mp3.h
deleted file mode 100644
index 72bc6e1b3e..0000000000
--- a/sound/decoders/mp3.h
+++ /dev/null
@@ -1,76 +0,0 @@
-/* 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$
- *
- */
-
-/**
- * @file
- * Sound decoder used in engines:
- * - agos
- * - draci
- * - kyra
- * - m4
- * - mohawk
- * - queen
- * - saga
- * - sci
- * - scumm
- * - sword1
- * - sword2
- * - touche
- * - tucker
- */
-
-#ifndef SOUND_MP3_H
-#define SOUND_MP3_H
-
-#include "common/scummsys.h"
-#include "common/types.h"
-
-#ifdef USE_MAD
-
-namespace Common {
- class SeekableReadStream;
-}
-
-namespace Audio {
-
-class AudioStream;
-class SeekableAudioStream;
-
-/**
- * Create a new SeekableAudioStream from the MP3 data in the given stream.
- * Allows for seeking (which is why we require a SeekableReadStream).
- *
- * @param stream the SeekableReadStream from which to read the MP3 data
- * @param disposeAfterUse whether to delete the stream after use
- * @return a new SeekableAudioStream, or NULL, if an error occurred
- */
-SeekableAudioStream *makeMP3Stream(
- Common::SeekableReadStream *stream,
- DisposeAfterUse::Flag disposeAfterUse);
-
-} // End of namespace Audio
-
-#endif // #ifdef USE_MAD
-#endif // #ifndef SOUND_MP3_H
diff --git a/sound/decoders/raw.cpp b/sound/decoders/raw.cpp
deleted file mode 100644
index aedddbf6c4..0000000000
--- a/sound/decoders/raw.cpp
+++ /dev/null
@@ -1,356 +0,0 @@
-/* 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 "common/endian.h"
-#include "common/memstream.h"
-
-#include "sound/audiostream.h"
-#include "sound/mixer.h"
-#include "sound/decoders/raw.h"
-
-namespace Audio {
-
-// This used to be an inline template function, but
-// buggy template function handling in MSVC6 forced
-// us to go with the macro approach. So far this is
-// the only template function that MSVC6 seemed to
-// compile incorrectly. Knock on wood.
-#define READ_ENDIAN_SAMPLE(is16Bit, isUnsigned, ptr, isLE) \
- ((is16Bit ? (isLE ? READ_LE_UINT16(ptr) : READ_BE_UINT16(ptr)) : (*ptr << 8)) ^ (isUnsigned ? 0x8000 : 0))
-
-
-#pragma mark -
-#pragma mark --- RawStream ---
-#pragma mark -
-
-/**
- * This is a stream, which allows for playing raw PCM data from a stream.
- * It also features playback of multiple blocks from a given stream.
- */
-template<bool is16Bit, bool isUnsigned, bool isLE>
-class RawStream : public SeekableAudioStream {
-public:
- RawStream(int rate, bool stereo, DisposeAfterUse::Flag disposeStream, Common::SeekableReadStream *stream, const RawStreamBlockList &blocks)
- : _rate(rate), _isStereo(stereo), _playtime(0, rate), _stream(stream), _disposeAfterUse(disposeStream), _blocks(blocks), _curBlock(_blocks.begin()), _blockLeft(0), _buffer(0) {
-
- assert(_blocks.size() > 0);
-
- // Setup our buffer for readBuffer
- _buffer = new byte[kSampleBufferLength * (is16Bit ? 2 : 1)];
- assert(_buffer);
-
- // Set current buffer state, playing first block
- _stream->seek(_curBlock->pos, SEEK_SET);
-
- // In case of an error we will stop (or rather
- // not start) stream playback.
- if (_stream->err()) {
- _blockLeft = 0;
- _curBlock = _blocks.end();
- } else {
- _blockLeft = _curBlock->len;
- }
-
- // Add up length of all blocks in order to caluclate total play time
- int32 len = 0;
- for (RawStreamBlockList::const_iterator i = _blocks.begin(); i != _blocks.end(); ++i) {
- assert(i->len % (_isStereo ? 2 : 1) == 0);
- len += i->len;
- }
-
- _playtime = Timestamp(0, len / (_isStereo ? 2 : 1), rate);
- }
-
- ~RawStream() {
- if (_disposeAfterUse == DisposeAfterUse::YES)
- delete _stream;
-
- delete[] _buffer;
- }
-
- int readBuffer(int16 *buffer, const int numSamples);
-
- bool isStereo() const { return _isStereo; }
- bool endOfData() const { return (_curBlock == _blocks.end()) && (_blockLeft == 0); }
-
- int getRate() const { return _rate; }
- Timestamp getLength() const { return _playtime; }
-
- bool seek(const Timestamp &where);
-private:
- const int _rate; ///< Sample rate of stream
- const bool _isStereo; ///< Whether this is an stereo stream
- Timestamp _playtime; ///< Calculated total play time
- Common::SeekableReadStream *_stream; ///< Stream to read data from
- const DisposeAfterUse::Flag _disposeAfterUse; ///< Indicates whether the stream object should be deleted when this RawStream is destructed
- const RawStreamBlockList _blocks; ///< Audio block list
-
- RawStreamBlockList::const_iterator _curBlock; ///< Current audio block number
- int32 _blockLeft; ///< How many bytes are still left in the current block
-
- /**
- * Advance one block in the stream in case
- * the current one is empty.
- */
- void updateBlockIfNeeded();
-
- byte *_buffer; ///< Buffer used in readBuffer
- enum {
- /**
- * How many samples we can buffer at once.
- *
- * TODO: Check whether this size suffices
- * for systems with slow disk I/O.
- */
- kSampleBufferLength = 2048
- };
-
- /**
- * Fill the temporary sample buffer used in readBuffer.
- *
- * @param maxSamples Maximum samples to read.
- * @return actual count of samples read.
- */
- int fillBuffer(int maxSamples);
-};
-
-template<bool is16Bit, bool isUnsigned, bool isLE>
-int RawStream<is16Bit, isUnsigned, isLE>::readBuffer(int16 *buffer, const int numSamples) {
- int samplesLeft = numSamples;
-
- while (samplesLeft > 0) {
- // Try to read up to "samplesLeft" samples.
- int len = fillBuffer(samplesLeft);
-
- // In case we were not able to read any samples
- // we will stop reading here.
- if (!len)
- break;
-
- // Adjust the samples left to read.
- samplesLeft -= len;
-
- // Copy the data to the caller's buffer.
- const byte *src = _buffer;
- while (len-- > 0) {
- *buffer++ = READ_ENDIAN_SAMPLE(is16Bit, isUnsigned, src, isLE);
- src += (is16Bit ? 2 : 1);
- }
- }
-
- return numSamples - samplesLeft;
-}
-
-template<bool is16Bit, bool isUnsigned, bool isLE>
-int RawStream<is16Bit, isUnsigned, isLE>::fillBuffer(int maxSamples) {
- int bufferedSamples = 0;
- byte *dst = _buffer;
-
- // We can only read up to "kSampleBufferLength" samples
- // so we take this into consideration, when trying to
- // read up to maxSamples.
- maxSamples = MIN<int>(kSampleBufferLength, maxSamples);
-
- // We will only read up to maxSamples
- while (maxSamples > 0 && !endOfData()) {
- // Calculate how many samples we can safely read
- // from the current block.
- const int len = MIN<int>(maxSamples, _blockLeft);
-
- // Try to read all the sample data and update the
- // destination pointer.
- const int bytesRead = _stream->read(dst, len * (is16Bit ? 2 : 1));
- dst += bytesRead;
-
- // Calculate how many samples we actually read.
- const int samplesRead = bytesRead / (is16Bit ? 2 : 1);
-
- // Update all status variables
- bufferedSamples += samplesRead;
- maxSamples -= samplesRead;
- _blockLeft -= samplesRead;
-
- // In case of an error we will stop
- // stream playback.
- if (_stream->err()) {
- _blockLeft = 0;
- _curBlock = _blocks.end();
- }
-
- // Advance to the next block in case the current
- // one is already finished.
- updateBlockIfNeeded();
- }
-
- return bufferedSamples;
-}
-
-template<bool is16Bit, bool isUnsigned, bool isLE>
-void RawStream<is16Bit, isUnsigned, isLE>::updateBlockIfNeeded() {
- // Have we now finished this block? If so, read the next block
- if (_blockLeft == 0 && _curBlock != _blocks.end()) {
- // Next block
- ++_curBlock;
-
- // Check whether we reached the end of the stream
- // yet. In case we did not do this, we will just
- // setup the next block as new block.
- if (_curBlock != _blocks.end()) {
- _stream->seek(_curBlock->pos, SEEK_SET);
-
- // In case of an error we will stop
- // stream playback.
- if (_stream->err()) {
- _blockLeft = 0;
- _curBlock = _blocks.end();
- } else {
- _blockLeft = _curBlock->len;
- }
- }
- }
-}
-
-template<bool is16Bit, bool isUnsigned, bool isLE>
-bool RawStream<is16Bit, isUnsigned, isLE>::seek(const Timestamp &where) {
- _blockLeft = 0;
- _curBlock = _blocks.end();
-
- if (where > _playtime)
- return false;
-
- const uint32 seekSample = convertTimeToStreamPos(where, getRate(), isStereo()).totalNumberOfFrames();
- uint32 curSample = 0;
-
- // Search for the disk block in which the specific sample is placed
- for (_curBlock = _blocks.begin(); _curBlock != _blocks.end(); ++_curBlock) {
- uint32 nextBlockSample = curSample + _curBlock->len;
-
- if (nextBlockSample > seekSample)
- break;
-
- curSample = nextBlockSample;
- }
-
- if (_curBlock == _blocks.end()) {
- return ((seekSample - curSample) == 0);
- } else {
- const uint32 offset = seekSample - curSample;
-
- _stream->seek(_curBlock->pos + offset * (is16Bit ? 2 : 1), SEEK_SET);
-
- // In case of an error we will stop
- // stream playback.
- if (_stream->err()) {
- _blockLeft = 0;
- _curBlock = _blocks.end();
- } else {
- _blockLeft = _curBlock->len - offset;
- }
-
- return true;
- }
-}
-
-#pragma mark -
-#pragma mark --- Raw stream factories ---
-#pragma mark -
-
-/* In the following, we use preprocessor / macro tricks to simplify the code
- * which instantiates the input streams. We used to use template functions for
- * this, but MSVC6 / EVC 3-4 (used for WinCE builds) are extremely buggy when it
- * comes to this feature of C++... so as a compromise we use macros to cut down
- * on the (source) code duplication a bit.
- * So while normally macro tricks are said to make maintenance harder, in this
- * particular case it should actually help it :-)
- */
-
-#define MAKE_RAW_STREAM(UNSIGNED) \
- if (is16Bit) { \
- if (isLE) \
- return new RawStream<true, UNSIGNED, true>(rate, isStereo, disposeAfterUse, stream, blockList); \
- else \
- return new RawStream<true, UNSIGNED, false>(rate, isStereo, disposeAfterUse, stream, blockList); \
- } else \
- return new RawStream<false, UNSIGNED, false>(rate, isStereo, disposeAfterUse, stream, blockList)
-
-SeekableAudioStream *makeRawStream(Common::SeekableReadStream *stream,
- const RawStreamBlockList &blockList,
- int rate,
- byte flags,
- DisposeAfterUse::Flag disposeAfterUse) {
- const bool isStereo = (flags & Audio::FLAG_STEREO) != 0;
- const bool is16Bit = (flags & Audio::FLAG_16BITS) != 0;
- const bool isUnsigned = (flags & Audio::FLAG_UNSIGNED) != 0;
- const bool isLE = (flags & Audio::FLAG_LITTLE_ENDIAN) != 0;
-
- if (blockList.empty()) {
- warning("Empty block list passed to makeRawStream");
- if (disposeAfterUse == DisposeAfterUse::YES)
- delete stream;
- return 0;
- }
-
- if (isUnsigned) {
- MAKE_RAW_STREAM(true);
- } else {
- MAKE_RAW_STREAM(false);
- }
-}
-
-SeekableAudioStream *makeRawStream(Common::SeekableReadStream *stream,
- int rate, byte flags,
- DisposeAfterUse::Flag disposeAfterUse) {
- RawStreamBlockList blocks;
- RawStreamBlock block;
- block.pos = 0;
-
- const bool isStereo = (flags & Audio::FLAG_STEREO) != 0;
- const bool is16Bit = (flags & Audio::FLAG_16BITS) != 0;
-
- assert(stream->size() % ((is16Bit ? 2 : 1) * (isStereo ? 2 : 1)) == 0);
-
- block.len = stream->size() / (is16Bit ? 2 : 1);
- blocks.push_back(block);
-
- return makeRawStream(stream, blocks, rate, flags, disposeAfterUse);
-}
-
-SeekableAudioStream *makeRawStream(const byte *buffer, uint32 size,
- int rate, byte flags,
- DisposeAfterUse::Flag disposeAfterUse) {
- return makeRawStream(new Common::MemoryReadStream(buffer, size, disposeAfterUse), rate, flags, DisposeAfterUse::YES);
-}
-
-SeekableAudioStream *makeRawDiskStream_OLD(Common::SeekableReadStream *stream, RawStreamBlock *block, int numBlocks,
- int rate, byte flags, DisposeAfterUse::Flag disposeStream) {
- assert(numBlocks > 0);
- RawStreamBlockList blocks;
- for (int i = 0; i < numBlocks; ++i)
- blocks.push_back(block[i]);
-
- return makeRawStream(stream, blocks, rate, flags, disposeStream);
-}
-
-} // End of namespace Audio
diff --git a/sound/decoders/raw.h b/sound/decoders/raw.h
deleted file mode 100644
index 3e9426012c..0000000000
--- a/sound/decoders/raw.h
+++ /dev/null
@@ -1,153 +0,0 @@
-/* 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_RAW_H
-#define SOUND_RAW_H
-
-#include "common/scummsys.h"
-#include "common/types.h"
-
-#include "common/list.h"
-
-
-namespace Common { class SeekableReadStream; }
-
-
-namespace Audio {
-
-class AudioStream;
-class SeekableAudioStream;
-
-/**
- * Various flags which can be bit-ORed and then passed to
- * makeRawStream and some other AudioStream factories
- * to control their behavior.
- *
- * Engine authors are advised not to rely on a certain value or
- * order of these flags (in particular, do not store them verbatim
- * in savestates).
- */
-enum RawFlags {
- /** unsigned samples (default: signed) */
- FLAG_UNSIGNED = 1 << 0,
-
- /** sound is 16 bits wide (default: 8bit) */
- FLAG_16BITS = 1 << 1,
-
- /** samples are little endian (default: big endian) */
- FLAG_LITTLE_ENDIAN = 1 << 2,
-
- /** sound is in stereo (default: mono) */
- FLAG_STEREO = 1 << 3
-};
-
-
-/**
- * Struct used to define the audio data to be played by a RawStream.
- */
-struct RawStreamBlock {
- int32 pos; ///< Position in stream of the block (in bytes of course!)
- int32 len; ///< Length of the block (in raw samples, not sample pairs!)
-};
-
-/**
- * List containing all blocks of a raw stream.
- * @see RawStreamBlock
- */
-typedef Common::List<RawStreamBlock> RawStreamBlockList;
-
-/**
- * Creates an audio stream, which plays from the given buffer.
- *
- * @param buffer Buffer to play from.
- * @param size Size of the buffer in bytes.
- * @param rate Rate of the sound data.
- * @param flags Audio flags combination.
- * @see RawFlags
- * @param disposeAfterUse Whether to free the buffer after use (with free!).
- * @return The new SeekableAudioStream (or 0 on failure).
- */
-SeekableAudioStream *makeRawStream(const byte *buffer, uint32 size,
- int rate, byte flags,
- DisposeAfterUse::Flag disposeAfterUse = DisposeAfterUse::YES);
-
-/**
- * Creates an audio stream, which plays from the given stream.
- *
- * @param stream Stream object to play from.
- * @param rate Rate of the sound data.
- * @param flags Audio flags combination.
- * @see RawFlags
- * @param disposeAfterUse Whether to delete the stream after use.
- * @return The new SeekableAudioStream (or 0 on failure).
- */
-SeekableAudioStream *makeRawStream(Common::SeekableReadStream *stream,
- int rate, byte flags,
- DisposeAfterUse::Flag disposeAfterUse = DisposeAfterUse::YES);
-
-/**
- * Creates an audio stream, which plays from the given stream.
- *
- * @param stream Stream object to play from.
- * @param blockList List of blocks to play.
- * @see RawDiskStreamAudioBlock
- * @see RawStreamBlockList
- * @param rate Rate of the sound data.
- * @param flags Audio flags combination.
- * @see RawFlags
- * @param disposeAfterUse Whether to delete the stream after use.
- * @return The new SeekableAudioStream (or 0 on failure).
- */
-SeekableAudioStream *makeRawStream(Common::SeekableReadStream *stream,
- const RawStreamBlockList &blockList,
- int rate,
- byte flags,
- DisposeAfterUse::Flag disposeAfterUse = DisposeAfterUse::YES);
-
-/**
- * NOTE:
- * This API is considered deprecated.
- *
- * Creates a audio stream, which plays from given stream.
- *
- * @param stream Stream to play from
- * @param block Pointer to an RawStreamBlock array
- * @see RawStreamBlock
- * @param numBlocks Number of blocks.
- * @param rate The rate
- * @param flags Flags combination.
- * @see RawFlags
- * @param disposeStream Whether the "stream" object should be destroyed after playback.
- * @return The new SeekableAudioStream (or 0 on failure).
- */
-SeekableAudioStream *makeRawDiskStream_OLD(Common::SeekableReadStream *stream,
- RawStreamBlock *block, int numBlocks,
- int rate, byte flags,
- DisposeAfterUse::Flag disposeStream);
-
-
-} // End of namespace Audio
-
-#endif
diff --git a/sound/decoders/vag.cpp b/sound/decoders/vag.cpp
deleted file mode 100644
index d3f0811f2b..0000000000
--- a/sound/decoders/vag.cpp
+++ /dev/null
@@ -1,150 +0,0 @@
-/* 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/decoders/vag.h"
-#include "sound/audiostream.h"
-#include "common/stream.h"
-
-namespace Audio {
-
-class VagStream : public Audio::RewindableAudioStream {
-public:
- VagStream(Common::SeekableReadStream *stream, int rate);
- ~VagStream();
-
- bool isStereo() const { return false; }
- bool endOfData() const { return _stream->pos() == _stream->size(); }
- int getRate() const { return _rate; }
- int readBuffer(int16 *buffer, const int numSamples);
-
- bool rewind();
-private:
- Common::SeekableReadStream *_stream;
-
- byte _predictor;
- double _samples[28];
- byte _samplesRemaining;
- int _rate;
- double _s1, _s2;
-};
-
-VagStream::VagStream(Common::SeekableReadStream *stream, int rate) : _stream(stream) {
- _samplesRemaining = 0;
- _predictor = 0;
- _s1 = _s2 = 0.0;
- _rate = rate;
-}
-
-
-VagStream::~VagStream() {
- delete _stream;
-}
-
-static const double s_vagDataTable[5][2] =
- {
- { 0.0, 0.0 },
- { 60.0 / 64.0, 0.0 },
- { 115.0 / 64.0, -52.0 / 64.0 },
- { 98.0 / 64.0, -55.0 / 64.0 },
- { 122.0 / 64.0, -60.0 / 64.0 }
- };
-
-int VagStream::readBuffer(int16 *buffer, const int numSamples) {
- int32 samplesDecoded = 0;
-
- if (_samplesRemaining) {
- byte i = 0;
-
- for (i = 28 - _samplesRemaining; i < 28 && samplesDecoded < numSamples; i++) {
- _samples[i] = _samples[i] + _s1 * s_vagDataTable[_predictor][0] + _s2 * s_vagDataTable[_predictor][1];
- _s2 = _s1;
- _s1 = _samples[i];
- int16 d = (int) (_samples[i] + 0.5);
- buffer[samplesDecoded] = d;
- samplesDecoded++;
- }
-
-#if 0
- assert(i == 28); // We're screwed if this fails :P
-#endif
- // This might mean the file is corrupted, or that the stream has
- // been closed.
- if (i != 28) return 0;
-
- _samplesRemaining = 0;
- }
-
- while (samplesDecoded < numSamples) {
- byte i = 0;
-
- _predictor = _stream->readByte();
- byte shift = _predictor & 0xf;
- _predictor >>= 4;
-
- if (_stream->readByte() == 7)
- return samplesDecoded;
-
- for (i = 0; i < 28; i += 2) {
- byte d = _stream->readByte();
- int16 s = (d & 0xf) << 12;
- if (s & 0x8000)
- s |= 0xffff0000;
- _samples[i] = (double)(s >> shift);
- s = (d & 0xf0) << 8;
- if (s & 0x8000)
- s |= 0xffff0000;
- _samples[i + 1] = (double)(s >> shift);
- }
-
- for (i = 0; i < 28 && samplesDecoded < numSamples; i++) {
- _samples[i] = _samples[i] + _s1 * s_vagDataTable[_predictor][0] + _s2 * s_vagDataTable[_predictor][1];
- _s2 = _s1;
- _s1 = _samples[i];
- int16 d = (int) (_samples[i] + 0.5);
- buffer[samplesDecoded] = d;
- samplesDecoded++;
- }
-
- if (i != 27)
- _samplesRemaining = 28 - i;
- }
-
- return samplesDecoded;
-}
-
-bool VagStream::rewind() {
- _stream->seek(0);
- _samplesRemaining = 0;
- _predictor = 0;
- _s1 = _s2 = 0.0;
-
- return true;
-}
-
-RewindableAudioStream *makeVagStream(Common::SeekableReadStream *stream, int rate) {
- return new VagStream(stream, rate);
-}
-
-}
diff --git a/sound/decoders/vag.h b/sound/decoders/vag.h
deleted file mode 100644
index cdf91a8ea1..0000000000
--- a/sound/decoders/vag.h
+++ /dev/null
@@ -1,60 +0,0 @@
-/* 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$
- *
- */
-
-/**
- * @file
- * Sound decoder used in engines:
- * - sword1 (PSX port of the game)
- * - sword2 (PSX port of the game)
- * - tinsel (PSX port of the game)
- */
-
-#ifndef SOUND_VAG_H
-#define SOUND_VAG_H
-
-namespace Common {
- class SeekableReadStream;
-}
-
-namespace Audio {
-
-class AudioStream;
-class RewindableAudioStream;
-
-/**
- * Takes an input stream containing Vag sound data and creates
- * an RewindableAudioStream from that.
- *
- * @param stream the SeekableReadStream from which to read the ADPCM data
- * @param rate the sampling rate
- * @return a new RewindableAudioStream, or NULL, if an error occurred
- */
-RewindableAudioStream *makeVagStream(
- Common::SeekableReadStream *stream,
- int rate = 11025);
-
-} // End of namespace Sword1
-
-#endif
diff --git a/sound/decoders/voc.cpp b/sound/decoders/voc.cpp
deleted file mode 100644
index e9af7ece3f..0000000000
--- a/sound/decoders/voc.cpp
+++ /dev/null
@@ -1,403 +0,0 @@
-/* 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 "common/debug.h"
-#include "common/endian.h"
-#include "common/util.h"
-#include "common/stream.h"
-
-#include "sound/audiostream.h"
-#include "sound/mixer.h"
-#include "sound/decoders/raw.h"
-#include "sound/decoders/voc.h"
-
-
-namespace Audio {
-
-int getSampleRateFromVOCRate(int vocSR) {
- if (vocSR == 0xa5 || vocSR == 0xa6) {
- return 11025;
- } else if (vocSR == 0xd2 || vocSR == 0xd3) {
- return 22050;
- } else {
- int sr = 1000000L / (256L - vocSR);
- // inexact sampling rates occur e.g. in the kitchen in Monkey Island,
- // very easy to reach right from the start of the game.
- //warning("inexact sample rate used: %i (0x%x)", sr, vocSR);
- return sr;
- }
-}
-
-static byte *loadVOCFromStream(Common::ReadStream &stream, int &size, int &rate, int &loops, int &begin_loop, int &end_loop) {
- VocFileHeader fileHeader;
-
- debug(2, "loadVOCFromStream");
-
- if (stream.read(&fileHeader, 8) != 8)
- goto invalid;
-
- if (!memcmp(&fileHeader, "VTLK", 4)) {
- if (stream.read(&fileHeader, sizeof(VocFileHeader)) != sizeof(VocFileHeader))
- goto invalid;
- } else if (!memcmp(&fileHeader, "Creative", 8)) {
- if (stream.read(((byte *)&fileHeader) + 8, sizeof(VocFileHeader) - 8) != sizeof(VocFileHeader) - 8)
- goto invalid;
- } else {
- invalid:;
- warning("loadVOCFromStream: Invalid header");
- return NULL;
- }
-
- if (memcmp(fileHeader.desc, "Creative Voice File", 19) != 0)
- error("loadVOCFromStream: Invalid header");
- if (fileHeader.desc[19] != 0x1A)
- debug(3, "loadVOCFromStream: Partially invalid header");
-
- int32 offset = FROM_LE_16(fileHeader.datablock_offset);
- int16 version = FROM_LE_16(fileHeader.version);
- int16 code = FROM_LE_16(fileHeader.id);
- assert(offset == sizeof(VocFileHeader));
- // 0x100 is an invalid VOC version used by German version of DOTT (Disk) and
- // French version of Simon the Sorcerer 2 (CD)
- assert(version == 0x010A || version == 0x0114 || version == 0x0100);
- assert(code == ~version + 0x1234);
-
- int len;
- byte *ret_sound = 0;
- size = 0;
- begin_loop = 0;
- end_loop = 0;
-
- while ((code = stream.readByte())) {
- len = stream.readByte();
- len |= stream.readByte() << 8;
- len |= stream.readByte() << 16;
-
- debug(2, "Block code %d, len %d", code, len);
-
- switch (code) {
- case 1:
- case 9: {
- int packing;
- if (code == 1) {
- int time_constant = stream.readByte();
- packing = stream.readByte();
- len -= 2;
- rate = getSampleRateFromVOCRate(time_constant);
- } else {
- rate = stream.readUint32LE();
- int bits = stream.readByte();
- int channels = stream.readByte();
- if (bits != 8 || channels != 1) {
- warning("Unsupported VOC file format (%d bits per sample, %d channels)", bits, channels);
- break;
- }
- packing = stream.readUint16LE();
- stream.readUint32LE();
- len -= 12;
- }
- debug(9, "VOC Data Block: %d, %d, %d", rate, packing, len);
- if (packing == 0) {
- if (size) {
- ret_sound = (byte *)realloc(ret_sound, size + len);
- } else {
- ret_sound = (byte *)malloc(len);
- }
- stream.read(ret_sound + size, len);
- size += len;
- begin_loop = size;
- end_loop = size;
- } else {
- warning("VOC file packing %d unsupported", packing);
- }
- } break;
- case 3: // silence
- // occur with a few Igor sounds, voc file starts with a silence block with a
- // frequency different from the data block. Just ignore fow now (implementing
- // it wouldn't make a big difference anyway...)
- assert(len == 3);
- stream.readUint16LE();
- stream.readByte();
- break;
- case 6: // begin of loop
- assert(len == 2);
- loops = stream.readUint16LE();
- break;
- case 7: // end of loop
- assert(len == 0);
- break;
- case 8: { // "Extended"
- // This occures in the LoL Intro demo.
- // This block overwrites the next parameters of a block 1 "Sound data".
- // To assure we never get any bad data here, we will assert in case
- // this tries to define a stereo sound block or tries to use something
- // different than 8bit unsigned sound data.
- // TODO: Actually we would need to check the frequency divisor (the
- // first word) here too. It is used in the following equation:
- // sampleRate = 256000000/(channels * (65536 - frequencyDivisor))
- assert(len == 4);
- stream.readUint16LE();
- uint8 codec = stream.readByte();
- uint8 channels = stream.readByte() + 1;
- assert(codec == 0 && channels == 1);
- } break;
- default:
- warning("Unhandled code %d in VOC file (len %d)", code, len);
- return ret_sound;
- }
- }
- debug(4, "VOC Data Size : %d", size);
- return ret_sound;
-}
-
-byte *loadVOCFromStream(Common::ReadStream &stream, int &size, int &rate) {
- int loops, begin_loop, end_loop;
- return loadVOCFromStream(stream, size, rate, loops, begin_loop, end_loop);
-}
-
-
-#ifdef STREAM_AUDIO_FROM_DISK
-
-int parseVOCFormat(Common::SeekableReadStream& stream, RawStreamBlock* block, int &rate, int &loops, int &begin_loop, int &end_loop) {
- VocFileHeader fileHeader;
- int currentBlock = 0;
- int size = 0;
-
- debug(2, "parseVOCFormat");
-
- if (stream.read(&fileHeader, 8) != 8)
- goto invalid;
-
- if (!memcmp(&fileHeader, "VTLK", 4)) {
- if (stream.read(&fileHeader, sizeof(VocFileHeader)) != sizeof(VocFileHeader))
- goto invalid;
- } else if (!memcmp(&fileHeader, "Creative", 8)) {
- if (stream.read(((byte *)&fileHeader) + 8, sizeof(VocFileHeader) - 8) != sizeof(VocFileHeader) - 8)
- goto invalid;
- } else {
- invalid:;
- warning("loadVOCFromStream: Invalid header");
- return 0;
- }
-
- if (memcmp(fileHeader.desc, "Creative Voice File", 19) != 0)
- error("loadVOCFromStream: Invalid header");
- if (fileHeader.desc[19] != 0x1A)
- debug(3, "loadVOCFromStream: Partially invalid header");
-
- int32 offset = FROM_LE_16(fileHeader.datablock_offset);
- int16 version = FROM_LE_16(fileHeader.version);
- int16 code = FROM_LE_16(fileHeader.id);
- assert(offset == sizeof(VocFileHeader));
- // 0x100 is an invalid VOC version used by German version of DOTT (Disk) and
- // French version of Simon the Sorcerer 2 (CD)
- assert(version == 0x010A || version == 0x0114 || version == 0x0100);
- assert(code == ~version + 0x1234);
-
- int len;
- size = 0;
- begin_loop = 0;
- end_loop = 0;
-
- while ((code = stream.readByte())) {
- len = stream.readByte();
- len |= stream.readByte() << 8;
- len |= stream.readByte() << 16;
-
- debug(2, "Block code %d, len %d", code, len);
-
- switch (code) {
- case 1:
- case 9: {
- int packing;
- if (code == 1) {
- int time_constant = stream.readByte();
- packing = stream.readByte();
- len -= 2;
- rate = getSampleRateFromVOCRate(time_constant);
- } else {
- rate = stream.readUint32LE();
- int bits = stream.readByte();
- int channels = stream.readByte();
- if (bits != 8 || channels != 1) {
- warning("Unsupported VOC file format (%d bits per sample, %d channels)", bits, channels);
- break;
- }
- packing = stream.readUint16LE();
- stream.readUint32LE();
- len -= 12;
- }
- debug(9, "VOC Data Block: %d, %d, %d", rate, packing, len);
- if (packing == 0) {
-
- // Found a data block - so add it to the block list
- block[currentBlock].pos = stream.pos();
- block[currentBlock].len = len;
- currentBlock++;
-
- stream.seek(len, SEEK_CUR);
-
- size += len;
- begin_loop = size;
- end_loop = size;
- } else {
- warning("VOC file packing %d unsupported", packing);
- }
- } break;
- case 3: // silence
- // occur with a few Igor sounds, voc file starts with a silence block with a
- // frequency different from the data block. Just ignore fow now (implementing
- // it wouldn't make a big difference anyway...)
- assert(len == 3);
- stream.readUint16LE();
- stream.readByte();
- break;
- case 6: // begin of loop
- assert(len == 2);
- loops = stream.readUint16LE();
- break;
- case 7: // end of loop
- assert(len == 0);
- break;
- case 8: // "Extended"
- // This occures in the LoL Intro demo. This block can usually be used to create stereo
- // sound, but the LoL intro has only an empty block, thus this dummy implementation will
- // work.
- assert(len == 4);
- stream.readUint16LE();
- stream.readByte();
- stream.readByte();
- break;
- default:
- warning("Unhandled code %d in VOC file (len %d)", code, len);
- return 0;
- }
- }
- debug(4, "VOC Data Size : %d", size);
- return currentBlock;
-}
-
-AudioStream *makeVOCDiskStream(Common::SeekableReadStream *stream, byte flags, DisposeAfterUse::Flag disposeAfterUse) {
- const int MAX_AUDIO_BLOCKS = 256;
-
- RawStreamBlock *block = new RawStreamBlock[MAX_AUDIO_BLOCKS];
- int rate, loops, begin_loop, end_loop;
-
- int numBlocks = parseVOCFormat(*stream, block, rate, loops, begin_loop, end_loop);
-
- AudioStream *audioStream = 0;
-
- // Create an audiostream from the data. Note the numBlocks may be 0,
- // e.g. when invalid data is encountered. See bug #2890038.
- if (numBlocks)
- audioStream = makeRawDiskStream_OLD(stream, block, numBlocks, rate, flags, disposeAfterUse/*, begin_loop, end_loop*/);
-
- delete[] block;
-
- return audioStream;
-}
-
-SeekableAudioStream *makeVOCDiskStreamNoLoop(Common::SeekableReadStream *stream, byte flags, DisposeAfterUse::Flag disposeAfterUse) {
- const int MAX_AUDIO_BLOCKS = 256;
-
- RawStreamBlock *block = new RawStreamBlock[MAX_AUDIO_BLOCKS];
- int rate, loops, begin_loop, end_loop;
-
- int numBlocks = parseVOCFormat(*stream, block, rate, loops, begin_loop, end_loop);
-
- SeekableAudioStream *audioStream = 0;
-
- // Create an audiostream from the data. Note the numBlocks may be 0,
- // e.g. when invalid data is encountered. See bug #2890038.
- if (numBlocks)
- audioStream = makeRawDiskStream_OLD(stream, block, numBlocks, rate, flags, disposeAfterUse);
-
- delete[] block;
-
- return audioStream;
-}
-
-#endif
-
-
-AudioStream *makeVOCStream(Common::SeekableReadStream *stream, byte flags, uint loopStart, uint loopEnd, DisposeAfterUse::Flag disposeAfterUse) {
-#ifdef STREAM_AUDIO_FROM_DISK
- return makeVOCDiskStream(stream, flags, disposeAfterUse);
-#else
- int size, rate;
-
- byte *data = loadVOCFromStream(*stream, size, rate);
-
- if (!data) {
- if (disposeAfterUse == DisposeAfterUse::YES)
- delete stream;
- return 0;
- }
-
- SeekableAudioStream *s = Audio::makeRawStream(data, size, rate, flags);
-
- if (loopStart != loopEnd) {
- const bool isStereo = (flags & Audio::FLAG_STEREO) != 0;
- const bool is16Bit = (flags & Audio::FLAG_16BITS) != 0;
-
- if (loopEnd == 0)
- loopEnd = size;
- assert(loopStart <= loopEnd);
- assert(loopEnd <= (uint)size);
-
- // Verify the buffer sizes are sane
- if (is16Bit && isStereo)
- assert((loopStart & 3) == 0 && (loopEnd & 3) == 0);
- else if (is16Bit || isStereo)
- assert((loopStart & 1) == 0 && (loopEnd & 1) == 0);
-
- const uint32 extRate = s->getRate() * (is16Bit ? 2 : 1) * (isStereo ? 2 : 1);
-
- return new SubLoopingAudioStream(s, 0, Timestamp(0, loopStart, extRate), Timestamp(0, loopEnd, extRate));
- } else {
- return s;
- }
-#endif
-}
-
-SeekableAudioStream *makeVOCStream(Common::SeekableReadStream *stream, byte flags, DisposeAfterUse::Flag disposeAfterUse) {
-#ifdef STREAM_AUDIO_FROM_DISK
- return makeVOCDiskStreamNoLoop(stream, flags, disposeAfterUse);
-#else
- int size, rate;
-
- byte *data = loadVOCFromStream(*stream, size, rate);
-
- if (!data) {
- if (disposeAfterUse == DisposeAfterUse::YES)
- delete stream;
- return 0;
- }
-
- return makeRawStream(data, size, rate, flags);
-#endif
-}
-
-} // End of namespace Audio
diff --git a/sound/decoders/voc.h b/sound/decoders/voc.h
deleted file mode 100644
index 82cc261f2c..0000000000
--- a/sound/decoders/voc.h
+++ /dev/null
@@ -1,107 +0,0 @@
-/* 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$
- *
- */
-
-/**
- * @file
- * Sound decoder used in engines:
- * - agos
- * - drascula
- * - kyra
- * - made
- * - saga
- * - scumm
- * - touche
- */
-
-#ifndef SOUND_VOC_H
-#define SOUND_VOC_H
-
-#include "common/scummsys.h"
-#include "common/types.h"
-
-namespace Common { class ReadStream; }
-namespace Common { class SeekableReadStream; }
-
-namespace Audio {
-
-class AudioStream;
-class SeekableAudioStream;
-
-
-#include "common/pack-start.h" // START STRUCT PACKING
-
-struct VocFileHeader {
- uint8 desc[20];
- uint16 datablock_offset;
- uint16 version;
- uint16 id;
-} PACKED_STRUCT;
-
-struct VocBlockHeader {
- uint8 blocktype;
- uint8 size[3];
- uint8 sr;
- uint8 pack;
-} PACKED_STRUCT;
-
-#include "common/pack-end.h" // END STRUCT PACKING
-
-/**
- * Take a sample rate parameter as it occurs in a VOC sound header, and
- * return the corresponding sample frequency.
- *
- * This method has special cases for the standard rates of 11025 and 22050 kHz,
- * which due to limitations of the format, cannot be encoded exactly in a VOC
- * file. As a consequence, many game files have sound data sampled with those
- * rates, but the VOC marks them incorrectly as 11111 or 22222 kHz. This code
- * works around that and "unrounds" the sampling rates.
- */
-extern int getSampleRateFromVOCRate(int vocSR);
-
-/**
- * Try to load a VOC from the given stream. Returns a pointer to memory
- * containing the PCM sample data (allocated with malloc). It is the callers
- * responsibility to dellocate that data again later on! Currently this
- * function only supports uncompressed raw PCM data.
- */
-extern byte *loadVOCFromStream(Common::ReadStream &stream, int &size, int &rate);
-
-/**
- * Try to load a VOC from the given seekable stream and create an AudioStream
- * from that data. Currently this function only supports uncompressed raw PCM
- * data. Optionally supports (infinite) looping of a portion of the data.
- *
- * This function uses loadVOCFromStream() internally.
- */
-AudioStream *makeVOCStream(Common::SeekableReadStream *stream, byte flags = 0, uint loopStart = 0, uint loopEnd = 0, DisposeAfterUse::Flag disposeAfterUse = DisposeAfterUse::NO);
-
-/**
- * This does not use any of the looping features of VOC files!
- */
-SeekableAudioStream *makeVOCStream(Common::SeekableReadStream *stream, byte flags, DisposeAfterUse::Flag disposeAfterUse);
-
-} // End of namespace Audio
-
-#endif
diff --git a/sound/decoders/vorbis.cpp b/sound/decoders/vorbis.cpp
deleted file mode 100644
index 425eb6b751..0000000000
--- a/sound/decoders/vorbis.cpp
+++ /dev/null
@@ -1,262 +0,0 @@
-/* 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$
- *
- */
-
-// Disable symbol overrides for FILE and fseek as those are used in the
-// Vorbis headers.
-#define FORBIDDEN_SYMBOL_EXCEPTION_FILE
-#define FORBIDDEN_SYMBOL_EXCEPTION_fseek
-
-#include "sound/decoders/vorbis.h"
-
-#ifdef USE_VORBIS
-
-#include "common/debug.h"
-#include "common/stream.h"
-#include "common/util.h"
-
-#include "sound/audiostream.h"
-
-#ifdef USE_TREMOR
-#if defined(__GP32__) // custom libtremor locations
-#include <ivorbisfile.h>
-#else
-#include <tremor/ivorbisfile.h>
-#endif
-#else
-#include <vorbis/vorbisfile.h>
-#endif
-
-
-namespace Audio {
-
-// These are wrapper functions to allow using a SeekableReadStream object to
-// provide data to the OggVorbis_File object.
-
-static size_t read_stream_wrap(void *ptr, size_t size, size_t nmemb, void *datasource) {
- Common::SeekableReadStream *stream = (Common::SeekableReadStream *)datasource;
-
- uint32 result = stream->read(ptr, size * nmemb);
-
- return result / size;
-}
-
-static int seek_stream_wrap(void *datasource, ogg_int64_t offset, int whence) {
- Common::SeekableReadStream *stream = (Common::SeekableReadStream *)datasource;
- stream->seek((int32)offset, whence);
- return stream->pos();
-}
-
-static int close_stream_wrap(void *datasource) {
- // Do nothing -- we leave it up to the VorbisStream to free memory as appropriate.
- return 0;
-}
-
-static long tell_stream_wrap(void *datasource) {
- Common::SeekableReadStream *stream = (Common::SeekableReadStream *)datasource;
- return stream->pos();
-}
-
-static ov_callbacks g_stream_wrap = {
- read_stream_wrap, seek_stream_wrap, close_stream_wrap, tell_stream_wrap
-};
-
-
-
-#pragma mark -
-#pragma mark --- Ogg Vorbis stream ---
-#pragma mark -
-
-
-class VorbisStream : public SeekableAudioStream {
-protected:
- Common::SeekableReadStream *_inStream;
- DisposeAfterUse::Flag _disposeAfterUse;
-
- bool _isStereo;
- int _rate;
-
- Timestamp _length;
-
- OggVorbis_File _ovFile;
-
- int16 _buffer[4096];
- const int16 *_bufferEnd;
- const int16 *_pos;
-
-public:
- // startTime / duration are in milliseconds
- VorbisStream(Common::SeekableReadStream *inStream, DisposeAfterUse::Flag dispose);
- ~VorbisStream();
-
- int readBuffer(int16 *buffer, const int numSamples);
-
- bool endOfData() const { return _pos >= _bufferEnd; }
- bool isStereo() const { return _isStereo; }
- int getRate() const { return _rate; }
-
- bool seek(const Timestamp &where);
- Timestamp getLength() const { return _length; }
-protected:
- bool refill();
-};
-
-VorbisStream::VorbisStream(Common::SeekableReadStream *inStream, DisposeAfterUse::Flag dispose) :
- _inStream(inStream),
- _disposeAfterUse(dispose),
- _length(0, 1000),
- _bufferEnd(_buffer + ARRAYSIZE(_buffer)) {
-
- int res = ov_open_callbacks(inStream, &_ovFile, NULL, 0, g_stream_wrap);
- if (res < 0) {
- warning("Could not create Vorbis stream (%d)", res);
- _pos = _bufferEnd;
- return;
- }
-
- // Read in initial data
- if (!refill())
- return;
-
- // Setup some header information
- _isStereo = ov_info(&_ovFile, -1)->channels >= 2;
- _rate = ov_info(&_ovFile, -1)->rate;
-
-#ifdef USE_TREMOR
- _length = Timestamp(ov_time_total(&_ovFile, -1), getRate());
-#else
- _length = Timestamp(uint32(ov_time_total(&_ovFile, -1) * 1000.0), getRate());
-#endif
-}
-
-VorbisStream::~VorbisStream() {
- ov_clear(&_ovFile);
- if (_disposeAfterUse == DisposeAfterUse::YES)
- delete _inStream;
-}
-
-int VorbisStream::readBuffer(int16 *buffer, const int numSamples) {
- int samples = 0;
- while (samples < numSamples && _pos < _bufferEnd) {
- const int len = MIN(numSamples - samples, (int)(_bufferEnd - _pos));
- memcpy(buffer, _pos, len * 2);
- buffer += len;
- _pos += len;
- samples += len;
- if (_pos >= _bufferEnd) {
- if (!refill())
- break;
- }
- }
- return samples;
-}
-
-bool VorbisStream::seek(const Timestamp &where) {
- // Vorbisfile uses the sample pair number, thus we always use "false" for the isStereo parameter
- // of the convertTimeToStreamPos helper.
- int res = ov_pcm_seek(&_ovFile, convertTimeToStreamPos(where, getRate(), false).totalNumberOfFrames());
- if (res) {
- warning("Error seeking in Vorbis stream (%d)", res);
- _pos = _bufferEnd;
- return false;
- }
-
- return refill();
-}
-
-bool VorbisStream::refill() {
- // Read the samples
- uint len_left = sizeof(_buffer);
- char *read_pos = (char *)_buffer;
-
- while (len_left > 0) {
- long result;
-
-#ifdef USE_TREMOR
- // Tremor ov_read() always returns data as signed 16 bit interleaved PCM
- // in host byte order. As such, it does not take arguments to request
- // specific signedness, byte order or bit depth as in Vorbisfile.
- result = ov_read(&_ovFile, read_pos, len_left,
- NULL);
-#else
-#ifdef SCUMM_BIG_ENDIAN
- result = ov_read(&_ovFile, read_pos, len_left,
- 1,
- 2, // 16 bit
- 1, // signed
- NULL);
-#else
- result = ov_read(&_ovFile, read_pos, len_left,
- 0,
- 2, // 16 bit
- 1, // signed
- NULL);
-#endif
-#endif
- if (result == OV_HOLE) {
- // Possibly recoverable, just warn about it
- warning("Corrupted data in Vorbis file");
- } else if (result == 0) {
- //warning("End of file while reading from Vorbis file");
- //_pos = _bufferEnd;
- //return false;
- break;
- } else if (result < 0) {
- warning("Error reading from Vorbis stream (%d)", int(result));
- _pos = _bufferEnd;
- // Don't delete it yet, that causes problems in
- // the CD player emulation code.
- return false;
- } else {
- len_left -= result;
- read_pos += result;
- }
- }
-
- _pos = _buffer;
- _bufferEnd = (int16 *)read_pos;
-
- return true;
-}
-
-
-#pragma mark -
-#pragma mark --- Ogg Vorbis factory functions ---
-#pragma mark -
-
-SeekableAudioStream *makeVorbisStream(
- Common::SeekableReadStream *stream,
- DisposeAfterUse::Flag disposeAfterUse) {
- SeekableAudioStream *s = new VorbisStream(stream, disposeAfterUse);
- if (s && s->endOfData()) {
- delete s;
- return 0;
- } else {
- return s;
- }
-}
-
-} // End of namespace Audio
-
-#endif // #ifdef USE_VORBIS
diff --git a/sound/decoders/vorbis.h b/sound/decoders/vorbis.h
deleted file mode 100644
index 7cc395cccb..0000000000
--- a/sound/decoders/vorbis.h
+++ /dev/null
@@ -1,75 +0,0 @@
-/* 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$
- *
- */
-
-/**
- * @file
- * Sound decoder used in engines:
- * - agos
- * - draci
- * - kyra
- * - m4
- * - queen
- * - saga
- * - sci
- * - scumm
- * - sword1
- * - sword2
- * - touche
- * - tucker
- */
-
-#ifndef SOUND_VORBIS_H
-#define SOUND_VORBIS_H
-
-#include "common/scummsys.h"
-#include "common/types.h"
-
-#ifdef USE_VORBIS
-
-namespace Common {
- class SeekableReadStream;
-}
-
-namespace Audio {
-
-class AudioStream;
-class SeekableAudioStream;
-
-/**
- * Create a new SeekableAudioStream from the Ogg Vorbis data in the given stream.
- * Allows for seeking (which is why we require a SeekableReadStream).
- *
- * @param stream the SeekableReadStream from which to read the Ogg Vorbis data
- * @param disposeAfterUse whether to delete the stream after use
- * @return a new SeekableAudioStream, or NULL, if an error occurred
- */
-SeekableAudioStream *makeVorbisStream(
- Common::SeekableReadStream *stream,
- DisposeAfterUse::Flag disposeAfterUse);
-
-} // End of namespace Audio
-
-#endif // #ifdef USE_VORBIS
-#endif // #ifndef SOUND_VORBIS_H
diff --git a/sound/decoders/wave.cpp b/sound/decoders/wave.cpp
deleted file mode 100644
index fcaace5301..0000000000
--- a/sound/decoders/wave.cpp
+++ /dev/null
@@ -1,194 +0,0 @@
-/* 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 "common/debug.h"
-#include "common/util.h"
-#include "common/stream.h"
-
-#include "sound/audiostream.h"
-#include "sound/mixer.h"
-#include "sound/decoders/wave.h"
-#include "sound/decoders/adpcm.h"
-#include "sound/decoders/raw.h"
-
-namespace Audio {
-
-bool loadWAVFromStream(Common::SeekableReadStream &stream, int &size, int &rate, byte &flags, uint16 *wavType, int *blockAlign_) {
- const int32 initialPos = stream.pos();
- byte buf[4+1];
-
- buf[4] = 0;
-
- stream.read(buf, 4);
- if (memcmp(buf, "RIFF", 4) != 0) {
- warning("getWavInfo: No 'RIFF' header");
- return false;
- }
-
- int32 wavLength = stream.readUint32LE();
-
- stream.read(buf, 4);
- if (memcmp(buf, "WAVE", 4) != 0) {
- warning("getWavInfo: No 'WAVE' header");
- return false;
- }
-
- stream.read(buf, 4);
- if (memcmp(buf, "fmt ", 4) != 0) {
- warning("getWavInfo: No 'fmt' header");
- return false;
- }
-
- uint32 fmtLength = stream.readUint32LE();
- if (fmtLength < 16) {
- // A valid fmt chunk always contains at least 16 bytes
- warning("getWavInfo: 'fmt' header is too short");
- return false;
- }
-
- // Next comes the "type" field of the fmt header. Some typical
- // values for it:
- // 1 -> uncompressed PCM
- // 17 -> IMA ADPCM compressed WAVE
- // See <http://www.saettler.com/RIFFNEW/RIFFNEW.htm> for a more complete
- // list of common WAVE compression formats...
- uint16 type = stream.readUint16LE(); // == 1 for PCM data
- uint16 numChannels = stream.readUint16LE(); // 1 for mono, 2 for stereo
- uint32 samplesPerSec = stream.readUint32LE(); // in Hz
- uint32 avgBytesPerSec = stream.readUint32LE(); // == SampleRate * NumChannels * BitsPerSample/8
-
- uint16 blockAlign = stream.readUint16LE(); // == NumChannels * BitsPerSample/8
- uint16 bitsPerSample = stream.readUint16LE(); // 8, 16 ...
- // 8 bit data is unsigned, 16 bit data signed
-
-
- if (wavType != 0)
- *wavType = type;
-
- if (blockAlign_ != 0)
- *blockAlign_ = blockAlign;
-#if 0
- debug("WAVE information:");
- debug(" total size: %d", wavLength);
- debug(" fmt size: %d", fmtLength);
- debug(" type: %d", type);
- debug(" numChannels: %d", numChannels);
- debug(" samplesPerSec: %d", samplesPerSec);
- debug(" avgBytesPerSec: %d", avgBytesPerSec);
- debug(" blockAlign: %d", blockAlign);
- debug(" bitsPerSample: %d", bitsPerSample);
-#endif
-
- if (type != 1 && type != 2 && type != 17) {
- warning("getWavInfo: only PCM, MS ADPCM or IMA ADPCM data is supported (type %d)", type);
- return false;
- }
-
- if (blockAlign != numChannels * bitsPerSample / 8 && type != 2) {
- debug(0, "getWavInfo: blockAlign is invalid");
- }
-
- if (avgBytesPerSec != samplesPerSec * blockAlign && type != 2) {
- debug(0, "getWavInfo: avgBytesPerSec is invalid");
- }
-
- // Prepare the return values.
- rate = samplesPerSec;
-
- flags = 0;
- if (bitsPerSample == 8) // 8 bit data is unsigned
- flags |= Audio::FLAG_UNSIGNED;
- else if (bitsPerSample == 16) // 16 bit data is signed little endian
- flags |= (Audio::FLAG_16BITS | Audio::FLAG_LITTLE_ENDIAN);
- else if (bitsPerSample == 4 && (type == 2 || type == 17))
- flags |= Audio::FLAG_16BITS;
- else {
- warning("getWavInfo: unsupported bitsPerSample %d", bitsPerSample);
- return false;
- }
-
- if (numChannels == 2)
- flags |= Audio::FLAG_STEREO;
- else if (numChannels != 1) {
- warning("getWavInfo: unsupported number of channels %d", numChannels);
- return false;
- }
-
- // It's almost certainly a WAV file, but we still need to find its
- // 'data' chunk.
-
- // Skip over the rest of the fmt chunk.
- int offset = fmtLength - 16;
-
- do {
- stream.seek(offset, SEEK_CUR);
- if (stream.pos() >= initialPos + wavLength + 8) {
- warning("getWavInfo: Can't find 'data' chunk");
- return false;
- }
- stream.read(buf, 4);
- offset = stream.readUint32LE();
-
-#if 0
- debug(" found a '%s' tag of size %d", buf, offset);
-#endif
- } while (memcmp(buf, "data", 4) != 0);
-
- // Stream now points at 'offset' bytes of sample data...
- size = offset;
-
- return true;
-}
-
-RewindableAudioStream *makeWAVStream(Common::SeekableReadStream *stream, DisposeAfterUse::Flag disposeAfterUse) {
- int size, rate;
- byte flags;
- uint16 type;
- int blockAlign;
-
- if (!loadWAVFromStream(*stream, size, rate, flags, &type, &blockAlign)) {
- if (disposeAfterUse == DisposeAfterUse::YES)
- delete stream;
- return 0;
- }
-
- if (type == 17) // MS IMA ADPCM
- return makeADPCMStream(stream, disposeAfterUse, size, Audio::kADPCMMSIma, rate, (flags & Audio::FLAG_STEREO) ? 2 : 1, blockAlign);
- else if (type == 2) // MS ADPCM
- return makeADPCMStream(stream, disposeAfterUse, size, Audio::kADPCMMS, rate, (flags & Audio::FLAG_STEREO) ? 2 : 1, blockAlign);
-
- // Raw PCM. Just read everything at once.
- // TODO: More elegant would be to wrap the stream.
- byte *data = (byte *)malloc(size);
- assert(data);
- stream->read(data, size);
-
- if (disposeAfterUse == DisposeAfterUse::YES)
- delete stream;
-
- return makeRawStream(data, size, rate, flags);
-}
-
-} // End of namespace Audio
diff --git a/sound/decoders/wave.h b/sound/decoders/wave.h
deleted file mode 100644
index 2bdbe8f0b6..0000000000
--- a/sound/decoders/wave.h
+++ /dev/null
@@ -1,84 +0,0 @@
-/* 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$
- *
- */
-
-/**
- * @file
- * Sound decoder used in engines:
- * - agos
- * - gob
- * - mohawk
- * - saga
- * - sci
- * - scumm
- * - sword1
- * - sword2
- * - tucker
- */
-
-#ifndef SOUND_WAVE_H
-#define SOUND_WAVE_H
-
-#include "common/scummsys.h"
-#include "common/types.h"
-
-namespace Common { class SeekableReadStream; }
-
-namespace Audio {
-
-class RewindableAudioStream;
-
-/**
- * Try to load a WAVE from the given seekable stream. Returns true if
- * successful. In that case, the stream's seek position will be set to the
- * start of the audio data, and size, rate and flags contain information
- * necessary for playback. Currently this function supports uncompressed
- * raw PCM data, MS IMA ADPCM and MS ADPCM (uses makeADPCMStream internally).
- */
-extern bool loadWAVFromStream(
- Common::SeekableReadStream &stream,
- int &size,
- int &rate,
- byte &flags,
- uint16 *wavType = 0,
- int *blockAlign = 0);
-
-/**
- * Try to load a WAVE from the given seekable stream and create an AudioStream
- * from that data. Currently this function supports uncompressed
- * raw PCM data, MS IMA ADPCM and MS ADPCM (uses makeADPCMStream internally).
- *
- * This function uses loadWAVFromStream() internally.
- *
- * @param stream the SeekableReadStream from which to read the WAVE data
- * @param disposeAfterUse whether to delete the stream after use
- * @return a new RewindableAudioStream, or NULL, if an error occurred
- */
-RewindableAudioStream *makeWAVStream(
- Common::SeekableReadStream *stream,
- DisposeAfterUse::Flag disposeAfterUse);
-
-} // End of namespace Audio
-
-#endif
diff --git a/sound/fmopl.cpp b/sound/fmopl.cpp
deleted file mode 100644
index ee54a79a46..0000000000
--- a/sound/fmopl.cpp
+++ /dev/null
@@ -1,197 +0,0 @@
-/* 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/fmopl.h"
-
-#include "sound/softsynth/opl/dosbox.h"
-#include "sound/softsynth/opl/mame.h"
-
-#include "common/config-manager.h"
-#include "common/translation.h"
-
-namespace OPL {
-
-// Config implementation
-
-enum OplEmulator {
- kAuto = 0,
- kMame = 1,
- kDOSBox = 2
-};
-
-OPL::OPL() {
- if (_hasInstance)
- error("There are multiple OPL output instances running");
- _hasInstance = true;
-}
-
-const Config::EmulatorDescription Config::_drivers[] = {
- { "auto", "<default>", kAuto, kFlagOpl2 | kFlagDualOpl2 | kFlagOpl3 },
- { "mame", _s("MAME OPL emulator"), kMame, kFlagOpl2 },
-#ifndef DISABLE_DOSBOX_OPL
- { "db", _s("DOSBox OPL emulator"), kDOSBox, kFlagOpl2 | kFlagDualOpl2 | kFlagOpl3 },
-#endif
- { 0, 0, 0, 0 }
-};
-
-Config::DriverId Config::parse(const Common::String &name) {
- for (int i = 0; _drivers[i].name; ++i) {
- if (name.equalsIgnoreCase(_drivers[i].name))
- return _drivers[i].id;
- }
-
- return -1;
-}
-
-Config::DriverId Config::detect(OplType type) {
- uint32 flags = 0;
- switch (type) {
- case kOpl2:
- flags = kFlagOpl2;
- break;
-
- case kDualOpl2:
- flags = kFlagDualOpl2;
- break;
-
- case kOpl3:
- flags = kFlagOpl3;
- break;
- }
-
- DriverId drv = parse(ConfMan.get("opl_driver"));
-
- // When a valid driver is selected, check whether it supports
- // the requested OPL chip.
- if (drv != -1 && drv != kAuto) {
- // If the chip is supported, just use the driver.
- if ((flags & _drivers[drv].flags)) {
- return drv;
- } 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);
- return -1;
- }
- }
-
- // Detect the first matching emulator
- drv = -1;
-
- for (int i = 1; _drivers[i].name; ++i) {
- if (_drivers[i].flags & flags) {
- drv = _drivers[i].id;
- break;
- }
- }
-
- return drv;
-}
-
-OPL *Config::create(OplType type) {
- return create(kAuto, type);
-}
-
-OPL *Config::create(DriverId driver, OplType type) {
- // On invalid driver selection, we try to do some fallback detection
- if (driver == -1) {
- warning("Invalid OPL driver selected, trying to detect a fallback emulator");
- driver = kAuto;
- }
-
- // If autodetection is selected, we search for a matching
- // driver.
- if (driver == kAuto) {
- driver = detect(type);
-
- // No emulator for the specified OPL chip could
- // be found, thus stop here.
- if (driver == -1) {
- warning("No OPL emulator available for type %d", type);
- return 0;
- }
- }
-
- switch (driver) {
- case kMame:
- if (type == kOpl2)
- return new MAME::OPL();
- else
- warning("MAME OPL emulator only supports OPL2 emulation");
- return 0;
-
-#ifndef DISABLE_DOSBOX_OPL
- case kDOSBox:
- return new DOSBox::OPL(type);
-#endif
-
- default:
- warning("Unsupported OPL emulator %d", driver);
- // TODO: Maybe we should add some dummy emulator too, which just outputs
- // silence as sound?
- return 0;
- }
-}
-
-bool OPL::_hasInstance = false;
-
-} // End of namespace OPL
-
-void OPLDestroy(FM_OPL *OPL) {
- delete OPL;
-}
-
-void OPLResetChip(FM_OPL *OPL) {
- OPL->reset();
-}
-
-void OPLWrite(FM_OPL *OPL, int a, int v) {
- OPL->write(a, v);
-}
-
-unsigned char OPLRead(FM_OPL *OPL, int a) {
- return OPL->read(a);
-}
-
-void OPLWriteReg(FM_OPL *OPL, int r, int v) {
- OPL->writeReg(r, v);
-}
-
-void YM3812UpdateOne(FM_OPL *OPL, int16 *buffer, int length) {
- OPL->readBuffer(buffer, length);
-}
-
-FM_OPL *makeAdLibOPL(int rate) {
- FM_OPL *opl = OPL::Config::create();
-
- if (opl) {
- if (!opl->init(rate)) {
- delete opl;
- opl = 0;
- }
- }
-
- return opl;
-}
-
diff --git a/sound/fmopl.h b/sound/fmopl.h
deleted file mode 100644
index 33235f3545..0000000000
--- a/sound/fmopl.h
+++ /dev/null
@@ -1,179 +0,0 @@
-/* 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_FMOPL_H
-#define SOUND_FMOPL_H
-
-#include "common/scummsys.h"
-#include "common/str.h"
-
-namespace OPL {
-
-class OPL;
-
-class Config {
-public:
- enum OplFlags {
- kFlagOpl2 = (1 << 0),
- kFlagDualOpl2 = (1 << 1),
- kFlagOpl3 = (1 << 2)
- };
-
- /**
- * OPL type to emulate.
- */
- enum OplType {
- kOpl2,
- kDualOpl2,
- kOpl3
- };
-
- typedef int8 DriverId;
- struct EmulatorDescription {
- const char *name;
- const char *description;
-
- DriverId id; // A unique ID for each driver
- uint32 flags; // Capabilities of this driver
- };
-
- /**
- * Get a list of all available OPL emulators.
- * @return list of all available OPL emulators, terminated by a zero entry
- */
- static const EmulatorDescription *getAvailable() { return _drivers; }
-
- /**
- * Returns the driver id of a given name.
- */
- static DriverId parse(const Common::String &name);
-
- /**
- * Detects a driver for the specific type.
- *
- * @return Returns a valid driver id on success, -1 otherwise.
- */
- static DriverId detect(OplType type);
-
- /**
- * Creates the specific driver with a specific type setup.
- */
- static OPL *create(DriverId driver, OplType type);
-
- /**
- * Wrapper to easily init an OPL chip, without specifing an emulator.
- * By default it will try to initialize an OPL2 emulator, thus an AdLib card.
- */
- static OPL *create(OplType type = kOpl2);
-
-private:
- static const EmulatorDescription _drivers[];
-};
-
-class OPL {
-private:
- static bool _hasInstance;
-public:
- OPL();
- virtual ~OPL() { _hasInstance = false; }
-
- /**
- * Initializes the OPL emulator.
- *
- * @param rate output sample rate
- * @return true on success, false on failure
- */
- virtual bool init(int rate) = 0;
-
- /**
- * Reinitializes the OPL emulator
- */
- virtual void reset() = 0;
-
- /**
- * Writes a byte to the given I/O port.
- *
- * @param a port address
- * @param v value, which will be written
- */
- virtual void write(int a, int v) = 0;
-
- /**
- * Reads a byte from the given I/O port.
- *
- * @param a port address
- * @return value read
- */
- virtual byte read(int a) = 0;
-
- /**
- * Function to directly write to a specific OPL register.
- * This writes to *both* chips for a Dual OPL2.
- *
- * @param r hardware register number to write to
- * @param v value, which will be written
- */
- virtual void writeReg(int r, int v) = 0;
-
- /**
- * Read up to 'length' samples.
- *
- * Data will be in native endianess, 16 bit per sample, signed.
- * For stereo OPL, buffer will be filled with interleaved
- * left and right channel samples, starting with a left sample.
- * Furthermore, the samples in the left and right are summed up.
- * So if you request 4 samples from a stereo OPL, you will get
- * a total of two left channel and two right channel samples.
- */
- virtual void readBuffer(int16 *buffer, int length) = 0;
-
- /**
- * Returns whether the setup OPL mode is stereo or not
- */
- virtual bool isStereo() const = 0;
-};
-
-} // End of namespace OPL
-
-// Legacy API
-// !You should not write any new code using the legacy API!
-typedef OPL::OPL FM_OPL;
-
-void OPLDestroy(FM_OPL *OPL);
-
-void OPLResetChip(FM_OPL *OPL);
-void OPLWrite(FM_OPL *OPL, int a, int v);
-unsigned char OPLRead(FM_OPL *OPL, int a);
-void OPLWriteReg(FM_OPL *OPL, int r, int v);
-void YM3812UpdateOne(FM_OPL *OPL, int16 *buffer, int length);
-
-/**
- * Legacy factory to create an AdLib (OPL2) chip.
- *
- * !You should not write any new code using the legacy API!
- */
-FM_OPL *makeAdLibOPL(int rate);
-
-#endif
-
diff --git a/sound/mididrv.cpp b/sound/mididrv.cpp
deleted file mode 100644
index 20d5a4e233..0000000000
--- a/sound/mididrv.cpp
+++ /dev/null
@@ -1,326 +0,0 @@
-/* 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 "engines/engine.h"
-#include "common/config-manager.h"
-#include "common/str.h"
-#include "common/system.h"
-#include "common/util.h"
-#include "sound/mididrv.h"
-#include "sound/musicplugin.h"
-#include "common/translation.h"
-
-const byte MidiDriver::_mt32ToGm[128] = {
-// 0 1 2 3 4 5 6 7 8 9 A B C D E F
- 0, 1, 0, 2, 4, 4, 5, 3, 16, 17, 18, 16, 16, 19, 20, 21, // 0x
- 6, 6, 6, 7, 7, 7, 8, 112, 62, 62, 63, 63, 38, 38, 39, 39, // 1x
- 88, 95, 52, 98, 97, 99, 14, 54, 102, 96, 53, 102, 81, 100, 14, 80, // 2x
- 48, 48, 49, 45, 41, 40, 42, 42, 43, 46, 45, 24, 25, 28, 27, 104, // 3x
- 32, 32, 34, 33, 36, 37, 35, 35, 79, 73, 72, 72, 74, 75, 64, 65, // 4x
- 66, 67, 71, 71, 68, 69, 70, 22, 56, 59, 57, 57, 60, 60, 58, 61, // 5x
- 61, 11, 11, 98, 14, 9, 14, 13, 12, 107, 107, 77, 78, 78, 76, 76, // 6x
- 47, 117, 127, 118, 118, 116, 115, 119, 115, 112, 55, 124, 123, 0, 14, 117 // 7x
-};
-
-const byte MidiDriver::_gmToMt32[128] = {
-// 0 1 2 3 4 5 6 7 8 9 A B C D E F
- 5, 1, 2, 7, 3, 5, 16, 21, 22, 101, 101, 97, 104, 103, 102, 20, // 0x
- 8, 9, 11, 12, 14, 15, 87, 15, 59, 60, 61, 62, 67, 44, 79, 23, // 1x
- 64, 67, 66, 70, 68, 69, 28, 31, 52, 54, 55, 56, 49, 51, 57, 112, // 2x
- 48, 50, 45, 26, 34, 35, 45, 122, 89, 90, 94, 81, 92, 95, 24, 25, // 3x
- 80, 78, 79, 78, 84, 85, 86, 82, 74, 72, 76, 77, 110, 107, 108, 76, // 4x
- 47, 44, 111, 45, 44, 34, 44, 30, 32, 33, 88, 34, 35, 35, 38, 33, // 5x
- 41, 36, 100, 37, 40, 34, 43, 40, 63, 21, 99, 105, 103, 86, 55, 84, // 6x
- 101, 103, 100, 120, 117, 113, 99, 128, 128, 128, 128, 124, 123, 128, 128, 128, // 7x
-};
-
-static const uint32 GUIOMapping[] = {
- MT_PCSPK, Common::GUIO_MIDIPCSPK,
- MT_CMS, Common::GUIO_MIDICMS,
- MT_PCJR, Common::GUIO_MIDIPCJR,
- MT_ADLIB, Common::GUIO_MIDIADLIB,
- MT_C64, Common::GUIO_MIDIC64,
- MT_AMIGA, Common::GUIO_MIDIAMIGA,
- MT_APPLEIIGS, Common::GUIO_MIDIAPPLEIIGS,
- MT_TOWNS, Common::GUIO_MIDITOWNS,
- MT_PC98, Common::GUIO_MIDIPC98,
- MT_GM, Common::GUIO_MIDIGM,
- MT_MT32, Common::GUIO_MIDIMT32,
- 0, 0
-};
-
-uint32 MidiDriver::musicType2GUIO(uint32 musicType) {
- uint32 res = 0;
-
- for (int i = 0; GUIOMapping[i] || GUIOMapping[i + 1]; i += 2) {
- if (musicType == GUIOMapping[i] || musicType == (uint32)-1)
- res |= GUIOMapping[i + 1];
- }
-
- return res;
-}
-
-bool MidiDriver::_forceTypeMT32 = false;
-
-MusicType MidiDriver::getMusicType(MidiDriver::DeviceHandle handle) {
- if (_forceTypeMT32)
- return MT_MT32;
-
- if (handle) {
- const MusicPlugin::List p = MusicMan.getPlugins();
- for (MusicPlugin::List::const_iterator m = p.begin(); m != p.end(); m++) {
- MusicDevices i = (**m)->getDevices();
- for (MusicDevices::iterator d = i.begin(); d != i.end(); d++) {
- if (handle == d->getHandle())
- return d->getMusicType();
- }
- }
- }
-
- return MT_INVALID;
-}
-
-Common::String MidiDriver::getDeviceString(DeviceHandle handle, DeviceStringType type) {
- if (handle) {
- const MusicPlugin::List p = MusicMan.getPlugins();
- for (MusicPlugin::List::const_iterator m = p.begin(); m != p.end(); m++) {
- MusicDevices i = (**m)->getDevices();
- for (MusicDevices::iterator d = i.begin(); d != i.end(); d++) {
- if (handle == d->getHandle()) {
- if (type == kDriverName)
- return d->getMusicDriverName();
- else if (type == kDriverId)
- return d->getMusicDriverId();
- else if (type == kDeviceId)
- return d->getCompleteId();
- else
- return Common::String("auto");
- }
- }
- }
- }
-
- return Common::String("auto");
-}
-
-MidiDriver::DeviceHandle MidiDriver::detectDevice(int flags) {
- // Query the selected music device (defaults to MT_AUTO device).
- DeviceHandle hdl = getDeviceHandle(ConfMan.get("music_driver"));
-
- _forceTypeMT32 = false;
-
- // Check whether the selected music driver is compatible with the
- // given flags.
- switch (getMusicType(hdl)) {
- case MT_PCSPK:
- if (flags & MDT_PCSPK)
- return hdl;
- break;
-
- case MT_PCJR:
- if (flags & MDT_PCJR)
- return hdl;
- break;
-
- case MT_CMS:
- if (flags & MDT_CMS)
- return hdl;
- break;
-
- case MT_ADLIB:
- if (flags & MDT_ADLIB)
- return hdl;
- break;
-
- case MT_C64:
- if (flags & MDT_C64)
- return hdl;
- break;
-
- case MT_AMIGA:
- if (flags & MDT_AMIGA)
- return hdl;
- break;
-
- case MT_APPLEIIGS:
- if (flags & MDT_APPLEIIGS)
- return hdl;
- break;
-
- case MT_TOWNS:
- if (flags & MDT_TOWNS)
- return hdl;
- break;
-
- case MT_PC98:
- if (flags & MDT_PC98)
- return hdl;
- break;
-
- case MT_GM:
- case MT_GS:
- case MT_MT32:
- if (flags & MDT_MIDI)
- return hdl;
- break;
-
- case MT_NULL:
- return hdl;
-
- default:
- break;
- }
-
- // If the selected driver did not match the flags setting,
- // we try to determine a suitable and "optimal" music driver.
- const MusicPlugin::List p = MusicMan.getPlugins();
- // If only MDT_MIDI but not MDT_PREFER_MT32 or MDT_PREFER_GM is set we prefer the other devices (which will always be
- // detected since they are hard coded and cannot be disabled.
- for (int l = (flags & (MDT_PREFER_GM | MDT_PREFER_MT32)) ? 1 : 0; l < 2; ++l) {
- if ((flags & MDT_MIDI) && (l == 1)) {
- // If a preferred MT32 or GM device has been selected that device gets returned
- if (flags & MDT_PREFER_MT32)
- hdl = getDeviceHandle(ConfMan.get("mt32_device"));
- else if (flags & MDT_PREFER_GM)
- hdl = getDeviceHandle(ConfMan.get("gm_device"));
- else
- hdl = getDeviceHandle("auto");
-
- const MusicType type = getMusicType(hdl);
-
- // If have a "Don't use GM/MT-32" setting we skip this part and jump
- // to AdLib, PC Speaker etc. detection right away.
- if (type != MT_NULL) {
- if (type != MT_AUTO && type != MT_INVALID) {
- if (flags & MDT_PREFER_MT32)
- // If we have a preferred MT32 device we disable the gm/mt32 mapping (more about this in mididrv.h)
- _forceTypeMT32 = true;
-
- return hdl;
- }
-
- // If we have no specific device selected (neither in the scummvm nor in the game domain)
- // and no preferred MT32 or GM device selected we arrive here.
- // If MT32 is preferred we try for the first available device with music type 'MT_MT32' (usually the mt32 emulator)
- if (flags & MDT_PREFER_MT32) {
- for (MusicPlugin::List::const_iterator m = p.begin(); m != p.end(); ++m) {
- MusicDevices i = (**m)->getDevices();
- for (MusicDevices::iterator d = i.begin(); d != i.end(); ++d) {
- if (d->getMusicType() == MT_MT32)
- return d->getHandle();
- }
- }
- }
-
- // Now we default to the first available device with music type 'MT_GM'
- for (MusicPlugin::List::const_iterator m = p.begin(); m != p.end(); ++m) {
- MusicDevices i = (**m)->getDevices();
- for (MusicDevices::iterator d = i.begin(); d != i.end(); ++d) {
- if (d->getMusicType() == MT_GM || d->getMusicType() == MT_GS)
- return d->getHandle();
- }
- }
- }
- }
-
- MusicType tp = MT_AUTO;
- if (flags & MDT_TOWNS)
- tp = MT_TOWNS;
- else if (flags & MDT_PC98)
- tp = MT_PC98;
- else if (flags & MDT_ADLIB)
- tp = MT_ADLIB;
- 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)
- tp = MT_AMIGA;
- else if (flags & MDT_APPLEIIGS)
- tp = MT_APPLEIIGS;
- else if (l == 0)
- // if we haven't tried to find a MIDI device yet we do this now.
- continue;
- else
- tp = MT_AUTO;
-
- for (MusicPlugin::List::const_iterator m = p.begin(); m != p.end(); ++m) {
- MusicDevices i = (**m)->getDevices();
- for (MusicDevices::iterator d = i.begin(); d != i.end(); ++d) {
- if (d->getMusicType() == tp)
- return d->getHandle();
- }
- }
- }
-
- return 0;
-}
-
-MidiDriver *MidiDriver::createMidi(MidiDriver::DeviceHandle handle) {
- MidiDriver *driver = 0;
- const MusicPlugin::List p = MusicMan.getPlugins();
- for (MusicPlugin::List::const_iterator m = p.begin(); m != p.end(); m++) {
- if (getDeviceString(handle, MidiDriver::kDriverId).equals((**m)->getId()))
- (**m)->createInstance(&driver, handle);
- }
-
- return driver;
-}
-
-MidiDriver::DeviceHandle MidiDriver::getDeviceHandle(const Common::String &identifier) {
- const MusicPlugin::List p = MusicMan.getPlugins();
-
- if (p.begin() == p.end())
- error("Music plugins must be loaded prior to calling this method");
-
- for (MusicPlugin::List::const_iterator m = p.begin(); m != p.end(); m++) {
- MusicDevices i = (**m)->getDevices();
- for (MusicDevices::iterator d = i.begin(); d != i.end(); d++) {
- // The music driver id isn't unique, but it will match
- // driver's first device. This is useful when selecting
- // the driver from the command line.
- if (identifier.equals(d->getMusicDriverId()) || identifier.equals(d->getCompleteId()) || identifier.equals(d->getCompleteName())) {
- return d->getHandle();
- }
- }
- }
-
- 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
deleted file mode 100644
index 9e649cba3d..0000000000
--- a/sound/mididrv.h
+++ /dev/null
@@ -1,288 +0,0 @@
-/* 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_MIDIDRV_H
-#define SOUND_MIDIDRV_H
-
-#include "common/scummsys.h"
-#include "common/timer.h"
-
-class MidiChannel;
-class MusicDevice;
-
-namespace Audio {
- class Mixer;
-}
-namespace Common { class String; }
-
-/**
- * Music Driver Types, used to uniquely identify each music driver.
- *
- * The pseudo drivers are listed first, then all native drivers,
- * then all other MIDI drivers, and finally the non-MIDI drivers.
- *
- * @todo Rename MidiDriverType to MusicDriverType
- */
-
-/**
- * Music types that music drivers can implement and engines can rely on.
- */
-enum MusicType {
- MT_INVALID = -1, // Invalid output
- MT_AUTO = 0, // Auto
- MT_NULL, // Null
- MT_PCSPK, // PC Speaker
- MT_PCJR, // PCjr
- MT_CMS, // CMS
- MT_ADLIB, // AdLib
- MT_C64, // C64
- MT_AMIGA, // Amiga
- MT_APPLEIIGS, // Apple IIGS
- MT_TOWNS, // FM-TOWNS
- MT_PC98, // PC98
- MT_GM, // General MIDI
- MT_MT32, // MT-32
- MT_GS // Roland GS
-};
-
-/**
- * A set of flags to be passed to detectDevice() which can be used to
- * specify what kind of music driver is preferred / accepted.
- *
- * The flags (except for MDT_PREFER_MT32 and MDT_PREFER_GM) indicate whether a given driver
- * type is acceptable. E.g. the TOWNS music driver could be returned by
- * detectDevice if and only if MDT_TOWNS is specified.
- *
- * @todo Rename MidiDriverFlags to MusicDriverFlags
- */
-enum MidiDriverFlags {
- MDT_NONE = 0,
- MDT_PCSPK = 1 << 0, // PC Speaker: Maps to MD_PCSPK and MD_PCJR
- MDT_CMS = 1 << 1, // Creative Music System / Gameblaster: Maps to MD_CMS
- MDT_PCJR = 1 << 2, // Tandy/PC Junior driver
- MDT_ADLIB = 1 << 3, // AdLib: Maps to MT_ADLIB
- MDT_C64 = 1 << 4,
- MDT_AMIGA = 1 << 5,
- MDT_APPLEIIGS = 1 << 6,
- MDT_TOWNS = 1 << 7, // FM-TOWNS: Maps to MT_TOWNS
- MDT_PC98 = 1 << 8, // FM-TOWNS: Maps to MT_PC98
- MDT_MIDI = 1 << 9, // Real MIDI
- MDT_PREFER_MT32 = 1 << 10, // MT-32 output is preferred
- MDT_PREFER_GM = 1 << 11 // GM output is preferred
-};
-
-/**
- * Abstract description of a MIDI driver. Used by the config file and command
- * line parsing code, and also to be able to give the user a list of available
- * drivers.
- *
- * @todo Rename MidiDriverType to MusicDriverType
- */
-
-/**
- * Abstract MIDI Driver Class
- *
- * @todo Rename MidiDriver to MusicDriver
- */
-class MidiDriver {
-public:
- /**
- * The device handle.
- *
- * The value 0 is reserved for an invalid device for now.
- * TODO: Maybe we should use -1 (i.e. 0xFFFFFFFF) as
- * invalid device?
- */
- typedef uint32 DeviceHandle;
-
- enum DeviceStringType {
- kDriverName,
- kDriverId,
- kDeviceId
- };
-
- static uint32 musicType2GUIO(uint32 musicType);
-
- /** Create music driver matching the given device handle, or NULL if there is no match. */
- static MidiDriver *createMidi(DeviceHandle handle);
-
- /** Returns device handle based on the present devices and the flags parameter. */
- static DeviceHandle detectDevice(int flags);
-
- /** Find the music driver matching the given driver name/description. */
- static DeviceHandle getDeviceHandle(const Common::String &identifier);
-
- /** Get the music type matching the given device handle, or MT_AUTO if there is no match. */
- static MusicType getMusicType(DeviceHandle handle);
-
- /** Get the device description string matching the given device handle and the given type. */
- static Common::String getDeviceString(DeviceHandle handle, DeviceStringType type);
-
-private:
- // If detectDevice() detects MT32 and we have a preferred MT32 device
- // we use this to force getMusicType() to return MT_MT32 so that we don't
- // have to rely on the 'True Roland MT-32' config manager setting (since nobody
- // would possibly think about activating 'True Roland MT-32' when he has set
- // 'Music Driver' to '<default>')
- static bool _forceTypeMT32;
-
-public:
- virtual ~MidiDriver() { }
-
- static const byte _mt32ToGm[128];
- static const byte _gmToMt32[128];
-
- /**
- * Error codes returned by open.
- * Can be converted to a string with getErrorName().
- */
- enum {
- MERR_CANNOT_CONNECT = 1,
-// MERR_STREAMING_NOT_AVAILABLE = 2,
- MERR_DEVICE_NOT_AVAILABLE = 3,
- MERR_ALREADY_OPEN = 4
- };
-
- enum {
-// PROP_TIMEDIV = 1,
- PROP_OLD_ADLIB = 2,
- PROP_CHANNEL_MASK = 3
- };
-
- /**
- * Open the midi driver.
- * @return 0 if successful, otherwise an error code.
- */
- virtual int open() = 0;
-
- /** Close the midi driver. */
- virtual void close() = 0;
-
- /**
- * Output a packed midi command to the midi stream.
- * The 'lowest' byte (i.e. b & 0xFF) is the status
- * code, then come (if used) the first and second
- * opcode.
- */
- virtual void send(uint32 b) = 0;
-
- /**
- * Output a midi command to the midi stream. Convenience wrapper
- * around the usual 'packed' send method.
- *
- * Do NOT use this for sysEx transmission; instead, use the sysEx()
- * method below.
- */
- void send(byte status, byte firstOp, byte secondOp) {
- send(status | ((uint32)firstOp << 8) | ((uint32)secondOp << 16));
- }
-
- /** Get or set a property. */
- virtual uint32 property(int prop, uint32 param) { return 0; }
-
- /** Retrieve a string representation of an error code. */
- static const char *getErrorName(int error_code);
-
- // HIGH-LEVEL SEMANTIC METHODS
- virtual void setPitchBendRange(byte channel, uint range) {
- send(0xB0 | channel, 101, 0);
- send(0xB0 | channel, 100, 0);
- send(0xB0 | channel, 6, range);
- send(0xB0 | channel, 38, 0);
- send(0xB0 | channel, 101, 127);
- send(0xB0 | channel, 100, 127);
- }
-
- /**
- * 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.
- * do NOT include the leading 0xF0 and the trailing 0xF7.
- *
- * Furthermore, the maximal supported length of a SysEx
- * is 264 bytes. Passing longer buffers can lead to
- * undefined behavior (most likely, a crash).
- */
- virtual void sysEx(const byte *msg, uint16 length) { }
-
- virtual void sysEx_customInstrument(byte channel, uint32 type, const byte *instr) { }
-
- virtual void metaEvent(byte type, byte *data, uint16 length) { }
-
- // Timing functions - MidiDriver now operates timers
- virtual void setTimerCallback(void *timer_param, Common::TimerManager::TimerProc timer_proc) = 0;
-
- /** The time in microseconds between invocations of the timer callback. */
- virtual uint32 getBaseTempo() = 0;
-
- // Channel allocation functions
- virtual MidiChannel *allocateChannel() = 0;
- virtual MidiChannel *getPercussionChannel() = 0;
-};
-
-class MidiChannel {
-public:
- virtual ~MidiChannel() {}
-
- virtual MidiDriver *device() = 0;
- virtual byte getNumber() = 0;
- virtual void release() = 0;
-
- virtual void send(uint32 b) = 0; // 4-bit channel portion is ignored
-
- // Regular messages
- virtual void noteOff(byte note) = 0;
- virtual void noteOn(byte note, byte velocity) = 0;
- virtual void programChange(byte program) = 0;
- virtual void pitchBend(int16 bend) = 0; // -0x2000 to +0x1FFF
-
- // Control Change messages
- virtual void controlChange(byte control, byte value) = 0;
- virtual void modulationWheel(byte value) { controlChange(1, value); }
- virtual void volume(byte value) { controlChange(7, value); }
- virtual void panPosition(byte value) { controlChange(10, value); }
- virtual void pitchBendFactor(byte value) = 0;
- virtual void detune(byte value) { controlChange(17, value); }
- virtual void priority(byte value) { }
- virtual void sustain(bool value) { controlChange(64, value ? 1 : 0); }
- virtual void effectLevel(byte value) { controlChange(91, value); }
- virtual void chorusLevel(byte value) { controlChange(93, value); }
- virtual void allNotesOff() { controlChange(123, 0); }
-
- // SysEx messages
- virtual void sysEx_customInstrument(uint32 type, const byte *instr) = 0;
-};
-
-#endif
diff --git a/sound/midiparser.cpp b/sound/midiparser.cpp
deleted file mode 100644
index bd51a96d46..0000000000
--- a/sound/midiparser.cpp
+++ /dev/null
@@ -1,467 +0,0 @@
-/* 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/midiparser.h"
-#include "sound/mididrv.h"
-#include "common/util.h"
-
-//////////////////////////////////////////////////
-//
-// MidiParser implementation
-//
-//////////////////////////////////////////////////
-
-MidiParser::MidiParser() :
-_hanging_notes_count(0),
-_driver(0),
-_timer_rate(0x4A0000),
-_ppqn(96),
-_tempo(500000),
-_psec_per_tick(5208), // 500000 / 96
-_autoLoop(false),
-_smartJump(false),
-_centerPitchWheelOnUnload(false),
-_sendSustainOffOnNotesOff(false),
-_num_tracks(0),
-_active_track(255),
-_abort_parse(0) {
- memset(_active_notes, 0, sizeof(_active_notes));
- _next_event.start = NULL;
- _next_event.delta = 0;
- _next_event.event = 0;
- _next_event.length = 0;
-}
-
-void MidiParser::property(int prop, int value) {
- switch (prop) {
- case mpAutoLoop:
- _autoLoop = (value != 0);
- break;
- case mpSmartJump:
- _smartJump = (value != 0);
- break;
- case mpCenterPitchWheelOnUnload:
- _centerPitchWheelOnUnload = (value != 0);
- break;
- case mpSendSustainOffOnNotesOff:
- _sendSustainOffOnNotesOff = (value != 0);
- break;
- }
-}
-
-void MidiParser::sendToDriver(uint32 b) {
- _driver->send(b);
-}
-
-void MidiParser::setTempo(uint32 tempo) {
- _tempo = tempo;
- if (_ppqn)
- _psec_per_tick = (tempo + (_ppqn >> 2)) / _ppqn;
-}
-
-// This is the conventional (i.e. SMF) variable length quantity
-uint32 MidiParser::readVLQ(byte * &data) {
- byte str;
- uint32 value = 0;
- int i;
-
- for (i = 0; i < 4; ++i) {
- str = data[0];
- ++data;
- value = (value << 7) | (str & 0x7F);
- if (!(str & 0x80))
- break;
- }
- return value;
-}
-
-void MidiParser::activeNote(byte channel, byte note, bool active) {
- if (note >= 128 || channel >= 16)
- return;
-
- if (active)
- _active_notes[note] |= (1 << channel);
- else
- _active_notes[note] &= ~(1 << channel);
-
- // See if there are hanging notes that we can cancel
- NoteTimer *ptr = _hanging_notes;
- int i;
- for (i = ARRAYSIZE(_hanging_notes); i; --i, ++ptr) {
- if (ptr->channel == channel && ptr->note == note && ptr->time_left) {
- ptr->time_left = 0;
- --_hanging_notes_count;
- break;
- }
- }
-}
-
-void MidiParser::hangingNote(byte channel, byte note, uint32 time_left, bool recycle) {
- NoteTimer *best = 0;
- NoteTimer *ptr = _hanging_notes;
- int i;
-
- if (_hanging_notes_count >= ARRAYSIZE(_hanging_notes)) {
- warning("MidiParser::hangingNote(): Exceeded polyphony");
- return;
- }
-
- for (i = ARRAYSIZE(_hanging_notes); i; --i, ++ptr) {
- if (ptr->channel == channel && ptr->note == note) {
- if (ptr->time_left && ptr->time_left < time_left && recycle)
- return;
- best = ptr;
- if (ptr->time_left) {
- if (recycle)
- sendToDriver(0x80 | channel, note, 0);
- --_hanging_notes_count;
- }
- break;
- } else if (!best && ptr->time_left == 0) {
- best = ptr;
- }
- }
-
- // Occassionally we might get a zero or negative note
- // length, if the note should be turned on and off in
- // the same iteration. For now just set it to 1 and
- // we'll turn it off in the next cycle.
- if (!time_left || time_left & 0x80000000)
- time_left = 1;
-
- if (best) {
- best->channel = channel;
- best->note = note;
- best->time_left = time_left;
- ++_hanging_notes_count;
- } else {
- // We checked this up top. We should never get here!
- warning("MidiParser::hangingNote(): Internal error");
- }
-}
-
-void MidiParser::onTimer() {
- uint32 end_time;
- uint32 event_time;
-
- if (!_position._play_pos || !_driver)
- return;
-
- _abort_parse = false;
- end_time = _position._play_time + _timer_rate;
-
- // Scan our hanging notes for any
- // that should be turned off.
- if (_hanging_notes_count) {
- NoteTimer *ptr = &_hanging_notes[0];
- int i;
- for (i = ARRAYSIZE(_hanging_notes); i; --i, ++ptr) {
- if (ptr->time_left) {
- if (ptr->time_left <= _timer_rate) {
- sendToDriver(0x80 | ptr->channel, ptr->note, 0);
- ptr->time_left = 0;
- --_hanging_notes_count;
- } else {
- ptr->time_left -= _timer_rate;
- }
- }
- }
- }
-
- while (!_abort_parse) {
- EventInfo &info = _next_event;
-
- event_time = _position._last_event_time + info.delta * _psec_per_tick;
- if (event_time > end_time)
- break;
-
- // Process the next info.
- _position._last_event_tick += info.delta;
- if (info.event < 0x80) {
- warning("Bad command or running status %02X", info.event);
- _position._play_pos = 0;
- return;
- }
-
- if (info.event == 0xF0) {
- // SysEx event
- // Check for trailing 0xF7 -- if present, remove it.
- if (info.ext.data[info.length-1] == 0xF7)
- _driver->sysEx(info.ext.data, (uint16)info.length-1);
- else
- _driver->sysEx(info.ext.data, (uint16)info.length);
- } else if (info.event == 0xFF) {
- // META event
- if (info.ext.type == 0x2F) {
- // End of Track must be processed by us,
- // as well as sending it to the output device.
- if (_autoLoop) {
- jumpToTick(0);
- parseNextEvent(_next_event);
- } else {
- stopPlaying();
- _driver->metaEvent(info.ext.type, info.ext.data, (uint16)info.length);
- }
- return;
- } else if (info.ext.type == 0x51) {
- if (info.length >= 3) {
- setTempo(info.ext.data[0] << 16 | info.ext.data[1] << 8 | info.ext.data[2]);
- }
- }
- _driver->metaEvent(info.ext.type, info.ext.data, (uint16)info.length);
- } else {
- if (info.command() == 0x8) {
- activeNote(info.channel(), info.basic.param1, false);
- } else if (info.command() == 0x9) {
- if (info.length > 0)
- hangingNote(info.channel(), info.basic.param1, info.length * _psec_per_tick - (end_time - event_time));
- else
- activeNote(info.channel(), info.basic.param1, true);
- }
- sendToDriver(info.event, info.basic.param1, info.basic.param2);
- }
-
-
- if (!_abort_parse) {
- _position._last_event_time = event_time;
- parseNextEvent(_next_event);
- }
- }
-
- if (!_abort_parse) {
- _position._play_time = end_time;
- _position._play_tick = (_position._play_time - _position._last_event_time) / _psec_per_tick + _position._last_event_tick;
- }
-}
-
-void MidiParser::allNotesOff() {
- if (!_driver)
- return;
-
- int i, j;
-
- // Turn off all active notes
- for (i = 0; i < 128; ++i) {
- for (j = 0; j < 16; ++j) {
- if (_active_notes[i] & (1 << j)) {
- sendToDriver(0x80 | j, i, 0);
- }
- }
- }
-
- // Turn off all hanging notes
- for (i = 0; i < ARRAYSIZE(_hanging_notes); i++) {
- if (_hanging_notes[i].time_left) {
- sendToDriver(0x80 | _hanging_notes[i].channel, _hanging_notes[i].note, 0);
- _hanging_notes[i].time_left = 0;
- }
- }
- _hanging_notes_count = 0;
-
- // To be sure, send an "All Note Off" event (but not all MIDI devices
- // support this...).
-
- for (i = 0; i < 16; ++i) {
- sendToDriver(0xB0 | i, 0x7b, 0); // All notes off
- if (_sendSustainOffOnNotesOff)
- sendToDriver(0xB0 | i, 0x40, 0); // Also send a sustain off event (bug #3116608)
- }
-
- memset(_active_notes, 0, sizeof(_active_notes));
-}
-
-void MidiParser::resetTracking() {
- _position.clear();
-}
-
-bool MidiParser::setTrack(int track) {
- if (track < 0 || track >= _num_tracks)
- return false;
- // We allow restarting the track via setTrack when
- // it isn't playing anymore. This allows us to reuse
- // a MidiParser when a track has finished and will
- // be restarted via setTrack by the client again.
- // This isn't exactly how setTrack behaved before though,
- // the old MidiParser code did not allow setTrack to be
- // used to restart a track, which was already finished.
- //
- // TODO: Check if any engine has problem with this
- // handling, if so we need to find a better way to handle
- // track restarts. (KYRA relies on this working)
- else if (track == _active_track && isPlaying())
- return true;
-
- if (_smartJump)
- hangAllActiveNotes();
- else
- allNotesOff();
-
- resetTracking();
- memset(_active_notes, 0, sizeof(_active_notes));
- _active_track = track;
- _position._play_pos = _tracks[track];
- parseNextEvent(_next_event);
- return true;
-}
-
-void MidiParser::stopPlaying() {
- allNotesOff();
- resetTracking();
-}
-
-void MidiParser::hangAllActiveNotes() {
- // Search for note off events until we have
- // accounted for every active note.
- uint16 temp_active[128];
- memcpy(temp_active, _active_notes, sizeof (temp_active));
-
- uint32 advance_tick = _position._last_event_tick;
- while (true) {
- int i;
- for (i = 0; i < 128; ++i)
- if (temp_active[i] != 0)
- break;
- if (i == 128)
- break;
- parseNextEvent(_next_event);
- advance_tick += _next_event.delta;
- if (_next_event.command() == 0x8) {
- if (temp_active[_next_event.basic.param1] & (1 << _next_event.channel())) {
- hangingNote(_next_event.channel(), _next_event.basic.param1, (advance_tick - _position._last_event_tick) * _psec_per_tick, false);
- temp_active[_next_event.basic.param1] &= ~ (1 << _next_event.channel());
- }
- } else if (_next_event.event == 0xFF && _next_event.ext.type == 0x2F) {
- // warning("MidiParser::hangAllActiveNotes(): Hit End of Track with active notes left");
- for (i = 0; i < 128; ++i) {
- for (int j = 0; j < 16; ++j) {
- if (temp_active[i] & (1 << j)) {
- activeNote(j, i, false);
- sendToDriver(0x80 | j, i, 0);
- }
- }
- }
- break;
- }
- }
-}
-
-bool MidiParser::jumpToTick(uint32 tick, bool fireEvents, bool stopNotes, bool dontSendNoteOn) {
- if (_active_track >= _num_tracks)
- return false;
-
- Tracker currentPos(_position);
- EventInfo currentEvent(_next_event);
-
- resetTracking();
- _position._play_pos = _tracks[_active_track];
- parseNextEvent(_next_event);
- if (tick > 0) {
- while (true) {
- EventInfo &info = _next_event;
- if (_position._last_event_tick + info.delta >= tick) {
- _position._play_time += (tick - _position._last_event_tick) * _psec_per_tick;
- _position._play_tick = tick;
- break;
- }
-
- _position._last_event_tick += info.delta;
- _position._last_event_time += info.delta * _psec_per_tick;
- _position._play_tick = _position._last_event_tick;
- _position._play_time = _position._last_event_time;
-
- if (info.event == 0xFF) {
- if (info.ext.type == 0x2F) { // End of track
- _position = currentPos;
- _next_event = currentEvent;
- return false;
- } else {
- if (info.ext.type == 0x51 && info.length >= 3) // Tempo
- setTempo(info.ext.data[0] << 16 | info.ext.data[1] << 8 | info.ext.data[2]);
- if (fireEvents)
- _driver->metaEvent(info.ext.type, info.ext.data, (uint16) info.length);
- }
- } else if (fireEvents) {
- if (info.event == 0xF0) {
- if (info.ext.data[info.length-1] == 0xF7)
- _driver->sysEx(info.ext.data, (uint16)info.length-1);
- else
- _driver->sysEx(info.ext.data, (uint16)info.length);
- } else {
- // The note on sending code is used by the SCUMM engine. Other engine using this code
- // (such as SCI) have issues with this, as all the notes sent can be heard when a song
- // is fast-forwarded. Thus, if the engine requests it, don't send note on events.
- if (info.command() == 0x9 && dontSendNoteOn) {
- // Don't send note on; doing so creates a "warble" with some instruments on the MT-32.
- // Refer to patch #3117577
- } else {
- sendToDriver(info.event, info.basic.param1, info.basic.param2);
- }
- }
- }
-
- parseNextEvent(_next_event);
- }
- }
-
- if (stopNotes) {
- if (!_smartJump || !currentPos._play_pos) {
- allNotesOff();
- } else {
- EventInfo targetEvent(_next_event);
- Tracker targetPosition(_position);
-
- _position = currentPos;
- _next_event = currentEvent;
- hangAllActiveNotes();
-
- _next_event = targetEvent;
- _position = targetPosition;
- }
- }
-
- _abort_parse = true;
- return true;
-}
-
-void MidiParser::unloadMusic() {
- resetTracking();
- allNotesOff();
- _num_tracks = 0;
- _active_track = 255;
- _abort_parse = true;
-
- if (_centerPitchWheelOnUnload) {
- // Center the pitch wheels in preparation for the next piece of
- // music. It's not safe to do this from within allNotesOff(),
- // and might not even be safe here, so we only do it if the
- // client has explicitly asked for it.
-
- if (_driver) {
- for (int i = 0; i < 16; ++i) {
- sendToDriver(0xE0 | i, 0, 0x40);
- }
- }
- }
-}
diff --git a/sound/midiparser.h b/sound/midiparser.h
deleted file mode 100644
index 0b18a19a5b..0000000000
--- a/sound/midiparser.h
+++ /dev/null
@@ -1,404 +0,0 @@
-/* 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$
- *
- */
-
-/// \brief Declarations related to the MidiParser class
-
-#ifndef SOUND_MIDIPARSER_H
-#define SOUND_MIDIPARSER_H
-
-#include "common/scummsys.h"
-#include "common/endian.h"
-
-class MidiParser;
-class MidiDriver;
-
-
-
-//////////////////////////////////////////////////
-//
-// Support entities
-//
-//////////////////////////////////////////////////
-
-/**
- * Maintains time and position state within a MIDI stream.
- * A single Tracker struct is used by MidiParser to keep track
- * of its current position in the MIDI stream. The Tracker
- * struct, however, allows alternative locations to be cached.
- * See MidiParser::jumpToTick() for an example of tracking
- * multiple locations within a MIDI stream. NOTE: It is
- * important to also maintain pre-parsed EventInfo data for
- * each Tracker location.
- */
-struct Tracker {
- byte * _play_pos; ///< A pointer to the next event to be parsed
- uint32 _play_time; ///< Current time in microseconds; may be in between event times
- uint32 _play_tick; ///< Current MIDI tick; may be in between event ticks
- uint32 _last_event_time; ///< The time, in microseconds, of the last event that was parsed
- uint32 _last_event_tick; ///< The tick at which the last parsed event occurs
- byte _running_status; ///< Cached MIDI command, for MIDI streams that rely on implied event codes
-
- Tracker() { clear(); }
-
- /// Copy constructor for each duplication of Tracker information.
- Tracker(const Tracker &copy) :
- _play_pos(copy._play_pos),
- _play_time(copy._play_time),
- _play_tick(copy._play_tick),
- _last_event_time(copy._last_event_time),
- _last_event_tick(copy._last_event_tick),
- _running_status(copy._running_status)
- { }
-
- /// Clears all data; used by the constructor for initialization.
- void clear() {
- _play_pos = 0;
- _play_time = 0;
- _play_tick = 0;
- _last_event_time = 0;
- _last_event_tick = 0;
- _running_status = 0;
- }
-};
-
-/**
- * Provides comprehensive information on the next event in the MIDI stream.
- * An EventInfo struct is instantiated by format-specific implementations
- * of MidiParser::parseNextEvent() each time another event is needed.
- */
-struct EventInfo {
- byte * start; ///< Position in the MIDI stream where the event starts.
- ///< For delta-based MIDI streams (e.g. SMF and XMIDI), this points to the delta.
- uint32 delta; ///< The number of ticks after the previous event that this event should occur.
- byte event; ///< Upper 4 bits are the command code, lower 4 bits are the MIDI channel.
- ///< For META, event == 0xFF. For SysEx, event == 0xF0.
- union {
- struct {
- byte param1; ///< The first parameter in a simple MIDI message.
- byte param2; ///< The second parameter in a simple MIDI message.
- } basic;
- struct {
- byte type; ///< For META events, this indicates the META type.
- byte * data; ///< For META and SysEx events, this points to the start of the data.
- } ext;
- };
- uint32 length; ///< For META and SysEx blocks, this indicates the length of the data.
- ///< For Note On events, a non-zero value indicates that no Note Off event
- ///< will occur, and the MidiParser will have to generate one itself.
- ///< For all other events, this value should always be zero.
-
- byte channel() { return event & 0x0F; } ///< Separates the MIDI channel from the event.
- byte command() { return event >> 4; } ///< Separates the command code from the event.
-};
-
-/**
- * Provides expiration tracking for hanging notes.
- * Hanging notes are used when a MIDI format does not include explicit Note Off
- * events, or when "Smart Jump" is enabled so that active notes are intelligently
- * expired when a jump occurs. The NoteTimer struct keeps track of how much
- * longer a note should remain active before being turned off.
- */
-struct NoteTimer {
- byte channel; ///< The MIDI channel on which the note was played
- byte note; ///< The note number for the active note
- uint32 time_left; ///< The time, in microseconds, remaining before the note should be turned off
- NoteTimer() : channel(0), note(0), time_left(0) {}
-};
-
-
-
-
-//////////////////////////////////////////////////
-//
-// MidiParser declaration
-//
-//////////////////////////////////////////////////
-
-/**
- * A framework and common functionality for parsing event-based music streams.
- * The MidiParser provides a framework in which to load,
- * parse and traverse event-based music data. Note the
- * avoidance of the phrase "MIDI data." Despite its name,
- * MidiParser derivatives can be used to manage a wide
- * variety of event-based music formats. It is, however,
- * based on the premise that the format in question can
- * be played in the form of specification MIDI events.
- *
- * In order to use MidiParser to parse your music format,
- * follow these steps:
- *
- * <b>STEP 1: Write a MidiParser derivative.</b>
- * The MidiParser base class provides functionality
- * considered common to the task of parsing event-based
- * music. In order to parse a particular format, create
- * a derived class that implements, at minimum, the
- * following format-specific methods:
- * - loadMusic
- * - parseNextEvent
- *
- * In addition to the above functions, the derived class
- * may also override the default MidiParser behavior for
- * the following methods:
- * - resetTracking
- * - allNotesOff
- * - unloadMusic
- * - property
- * - getTick
- *
- * Please see the documentation for these individual
- * functions for more information on their use.
- *
- * The naming convention for classes derived from
- * MidiParser is MidiParser_XXX, where "XXX" is some
- * short designator for the format the class will
- * support. For instance, the MidiParser derivative
- * for parsing the Standard MIDI File format is
- * MidiParser_SMF.
- *
- * <b>STEP 2: Create an object of your derived class.</b>
- * Each MidiParser object can parse at most one (1) song
- * at a time. However, a MidiParser object can be reused
- * to play another song once it is no longer needed to
- * play whatever it was playing. In other words, MidiParser
- * objects do not have to be destroyed and recreated from
- * one song to the next.
- *
- * <b>STEP 3: Specify a MidiDriver to send events to.</b>
- * MidiParser works by sending MIDI and meta events to a
- * MidiDriver. In the simplest configuration, you can plug
- * a single MidiParser directly into the output MidiDriver
- * being used. However, you can only plug in one at a time;
- * otherwise channel conflicts will occur. Furthermore,
- * meta events that may be needed to interactively control
- * music flow cannot be handled because they are being
- * sent directly to the output device.
- *
- * If you need more control over the MidiParser while it's
- * playing, you can create your own "pseudo-MidiDriver" and
- * place it in between your MidiParser and the output
- * MidiDriver. The MidiParser will send events to your
- * pseudo-MidiDriver, which in turn must send them to the
- * output MidiDriver (or do whatever special handling is
- * required).
- *
- * To specify the MidiDriver to send music output to,
- * use the MidiParser::setMidiDriver method.
- *
- * <b>STEP 4: Specify the onTimer call rate.</b>
- * MidiParser bases the timing of its parsing on an external
- * clock. Every time MidiParser::onTimer is called, a bit
- * more music is parsed. You must specify how many
- * microseconds will occur between each call to onTimer,
- * in order to ensure an accurate music tempo.
- *
- * To set the onTimer call rate, in microseconds,
- * use the MidiParser::setTimerRate method. The onTimer
- * call rate will typically match the timer rate for
- * the output MidiDriver used. This rate can be obtained
- * by calling MidiDriver::getBaseTempo.
- *
- * <b>STEP 5: Load the music.</b>
- * MidiParser requires that the music data already be loaded
- * into memory. The client code is responsible for memory
- * management on this block of memory. That means that the
- * client code must ensure that the data remain in memory
- * while the MidiParser is using it, and properly freed
- * after it is no longer needed. Some MidiParser variants may
- * require internal buffers as well; memory management for those
- * buffers is the responsibility of the MidiParser object.
- *
- * To load the music into the MidiParser, use the
- * MidiParser::loadMusic method, specifying a memory pointer
- * to the music data and the size of the data. (NOTE: Some
- * MidiParser variants don't require a size, and 0 is fine.
- * However, when writing client code to use MidiParser, it is
- * best to assume that a valid size will be required.
- *
- * Convention requires that each implementation of
- * MidiParser::loadMusic automatically set up default tempo
- * and current track. This effectively means that the
- * MidiParser will start playing as soon as timer events
- * start coming in.
- *
- * <b>STEP 6: Activate a timer source for the MidiParser.</b>
- * The easiest timer source to use is the timer of the
- * output MidiDriver. You can attach the MidiDriver's
- * timer output directly to a MidiParser by calling
- * MidiDriver::setTimerCallback. In this case, the timer_proc
- * will be the static method MidiParser::timerCallback,
- * and timer_param will be a pointer to your MidiParser object.
- *
- * This configuration only allows one MidiParser to be driven
- * by the MidiDriver at a time. To drive more MidiDrivers, you
- * will need to create a "pseudo-MidiDriver" as described earlier,
- * In such a configuration, the pseudo-MidiDriver should be set
- * as the timer recipient in MidiDriver::setTimerCallback, and
- * could then call MidiParser::onTimer for each MidiParser object.
- *
- * <b>STEP 7: Music shall begin to play!</b>
- * Congratulations! At this point everything should be hooked up
- * and the MidiParser should generate music. Note that there is
- * no way to "stop" the MidiParser. You can "pause" the MidiParser
- * simply by not sending timer events to it, or you can call
- * MidiParser::unloadMusic to permanently stop the music. (This
- * method resets everything and detaches the MidiParser from the
- * memory block containing the music data.)
- */
-class MidiParser {
-protected:
- uint16 _active_notes[128]; ///< Each uint16 is a bit mask for channels that have that note on.
- NoteTimer _hanging_notes[32]; ///< Maintains expiration info for up to 32 notes.
- ///< Used for "Smart Jump" and MIDI formats that do not include explicit Note Off events.
- byte _hanging_notes_count; ///< Count of hanging notes, used to optimize expiration.
-
- MidiDriver *_driver; ///< The device to which all events will be transmitted.
- uint32 _timer_rate; ///< The time in microseconds between onTimer() calls. Obtained from the MidiDriver.
- uint32 _ppqn; ///< Pulses Per Quarter Note. (We refer to "pulses" as "ticks".)
- uint32 _tempo; ///< Microseconds per quarter note.
- uint32 _psec_per_tick; ///< Microseconds per tick (_tempo / _ppqn).
- bool _autoLoop; ///< For lightweight clients that don't provide their own flow control.
- bool _smartJump; ///< Support smart expiration of hanging notes when jumping
- bool _centerPitchWheelOnUnload; ///< Center the pitch wheels when unloading a song
- bool _sendSustainOffOnNotesOff; ///< Send a sustain off on a notes off event, stopping hanging notes
- byte *_tracks[120]; ///< Multi-track MIDI formats are supported, up to 120 tracks.
- byte _num_tracks; ///< Count of total tracks for multi-track MIDI formats. 1 for single-track formats.
- byte _active_track; ///< Keeps track of the currently active track, in multi-track formats.
-
- Tracker _position; ///< The current time/position in the active track.
- EventInfo _next_event; ///< The next event to transmit. Events are preparsed
- ///< so each event is parsed only once; this permits
- ///< simulated events in certain formats.
- bool _abort_parse; ///< If a jump or other operation interrupts parsing, flag to abort.
-
-protected:
- static uint32 readVLQ(byte * &data);
- virtual void resetTracking();
- virtual void allNotesOff();
- virtual void parseNextEvent(EventInfo &info) = 0;
-
- void activeNote(byte channel, byte note, bool active);
- void hangingNote(byte channel, byte note, uint32 ticks_left, bool recycle = true);
- void hangAllActiveNotes();
-
- virtual void sendToDriver(uint32 b);
- void sendToDriver(byte status, byte firstOp, byte secondOp) {
- sendToDriver(status | ((uint32)firstOp << 8) | ((uint32)secondOp << 16));
- }
-
- /**
- * Platform independent BE uint32 read-and-advance.
- * This helper function reads Big Endian 32-bit numbers
- * from a memory pointer, at the same time advancing
- * the pointer.
- */
- uint32 read4high(byte * &data) {
- uint32 val = READ_BE_UINT32(data);
- data += 4;
- return val;
- }
-
- /**
- * Platform independent LE uint16 read-and-advance.
- * This helper function reads Little Endian 16-bit numbers
- * from a memory pointer, at the same time advancing
- * the pointer.
- */
- uint16 read2low(byte * &data) {
- uint16 val = READ_LE_UINT16(data);
- data += 2;
- return val;
- }
-
-public:
- /**
- * Configuration options for MidiParser
- * The following options can be set to modify MidiParser's
- * behavior.
- */
- enum {
- /**
- * Events containing a pitch bend command should be treated as
- * single-byte padding before the real event. This allows the
- * MidiParser to work with some malformed SMF files from Simon 1/2.
- */
- mpMalformedPitchBends = 1,
-
- /**
- * Sets auto-looping, which can be used by lightweight clients
- * that don't provide their own flow control.
- */
- mpAutoLoop = 2,
-
- /**
- * Sets smart jumping, which intelligently expires notes that are
- * active when a jump is made, rather than just cutting them off.
- */
- mpSmartJump = 3,
-
- /**
- * Center the pitch wheels when unloading music in preparation
- * for the next piece of music.
- */
- mpCenterPitchWheelOnUnload = 4,
-
- /**
- * Sends a sustain off event when a notes off event is triggered.
- * Stops hanging notes.
- */
- mpSendSustainOffOnNotesOff = 5
- };
-
-public:
- typedef void (*XMidiCallbackProc)(byte eventData, void *refCon);
-
- MidiParser();
- virtual ~MidiParser() { allNotesOff(); }
-
- virtual bool loadMusic(byte *data, uint32 size) = 0;
- virtual void unloadMusic();
- virtual void property(int prop, int value);
-
- void setMidiDriver(MidiDriver *driver) { _driver = driver; }
- void setTimerRate(uint32 rate) { _timer_rate = rate; }
- void setTempo(uint32 tempo);
- void onTimer();
-
- bool isPlaying() const { return (_position._play_pos != 0); }
- void stopPlaying();
-
- bool setTrack(int track);
- bool jumpToTick(uint32 tick, bool fireEvents = false, bool stopNotes = true, bool dontSendNoteOn = false);
-
- uint32 getPPQN() { return _ppqn; }
- virtual uint32 getTick() { return _position._play_tick; }
-
- static void defaultXMidiCallback(byte eventData, void *refCon);
-
- static MidiParser *createParser_SMF();
- static MidiParser *createParser_XMIDI(XMidiCallbackProc proc = defaultXMidiCallback, void *refCon = 0);
- static void timerCallback(void *data) { ((MidiParser *) data)->onTimer(); }
-};
-
-#endif
diff --git a/sound/midiparser_smf.cpp b/sound/midiparser_smf.cpp
deleted file mode 100644
index a9c6f1eb3b..0000000000
--- a/sound/midiparser_smf.cpp
+++ /dev/null
@@ -1,384 +0,0 @@
-/* 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/midiparser.h"
-#include "sound/mididrv.h"
-#include "common/util.h"
-
-/**
- * The Standard MIDI File version of MidiParser.
- */
-class MidiParser_SMF : public MidiParser {
-protected:
- byte *_buffer;
- bool _malformedPitchBends;
-
-protected:
- void compressToType0();
- void parseNextEvent(EventInfo &info);
-
-public:
- MidiParser_SMF() : _buffer(0), _malformedPitchBends(false) {}
- ~MidiParser_SMF();
-
- bool loadMusic(byte *data, uint32 size);
- void property(int property, int value);
-};
-
-
-static const byte command_lengths[8] = { 3, 3, 3, 3, 2, 2, 3, 0 };
-static const byte special_lengths[16] = { 0, 2, 3, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0 };
-
-MidiParser_SMF::~MidiParser_SMF() {
- free(_buffer);
-}
-
-void MidiParser_SMF::property(int prop, int value) {
- switch (prop) {
- case mpMalformedPitchBends:
- _malformedPitchBends = (value > 0);
- default:
- MidiParser::property(prop, value);
- }
-}
-
-void MidiParser_SMF::parseNextEvent(EventInfo &info) {
- info.start = _position._play_pos;
- info.delta = readVLQ(_position._play_pos);
-
- // Process the next info. If mpMalformedPitchBends
- // was set, we must skip over any pitch bend events
- // because they are from Simon games and are not
- // real pitch bend events, they're just two-byte
- // prefixes before the real info.
- do {
- if ((_position._play_pos[0] & 0xF0) >= 0x80)
- info.event = *(_position._play_pos++);
- else
- info.event = _position._running_status;
- } while (_malformedPitchBends && (info.event & 0xF0) == 0xE0 && _position._play_pos++);
- if (info.event < 0x80)
- return;
-
- _position._running_status = info.event;
- switch (info.command()) {
- case 0x9: // Note On
- info.basic.param1 = *(_position._play_pos++);
- info.basic.param2 = *(_position._play_pos++);
- if (info.basic.param2 == 0)
- info.event = info.channel() | 0x80;
- info.length = 0;
- break;
-
- case 0xC:
- case 0xD:
- info.basic.param1 = *(_position._play_pos++);
- info.basic.param2 = 0;
- break;
-
- case 0x8:
- case 0xA:
- case 0xB:
- case 0xE:
- info.basic.param1 = *(_position._play_pos++);
- info.basic.param2 = *(_position._play_pos++);
- info.length = 0;
- break;
-
- case 0xF: // System Common, Meta or SysEx event
- switch (info.event & 0x0F) {
- case 0x2: // Song Position Pointer
- info.basic.param1 = *(_position._play_pos++);
- info.basic.param2 = *(_position._play_pos++);
- break;
-
- case 0x3: // Song Select
- info.basic.param1 = *(_position._play_pos++);
- info.basic.param2 = 0;
- break;
-
- case 0x6:
- case 0x8:
- case 0xA:
- case 0xB:
- case 0xC:
- case 0xE:
- info.basic.param1 = info.basic.param2 = 0;
- break;
-
- case 0x0: // SysEx
- info.length = readVLQ(_position._play_pos);
- info.ext.data = _position._play_pos;
- _position._play_pos += info.length;
- break;
-
- case 0xF: // META event
- info.ext.type = *(_position._play_pos++);
- info.length = readVLQ(_position._play_pos);
- info.ext.data = _position._play_pos;
- _position._play_pos += info.length;
- break;
-
- default:
- warning("MidiParser_SMF::parseNextEvent: Unsupported event code %x", info.event);
- }
- }
-}
-
-bool MidiParser_SMF::loadMusic(byte *data, uint32 size) {
- uint32 len;
- byte midi_type;
- uint32 total_size;
- bool isGMF;
-
- unloadMusic();
- byte *pos = data;
- isGMF = false;
-
- if (!memcmp(pos, "RIFF", 4)) {
- // Skip the outer RIFF header.
- pos += 8;
- }
-
- if (!memcmp(pos, "MThd", 4)) {
- // SMF with MTHd information.
- pos += 4;
- len = read4high(pos);
- if (len != 6) {
- warning("MThd length 6 expected but found %d", (int)len);
- return false;
- }
-
- // Verify that this MIDI either is a Type 2
- // or has only 1 track. We do not support
- // multitrack Type 1 files.
- _num_tracks = pos[2] << 8 | pos[3];
- midi_type = pos[1];
- if (midi_type > 2 /*|| (midi_type < 2 && _num_tracks > 1)*/) {
- warning("No support for a Type %d MIDI with %d tracks", (int)midi_type, (int)_num_tracks);
- return false;
- }
- _ppqn = pos[4] << 8 | pos[5];
- pos += len;
- } else if (!memcmp(pos, "GMF\x1", 4)) {
- // Older GMD/MUS file with no header info.
- // Assume 1 track, 192 PPQN, and no MTrk headers.
- isGMF = true;
- midi_type = 0;
- _num_tracks = 1;
- _ppqn = 192;
- pos += 7; // 'GMD\x1' + 3 bytes of useless (translate: unknown) information
- } else {
- warning("Expected MThd or GMD header but found '%c%c%c%c' instead", pos[0], pos[1], pos[2], pos[3]);
- return false;
- }
-
- // Now we identify and store the location for each track.
- if (_num_tracks > ARRAYSIZE(_tracks)) {
- warning("Can only handle %d tracks but was handed %d", (int)ARRAYSIZE(_tracks), (int)_num_tracks);
- return false;
- }
-
- total_size = 0;
- int tracks_read = 0;
- while (tracks_read < _num_tracks) {
- if (memcmp(pos, "MTrk", 4) && !isGMF) {
- warning("Position: %p ('%c')", pos, *pos);
- warning("Hit invalid block '%c%c%c%c' while scanning for track locations", pos[0], pos[1], pos[2], pos[3]);
- return false;
- }
-
- // If needed, skip the MTrk and length bytes
- _tracks[tracks_read] = pos + (isGMF ? 0 : 8);
- if (!isGMF) {
- pos += 4;
- len = read4high(pos);
- total_size += len;
- pos += len;
- } else {
- // An SMF End of Track meta event must be placed
- // at the end of the stream.
- data[size++] = 0xFF;
- data[size++] = 0x2F;
- data[size++] = 0x00;
- data[size++] = 0x00;
- }
- ++tracks_read;
- }
-
- // If this is a Type 1 MIDI, we need to now compress
- // our tracks down into a single Type 0 track.
- free(_buffer);
- _buffer = 0;
-
- if (midi_type == 1) {
- // FIXME: Doubled the buffer size to prevent crashes with the
- // Inherit the Earth MIDIs. Jamieson630 said something about a
- // better fix, but this will have to do in the meantime.
- _buffer = (byte *)malloc(size * 2);
- compressToType0();
- _num_tracks = 1;
- _tracks[0] = _buffer;
- }
-
- // Note that we assume the original data passed in
- // will persist beyond this call, i.e. we do NOT
- // copy the data to our own buffer. Take warning....
- resetTracking();
- setTempo(500000);
- setTrack(0);
- return true;
-}
-
-void MidiParser_SMF::compressToType0() {
- // We assume that _buffer has been allocated
- // to sufficient size for this operation.
-
- // using 0xFF since it could write track_pos[0 to _num_tracks] here
- // this would cause some illegal writes and could lead to segfaults
- // (it crashed for some midis for me, they're not used in any game
- // scummvm supports though). *Maybe* handle this in another way,
- // it's at the moment only to be sure, that nothing goes wrong.
- byte *track_pos[0xFF];
- byte running_status[0xFF];
- uint32 track_timer[0xFF];
- uint32 delta;
- int i;
-
- for (i = 0; i < _num_tracks; ++i) {
- running_status[i] = 0;
- track_pos[i] = _tracks[i];
- track_timer[i] = readVLQ(track_pos[i]);
- running_status[i] = 0;
- }
-
- int best_i;
- uint32 length;
- byte *output = _buffer;
- byte *pos, *pos2;
- byte event;
- uint32 copy_bytes;
- bool write;
- byte active_tracks = (byte)_num_tracks;
-
- while (active_tracks) {
- write = true;
- best_i = 255;
- for (i = 0; i < _num_tracks; ++i) {
- if (track_pos[i] && (best_i == 255 || track_timer[i] < track_timer[best_i]))
- best_i = i;
- }
- if (best_i == 255) {
- warning("Premature end of tracks");
- break;
- }
-
- // Initial VLQ delta computation
- delta = 0;
- length = track_timer[best_i];
- for (i = 0; length; ++i) {
- delta = (delta << 8) | (length & 0x7F) | (i ? 0x80 : 0);
- length >>= 7;
- }
-
- // Process MIDI event.
- bool implicitEvent = false;
- copy_bytes = 0;
- pos = track_pos[best_i];
- do {
- event = *(pos++);
- if (event < 0x80) {
- event = running_status[best_i];
- implicitEvent = true;
- }
- } while (_malformedPitchBends && (event & 0xF0) == 0xE0 && pos++);
- running_status[best_i] = event;
-
- if (command_lengths[(event >> 4) - 8] > 0) {
- copy_bytes = command_lengths[(event >> 4) - 8];
- } else if (special_lengths[(event & 0x0F)] > 0) {
- copy_bytes = special_lengths[(event & 0x0F)];
- } else if (event == 0xF0) {
- // SysEx
- pos2 = pos;
- length = readVLQ(pos);
- copy_bytes = 1 + (pos - pos2) + length;
- } else if (event == 0xFF) {
- // META
- event = *(pos++);
- if (event == 0x2F && active_tracks > 1) {
- track_pos[best_i] = 0;
- write = false;
- } else {
- pos2 = pos;
- length = readVLQ(pos);
- copy_bytes = 2 + (pos - pos2) + length;
- }
- if (event == 0x2F)
- --active_tracks;
- } else {
- warning("Bad MIDI command %02X", (int)event);
- track_pos[best_i] = 0;
- }
-
- // Update all tracks' deltas
- if (write) {
- for (i = 0; i < _num_tracks; ++i) {
- if (track_pos[i] && i != best_i)
- track_timer[i] -= track_timer[best_i];
- }
- }
-
- if (track_pos[best_i]) {
- if (write) {
- track_timer[best_i] = 0;
-
- // Write VLQ delta
- while (delta & 0x80) {
- *output++ = (byte)(delta & 0xFF);
- delta >>= 8;
- }
- *output++ = (byte)(delta & 0xFF);
-
- // Write MIDI data
- if (!implicitEvent)
- ++track_pos[best_i];
- --copy_bytes;
- *output++ = running_status[best_i];
- memcpy(output, track_pos[best_i], copy_bytes);
- output += copy_bytes;
- }
-
- // Fetch new VLQ delta for winning track
- track_pos[best_i] += copy_bytes;
- if (active_tracks)
- track_timer[best_i] += readVLQ(track_pos[best_i]);
- }
- }
-
- *output++ = 0x00;
-}
-
-MidiParser *MidiParser::createParser_SMF() { return new MidiParser_SMF; }
diff --git a/sound/midiparser_xmidi.cpp b/sound/midiparser_xmidi.cpp
deleted file mode 100644
index 343ca34659..0000000000
--- a/sound/midiparser_xmidi.cpp
+++ /dev/null
@@ -1,375 +0,0 @@
-/* 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/midiparser.h"
-#include "sound/mididrv.h"
-#include "common/util.h"
-
-/**
- * The XMIDI version of MidiParser.
- *
- * Much of this code is adapted from the XMIDI implementation from the exult
- * project.
- */
-class MidiParser_XMIDI : public MidiParser {
-protected:
- NoteTimer _notes_cache[32];
- uint32 _inserted_delta; // Track simulated deltas for note-off events
-
- struct Loop {
- byte *pos;
- byte repeat;
- };
-
- Loop _loop[4];
- int _loopCount;
-
- XMidiCallbackProc _callbackProc;
- void *_callbackData;
-
-protected:
- uint32 readVLQ2(byte * &data);
- void resetTracking();
- void parseNextEvent(EventInfo &info);
-
-public:
- MidiParser_XMIDI(XMidiCallbackProc proc, void *data) : _inserted_delta(0), _callbackProc(proc), _callbackData(data) {}
- ~MidiParser_XMIDI() { }
-
- bool loadMusic(byte *data, uint32 size);
-};
-
-
-// This is a special XMIDI variable length quantity
-uint32 MidiParser_XMIDI::readVLQ2(byte * &pos) {
- uint32 value = 0;
- while (!(pos[0] & 0x80)) {
- value += *pos++;
- }
- return value;
-}
-
-void MidiParser_XMIDI::parseNextEvent(EventInfo &info) {
- info.start = _position._play_pos;
- info.delta = readVLQ2(_position._play_pos) - _inserted_delta;
-
- // Process the next event.
- _inserted_delta = 0;
- info.event = *(_position._play_pos++);
- switch (info.event >> 4) {
- case 0x9: // Note On
- info.basic.param1 = *(_position._play_pos++);
- info.basic.param2 = *(_position._play_pos++);
- info.length = readVLQ(_position._play_pos);
- if (info.basic.param2 == 0) {
- info.event = info.channel() | 0x80;
- info.length = 0;
- }
- break;
-
- case 0xC:
- case 0xD:
- info.basic.param1 = *(_position._play_pos++);
- info.basic.param2 = 0;
- break;
-
- case 0x8:
- case 0xA:
- case 0xE:
- info.basic.param1 = *(_position._play_pos++);
- info.basic.param2 = *(_position._play_pos++);
- break;
-
- case 0xB:
- info.basic.param1 = *(_position._play_pos++);
- info.basic.param2 = *(_position._play_pos++);
-
- // This isn't a full XMIDI implementation, but it should
- // hopefully be "good enough" for most things.
-
- switch (info.basic.param1) {
- // Simplified XMIDI looping.
- case 0x74: { // XMIDI_CONTROLLER_FOR_LOOP
- byte *pos = _position._play_pos;
- if (_loopCount < ARRAYSIZE(_loop) - 1)
- _loopCount++;
- else
- warning("XMIDI: Exceeding maximum loop count %d", ARRAYSIZE(_loop));
-
- _loop[_loopCount].pos = pos;
- _loop[_loopCount].repeat = info.basic.param2;
- break;
- }
-
- case 0x75: // XMIDI_CONTORLLER_NEXT_BREAK
- if (_loopCount >= 0) {
- if (info.basic.param2 < 64) {
- // End the current loop.
- _loopCount--;
- } else {
- // Repeat 0 means "loop forever".
- if (_loop[_loopCount].repeat) {
- if (--_loop[_loopCount].repeat == 0)
- _loopCount--;
- else
- _position._play_pos = _loop[_loopCount].pos;
- } else {
- _position._play_pos = _loop[_loopCount].pos;
- }
- }
- }
- break;
-
- case 0x77: // XMIDI_CONTROLLER_CALLBACK_TRIG
- if (_callbackProc)
- _callbackProc(info.basic.param2, _callbackData);
- break;
-
- case 0x6e: // XMIDI_CONTROLLER_CHAN_LOCK
- case 0x6f: // XMIDI_CONTROLLER_CHAN_LOCK_PROT
- case 0x70: // XMIDI_CONTROLLER_VOICE_PROT
- case 0x71: // XMIDI_CONTROLLER_TIMBRE_PROT
- case 0x72: // XMIDI_CONTROLLER_BANK_CHANGE
- case 0x73: // XMIDI_CONTROLLER_IND_CTRL_PREFIX
- case 0x76: // XMIDI_CONTROLLER_CLEAR_BB_COUNT
- case 0x78: // XMIDI_CONTROLLER_SEQ_BRANCH_INDEX
- default:
- if (info.basic.param1 >= 0x6e && info.basic.param1 <= 0x78) {
- warning("Unsupported XMIDI controller %d (0x%2x)",
- info.basic.param1, info.basic.param1);
- }
- }
-
- // Should we really keep passing the XMIDI controller events to
- // the MIDI driver, or should we turn them into some kind of
- // NOP events? (Dummy meta events, perhaps?) Ah well, it has
- // worked so far, so it shouldn't cause any damage...
-
- break;
-
- case 0xF: // Meta or SysEx event
- switch (info.event & 0x0F) {
- case 0x2: // Song Position Pointer
- info.basic.param1 = *(_position._play_pos++);
- info.basic.param2 = *(_position._play_pos++);
- break;
-
- case 0x3: // Song Select
- info.basic.param1 = *(_position._play_pos++);
- info.basic.param2 = 0;
- break;
-
- case 0x6:
- case 0x8:
- case 0xA:
- case 0xB:
- case 0xC:
- case 0xE:
- info.basic.param1 = info.basic.param2 = 0;
- break;
-
- case 0x0: // SysEx
- info.length = readVLQ(_position._play_pos);
- info.ext.data = _position._play_pos;
- _position._play_pos += info.length;
- break;
-
- case 0xF: // META event
- info.ext.type = *(_position._play_pos++);
- info.length = readVLQ(_position._play_pos);
- info.ext.data = _position._play_pos;
- _position._play_pos += info.length;
- if (info.ext.type == 0x51 && info.length == 3) {
- // Tempo event. We want to make these constant 500,000.
- info.ext.data[0] = 0x07;
- info.ext.data[1] = 0xA1;
- info.ext.data[2] = 0x20;
- }
- break;
-
- default:
- warning("MidiParser_XMIDI::parseNextEvent: Unsupported event code %x", info.event);
- }
- }
-}
-
-bool MidiParser_XMIDI::loadMusic(byte *data, uint32 size) {
- uint32 i = 0;
- byte *start;
- uint32 len;
- uint32 chunk_len;
- char buf[32];
-
- _loopCount = -1;
-
- unloadMusic();
- byte *pos = data;
-
- if (!memcmp(pos, "FORM", 4)) {
- pos += 4;
-
- // Read length of
- len = read4high(pos);
- start = pos;
-
- // XDIRless XMIDI, we can handle them here.
- if (!memcmp(pos, "XMID", 4)) {
- warning("XMIDI doesn't have XDIR");
- pos += 4;
- _num_tracks = 1;
- } else if (memcmp(pos, "XDIR", 4)) {
- // Not an XMIDI that we recognise
- warning("Expected 'XDIR' but found '%c%c%c%c'", pos[0], pos[1], pos[2], pos[3]);
- return false;
- } else {
- // Seems Valid
- pos += 4;
- _num_tracks = 0;
-
- for (i = 4; i < len; i++) {
- // Read 4 bytes of type
- memcpy(buf, pos, 4);
- pos += 4;
-
- // Read length of chunk
- chunk_len = read4high(pos);
-
- // Add eight bytes
- i += 8;
-
- if (memcmp(buf, "INFO", 4)) {
- // Must align
- pos += (chunk_len + 1) & ~1;
- i += (chunk_len + 1) & ~1;
- continue;
- }
-
- // Must be at least 2 bytes long
- if (chunk_len < 2) {
- warning("Invalid chunk length %d for 'INFO' block", (int)chunk_len);
- return false;
- }
-
- _num_tracks = (byte)read2low(pos);
-
- if (chunk_len > 2) {
- warning("Chunk length %d is greater than 2", (int)chunk_len);
- pos += chunk_len - 2;
- }
- break;
- }
-
- // Didn't get to fill the header
- if (_num_tracks == 0) {
- warning("Didn't find a valid track count");
- return false;
- }
-
- // Ok now to start part 2
- // Goto the right place
- pos = start + ((len + 1) & ~1);
-
- if (memcmp(pos, "CAT ", 4)) {
- // Not an XMID
- warning("Expected 'CAT ' but found '%c%c%c%c'", pos[0], pos[1], pos[2], pos[3]);
- return false;
- }
- pos += 4;
-
- // Now read length of this track
- len = read4high(pos);
-
- if (memcmp(pos, "XMID", 4)) {
- // Not an XMID
- warning("Expected 'XMID' but found '%c%c%c%c'", pos[0], pos[1], pos[2], pos[3]);
- return false;
- }
- pos += 4;
-
- }
-
- // Ok it's an XMIDI.
- // We're going to identify and store the location for each track.
- if (_num_tracks > ARRAYSIZE(_tracks)) {
- warning("Can only handle %d tracks but was handed %d", (int)ARRAYSIZE(_tracks), (int)_num_tracks);
- return false;
- }
-
- int tracks_read = 0;
- while (tracks_read < _num_tracks) {
- if (!memcmp(pos, "FORM", 4)) {
- // Skip this plus the 4 bytes after it.
- pos += 8;
- } else if (!memcmp(pos, "XMID", 4)) {
- // Skip this.
- pos += 4;
- } else if (!memcmp(pos, "TIMB", 4)) {
- // Custom timbres?
- // We don't support them.
- // Read the length, skip it, and hope there was nothing there.
- pos += 4;
- len = read4high(pos);
- pos += (len + 1) & ~1;
- } else if (!memcmp(pos, "EVNT", 4)) {
- // Ahh! What we're looking for at last.
- _tracks[tracks_read] = pos + 8; // Skip the EVNT and length bytes
- pos += 4;
- len = read4high(pos);
- pos += (len + 1) & ~1;
- ++tracks_read;
- } else {
- warning("Hit invalid block '%c%c%c%c' while scanning for track locations", pos[0], pos[1], pos[2], pos[3]);
- return false;
- }
- }
-
- // If we got this far, we successfully established
- // the locations for each of our tracks.
- // Note that we assume the original data passed in
- // will persist beyond this call, i.e. we do NOT
- // copy the data to our own buffer. Take warning....
- _ppqn = 60;
- resetTracking();
- setTempo(500000);
- _inserted_delta = 0;
- setTrack(0);
- return true;
- }
-
- return false;
-}
-
-void MidiParser_XMIDI::resetTracking() {
- MidiParser::resetTracking();
- _inserted_delta = 0;
-}
-
-void MidiParser::defaultXMidiCallback(byte eventData, void *data) {
- warning("MidiParser: defaultXMidiCallback(%d)", eventData);
-}
-
-MidiParser *MidiParser::createParser_XMIDI(XMidiCallbackProc proc, void *data) {
- return new MidiParser_XMIDI(proc, data);
-}
diff --git a/sound/mixer.cpp b/sound/mixer.cpp
deleted file mode 100644
index c40aa95d73..0000000000
--- a/sound/mixer.cpp
+++ /dev/null
@@ -1,556 +0,0 @@
-/* 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 "common/util.h"
-#include "common/system.h"
-
-#include "sound/mixer_intern.h"
-#include "sound/rate.h"
-#include "sound/audiostream.h"
-#include "sound/timestamp.h"
-
-
-namespace Audio {
-
-#pragma mark -
-#pragma mark --- Channel classes ---
-#pragma mark -
-
-
-/**
- * Channel used by the default Mixer implementation.
- */
-class Channel {
-public:
- Channel(Mixer *mixer, Mixer::SoundType type, AudioStream *stream, DisposeAfterUse::Flag autofreeStream, bool reverseStereo, int id, bool permanent);
- ~Channel();
-
- /**
- * Mixes the channel's samples into the given buffer.
- *
- * @param data buffer where to mix the data
- * @param len number of sample *pairs*. So a value of
- * 10 means that the buffer contains twice 10 sample, each
- * 16 bits, for a total of 40 bytes.
- */
- void mix(int16 *data, uint len);
-
- /**
- * Queries whether the channel is still playing or not.
- */
- bool isFinished() const { return _stream->endOfStream(); }
-
- /**
- * Queries whether the channel is a permanent channel.
- * A permanent channel is not affected by a Mixer::stopAll
- * call.
- */
- bool isPermanent() const { return _permanent; }
-
- /**
- * Returns the id of the channel.
- */
- int getId() const { return _id; }
-
- /**
- * Pauses or unpaused the channel in a recursive fashion.
- *
- * @param paused true, when the channel should be paused.
- * false when it should be unpaused.
- */
- void pause(bool paused);
-
- /**
- * Queries whether the channel is currently paused.
- */
- bool isPaused() const { return (_pauseLevel != 0); }
-
- /**
- * Sets the channel's own volume.
- *
- * @param volume new volume
- */
- void setVolume(const byte volume);
-
- /**
- * Sets the channel's balance setting.
- *
- * @param balance new balance
- */
- void setBalance(const int8 balance);
-
- /**
- * Notifies the channel that the global sound type
- * volume settings changed.
- */
- void notifyGlobalVolChange() { updateChannelVolumes(); }
-
- /**
- * Queries how long the channel has been playing.
- */
- Timestamp getElapsedTime();
-
- /**
- * Queries the channel's sound type.
- */
- Mixer::SoundType getType() const { return _type; }
-
- /**
- * Sets the channel's sound handle.
- *
- * @param handle new handle
- */
- void setHandle(const SoundHandle handle) { _handle = handle; }
-
- /**
- * Queries the channel's sound handle.
- */
- SoundHandle getHandle() const { return _handle; }
-
-private:
- const Mixer::SoundType _type;
- SoundHandle _handle;
- bool _permanent;
- int _pauseLevel;
- int _id;
-
- byte _volume;
- int8 _balance;
-
- void updateChannelVolumes();
- st_volume_t _volL, _volR;
-
- Mixer *_mixer;
-
- uint32 _samplesConsumed;
- uint32 _samplesDecoded;
- uint32 _mixerTimeStamp;
- uint32 _pauseStartTime;
- uint32 _pauseTime;
-
- DisposeAfterUse::Flag _autofreeStream;
- RateConverter *_converter;
- AudioStream *_stream;
-};
-
-#pragma mark -
-#pragma mark --- Mixer ---
-#pragma mark -
-
-
-MixerImpl::MixerImpl(OSystem *system, uint sampleRate)
- : _syst(system), _sampleRate(sampleRate), _mixerReady(false), _handleSeed(0) {
-
- assert(sampleRate > 0);
-
- int i;
-
- for (i = 0; i < ARRAYSIZE(_volumeForSoundType); i++)
- _volumeForSoundType[i] = kMaxMixerVolume;
-
- for (i = 0; i != NUM_CHANNELS; i++)
- _channels[i] = 0;
-}
-
-MixerImpl::~MixerImpl() {
- for (int i = 0; i != NUM_CHANNELS; i++)
- delete _channels[i];
-}
-
-void MixerImpl::setReady(bool ready) {
- _mixerReady = ready;
-}
-
-uint MixerImpl::getOutputRate() const {
- return _sampleRate;
-}
-
-void MixerImpl::insertChannel(SoundHandle *handle, Channel *chan) {
- int index = -1;
- for (int i = 0; i != NUM_CHANNELS; i++) {
- if (_channels[i] == 0) {
- index = i;
- break;
- }
- }
- if (index == -1) {
- warning("MixerImpl::out of mixer slots");
- delete chan;
- return;
- }
-
- _channels[index] = chan;
-
- SoundHandle chanHandle;
- chanHandle._val = index + (_handleSeed * NUM_CHANNELS);
-
- chan->setHandle(chanHandle);
- _handleSeed++;
- if (handle)
- *handle = chanHandle;
-}
-
-void MixerImpl::playStream(
- SoundType type,
- SoundHandle *handle,
- AudioStream *stream,
- int id, byte volume, int8 balance,
- DisposeAfterUse::Flag autofreeStream,
- bool permanent,
- bool reverseStereo) {
- Common::StackLock lock(_mutex);
-
- if (stream == 0) {
- warning("stream is 0");
- return;
- }
-
-
- assert(_mixerReady);
-
- // Prevent duplicate sounds
- if (id != -1) {
- for (int i = 0; i != NUM_CHANNELS; i++)
- if (_channels[i] != 0 && _channels[i]->getId() == id) {
- // Delete the stream if were asked to auto-dispose it.
- // Note: This could cause trouble if the client code does not
- // yet expect the stream to be gone. The primary example to
- // keep in mind here is QueuingAudioStream.
- // Thus, as a quick rule of thumb, you should never, ever,
- // try to play QueuingAudioStreams with a sound id.
- if (autofreeStream == DisposeAfterUse::YES)
- delete stream;
- return;
- }
- }
-
-#ifdef AUDIO_REVERSE_STEREO
- reverseStereo = !reverseStereo;
-#endif
-
- // Create the channel
- Channel *chan = new Channel(this, type, stream, autofreeStream, reverseStereo, id, permanent);
- chan->setVolume(volume);
- chan->setBalance(balance);
- insertChannel(handle, chan);
-}
-
-void MixerImpl::mixCallback(byte *samples, uint len) {
- assert(samples);
-
- Common::StackLock lock(_mutex);
-
- int16 *buf = (int16 *)samples;
- len >>= 2;
-
- // Since the mixer callback has been called, the mixer must be ready...
- _mixerReady = true;
-
- // zero the buf
- memset(buf, 0, 2 * len * sizeof(int16));
-
- // mix all channels
- for (int i = 0; i != NUM_CHANNELS; i++)
- if (_channels[i]) {
- if (_channels[i]->isFinished()) {
- delete _channels[i];
- _channels[i] = 0;
- } else if (!_channels[i]->isPaused())
- _channels[i]->mix(buf, len);
- }
-}
-
-void MixerImpl::stopAll() {
- Common::StackLock lock(_mutex);
- for (int i = 0; i != NUM_CHANNELS; i++) {
- if (_channels[i] != 0 && !_channels[i]->isPermanent()) {
- delete _channels[i];
- _channels[i] = 0;
- }
- }
-}
-
-void MixerImpl::stopID(int id) {
- Common::StackLock lock(_mutex);
- for (int i = 0; i != NUM_CHANNELS; i++) {
- if (_channels[i] != 0 && _channels[i]->getId() == id) {
- delete _channels[i];
- _channels[i] = 0;
- }
- }
-}
-
-void MixerImpl::stopHandle(SoundHandle handle) {
- Common::StackLock lock(_mutex);
-
- // Simply ignore stop requests for handles of sounds that already terminated
- const int index = handle._val % NUM_CHANNELS;
- if (!_channels[index] || _channels[index]->getHandle()._val != handle._val)
- return;
-
- delete _channels[index];
- _channels[index] = 0;
-}
-
-void MixerImpl::setChannelVolume(SoundHandle handle, byte volume) {
- Common::StackLock lock(_mutex);
-
- const int index = handle._val % NUM_CHANNELS;
- if (!_channels[index] || _channels[index]->getHandle()._val != handle._val)
- return;
-
- _channels[index]->setVolume(volume);
-}
-
-void MixerImpl::setChannelBalance(SoundHandle handle, int8 balance) {
- Common::StackLock lock(_mutex);
-
- const int index = handle._val % NUM_CHANNELS;
- if (!_channels[index] || _channels[index]->getHandle()._val != handle._val)
- return;
-
- _channels[index]->setBalance(balance);
-}
-
-uint32 MixerImpl::getSoundElapsedTime(SoundHandle handle) {
- return getElapsedTime(handle).msecs();
-}
-
-Timestamp MixerImpl::getElapsedTime(SoundHandle handle) {
- Common::StackLock lock(_mutex);
-
- const int index = handle._val % NUM_CHANNELS;
- if (!_channels[index] || _channels[index]->getHandle()._val != handle._val)
- return Timestamp(0, _sampleRate);
-
- return _channels[index]->getElapsedTime();
-}
-
-void MixerImpl::pauseAll(bool paused) {
- Common::StackLock lock(_mutex);
- for (int i = 0; i != NUM_CHANNELS; i++) {
- if (_channels[i] != 0) {
- _channels[i]->pause(paused);
- }
- }
-}
-
-void MixerImpl::pauseID(int id, bool paused) {
- Common::StackLock lock(_mutex);
- for (int i = 0; i != NUM_CHANNELS; i++) {
- if (_channels[i] != 0 && _channels[i]->getId() == id) {
- _channels[i]->pause(paused);
- return;
- }
- }
-}
-
-void MixerImpl::pauseHandle(SoundHandle handle, bool paused) {
- Common::StackLock lock(_mutex);
-
- // Simply ignore (un)pause requests for sounds that already terminated
- const int index = handle._val % NUM_CHANNELS;
- if (!_channels[index] || _channels[index]->getHandle()._val != handle._val)
- return;
-
- _channels[index]->pause(paused);
-}
-
-bool MixerImpl::isSoundIDActive(int id) {
- Common::StackLock lock(_mutex);
- for (int i = 0; i != NUM_CHANNELS; i++)
- if (_channels[i] && _channels[i]->getId() == id)
- return true;
- return false;
-}
-
-int MixerImpl::getSoundID(SoundHandle handle) {
- Common::StackLock lock(_mutex);
- const int index = handle._val % NUM_CHANNELS;
- if (_channels[index] && _channels[index]->getHandle()._val == handle._val)
- return _channels[index]->getId();
- return 0;
-}
-
-bool MixerImpl::isSoundHandleActive(SoundHandle handle) {
- Common::StackLock lock(_mutex);
- const int index = handle._val % NUM_CHANNELS;
- return _channels[index] && _channels[index]->getHandle()._val == handle._val;
-}
-
-bool MixerImpl::hasActiveChannelOfType(SoundType type) {
- Common::StackLock lock(_mutex);
- for (int i = 0; i != NUM_CHANNELS; i++)
- if (_channels[i] && _channels[i]->getType() == type)
- return true;
- return false;
-}
-
-void MixerImpl::setVolumeForSoundType(SoundType type, int volume) {
- assert(0 <= type && type < ARRAYSIZE(_volumeForSoundType));
-
- // Check range
- if (volume > kMaxMixerVolume)
- volume = kMaxMixerVolume;
- else if (volume < 0)
- volume = 0;
-
- // TODO: Maybe we should do logarithmic (not linear) volume
- // scaling? See also Player_V2::setMasterVolume
-
- Common::StackLock lock(_mutex);
- _volumeForSoundType[type] = volume;
-
- for (int i = 0; i != NUM_CHANNELS; ++i) {
- if (_channels[i] && _channels[i]->getType() == type)
- _channels[i]->notifyGlobalVolChange();
- }
-}
-
-int MixerImpl::getVolumeForSoundType(SoundType type) const {
- assert(0 <= type && type < ARRAYSIZE(_volumeForSoundType));
-
- return _volumeForSoundType[type];
-}
-
-
-#pragma mark -
-#pragma mark --- Channel implementations ---
-#pragma mark -
-
-Channel::Channel(Mixer *mixer, Mixer::SoundType type, AudioStream *stream,
- DisposeAfterUse::Flag autofreeStream, bool reverseStereo, int id, bool permanent)
- : _type(type), _mixer(mixer), _id(id), _permanent(permanent), _volume(Mixer::kMaxChannelVolume),
- _balance(0), _pauseLevel(0), _samplesConsumed(0), _samplesDecoded(0), _mixerTimeStamp(0),
- _pauseStartTime(0), _pauseTime(0), _autofreeStream(autofreeStream), _converter(0),
- _stream(stream) {
- assert(mixer);
- assert(stream);
-
- // Get a rate converter instance
- _converter = makeRateConverter(_stream->getRate(), mixer->getOutputRate(), _stream->isStereo(), reverseStereo);
-}
-
-Channel::~Channel() {
- delete _converter;
- if (_autofreeStream == DisposeAfterUse::YES)
- delete _stream;
-}
-
-void Channel::setVolume(const byte volume) {
- _volume = volume;
- updateChannelVolumes();
-}
-
-void Channel::setBalance(const int8 balance) {
- _balance = balance;
- updateChannelVolumes();
-}
-
-void Channel::updateChannelVolumes() {
- // From the channel balance/volume and the global volume, we compute
- // the effective volume for the left and right channel. Note the
- // slightly odd divisor: the 255 reflects the fact that the maximal
- // value for _volume is 255, while the 127 is there because the
- // balance value ranges from -127 to 127. The mixer (music/sound)
- // volume is in the range 0 - kMaxMixerVolume.
- // Hence, the vol_l/vol_r values will be in that range, too
-
- int vol = _mixer->getVolumeForSoundType(_type) * _volume;
-
- if (_balance == 0) {
- _volL = vol / Mixer::kMaxChannelVolume;
- _volR = vol / Mixer::kMaxChannelVolume;
- } else if (_balance < 0) {
- _volL = vol / Mixer::kMaxChannelVolume;
- _volR = ((127 + _balance) * vol) / (Mixer::kMaxChannelVolume * 127);
- } else {
- _volL = ((127 - _balance) * vol) / (Mixer::kMaxChannelVolume * 127);
- _volR = vol / Mixer::kMaxChannelVolume;
- }
-}
-
-void Channel::pause(bool paused) {
- //assert((paused && _pauseLevel >= 0) || (!paused && _pauseLevel));
-
- if (paused) {
- _pauseLevel++;
-
- if (_pauseLevel == 1)
- _pauseStartTime = g_system->getMillis();
- } else if (_pauseLevel > 0) {
- _pauseLevel--;
-
- if (!_pauseLevel) {
- _pauseTime = (g_system->getMillis() - _pauseStartTime);
- _pauseStartTime = 0;
- }
- }
-}
-
-Timestamp Channel::getElapsedTime() {
- const uint32 rate = _mixer->getOutputRate();
- uint32 delta = 0;
-
- Audio::Timestamp ts(0, rate);
-
- if (_mixerTimeStamp == 0)
- return ts;
-
- if (isPaused())
- delta = _pauseStartTime - _mixerTimeStamp;
- else
- delta = g_system->getMillis() - _mixerTimeStamp - _pauseTime;
-
- // Convert the number of samples into a time duration.
-
- ts = ts.addFrames(_samplesConsumed);
- ts = ts.addMsecs(delta);
-
- // In theory it would seem like a good idea to limit the approximation
- // so that it never exceeds the theoretical upper bound set by
- // _samplesDecoded. Meanwhile, back in the real world, doing so makes
- // the Broken Sword cutscenes noticeably jerkier. I guess the mixer
- // isn't invoked at the regular intervals that I first imagined.
-
- return ts;
-}
-
-void Channel::mix(int16 *data, uint len) {
- assert(_stream);
-
- if (_stream->endOfData()) {
- // TODO: call drain method
- } else {
- assert(_converter);
-
- _samplesConsumed = _samplesDecoded;
- _mixerTimeStamp = g_system->getMillis();
- _pauseTime = 0;
- _samplesDecoded += _converter->flow(*_stream, data, len, _volL, _volR);
- }
-}
-
-} // End of namespace Audio
diff --git a/sound/mixer.h b/sound/mixer.h
deleted file mode 100644
index b2accc550d..0000000000
--- a/sound/mixer.h
+++ /dev/null
@@ -1,265 +0,0 @@
-/* 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_MIXER_H
-#define SOUND_MIXER_H
-
-#include "common/types.h"
-#include "common/mutex.h"
-#include "common/noncopyable.h"
-
-#include "sound/timestamp.h"
-
-class OSystem;
-
-
-namespace Audio {
-
-class AudioStream;
-class Channel;
-class Mixer;
-class MixerImpl;
-
-/**
- * A SoundHandle instances corresponds to a specific sound
- * being played via the mixer. It can be used to control that
- * sound (pause it, stop it, etc.).
- * @see The Mixer class
- */
-class SoundHandle {
- friend class Channel;
- friend class MixerImpl;
- uint32 _val;
-public:
- inline SoundHandle() : _val(0xFFFFFFFF) {}
-};
-
-/**
- * The main audio mixer handles mixing of an arbitrary number of
- * audio streams (in the form of AudioStream instances).
- */
-class Mixer : Common::NonCopyable {
-public:
- enum SoundType {
- kPlainSoundType = 0,
-
- kMusicSoundType = 1,
- kSFXSoundType = 2,
- kSpeechSoundType = 3
- };
-
- enum {
- kMaxChannelVolume = 255,
- kMaxMixerVolume = 256
- };
-
-public:
- Mixer() {}
- virtual ~Mixer() {}
-
-
-
- /**
- * Is the mixer ready and setup? This may not be the case on systems which
- * don't support digital sound output. In that case, the mixer proc may
- * never be called. That in turn can cause breakage in games which try to
- * sync with an audio stream. In particular, the AdLib MIDI emulation...
- *
- * @return whether the mixer is ready and setup
- *
- * @todo get rid of this?
- */
- virtual bool isReady() const = 0;
-
-
- /**
- * Start playing the given audio stream.
- *
- * Note that the sound id assigned below is unique. At most one stream
- * with a given id can play at any given time. Trying to play a sound
- * with an id that is already in use causes the new sound to be not played.
- *
- * @param type the type (voice/sfx/music) of the stream
- * @param handle a SoundHandle which can be used to reference and control
- * the stream via suitable mixer methods
- * @param stream the actual AudioStream to be played
- * @param id a unique id assigned to this stream
- * @param volume the volume with which to play the sound, ranging from 0 to 255
- * @param balance the balance with which to play the sound, ranging from -128 to 127
- * @param autofreeStream a flag indicating whether the stream should be
- * freed after playback finished
- * @param permanent a flag indicating whether a plain stopAll call should
- * not stop this particular stream
- * @param reverseStereo a flag indicating whether left and right channels shall be swapped
- */
- virtual void playStream(
- SoundType type,
- SoundHandle *handle,
- AudioStream *stream,
- int id = -1,
- byte volume = kMaxChannelVolume,
- int8 balance = 0,
- DisposeAfterUse::Flag autofreeStream = DisposeAfterUse::YES,
- bool permanent = false,
- bool reverseStereo = false) = 0;
-
- /**
- * Stop all currently playing sounds.
- */
- virtual void stopAll() = 0;
-
- /**
- * Stop playing the sound with given ID.
- *
- * @param id the ID of the sound to affect
- */
- virtual void stopID(int id) = 0;
-
- /**
- * Stop playing the sound corresponding to the given handle.
- *
- * @param handle the sound to affect
- */
- virtual void stopHandle(SoundHandle handle) = 0;
-
-
-
- /**
- * Pause/unpause all sounds, including all regular and permanent
- * channels
- *
- * @param paused true to pause everything, false to unpause
- */
- virtual void pauseAll(bool paused) = 0;
-
- /**
- * Pause/unpause the sound with the given ID.
- *
- * @param id the ID of the sound to affect
- * @param paused true to pause the sound, false to unpause it
- */
- virtual void pauseID(int id, bool paused) = 0;
-
- /**
- * Pause/unpause the sound corresponding to the given handle.
- *
- * @param handle the sound to affect
- * @param paused true to pause the sound, false to unpause it
- */
- virtual void pauseHandle(SoundHandle handle, bool paused) = 0;
-
-
-
- /**
- * Check if a sound with the given ID is active.
- *
- * @param id the ID of the sound to query
- * @return true if the sound is active
- */
- virtual bool isSoundIDActive(int id) = 0;
-
- /**
- * Get the sound ID of handle sound
- *
- * @param handle sound to query
- * @return sound ID if active
- */
- virtual int getSoundID(SoundHandle handle) = 0;
-
- /**
- * Check if a sound with the given handle is active.
- *
- * @param handle sound to query
- * @return true if the sound is active
- */
- virtual bool isSoundHandleActive(SoundHandle handle) = 0;
-
-
-
- /**
- * Set the channel volume for the given handle.
- *
- * @param handle the sound to affect
- * @param volume the new channel volume (0 - kMaxChannelVolume)
- */
- virtual void setChannelVolume(SoundHandle handle, byte volume) = 0;
-
- /**
- * Set the channel balance for the given handle.
- *
- * @param handle the sound to affect
- * @param balance the new channel balance:
- * (-127 ... 0 ... 127) corresponds to (left ... center ... right)
- */
- virtual void setChannelBalance(SoundHandle handle, int8 balance) = 0;
-
- /**
- * Get approximation of for how long the channel has been playing.
- */
- virtual uint32 getSoundElapsedTime(SoundHandle handle) = 0;
-
- /**
- * Get approximation of for how long the channel has been playing.
- */
- virtual Timestamp getElapsedTime(SoundHandle handle) = 0;
-
- /**
- * Check whether any channel of the given sound type is active.
- * For example, this can be used to check whether any SFX sound
- * is currently playing, by checking for type kSFXSoundType.
- *
- * @param type the sound type to look for
- * @return true if any channels of the specified type are active.
- */
- virtual bool hasActiveChannelOfType(SoundType type) = 0;
-
- /**
- * Set the volume for the given sound type.
- *
- * @param type the sound type
- * @param volume the new global volume, 0 - kMaxMixerVolume
- */
- virtual void setVolumeForSoundType(SoundType type, int volume) = 0;
-
- /**
- * Query the global volume.
- *
- * @param type the sound type
- * @return the global music volume, 0 - kMaxMixerVolume
- */
- virtual int getVolumeForSoundType(SoundType type) const = 0;
-
- /**
- * Query the system's audio output sample rate.
- *
- * @return the output sample rate in Hz
- */
- virtual uint getOutputRate() const = 0;
-};
-
-
-} // End of namespace Audio
-
-#endif
diff --git a/sound/mixer_intern.h b/sound/mixer_intern.h
deleted file mode 100644
index 014be7abf2..0000000000
--- a/sound/mixer_intern.h
+++ /dev/null
@@ -1,135 +0,0 @@
-/* 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_MIXER_INTERN_H
-#define SOUND_MIXER_INTERN_H
-
-#include "common/scummsys.h"
-#include "common/mutex.h"
-#include "sound/mixer.h"
-
-namespace Audio {
-
-/**
- * The (default) implementation of the ScummVM audio mixing subsystem.
- *
- * Backends are responsible for allocating (and later releasing) an instance
- * of this class, which engines can access via OSystem::getMixer().
- *
- * Initialisation of instances of this class usually happens as follows:
- * 1) Creat a new Audio::MixerImpl instance.
- * 2) Set the hardware output sample rate via the setSampleRate() method.
- * 3) Hook up the mixCallback() in a suitable audio processing thread/callback.
- * 4) Change the mixer into ready mode via setReady(true).
- * 5) Start audio processing (e.g. by resuming the audio thread, if applicable).
- *
- * In the future, we might make it possible for backends to provide
- * (partial) alternative implementations of the mixer, e.g. to make
- * better use of native sound mixing support on low-end devices.
- *
- * @see OSystem::getMixer()
- */
-class MixerImpl : public Mixer {
-private:
- enum {
- NUM_CHANNELS = 16
- };
-
- OSystem *_syst;
- Common::Mutex _mutex;
-
- const uint _sampleRate;
- bool _mixerReady;
- uint32 _handleSeed;
-
- int _volumeForSoundType[4];
- Channel *_channels[NUM_CHANNELS];
-
-
-public:
-
- MixerImpl(OSystem *system, uint sampleRate);
- ~MixerImpl();
-
- virtual bool isReady() const { return _mixerReady; }
-
- virtual void playStream(
- SoundType type,
- SoundHandle *handle,
- AudioStream *input,
- int id, byte volume, int8 balance,
- DisposeAfterUse::Flag autofreeStream,
- bool permanent,
- bool reverseStereo);
-
- virtual void stopAll();
- virtual void stopID(int id);
- virtual void stopHandle(SoundHandle handle);
-
- virtual void pauseAll(bool paused);
- virtual void pauseID(int id, bool paused);
- virtual void pauseHandle(SoundHandle handle, bool paused);
-
- virtual bool isSoundIDActive(int id);
- virtual int getSoundID(SoundHandle handle);
-
- virtual bool isSoundHandleActive(SoundHandle handle);
-
- virtual void setChannelVolume(SoundHandle handle, byte volume);
- virtual void setChannelBalance(SoundHandle handle, int8 balance);
-
- virtual uint32 getSoundElapsedTime(SoundHandle handle);
- virtual Timestamp getElapsedTime(SoundHandle handle);
-
- virtual bool hasActiveChannelOfType(SoundType type);
-
- virtual void setVolumeForSoundType(SoundType type, int volume);
- virtual int getVolumeForSoundType(SoundType type) const;
-
- virtual uint getOutputRate() const;
-
-protected:
- void insertChannel(SoundHandle *handle, Channel *chan);
-
-public:
- /**
- * The mixer callback function, to be called at regular intervals by
- * the backend (e.g. from an audio mixing thread). All the actual mixing
- * work is done from here.
- */
- void mixCallback(byte *samples, uint len);
-
- /**
- * Set the internal 'is ready' flag of the mixer.
- * Backends should invoke Mixer::setReady(true) once initialisation of
- * their audio system has been completed.
- */
- void setReady(bool ready);
-};
-
-
-} // End of namespace Audio
-
-#endif
diff --git a/sound/mods/infogrames.cpp b/sound/mods/infogrames.cpp
deleted file mode 100644
index 048872d4a0..0000000000
--- a/sound/mods/infogrames.cpp
+++ /dev/null
@@ -1,470 +0,0 @@
-/* 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/mods/infogrames.h"
-#include "common/endian.h"
-#include "common/file.h"
-#include "common/memstream.h"
-
-namespace Audio {
-
-Infogrames::Instruments::Instruments() {
- init();
-}
-
-Infogrames::Instruments::~Instruments() {
- delete[] _sampleData;
-}
-
-void Infogrames::Instruments::init() {
- int i;
-
- for (i = 0; i < 32; i++) {
- _samples[i].data = 0;
- _samples[i].dataRepeat = 0;
- _samples[i].length = 0;
- _samples[i].lengthRepeat = 0;
- }
- _count = 0;
- _sampleData = 0;
-}
-
-bool Infogrames::Instruments::load(const char *ins) {
- Common::File f;
-
- if (f.open(ins))
- return load(f);
- return false;
-}
-
-bool Infogrames::Instruments::load(Common::SeekableReadStream &ins) {
- int i;
- int32 fsize;
- int32 offset[32];
- int32 offsetRepeat[32];
- int32 dataOffset;
-
- unload();
-
- fsize = ins.readUint32BE();
- dataOffset = fsize;
- for (i = 0; (i < 32) && !ins.eos(); i++) {
- offset[i] = ins.readUint32BE();
- offsetRepeat[i] = ins.readUint32BE();
- if ((offset[i] > fsize) || (offsetRepeat[i] > fsize) ||
- (offset[i] < (ins.pos() + 4)) ||
- (offsetRepeat[i] < (ins.pos() + 4))) {
- // Definitely no real entry anymore
- ins.seek(-8, SEEK_CUR);
- break;
- }
-
- dataOffset = MIN(dataOffset, MIN(offset[i], offsetRepeat[i]));
- ins.skip(4); // Unknown
- _samples[i].length = ins.readUint16BE() * 2;
- _samples[i].lengthRepeat = ins.readUint16BE() * 2;
- }
-
- if (dataOffset >= fsize)
- return false;
-
- _count = i;
- _sampleData = new int8[fsize - dataOffset];
- ins.seek(dataOffset + 4);
- ins.read(_sampleData, fsize - dataOffset);
-
- for (i--; i >= 0; i--) {
- _samples[i].data = _sampleData + (offset[i] - dataOffset);
- _samples[i].dataRepeat = _sampleData + (offsetRepeat[i] - dataOffset);
- }
-
- return true;
-}
-
-void Infogrames::Instruments::unload() {
- delete[] _sampleData;
- init();
-}
-
-const uint8 Infogrames::tickCount[] =
- {2, 3, 4, 6, 8, 12, 16, 24, 32, 48, 64, 96};
-const uint16 Infogrames::periods[] =
- {0x6ACC, 0x64CC, 0x5F25, 0x59CE, 0x54C3, 0x5003, 0x4B86, 0x4747, 0x4346,
- 0x3F8B, 0x3BF3, 0x3892, 0x3568, 0x3269, 0x2F93, 0x2CEA, 0x2A66, 0x2801,
- 0x2566, 0x23A5, 0x21AF, 0x1FC4, 0x1DFE, 0x1C4E, 0x1ABC, 0x1936, 0x17CC,
- 0x1676, 0x1533, 0x1401, 0x12E4, 0x11D5, 0x10D4, 0x0FE3, 0x0EFE, 0x0E26,
- 0x0D5B, 0x0C9B, 0x0BE5, 0x0B3B, 0x0A9B, 0x0A02, 0x0972, 0x08E9, 0x0869,
- 0x07F1, 0x077F, 0x0713, 0x06AD, 0x064D, 0x05F2, 0x059D, 0x054D, 0x0500,
- 0x04B8, 0x0475, 0x0435, 0x03F8, 0x03BF, 0x038A, 0x0356, 0x0326, 0x02F9,
- 0x02CF, 0x02A6, 0x0280, 0x025C, 0x023A, 0x021A, 0x01FC, 0x01E0, 0x01C5,
- 0x01AB, 0x0193, 0x017D, 0x0167, 0x0153, 0x0140, 0x012E, 0x011D, 0x010D,
- 0x00FE, 0x00F0, 0x00E2, 0x00D6, 0x00CA, 0x00BE, 0x00B4, 0x00AA, 0x00A0,
- 0x0097, 0x008F, 0x0087, 0x007F, 0x0078, 0x0070, 0x0060, 0x0050, 0x0040,
- 0x0030, 0x0020, 0x0010, 0x0000, 0x0000, 0x0020, 0x2020, 0x2020, 0x2020,
- 0x2020, 0x3030, 0x3030, 0x3020, 0x2020, 0x2020, 0x2020, 0x2020, 0x2020,
- 0x2020, 0x2020, 0x2020, 0x2090, 0x4040, 0x4040, 0x4040, 0x4040, 0x4040,
- 0x4040, 0x4040, 0x400C, 0x0C0C, 0x0C0C, 0x0C0C, 0x0C0C, 0x0C40, 0x4040,
- 0x4040, 0x4040, 0x0909, 0x0909, 0x0909, 0x0101, 0x0101, 0x0101, 0x0101,
- 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x4040, 0x4040, 0x4040,
- 0x0A0A, 0x0A0A, 0x0A0A, 0x0202, 0x0202, 0x0202, 0x0202, 0x0202, 0x0202,
- 0x0202, 0x0202, 0x0202, 0x0202, 0x4040, 0x4040, 0x2000};
-
-Infogrames::Infogrames(Instruments &ins, bool stereo, int rate,
- int interruptFreq) : Paula(stereo, rate, interruptFreq) {
- _instruments = &ins;
- _data = 0;
- _repCount = -1;
-
- reset();
-}
-
-Infogrames::~Infogrames() {
- delete[] _data;
-}
-
-void Infogrames::init() {
- int i;
-
- _volume = 0;
- _period = 0;
- _sample = 0;
- _speedCounter = _speed;
-
- for (i = 0; i < 4; i++) {
- _chn[i].cmds = 0;
- _chn[i].cmdBlocks = 0;
- _chn[i].volSlide.finetuneNeg = 0;
- _chn[i].volSlide.finetunePos = 0;
- _chn[i].volSlide.data = 0;
- _chn[i].volSlide.amount = 0;
- _chn[i].volSlide.dataOffset = 0;
- _chn[i].volSlide.flags = 0;
- _chn[i].volSlide.curDelay1 = 0;
- _chn[i].volSlide.curDelay2 = 0;
- _chn[i].periodSlide.finetuneNeg = 0;
- _chn[i].periodSlide.finetunePos = 0;
- _chn[i].periodSlide.data = 0;
- _chn[i].periodSlide.amount = 0;
- _chn[i].periodSlide.dataOffset = 0;
- _chn[i].periodSlide.flags = 0;
- _chn[i].periodSlide.curDelay1 = 0;
- _chn[i].periodSlide.curDelay2 = 0;
- _chn[i].period = 0;
- _chn[i].flags = 0x81;
- _chn[i].ticks = 0;
- _chn[i].tickCount = 0;
- _chn[i].periodMod = 0;
- }
-
- _end = (_data == 0);
-}
-
-void Infogrames::reset() {
- int i;
-
- stopPlay();
- init();
-
- _volSlideBlocks = 0;
- _periodSlideBlocks = 0;
- _subSong = 0;
- _cmdBlocks = 0;
- _speedCounter = 0;
- _speed = 0;
-
- for (i = 0; i < 4; i++)
- _chn[i].cmdBlockIndices = 0;
-}
-
-bool Infogrames::load(const char *dum) {
- Common::File f;
-
- if (f.open(dum))
- return load(f);
- return false;
-}
-
-bool Infogrames::load(Common::SeekableReadStream &dum) {
- int subSong = 0;
- int i;
- uint32 size;
-
- size = dum.size();
- if (size < 20)
- return false;
-
- _data = new uint8[size];
- dum.seek(0);
- dum.read(_data, size);
-
- Common::MemoryReadStream dataStr(_data, size);
-
- dataStr.seek(subSong * 2);
- dataStr.seek(dataStr.readUint16BE());
- _subSong = _data + dataStr.pos();
- if (_subSong > (_data + size))
- return false;
-
- _speedCounter = dataStr.readUint16BE();
- _speed = _speedCounter;
- _volSlideBlocks = _subSong + dataStr.readUint16BE();
- _periodSlideBlocks = _subSong + dataStr.readUint16BE();
- for (i = 0; i < 4; i++) {
- _chn[i].cmdBlockIndices = _subSong + dataStr.readUint16BE();
- _chn[i].flags = 0x81;
- }
- _cmdBlocks = _data + dataStr.pos() + 2;
-
- if ((_volSlideBlocks > (_data + size)) ||
- (_periodSlideBlocks > (_data + size)) ||
- (_chn[0].cmdBlockIndices > (_data + size)) ||
- (_chn[1].cmdBlockIndices > (_data + size)) ||
- (_chn[2].cmdBlockIndices > (_data + size)) ||
- (_chn[3].cmdBlockIndices > (_data + size)) ||
- (_cmdBlocks > (_data + size)))
- return false;
-
- startPaula();
- return true;
-}
-
-void Infogrames::unload() {
- stopPlay();
-
- delete[] _data;
- _data = 0;
-
- clearVoices();
- reset();
-}
-
-void Infogrames::getNextSample(Channel &chn) {
- byte *data;
- byte cmdBlock = 0;
- uint16 cmd;
- bool cont = false;
-
- if (chn.flags & 64)
- return;
-
- if (chn.flags & 1) {
- chn.flags &= ~1;
- chn.cmdBlocks = chn.cmdBlockIndices;
- } else {
- chn.flags &= ~1;
- if (_speedCounter == 0)
- chn.ticks--;
- if (chn.ticks != 0) {
- _volume = MAX((int16) 0, tune(chn.volSlide, 0));
- _period = tune(chn.periodSlide, chn.period);
- return;
- } else {
- chn.ticks = chn.tickCount;
- cont = true;
- }
- }
-
- while (1) {
- while (cont || ((cmdBlock = *chn.cmdBlocks) != 0xFF)) {
- if (!cont) {
- chn.cmdBlocks++;
- chn.cmds = _subSong +
- READ_BE_UINT16(_cmdBlocks + (cmdBlock * 2));
- } else
- cont = false;
- while ((cmd = *chn.cmds) != 0xFF) {
- chn.cmds++;
- if (cmd & 128)
- {
- switch (cmd & 0xE0) {
- case 0x80: // 100xxxxx - Set ticks
- chn.ticks = tickCount[cmd & 0xF];
- chn.tickCount = tickCount[cmd & 0xF];
- break;
- case 0xA0: // 101xxxxx - Set sample
- _sample = cmd & 0x1F;
- break;
- case 0xC0: // 110xxxxx - Set volume slide/finetune
- data = _volSlideBlocks + (cmd & 0x1F) * 13;
- chn.volSlide.flags = (*data & 0x80) | 1;
- chn.volSlide.amount = *data++ & 0x7F;
- chn.volSlide.data = data;
- chn.volSlide.dataOffset = 0;
- chn.volSlide.finetunePos = 0;
- chn.volSlide.finetuneNeg = 0;
- chn.volSlide.curDelay1 = 0;
- chn.volSlide.curDelay2 = 0;
- break;
- case 0xE0: // 111xxxxx - Extended
- switch (cmd & 0x1F) {
- case 0: // Set period modifier
- chn.periodMod = (int8) *chn.cmds++;
- break;
- case 1: // Set continuous period slide
- chn.periodSlide.data =
- _periodSlideBlocks + *chn.cmds++ * 13 + 1;
- chn.periodSlide.amount = 0;
- chn.periodSlide.dataOffset = 0;
- chn.periodSlide.finetunePos = 0;
- chn.periodSlide.finetuneNeg = 0;
- chn.periodSlide.curDelay1 = 0;
- chn.periodSlide.curDelay2 = 0;
- chn.periodSlide.flags = 0x81;
- break;
- case 2: // Set non-continuous period slide
- chn.periodSlide.data =
- _periodSlideBlocks + *chn.cmds++ * 13 + 1;
- chn.periodSlide.amount = 0;
- chn.periodSlide.dataOffset = 0;
- chn.periodSlide.finetunePos = 0;
- chn.periodSlide.finetuneNeg = 0;
- chn.periodSlide.curDelay1 = 0;
- chn.periodSlide.curDelay2 = 0;
- chn.periodSlide.flags = 1;
- break;
- case 3: // NOP
- break;
- default:
- warning("Unknown Infogrames command: %X", cmd);
- }
- break;
- }
- } else { // 0xxxxxxx - Set period
- if (cmd != 0)
- cmd += chn.periodMod;
- chn.period = periods[cmd];
- chn.volSlide.dataOffset = 0;
- chn.volSlide.finetunePos = 0;
- chn.volSlide.finetuneNeg = 0;
- chn.volSlide.curDelay1 = 0;
- chn.volSlide.curDelay2 = 0;
- chn.volSlide.flags |= 1;
- chn.volSlide.flags &= ~4;
- chn.periodSlide.dataOffset = 0;
- chn.periodSlide.finetunePos = 0;
- chn.periodSlide.finetuneNeg = 0;
- chn.periodSlide.curDelay1 = 0;
- chn.periodSlide.curDelay2 = 0;
- chn.periodSlide.flags |= 1;
- chn.periodSlide.flags &= ~4;
- _volume = MAX((int16) 0, tune(chn.volSlide, 0));
- _period = tune(chn.periodSlide, chn.period);
- return;
- }
- }
- }
- if (!(chn.flags & 32)) {
- chn.flags |= 0x40;
- _volume = 0;
- return;
- } else
- chn.cmdBlocks = chn.cmdBlockIndices;
- }
-}
-
-int16 Infogrames::tune(Slide &slide, int16 start) const {
- byte *data;
- uint8 off;
-
- data = slide.data + slide.dataOffset;
-
- if (slide.flags & 1)
- slide.finetunePos += (int8) data[1];
- slide.flags &= ~1;
-
- start += slide.finetunePos - slide.finetuneNeg;
- if (start < 0)
- start = 0;
-
- if (slide.flags & 4)
- return start;
-
- slide.curDelay1++;
- if (slide.curDelay1 != data[2])
- return start;
- slide.curDelay2++;
- slide.curDelay1 = 0;
- if (slide.curDelay2 == data[0]) {
- slide.curDelay2 = 0;
- off = slide.dataOffset + 3;
- if (off == 12) {
- if (slide.flags == 0) {
- slide.flags |= 4;
- return start;
- } else {
- slide.curDelay2 = 0;
- slide.finetuneNeg += slide.amount;
- off = 3;
- }
- }
- slide.dataOffset = off;
- }
- slide.flags |= 1;
- return start;
-}
-
-void Infogrames::interrupt() {
- int chn;
-
- if (!_data) {
- clearVoices();
- return;
- }
-
- _speedCounter--;
- _sample = 0xFF;
- for (chn = 0; chn < 4; chn++) {
- _volume = 0;
- _period = 0;
- getNextSample(_chn[chn]);
- setChannelVolume(chn, _volume);
- setChannelPeriod(chn, _period);
- if ((_sample != 0xFF) && (_sample < _instruments->_count)) {
- setChannelData(chn,
- _instruments->_samples[_sample].data,
- _instruments->_samples[_sample].dataRepeat,
- _instruments->_samples[_sample].length,
- _instruments->_samples[_sample].lengthRepeat);
- _sample = 0xFF;
- }
- }
- if (_speedCounter == 0)
- _speedCounter = _speed;
-
- // End reached?
- if ((_chn[0].flags & 64) && (_chn[1].flags & 64) &&
- (_chn[2].flags & 64) && (_chn[3].flags & 64)) {
- if (_repCount > 0) {
- _repCount--;
- init();
- } else if (_repCount != -1) {
- stopPaula();
- } else {
- init();
- }
- }
-}
-
-} // End of namespace Audio
diff --git a/sound/mods/infogrames.h b/sound/mods/infogrames.h
deleted file mode 100644
index 1f3d74f38b..0000000000
--- a/sound/mods/infogrames.h
+++ /dev/null
@@ -1,148 +0,0 @@
-/* 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$
- *
- */
-
-/**
- * @file
- * Sound decoder used in engines:
- * - gob
- */
-
-#ifndef SOUND_MODS_INFOGRAMES_H
-#define SOUND_MODS_INFOGRAMES_H
-
-#include "sound/mods/paula.h"
-#include "common/stream.h"
-
-namespace Audio {
-
-/** A player for the Infogrames/RobHubbard2 format */
-class Infogrames : public Paula {
-public:
- class Instruments {
- public:
- Instruments();
- template<typename T> Instruments(T ins) {
- init();
- bool result = load(ins);
- assert(result);
- }
- ~Instruments();
-
- bool load(Common::SeekableReadStream &ins);
- bool load(const char *ins);
- void unload();
-
- uint8 getCount() const { return _count; }
-
- protected:
- struct Sample {
- int8 *data;
- int8 *dataRepeat;
- uint32 length;
- uint32 lengthRepeat;
- } _samples[32];
-
- uint8 _count;
- int8 *_sampleData;
-
- void init();
-
- friend class Infogrames;
- };
-
- Infogrames(Instruments &ins, bool stereo = false, int rate = 44100,
- int interruptFreq = 0);
- ~Infogrames();
-
- Instruments *getInstruments() const { return _instruments; }
- bool getRepeating() const { return _repCount != 0; }
- void setRepeating (int32 repCount) { _repCount = repCount; }
-
- bool load(Common::SeekableReadStream &dum);
- bool load(const char *dum);
- void unload();
- void restart() {
- if (_data) {
- // Use the mutex here to ensure we do not call init()
- // while data is being read by the mixer thread.
- _mutex.lock();
- init();
- startPlay();
- _mutex.unlock();
- }
- }
-
-protected:
- Instruments *_instruments;
-
- static const uint8 tickCount[];
- static const uint16 periods[];
- byte *_data;
- int32 _repCount;
-
- byte *_subSong;
- byte *_cmdBlocks;
- byte *_volSlideBlocks;
- byte *_periodSlideBlocks;
- uint8 _speedCounter;
- uint8 _speed;
-
- uint16 _volume;
- int16 _period;
- uint8 _sample;
-
- struct Slide {
- byte *data;
- int8 amount;
- uint8 dataOffset;
- int16 finetuneNeg;
- int16 finetunePos;
- uint8 curDelay1;
- uint8 curDelay2;
- uint8 flags; // 0: Apply finetune modifier, 2: Don't slide, 7: Continuous
- };
- struct Channel {
- byte *cmdBlockIndices;
- byte *cmdBlocks;
- byte *cmds;
- uint8 ticks;
- uint8 tickCount;
- Slide volSlide;
- Slide periodSlide;
- int16 period;
- int8 periodMod;
- uint8 flags; // 0: Need init, 5: Loop cmdBlocks, 6: Ignore channel
- } _chn[4];
-
- void init();
- void reset();
- void getNextSample(Channel &chn);
- int16 tune(Slide &slide, int16 start) const;
- virtual void interrupt();
-};
-
-} // End of namespace Audio
-
-#endif
diff --git a/sound/mods/maxtrax.cpp b/sound/mods/maxtrax.cpp
deleted file mode 100644
index 08e73fb96a..0000000000
--- a/sound/mods/maxtrax.cpp
+++ /dev/null
@@ -1,1040 +0,0 @@
-/* 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 "common/scummsys.h"
-#include "common/endian.h"
-#include "common/stream.h"
-#include "common/util.h"
-#include "common/debug.h"
-
-#include "sound/mods/maxtrax.h"
-
-// test for engines using this class.
-#if defined(SOUND_MODS_MAXTRAX_H)
-
-namespace {
-
-enum { K_VALUE = 0x9fd77, PREF_PERIOD = 0x8fd77, PERIOD_LIMIT = 0x6f73d };
-enum { NO_BEND = 64 << 7, MAX_BEND_RANGE = 24 };
-
-int32 precalcNote(byte baseNote, int16 tune, byte octave) {
- return K_VALUE + 0x3C000 - ((baseNote << 14) + (tune << 11) / 3) / 3 - (octave << 16);
-}
-
-int32 calcVolumeDelta(int32 delta, uint16 time, uint16 vBlankFreq) {
- const int32 div = time * vBlankFreq;
- // div <= 1000 means time to small (or even 0)
- return (div <= 1000) ? delta : (1000 * delta) / div;
-}
-
-int32 calcTempo(const uint16 tempo, uint16 vBlankFreq) {
- return (int32)(((uint32)(tempo & 0xFFF0) << 8) / (uint16)(5 * vBlankFreq));
-}
-
-void nullFunc(int) {}
-
-// Function to calculate 2^x, where x is a fixedpoint number with 16 fraction bits
-// using exp would be more accurate and needs less space if mathlibrary is already linked
-// but this function should be faster and doesnt use floats
-#if 1
-inline uint32 pow2Fixed(int32 val) {
- static const uint16 tablePow2[] = {
- 0, 178, 356, 535, 714, 893, 1073, 1254, 1435, 1617, 1799, 1981, 2164, 2348, 2532, 2716,
- 2902, 3087, 3273, 3460, 3647, 3834, 4022, 4211, 4400, 4590, 4780, 4971, 5162, 5353, 5546, 5738,
- 5932, 6125, 6320, 6514, 6710, 6906, 7102, 7299, 7496, 7694, 7893, 8092, 8292, 8492, 8693, 8894,
- 9096, 9298, 9501, 9704, 9908, 10113, 10318, 10524, 10730, 10937, 11144, 11352, 11560, 11769, 11979, 12189,
- 12400, 12611, 12823, 13036, 13249, 13462, 13676, 13891, 14106, 14322, 14539, 14756, 14974, 15192, 15411, 15630,
- 15850, 16071, 16292, 16514, 16737, 16960, 17183, 17408, 17633, 17858, 18084, 18311, 18538, 18766, 18995, 19224,
- 19454, 19684, 19915, 20147, 20379, 20612, 20846, 21080, 21315, 21550, 21786, 22023, 22260, 22498, 22737, 22977,
- 23216, 23457, 23698, 23940, 24183, 24426, 24670, 24915, 25160, 25406, 25652, 25900, 26148, 26396, 26645, 26895,
- 27146, 27397, 27649, 27902, 28155, 28409, 28664, 28919, 29175, 29432, 29690, 29948, 30207, 30466, 30727, 30988,
- 31249, 31512, 31775, 32039, 32303, 32568, 32834, 33101, 33369, 33637, 33906, 34175, 34446, 34717, 34988, 35261,
- 35534, 35808, 36083, 36359, 36635, 36912, 37190, 37468, 37747, 38028, 38308, 38590, 38872, 39155, 39439, 39724,
- 40009, 40295, 40582, 40870, 41158, 41448, 41738, 42029, 42320, 42613, 42906, 43200, 43495, 43790, 44087, 44384,
- 44682, 44981, 45280, 45581, 45882, 46184, 46487, 46791, 47095, 47401, 47707, 48014, 48322, 48631, 48940, 49251,
- 49562, 49874, 50187, 50500, 50815, 51131, 51447, 51764, 52082, 52401, 52721, 53041, 53363, 53685, 54008, 54333,
- 54658, 54983, 55310, 55638, 55966, 56296, 56626, 56957, 57289, 57622, 57956, 58291, 58627, 58964, 59301, 59640,
- 59979, 60319, 60661, 61003, 61346, 61690, 62035, 62381, 62727, 63075, 63424, 63774, 64124, 64476, 64828, 65182,
- 0
- };
- const uint16 whole = val >> 16;
- const uint8 index = (uint8)(val >> 8);
- // calculate fractional part.
- const uint16 base = tablePow2[index];
- // linear interpolation and add 1.0
- uint32 exponent = ((uint32)(uint16)(tablePow2[index + 1] - base) * (uint8)val) + ((uint32)base << 8) + (1 << 24);
-
- if (whole < 24) {
- // shift away all but the last fractional bit which is used for rounding,
- // then round to nearest integer
- exponent = ((exponent >> (23 - whole)) + 1) >> 1;
- } else if (whole < 32) {
- // no need to round here
- exponent <<= whole - 24;
- } else if (val > 0) {
- // overflow
- exponent = 0xFFFFFFFF;
- } else {
- // negative integer, test if >= -0.5
- exponent = (val >= -0x8000) ? 1 : 0;
- }
- return exponent;
-}
-#else
-inline uint32 pow2Fixed(int32 val) {
- return (uint32)(expf((float)val * (float)(0.69314718055994530942 / (1 << 16))) + 0.5f);
-}
-#endif
-
-} // End of namespace
-
-namespace Audio {
-
-MaxTrax::MaxTrax(int rate, bool stereo, uint16 vBlankFreq, uint16 maxScores)
- : Paula(stereo, rate, rate / vBlankFreq),
- _patch(),
- _scores(),
- _numScores() {
- _playerCtx.maxScoreNum = maxScores;
- _playerCtx.vBlankFreq = vBlankFreq;
- _playerCtx.frameUnit = (uint16)((1000 << 8) / vBlankFreq);
- _playerCtx.scoreIndex = -1;
- _playerCtx.volume = 0x40;
-
- _playerCtx.tempo = 120;
- _playerCtx.tempoTime = 0;
- _playerCtx.filterOn = true;
- _playerCtx.syncCallBack = &nullFunc;
-
- resetPlayer();
- for (int i = 0; i < ARRAYSIZE(_channelCtx); ++i)
- _channelCtx[i].regParamNumber = 0;
-}
-
-MaxTrax::~MaxTrax() {
- stopMusic();
- freePatches();
- freeScores();
-}
-
-void MaxTrax::interrupt() {
- // a5 - maxtraxm a4 . globaldata
-
- // TODO
- // test for changes in shared struct and make changes
- // specifically all used channels get marked altered
-
- _playerCtx.ticks += _playerCtx.tickUnit;
- const int32 millis = _playerCtx.ticks >> 8; // d4
-
- for (int i = 0; i < ARRAYSIZE(_voiceCtx); ++i) {
- VoiceContext &voice = _voiceCtx[i];
- if (voice.stopEventTime >= 0) {
- assert(voice.channel);
- voice.stopEventTime -= (voice.channel < &_channelCtx[kNumChannels]) ? _playerCtx.tickUnit : _playerCtx.frameUnit;
- if (voice.stopEventTime <= 0 && voice.status > VoiceContext::kStatusRelease) {
- if ((voice.channel->flags & ChannelContext::kFlagDamper) != 0)
- voice.hasDamper = true;
- else
- voice.status = VoiceContext::kStatusRelease;
- }
- }
- }
-
- if (_playerCtx.scoreIndex >= 0) {
- const Event *curEvent = _playerCtx.nextEvent;
- int32 eventDelta = _playerCtx.nextEventTime - millis;
- for (; eventDelta <= 0; eventDelta += (++curEvent)->startTime) {
- const byte cmd = curEvent->command;
- ChannelContext &channel = _channelCtx[curEvent->parameter & 0x0F];
-
- // outPutEvent(*curEvent);
- // debug("CurTime, EventDelta, NextDelta: %d, %d, %d", millis, eventDelta, eventDelta + curEvent[1].startTime );
-
- if (cmd < 0x80) { // Note
- const int8 voiceIndex = noteOn(channel, cmd, (curEvent->parameter & 0xF0) >> 1, kPriorityScore);
- if (voiceIndex >= 0)
- _voiceCtx[voiceIndex].stopEventTime = MAX<int32>(0, (eventDelta + curEvent->stopTime) << 8);
-
- } else {
- switch (cmd) {
-
- case 0x80: // TEMPO
- if ((_playerCtx.tickUnit >> 8) > curEvent->stopTime) {
- _playerCtx.tickUnit = calcTempo(curEvent->parameter << 4, _playerCtx.vBlankFreq);
- _playerCtx.tempoTime = 0;
- } else {
- _playerCtx.tempoStart = _playerCtx.tempo;
- _playerCtx.tempoDelta = (curEvent->parameter << 4) - _playerCtx.tempoStart;
- _playerCtx.tempoTime = (curEvent->stopTime << 8);
- _playerCtx.tempoTicks = 0;
- }
- break;
-
- case 0xC0: // PROGRAM
- channel.patch = &_patch[curEvent->stopTime & (kNumPatches - 1)];
- break;
-
- case 0xE0: // BEND
- channel.pitchBend = ((curEvent->stopTime & 0x7F00) >> 1) | (curEvent->stopTime & 0x7f);
- channel.pitchReal = (((int32)channel.pitchBendRange * channel.pitchBend) >> 5) - (channel.pitchBendRange << 8);
- channel.isAltered = true;
- break;
-
- case 0xFF: // END
- if (_playerCtx.musicLoop) {
- curEvent = _scores[_playerCtx.scoreIndex].events;
- eventDelta = curEvent->startTime - millis;
- _playerCtx.ticks = 0;
- } else
- _playerCtx.scoreIndex = -1;
- // stop processing for this tick
- goto endOfEventLoop;
-
- case 0xA0: // SPECIAL
- switch (curEvent->stopTime >> 8){
- case 0x01: // SPECIAL_SYNC
- _playerCtx.syncCallBack(curEvent->stopTime & 0xFF);
- break;
- case 0x02: // SPECIAL_BEGINREP
- // we allow a depth of 4 loops
- for (int i = 0; i < ARRAYSIZE(_playerCtx.repeatPoint); ++i) {
- if (!_playerCtx.repeatPoint[i]) {
- _playerCtx.repeatPoint[i] = curEvent;
- _playerCtx.repeatCount[i] = curEvent->stopTime & 0xFF;
- break;
- }
- }
- break;
- case 0x03: // SPECIAL_ENDREP
- for (int i = ARRAYSIZE(_playerCtx.repeatPoint) - 1; i >= 0; --i) {
- if (_playerCtx.repeatPoint[i]) {
- if (_playerCtx.repeatCount[i]--)
- curEvent = _playerCtx.repeatPoint[i]; // gets incremented by 1 at end of loop
- else
- _playerCtx.repeatPoint[i] = 0;
- break;
- }
- }
- break;
- }
- break;
-
- case 0xB0: // CONTROL
- controlCh(channel, (byte)(curEvent->stopTime >> 8), (byte)curEvent->stopTime);
- break;
-
- default:
- debug("Unhandled Command");
- outPutEvent(*curEvent);
- }
- }
- }
-endOfEventLoop:
- _playerCtx.nextEvent = curEvent;
- _playerCtx.nextEventTime = eventDelta + millis;
-
- // tempoEffect
- if (_playerCtx.tempoTime) {
- _playerCtx.tempoTicks += _playerCtx.tickUnit;
- uint16 newTempo = _playerCtx.tempoStart;
- if (_playerCtx.tempoTicks < _playerCtx.tempoTime) {
- newTempo += (uint16)((_playerCtx.tempoTicks * _playerCtx.tempoDelta) / _playerCtx.tempoTime);
- } else {
- _playerCtx.tempoTime = 0;
- newTempo += _playerCtx.tempoDelta;
- }
- _playerCtx.tickUnit = calcTempo(newTempo, _playerCtx.vBlankFreq);
- }
- }
-
- // Handling of Envelopes and Portamento
- for (int i = 0; i < ARRAYSIZE(_voiceCtx); ++i) {
- VoiceContext &voice = _voiceCtx[i];
- if (!voice.channel)
- continue;
- const ChannelContext &channel = *voice.channel;
- const Patch &patch = *voice.patch;
-
- switch (voice.status) {
- case VoiceContext::kStatusSustain:
- // we need to check if some voices have no sustainSample.
- // in that case they are finished after the attackSample is done
- if (voice.dmaOff && Paula::getChannelDmaCount((byte)i) >= voice.dmaOff ) {
- voice.dmaOff = 0;
- voice.isBlocked = 0;
- voice.priority = 0;
- // disable it in next tick
- voice.stopEventTime = 0;
- }
- if (!channel.isAltered && !voice.hasPortamento && !channel.modulation)
- continue;
- // Update Volume and Period
- break;
-
- case VoiceContext::kStatusHalt:
- killVoice((byte)i);
- continue;
-
- case VoiceContext::kStatusStart:
- if (patch.attackLen) {
- voice.envelope = patch.attackPtr;
- const uint16 duration = voice.envelope->duration;
- voice.envelopeLeft = patch.attackLen;
- voice.ticksLeft = duration << 8;
- voice.status = VoiceContext::kStatusAttack;
- voice.incrVolume = calcVolumeDelta((int32)voice.envelope->volume, duration, _playerCtx.vBlankFreq);
- // Process Envelope
- } else {
- voice.status = VoiceContext::kStatusSustain;
- voice.baseVolume = patch.volume;
- // Update Volume and Period
- }
- break;
-
- case VoiceContext::kStatusRelease:
- if (patch.releaseLen) {
- voice.envelope = patch.attackPtr + patch.attackLen;
- const uint16 duration = voice.envelope->duration;
- voice.envelopeLeft = patch.releaseLen;
- voice.ticksLeft = duration << 8;
- voice.status = VoiceContext::kStatusDecay;
- voice.incrVolume = calcVolumeDelta((int32)voice.envelope->volume - voice.baseVolume, duration, _playerCtx.vBlankFreq);
- // Process Envelope
- } else {
- voice.status = VoiceContext::kStatusHalt;
- voice.lastVolume = 0;
- // Send Audio Packet
- }
- voice.stopEventTime = -1;
- break;
- }
-
- // Process Envelope
- const uint16 envUnit = _playerCtx.frameUnit;
- if (voice.envelope) {
- if (voice.ticksLeft > envUnit) { // envelope still active
- voice.baseVolume = (uint16) MIN<int32>(MAX<int32>(0, voice.baseVolume + voice.incrVolume), 0x8000);
- voice.ticksLeft -= envUnit;
- // Update Volume and Period
-
- } else { // next or last Envelope
- voice.baseVolume = voice.envelope->volume;
- assert(voice.envelopeLeft > 0);
- if (--voice.envelopeLeft) {
- ++voice.envelope;
- const uint16 duration = voice.envelope->duration;
- voice.ticksLeft = duration << 8;
- voice.incrVolume = calcVolumeDelta((int32)voice.envelope->volume - voice.baseVolume, duration, _playerCtx.vBlankFreq);
- // Update Volume and Period
- } else if (voice.status == VoiceContext::kStatusDecay) {
- voice.status = VoiceContext::kStatusHalt;
- voice.envelope = 0;
- voice.lastVolume = 0;
- // Send Audio Packet
- } else {
- assert(voice.status == VoiceContext::kStatusAttack);
- voice.status = VoiceContext::kStatusSustain;
- voice.envelope = 0;
- // Update Volume and Period
- }
- }
- }
-
- // Update Volume and Period
- if (voice.status >= VoiceContext::kStatusDecay) {
- // Calc volume
- uint16 vol = (voice.noteVolume < (1 << 7)) ? (voice.noteVolume * _playerCtx.volume) >> 7 : _playerCtx.volume;
- if (voice.baseVolume < (1 << 15))
- vol = (uint16)(((uint32)vol * voice.baseVolume) >> 15);
- if (voice.channel->volume < (1 << 7))
- vol = (vol * voice.channel->volume) >> 7;
- voice.lastVolume = (byte)MIN(vol, (uint16)0x64);
-
- // Calc Period
- if (voice.hasPortamento) {
- voice.portaTicks += envUnit;
- if ((uint16)(voice.portaTicks >> 8) >= channel.portamentoTime) {
- voice.hasPortamento = false;
- voice.baseNote = voice.endNote;
- voice.preCalcNote = precalcNote(voice.baseNote, patch.tune, voice.octave);
- }
- voice.lastPeriod = calcNote(voice);
- } else if (channel.isAltered || channel.modulation)
- voice.lastPeriod = calcNote(voice);
- }
-
- // Send Audio Packet
- Paula::setChannelPeriod((byte)i, (voice.lastPeriod) ? voice.lastPeriod : 1000);
- Paula::setChannelVolume((byte)i, (voice.lastPeriod) ? voice.lastVolume : 0);
- }
- for (ChannelContext *c = _channelCtx; c != &_channelCtx[ARRAYSIZE(_channelCtx)]; ++c)
- c->isAltered = false;
-
-#ifdef MAXTRAX_HAS_MODULATION
- // original player had _playerCtx.sineValue = _playerCtx.frameUnit >> 2
- // this should fit the comments that modtime=1000 is one second ?
- _playerCtx.sineValue += _playerCtx.frameUnit;
-#endif
-}
-
-void MaxTrax::controlCh(ChannelContext &channel, const byte command, const byte data) {
- switch (command) {
- case 0x01: // modulation level MSB
- channel.modulation = data << 8;
- break;
- case 0x21: // modulation level LSB
- channel.modulation = (channel.modulation & 0xFF00) || ((data * 2) & 0xFF);
- break;
- case 0x05: // portamento time MSB
- channel.portamentoTime = data << 7;
- break;
- case 0x25: // portamento time LSB
- channel.portamentoTime = (channel.portamentoTime & 0x3f80) || data;
- break;
- case 0x06: // data entry MSB
- if (channel.regParamNumber == 0) {
- channel.pitchBendRange = (int8)MIN((uint8)MAX_BEND_RANGE, (uint8)data);
- channel.pitchReal = (((int32)channel.pitchBendRange * channel.pitchBend) >> 5) - (channel.pitchBendRange << 8);
- channel.isAltered = true;
- }
- break;
- case 0x07: // Main Volume MSB
- channel.volume = (data == 0) ? 0 : data + 1;
- channel.isAltered = true;
- break;
- case 0x0A: // Pan
- if (data > 0x40 || (data == 0x40 && ((&channel - _channelCtx) & 1) != 0))
- channel.flags |= ChannelContext::kFlagRightChannel;
- else
- channel.flags &= ~ChannelContext::kFlagRightChannel;
- break;
- case 0x10: // GPC as Modulation Time MSB
- channel.modulationTime = data << 7;
- break;
- case 0x30: // GPC as Modulation Time LSB
- channel.modulationTime = (channel.modulationTime & 0x3f80) || data;
- break;
- case 0x11: // GPC as Microtonal Set MSB
- channel.microtonal = data << 8;
- break;
- case 0x31: // GPC as Microtonal Set LSB
- channel.microtonal = (channel.microtonal & 0xFF00) || ((data * 2) & 0xFF);
- break;
- case 0x40: // Damper Pedal
- if ((data & 0x40) != 0)
- channel.flags |= ChannelContext::kFlagDamper;
- else {
- channel.flags &= ~ChannelContext::kFlagDamper;
- // release all dampered voices on this channel
- for (int i = 0; i < ARRAYSIZE(_voiceCtx); ++i) {
- if (_voiceCtx[i].channel == &channel && _voiceCtx[i].hasDamper) {
- _voiceCtx[i].hasDamper = false;
- _voiceCtx[i].status = VoiceContext::kStatusRelease;
- }
- }
- }
- break;
- case 0x41: // Portamento off/on
- if ((data & 0x40) != 0)
- channel.flags |= ChannelContext::kFlagPortamento;
- else
- channel.flags &= ~ChannelContext::kFlagPortamento;
- break;
- case 0x50: // Microtonal off/on
- if ((data & 0x40) != 0)
- channel.flags |= ChannelContext::kFlagMicrotonal;
- else
- channel.flags &= ~ChannelContext::kFlagMicrotonal;
- break;
- case 0x51: // Audio Filter off/on
- Paula::setAudioFilter(data > 0x40 || (data == 0x40 && _playerCtx.filterOn));
- break;
- case 0x65: // RPN MSB
- channel.regParamNumber = (data << 8) || (channel.regParamNumber & 0xFF);
- break;
- case 0x64: // RPN LSB
- channel.regParamNumber = (channel.regParamNumber & 0xFF00) || data;
- break;
- case 0x79: // Reset All Controllers
- resetChannel(channel, ((&channel - _channelCtx) & 1) != 0);
- break;
- case 0x7E: // MONO mode
- channel.flags |= ChannelContext::kFlagMono;
- goto allNotesOff;
- case 0x7F: // POLY mode
- channel.flags &= ~ChannelContext::kFlagMono;
- // Fallthrough
- case 0x7B: // All Notes Off
-allNotesOff:
- for (int i = 0; i < ARRAYSIZE(_voiceCtx); ++i) {
- if (_voiceCtx[i].channel == &channel) {
- if ((channel.flags & ChannelContext::kFlagDamper) != 0)
- _voiceCtx[i].hasDamper = true;
- else
- _voiceCtx[i].status = VoiceContext::kStatusRelease;
- }
- }
- break;
- case 0x78: // All Sounds Off
- for (int i = 0; i < ARRAYSIZE(_voiceCtx); ++i) {
- if (_voiceCtx[i].channel == &channel)
- killVoice((byte)i);
- }
- break;
- }
-}
-
-void MaxTrax::setTempo(const uint16 tempo) {
- Common::StackLock lock(_mutex);
- _playerCtx.tickUnit = calcTempo(tempo, _playerCtx.vBlankFreq);
-}
-
-void MaxTrax::resetPlayer() {
- for (int i = 0; i < ARRAYSIZE(_voiceCtx); ++i)
- killVoice((byte)i);
-
- for (int i = 0; i < ARRAYSIZE(_channelCtx); ++i) {
- _channelCtx[i].flags = 0;
- _channelCtx[i].lastNote = (uint8)-1;
- resetChannel(_channelCtx[i], (i & 1) != 0);
- _channelCtx[i].patch = (i < kNumChannels) ? &_patch[i] : 0;
- }
-
-#ifdef MAXTRAX_HAS_MICROTONAL
- for (int i = 0; i < ARRAYSIZE(_microtonal); ++i)
- _microtonal[i] = (int16)(i << 8);
-#endif
-}
-
-void MaxTrax::stopMusic() {
- Common::StackLock lock(_mutex);
- _playerCtx.scoreIndex = -1;
- for (int i = 0; i < ARRAYSIZE(_voiceCtx); ++i) {
- if (_voiceCtx[i].channel < &_channelCtx[kNumChannels])
- killVoice((byte)i);
- }
-}
-
-bool MaxTrax::playSong(int songIndex, bool loop) {
- if (songIndex < 0 || songIndex >= _numScores)
- return false;
- Common::StackLock lock(_mutex);
- _playerCtx.scoreIndex = -1;
- resetPlayer();
- for (int i = 0; i < ARRAYSIZE(_playerCtx.repeatPoint); ++i)
- _playerCtx.repeatPoint[i] = 0;
-
- setTempo(_playerCtx.tempoInitial << 4);
- Paula::setAudioFilter(_playerCtx.filterOn);
- _playerCtx.musicLoop = loop;
- _playerCtx.tempoTime = 0;
- _playerCtx.scoreIndex = songIndex;
- _playerCtx.ticks = 0;
-
- _playerCtx.nextEvent = _scores[songIndex].events;
- _playerCtx.nextEventTime = _playerCtx.nextEvent->startTime;
-
- Paula::startPaula();
- return true;
-}
-
-void MaxTrax::advanceSong(int advance) {
- Common::StackLock lock(_mutex);
- if (_playerCtx.scoreIndex >= 0) {
- const Event *cev = _playerCtx.nextEvent;
- if (cev) {
- for (; advance > 0; --advance) {
- // TODO - check for boundaries
- for (; cev->command != 0xFF && (cev->command != 0xA0 || (cev->stopTime >> 8) != 0x00); ++cev)
- ; // no end_command or special_command + end
- }
- _playerCtx.nextEvent = cev;
- }
- }
-}
-
-void MaxTrax::killVoice(byte num) {
- VoiceContext &voice = _voiceCtx[num];
- voice.channel = 0;
- voice.envelope = 0;
- voice.status = VoiceContext::kStatusFree;
- voice.isBlocked = 0;
- voice.hasDamper = false;
- voice.hasPortamento = false;
- voice.priority = 0;
- voice.stopEventTime = -1;
- voice.dmaOff = 0;
- voice.lastVolume = 0;
- voice.tieBreak = 0;
- //voice.uinqueId = 0;
-
- // "stop" voice, set period to 1, vol to 0
- Paula::disableChannel(num);
- Paula::setChannelPeriod(num, 1);
- Paula::setChannelVolume(num, 0);
-}
-
-int8 MaxTrax::pickvoice(uint pick, int16 pri) {
- enum { kPrioFlagFixedSide = 1 << 3 };
- pick &= 3;
- if ((pri & (kPrioFlagFixedSide)) == 0) {
- const bool leftSide = (uint)(pick - 1) > 1;
- const int leftBest = MIN(_voiceCtx[0].status, _voiceCtx[3].status);
- const int rightBest = MIN(_voiceCtx[1].status, _voiceCtx[2].status);
- const int sameSide = (leftSide) ? leftBest : rightBest;
- const int otherSide = leftBest + rightBest - sameSide;
-
- if (sameSide > VoiceContext::kStatusRelease && otherSide <= VoiceContext::kStatusRelease)
- pick ^= 1; // switches sides
- }
- pri &= ~kPrioFlagFixedSide;
-
- for (int i = 2; i > 0; --i) {
- VoiceContext *voice = &_voiceCtx[pick];
- VoiceContext *alternate = &_voiceCtx[pick ^ 3];
-
- const uint16 voiceVal = voice->status << 8 | voice->lastVolume;
- const uint16 altVal = alternate->status << 8 | alternate->lastVolume;
-
- if (voiceVal + voice->tieBreak > altVal
- || voice->isBlocked > alternate->isBlocked) {
-
- // this is somewhat different to the original player,
- // but has a similar result
- voice->tieBreak = 0;
- alternate->tieBreak = 1;
-
- pick ^= 3; // switch channels
- VoiceContext *tmp = voice;
- voice = alternate;
- alternate = tmp;
- }
-
- if (voice->isBlocked || voice->priority > pri) {
- // if not already done, switch sides and try again
- pick ^= 1;
- continue;
- }
- // succeded
- return (int8)pick;
- }
- // failed
- debug(5, "MaxTrax: could not find channel for note");
- return -1;
-}
-
-uint16 MaxTrax::calcNote(const VoiceContext &voice) {
- const ChannelContext &channel = *voice.channel;
- int16 bend = channel.pitchReal;
-
-#ifdef MAXTRAX_HAS_MICROTONAL
- if (voice.hasPortamento) {
- if ((channel.flags & ChannelContext::kFlagMicrotonal) != 0)
- bend += (int16)(((_microtonal[voice.endNote] - _microtonal[voice.baseNote]) * voice.portaTicks) >> 8) / channel.portamentoTime;
- else
- bend += (int16)(((int8)(voice.endNote - voice.baseNote)) * voice.portaTicks) / channel.portamentoTime;
- }
-
- if ((channel.flags & ChannelContext::kFlagMicrotonal) != 0)
- bend += _microtonal[voice.baseNote];
-#else
- if (voice.hasPortamento)
- bend += (int16)(((int8)(voice.endNote - voice.baseNote)) * voice.portaTicks) / channel.portamentoTime;
-#endif
-
-#ifdef MAXTRAX_HAS_MODULATION
- static const uint8 tableSine[] = {
- 0, 5, 12, 18, 24, 30, 37, 43, 49, 55, 61, 67, 73, 79, 85, 91,
- 97, 103, 108, 114, 120, 125, 131, 136, 141, 146, 151, 156, 161, 166, 171, 176,
- 180, 184, 189, 193, 197, 201, 205, 208, 212, 215, 219, 222, 225, 228, 230, 233,
- 236, 238, 240, 242, 244, 246, 247, 249, 250, 251, 252, 253, 254, 254, 255, 255,
- 255, 255, 255, 254, 254, 253, 252, 251, 250, 249, 247, 246, 244, 242, 240, 238,
- 236, 233, 230, 228, 225, 222, 219, 215, 212, 208, 205, 201, 197, 193, 189, 184,
- 180, 176, 171, 166, 161, 156, 151, 146, 141, 136, 131, 125, 120, 114, 108, 103,
- 97, 91, 85, 79, 73, 67, 61, 55, 49, 43, 37, 30, 24, 18, 12, 5
- };
- if (channel.modulation) {
- if ((channel.flags & ChannelContext::kFlagModVolume) == 0) {
- const uint8 sineByte = _playerCtx.sineValue / channel.modulationTime;
- const uint8 sineIndex = sineByte & 0x7F;
- const int16 modVal = ((uint32)(uint16)(tableSine[sineIndex] + (sineIndex ? 1 : 0)) * channel.modulation) >> 8;
- bend = (sineByte < 0x80) ? bend + modVal : bend - modVal;
- }
- }
-#endif
-
- // tone = voice.baseNote << 8 + microtonal
- // bend = channelPitch + porta + modulation
-
- const int32 tone = voice.preCalcNote + (bend << 6) / 3;
-
- return (tone >= PERIOD_LIMIT) ? (uint16)pow2Fixed(tone) : 0;
-}
-
-int8 MaxTrax::noteOn(ChannelContext &channel, const byte note, uint16 volume, uint16 pri) {
-#ifdef MAXTRAX_HAS_MICROTONAL
- if (channel.microtonal >= 0)
- _microtonal[note % 127] = channel.microtonal;
-#endif
-
- if (!volume)
- return -1;
-
- const Patch &patch = *channel.patch;
- if (!patch.samplePtr || patch.sampleTotalLen == 0)
- return -1;
- int8 voiceNum = -1;
- if ((channel.flags & ChannelContext::kFlagMono) == 0) {
- voiceNum = pickvoice((channel.flags & ChannelContext::kFlagRightChannel) != 0 ? 1 : 0, pri);
- } else {
- VoiceContext *voice = _voiceCtx + ARRAYSIZE(_voiceCtx) - 1;
- for (voiceNum = ARRAYSIZE(_voiceCtx) - 1; voiceNum >= 0 && voice->channel != &channel; --voiceNum, --voice)
- ;
- if (voiceNum < 0)
- voiceNum = pickvoice((channel.flags & ChannelContext::kFlagRightChannel) != 0 ? 1 : 0, pri);
- else if (voice->status >= VoiceContext::kStatusSustain && (channel.flags & ChannelContext::kFlagPortamento) != 0) {
- // reset previous porta
- if (voice->hasPortamento)
- voice->baseNote = voice->endNote;
- voice->preCalcNote = precalcNote(voice->baseNote, patch.tune, voice->octave);
- voice->noteVolume = (_playerCtx.handleVolume) ? volume + 1 : 128;
- voice->portaTicks = 0;
- voice->hasPortamento = true;
- voice->endNote = channel.lastNote = note;
- return voiceNum;
- }
- }
-
- if (voiceNum >= 0) {
- VoiceContext &voice = _voiceCtx[voiceNum];
- voice.hasDamper = false;
- voice.isBlocked = 0;
- voice.hasPortamento = false;
- if (voice.channel)
- killVoice(voiceNum);
- voice.channel = &channel;
- voice.patch = &patch;
- voice.baseNote = note;
-
- // always base octave on the note in the command, regardless of porta
- const int32 plainNote = precalcNote(note, patch.tune, 0);
- // calculate which sample to use
- const int useOctave = (plainNote <= PREF_PERIOD) ? 0 : MIN<int32>((plainNote + 0xFFFF - PREF_PERIOD) >> 16, patch.sampleOctaves - 1);
- voice.octave = (byte)useOctave;
- // adjust precalculated value
- voice.preCalcNote = plainNote - (useOctave << 16);
-
- // next calculate the actual period which depends on wether porta is enabled
- if (&channel < &_channelCtx[kNumChannels] && (channel.flags & ChannelContext::kFlagPortamento) != 0) {
- if ((channel.flags & ChannelContext::kFlagMono) != 0 && channel.lastNote < 0x80 && channel.lastNote != note) {
- voice.portaTicks = 0;
- voice.baseNote = channel.lastNote;
- voice.endNote = note;
- voice.hasPortamento = true;
- voice.preCalcNote = precalcNote(voice.baseNote, patch.tune, voice.octave);
- }
- channel.lastNote = note;
- }
-
- voice.lastPeriod = calcNote(voice);
-
- voice.priority = (byte)pri;
- voice.status = VoiceContext::kStatusStart;
-
- voice.noteVolume = (_playerCtx.handleVolume) ? volume + 1 : 128;
- voice.baseVolume = 0;
-
- // TODO: since the original player is using the OS-functions, more than 1 sample could be queued up already
- // get samplestart for the given octave
- const int8 *samplePtr = patch.samplePtr + (patch.sampleTotalLen << useOctave) - patch.sampleTotalLen;
- if (patch.sampleAttackLen) {
- Paula::setChannelSampleStart(voiceNum, samplePtr);
- Paula::setChannelSampleLen(voiceNum, (patch.sampleAttackLen << useOctave) / 2);
-
- Paula::enableChannel(voiceNum);
- // wait for dma-clear
- }
-
- if (patch.sampleTotalLen > patch.sampleAttackLen) {
- Paula::setChannelSampleStart(voiceNum, samplePtr + (patch.sampleAttackLen << useOctave));
- Paula::setChannelSampleLen(voiceNum, ((patch.sampleTotalLen - patch.sampleAttackLen) << useOctave) / 2);
- if (!patch.sampleAttackLen)
- Paula::enableChannel(voiceNum); // need to enable channel
- // another pointless wait for DMA-Clear???
-
- } else { // no sustain sample
- // this means we must stop playback after the attacksample finished
- // so we queue up an "empty" sample and note that we need to kill the sample after dma finished
- Paula::setChannelSampleStart(voiceNum, 0);
- Paula::setChannelSampleLen(voiceNum, 0);
- Paula::setChannelDmaCount(voiceNum);
- voice.dmaOff = 1;
- }
-
- Paula::setChannelPeriod(voiceNum, (voice.lastPeriod) ? voice.lastPeriod : 1000);
- Paula::setChannelVolume(voiceNum, 0);
- }
- return voiceNum;
-}
-
-void MaxTrax::resetChannel(ChannelContext &chan, bool rightChannel) {
- chan.modulation = 0;
- chan.modulationTime = 1000;
- chan.microtonal = -1;
- chan.portamentoTime = 500;
- chan.pitchBend = NO_BEND;
- chan.pitchReal = 0;
- chan.pitchBendRange = MAX_BEND_RANGE;
- chan.volume = 128;
- chan.flags &= ~(ChannelContext::kFlagPortamento | ChannelContext::kFlagMicrotonal | ChannelContext::kFlagRightChannel);
- chan.isAltered = true;
- if (rightChannel)
- chan.flags |= ChannelContext::kFlagRightChannel;
-}
-
-void MaxTrax::freeScores() {
- if (_scores) {
- for (int i = 0; i < _numScores; ++i)
- delete[] _scores[i].events;
- delete[] _scores;
- _scores = 0;
- }
- _numScores = 0;
- _playerCtx.tempo = 120;
- _playerCtx.filterOn = true;
-}
-
-void MaxTrax::freePatches() {
- for (int i = 0; i < ARRAYSIZE(_patch); ++i) {
- delete[] _patch[i].samplePtr;
- delete[] _patch[i].attackPtr;
- }
- memset(_patch, 0, sizeof(_patch));
-}
-
-void MaxTrax::setSignalCallback(void (*callback) (int)) {
- Common::StackLock lock(_mutex);
- _playerCtx.syncCallBack = (callback == 0) ? nullFunc : callback;
-}
-
-int MaxTrax::playNote(byte note, byte patch, uint16 duration, uint16 volume, bool rightSide) {
- Common::StackLock lock(_mutex);
- assert(patch < ARRAYSIZE(_patch));
-
- ChannelContext &channel = _channelCtx[kNumChannels];
- channel.flags = (rightSide) ? ChannelContext::kFlagRightChannel : 0;
- channel.isAltered = false;
- channel.patch = &_patch[patch];
- const int8 voiceIndex = noteOn(channel, note, (byte)volume, kPriorityNote);
- if (voiceIndex >= 0) {
- _voiceCtx[voiceIndex].stopEventTime = duration << 8;
- Paula::startPaula();
- }
- return voiceIndex;
-}
-
-bool MaxTrax::load(Common::SeekableReadStream &musicData, bool loadScores, bool loadSamples) {
- Common::StackLock lock(_mutex);
- stopMusic();
- if (loadSamples)
- freePatches();
- if (loadScores)
- freeScores();
- const char *errorMsg = 0;
- // 0x0000: 4 Bytes Header "MXTX"
- // 0x0004: uint16 tempo
- // 0x0006: uint16 flags. bit0 = lowpassfilter, bit1 = attackvolume, bit15 = microtonal
- if (musicData.size() < 10 || musicData.readUint32BE() != 0x4D585458) {
- warning("Maxtrax: File is not a Maxtrax Module");
- return false;
- }
- const uint16 songTempo = musicData.readUint16BE();
- const uint16 flags = musicData.readUint16BE();
- if (loadScores) {
- _playerCtx.tempoInitial = songTempo;
- _playerCtx.filterOn = (flags & 1) != 0;
- _playerCtx.handleVolume = (flags & 2) != 0;
- }
-
- if (flags & (1 << 15)) {
- debug(5, "Maxtrax: Song has microtonal");
-#ifdef MAXTRAX_HAS_MICROTONAL
- if (loadScores) {
- for (int i = 0; i < ARRAYSIZE(_microtonal); ++i)
- _microtonal[i] = musicData.readUint16BE();
- } else
- musicData.skip(128 * 2);
-#else
- musicData.skip(128 * 2);
-#endif
- }
-
- int scoresLoaded = 0;
- // uint16 number of Scores
- const uint16 scoresInFile = musicData.readUint16BE();
-
- if (musicData.err() || musicData.eos())
- goto ioError;
-
- if (loadScores) {
- const uint16 tempScores = MIN(scoresInFile, _playerCtx.maxScoreNum);
- Score *curScore = new Score[tempScores];
- if (!curScore)
- goto allocError;
- _scores = curScore;
-
- for (scoresLoaded = 0; scoresLoaded < tempScores; ++scoresLoaded, ++curScore) {
- const uint32 numEvents = musicData.readUint32BE();
- Event *curEvent = new Event[numEvents];
- if (!curEvent)
- goto allocError;
- curScore->events = curEvent;
- for (int j = numEvents; j > 0; --j, ++curEvent) {
- curEvent->command = musicData.readByte();
- curEvent->parameter = musicData.readByte();
- curEvent->startTime = musicData.readUint16BE();
- curEvent->stopTime = musicData.readUint16BE();
- }
- curScore->numEvents = numEvents;
- }
- _numScores = scoresLoaded;
- }
-
- if (loadSamples) {
- // skip over remaining scores in file
- for (int i = scoresInFile - scoresLoaded; i > 0; --i)
- musicData.skip(musicData.readUint32BE() * 6);
-
- // uint16 number of Samples
- const uint16 wavesInFile = musicData.readUint16BE();
- for (int i = wavesInFile; i > 0; --i) {
- // load disksample structure
- const uint16 number = musicData.readUint16BE();
- assert(number < ARRAYSIZE(_patch));
-
- Patch &curPatch = _patch[number];
- if (curPatch.attackPtr || curPatch.samplePtr) {
- delete curPatch.attackPtr;
- curPatch.attackPtr = 0;
- delete curPatch.samplePtr;
- curPatch.samplePtr = 0;
- }
- curPatch.tune = musicData.readSint16BE();
- curPatch.volume = musicData.readUint16BE();
- curPatch.sampleOctaves = musicData.readUint16BE();
- curPatch.sampleAttackLen = musicData.readUint32BE();
- const uint32 sustainLen = musicData.readUint32BE();
- curPatch.sampleTotalLen = curPatch.sampleAttackLen + sustainLen;
- // each octave the number of samples doubles.
- const uint32 totalSamples = curPatch.sampleTotalLen * ((1 << curPatch.sampleOctaves) - 1);
- curPatch.attackLen = musicData.readUint16BE();
- curPatch.releaseLen = musicData.readUint16BE();
- const uint32 totalEnvs = curPatch.attackLen + curPatch.releaseLen;
-
- // Allocate space for both attack and release Segment.
- Envelope *envPtr = new Envelope[totalEnvs];
- if (!envPtr)
- goto allocError;
- // Attack Segment
- curPatch.attackPtr = envPtr;
- // Release Segment
- // curPatch.releasePtr = envPtr + curPatch.attackLen;
-
- // Read Attack and Release Segments
- for (int j = totalEnvs; j > 0; --j, ++envPtr) {
- envPtr->duration = musicData.readUint16BE();
- envPtr->volume = musicData.readUint16BE();
- }
-
- // read Samples
- int8 *allocSamples = new int8[totalSamples];
- if (!allocSamples)
- goto allocError;
- curPatch.samplePtr = allocSamples;
- musicData.read(allocSamples, totalSamples);
- }
- }
- if (!musicData.err() && !musicData.eos())
- return true;
-ioError:
- errorMsg = "Maxtrax: Encountered IO-Error";
-allocError:
- if (!errorMsg)
- errorMsg = "Maxtrax: Could not allocate Memory";
-
- warning("%s", errorMsg);
- if (loadSamples)
- freePatches();
- if (loadScores)
- freeScores();
- return false;
-}
-
-#if !defined(NDEBUG) && 0
-void MaxTrax::outPutEvent(const Event &ev, int num) {
- struct {
- byte cmd;
- const char *name;
- const char *param;
- } COMMANDS[] = {
- {0x80, "TEMPO ", "TEMPO, N/A "},
- {0xa0, "SPECIAL ", "CHAN, SPEC # | VAL"},
- {0xb0, "CONTROL ", "CHAN, CTRL # | VAL"},
- {0xc0, "PROGRAM ", "CHANNEL, PROG # "},
- {0xe0, "BEND ", "CHANNEL, BEND VALUE"},
- {0xf0, "SYSEX ", "TYPE, SIZE "},
- {0xf8, "REALTIME", "REALTIME, N/A "},
- {0xff, "END ", "N/A, N/A "},
- {0xff, "NOTE ", "VOL | CHAN, STOP"},
- };
-
- int i = 0;
- for (; i < ARRAYSIZE(COMMANDS) - 1 && ev.command != COMMANDS[i].cmd; ++i)
- ;
-
- if (num == -1)
- debug("Event : %02X %s %s %02X %04X %04X", ev.command, COMMANDS[i].name, COMMANDS[i].param, ev.parameter, ev.startTime, ev.stopTime);
- else
- debug("Event %3d: %02X %s %s %02X %04X %04X", num, ev.command, COMMANDS[i].name, COMMANDS[i].param, ev.parameter, ev.startTime, ev.stopTime);
-}
-
-void MaxTrax::outPutScore(const Score &sc, int num) {
- if (num == -1)
- debug("score : %i Events", sc.numEvents);
- else
- debug("score %2d: %i Events", num, sc.numEvents);
- for (uint i = 0; i < sc.numEvents; ++i)
- outPutEvent(sc.events[i], i);
- debug("");
-}
-#else
-void MaxTrax::outPutEvent(const Event &ev, int num) {}
-void MaxTrax::outPutScore(const Score &sc, int num) {}
-#endif // #ifndef NDEBUG
-
-} // End of namespace Audio
-
-#endif // #if defined(SOUND_MODS_MAXTRAX_H)
diff --git a/sound/mods/maxtrax.h b/sound/mods/maxtrax.h
deleted file mode 100644
index 2c86b70288..0000000000
--- a/sound/mods/maxtrax.h
+++ /dev/null
@@ -1,225 +0,0 @@
-/* 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$
- *
- */
-
-// see if all engines using this class are DISABLED
-#if !defined(ENABLE_KYRA)
-
-// normal Header Guard
-#elif !defined SOUND_MODS_MAXTRAX_H
-#define SOUND_MODS_MAXTRAX_H
-
-// #define MAXTRAX_HAS_MODULATION
-// #define MAXTRAX_HAS_MICROTONAL
-
-#include "sound/mods/paula.h"
-
-namespace Audio {
-
-class MaxTrax : public Paula {
-public:
- MaxTrax(int rate, bool stereo, uint16 vBlankFreq = 50, uint16 maxScores = 128);
- virtual ~MaxTrax();
-
- bool load(Common::SeekableReadStream &musicData, bool loadScores = true, bool loadSamples = true);
- bool playSong(int songIndex, bool loop = false);
- void advanceSong(int advance = 1);
- int playNote(byte note, byte patch, uint16 duration, uint16 volume, bool rightSide);
- void setVolume(const byte volume) { Common::StackLock lock(_mutex); _playerCtx.volume = volume; }
- void setTempo(const uint16 tempo);
- void stopMusic();
- /**
- * Set a callback function for sync-events.
- * @param callback Callback function, will be called synchronously, so DONT modify the player
- * directly in response
- */
- void setSignalCallback(void (*callback) (int));
-
-protected:
- void interrupt();
-
-private:
- enum { kNumPatches = 64, kNumVoices = 4, kNumChannels = 16, kNumExtraChannels = 1 };
- enum { kPriorityScore, kPriorityNote, kPrioritySound };
-
-#ifdef MAXTRAX_HAS_MICROTONAL
- int16 _microtonal[128];
-#endif
-
- struct Event {
- uint16 startTime;
- uint16 stopTime;
- byte command;
- byte parameter;
- };
-
- const struct Score {
- const Event *events;
- uint32 numEvents;
- } *_scores;
-
- int _numScores;
-
- struct {
- uint32 sineValue;
- uint16 vBlankFreq;
- int32 ticks;
- int32 tickUnit;
- uint16 frameUnit;
-
- uint16 maxScoreNum;
- uint16 tempo;
- uint16 tempoInitial;
- uint16 tempoStart;
- int16 tempoDelta;
- int32 tempoTime;
- int32 tempoTicks;
-
- byte volume;
-
- bool filterOn;
- bool handleVolume;
- bool musicLoop;
-
- int scoreIndex;
- const Event *nextEvent;
- int32 nextEventTime;
-
- void (*syncCallBack) (int);
- const Event *repeatPoint[4];
- byte repeatCount[4];
- } _playerCtx;
-
- struct Envelope {
- uint16 duration;
- uint16 volume;
- };
-
- struct Patch {
- const Envelope *attackPtr;
- //Envelope *releasePtr;
- uint16 attackLen;
- uint16 releaseLen;
-
- int16 tune;
- uint16 volume;
-
- // this was the SampleData struct in the assembler source
- const int8 *samplePtr;
- uint32 sampleTotalLen;
- uint32 sampleAttackLen;
- uint16 sampleOctaves;
- } _patch[kNumPatches];
-
- struct ChannelContext {
- const Patch *patch;
- uint16 regParamNumber;
-
- uint16 modulation;
- uint16 modulationTime;
-
- int16 microtonal;
-
- uint16 portamentoTime;
-
- int16 pitchBend;
- int16 pitchReal;
- int8 pitchBendRange;
-
- uint8 volume;
-// uint8 voicesActive;
-
- enum {
- kFlagRightChannel = 1 << 0,
- kFlagPortamento = 1 << 1,
- kFlagDamper = 1 << 2,
- kFlagMono = 1 << 3,
- kFlagMicrotonal = 1 << 4,
- kFlagModVolume = 1 << 5
- };
- byte flags;
- bool isAltered;
-
- uint8 lastNote;
-// uint8 program;
-
- } _channelCtx[kNumChannels + kNumExtraChannels];
-
- struct VoiceContext {
- ChannelContext *channel;
- const Patch *patch;
- const Envelope *envelope;
-// uint32 uinqueId;
- int32 preCalcNote;
- uint32 ticksLeft;
- int32 portaTicks;
- int32 incrVolume;
-// int32 periodOffset;
- uint16 envelopeLeft;
- uint16 noteVolume;
- uint16 baseVolume;
- uint16 lastPeriod;
- byte baseNote;
- byte endNote;
- byte octave;
-// byte number;
-// byte link;
- enum {
- kStatusFree,
- kStatusHalt,
- kStatusDecay,
- kStatusRelease,
- kStatusSustain,
- kStatusAttack,
- kStatusStart
- };
- uint8 isBlocked;
- uint8 priority;
- byte status;
- byte lastVolume;
- byte tieBreak;
- bool hasDamper;
- bool hasPortamento;
- byte dmaOff;
-
- int32 stopEventTime;
- } _voiceCtx[kNumVoices];
-
- void controlCh(ChannelContext &channel, byte command, byte data);
- void freePatches();
- void freeScores();
- void resetChannel(ChannelContext &chan, bool rightChannel);
- void resetPlayer();
-
- int8 pickvoice(uint pick, int16 pri);
- uint16 calcNote(const VoiceContext &voice);
- int8 noteOn(ChannelContext &channel, byte note, uint16 volume, uint16 pri);
- void killVoice(byte num);
-
- static void outPutEvent(const Event &ev, int num = -1);
- static void outPutScore(const Score &sc, int num = -1);
-};
-} // End of namespace Audio
-
-#endif // !defined SOUND_MODS_MAXTRAX_H
diff --git a/sound/mods/module.cpp b/sound/mods/module.cpp
deleted file mode 100644
index 992c2a28e3..0000000000
--- a/sound/mods/module.cpp
+++ /dev/null
@@ -1,252 +0,0 @@
-/* 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/mods/module.h"
-
-#include "common/util.h"
-#include "common/endian.h"
-
-namespace Modules {
-
-const int16 Module::periods[16][60] = {
- {1712, 1616, 1524, 1440, 1356, 1280, 1208, 1140, 1076, 1016, 960 , 906,
- 856 , 808 , 762 , 720 , 678 , 640 , 604 , 570 , 538 , 508 , 480 , 453,
- 428 , 404 , 381 , 360 , 339 , 320 , 302 , 285 , 269 , 254 , 240 , 226,
- 214 , 202 , 190 , 180 , 170 , 160 , 151 , 143 , 135 , 127 , 120 , 113,
- 107 , 101 , 95 , 90 , 85 , 80 , 75 , 71 , 67 , 63 , 60 , 56 },
- {1700, 1604, 1514, 1430, 1348, 1274, 1202, 1134, 1070, 1010, 954 , 900,
- 850 , 802 , 757 , 715 , 674 , 637 , 601 , 567 , 535 , 505 , 477 , 450,
- 425 , 401 , 379 , 357 , 337 , 318 , 300 , 284 , 268 , 253 , 239 , 225,
- 213 , 201 , 189 , 179 , 169 , 159 , 150 , 142 , 134 , 126 , 119 , 113,
- 106 , 100 , 94 , 89 , 84 , 79 , 75 , 71 , 67 , 63 , 59 , 56 },
- {1688, 1592, 1504, 1418, 1340, 1264, 1194, 1126, 1064, 1004, 948 , 894,
- 844 , 796 , 752 , 709 , 670 , 632 , 597 , 563 , 532 , 502 , 474 , 447,
- 422 , 398 , 376 , 355 , 335 , 316 , 298 , 282 , 266 , 251 , 237 , 224,
- 211 , 199 , 188 , 177 , 167 , 158 , 149 , 141 , 133 , 125 , 118 , 112,
- 105 , 99 , 94 , 88 , 83 , 79 , 74 , 70 , 66 , 62 , 59 , 56 },
- {1676, 1582, 1492, 1408, 1330, 1256, 1184, 1118, 1056, 996 , 940 , 888,
- 838 , 791 , 746 , 704 , 665 , 628 , 592 , 559 , 528 , 498 , 470 , 444,
- 419 , 395 , 373 , 352 , 332 , 314 , 296 , 280 , 264 , 249 , 235 , 222,
- 209 , 198 , 187 , 176 , 166 , 157 , 148 , 140 , 132 , 125 , 118 , 111,
- 104 , 99 , 93 , 88 , 83 , 78 , 74 , 70 , 66 , 62 , 59 , 55 },
- {1664, 1570, 1482, 1398, 1320, 1246, 1176, 1110, 1048, 990 , 934 , 882,
- 832 , 785 , 741 , 699 , 660 , 623 , 588 , 555 , 524 , 495 , 467 , 441,
- 416 , 392 , 370 , 350 , 330 , 312 , 294 , 278 , 262 , 247 , 233 , 220,
- 208 , 196 , 185 , 175 , 165 , 156 , 147 , 139 , 131 , 124 , 117 , 110,
- 104 , 98 , 92 , 87 , 82 , 78 , 73 , 69 , 65 , 62 , 58 , 55 },
- {1652, 1558, 1472, 1388, 1310, 1238, 1168, 1102, 1040, 982 , 926 , 874,
- 826 , 779 , 736 , 694 , 655 , 619 , 584 , 551 , 520 , 491 , 463 , 437,
- 413 , 390 , 368 , 347 , 328 , 309 , 292 , 276 , 260 , 245 , 232 , 219,
- 206 , 195 , 184 , 174 , 164 , 155 , 146 , 138 , 130 , 123 , 116 , 109,
- 103 , 97 , 92 , 87 , 82 , 77 , 73 , 69 , 65 , 61 , 58 , 54 },
- {1640, 1548, 1460, 1378, 1302, 1228, 1160, 1094, 1032, 974 , 920 , 868,
- 820 , 774 , 730 , 689 , 651 , 614 , 580 , 547 , 516 , 487 , 460 , 434,
- 410 , 387 , 365 , 345 , 325 , 307 , 290 , 274 , 258 , 244 , 230 , 217,
- 205 , 193 , 183 , 172 , 163 , 154 , 145 , 137 , 129 , 122 , 115 , 109,
- 102 , 96 , 91 , 86 , 81 , 77 , 72 , 68 , 64 , 61 , 57 , 54 },
- {1628, 1536, 1450, 1368, 1292, 1220, 1150, 1086, 1026, 968 , 914 , 862,
- 814 , 768 , 725 , 684 , 646 , 610 , 575 , 543 , 513 , 484 , 457 , 431,
- 407 , 384 , 363 , 342 , 323 , 305 , 288 , 272 , 256 , 242 , 228 , 216,
- 204 , 192 , 181 , 171 , 161 , 152 , 144 , 136 , 128 , 121 , 114 , 108,
- 102 , 96 , 90 , 85 , 80 , 76 , 72 , 68 , 64 , 60 , 57 , 54 },
- {1814, 1712, 1616, 1524, 1440, 1356, 1280, 1208, 1140, 1076, 1016, 960,
- 907 , 856 , 808 , 762 , 720 , 678 , 640 , 604 , 570 , 538 , 508 , 480,
- 453 , 428 , 404 , 381 , 360 , 339 , 320 , 302 , 285 , 269 , 254 , 240,
- 226 , 214 , 202 , 190 , 180 , 170 , 160 , 151 , 143 , 135 , 127 , 120,
- 113 , 107 , 101 , 95 , 90 , 85 , 80 , 75 , 71 , 67 , 63 , 60 },
- {1800, 1700, 1604, 1514, 1430, 1350, 1272, 1202, 1134, 1070, 1010, 954,
- 900 , 850 , 802 , 757 , 715 , 675 , 636 , 601 , 567 , 535 , 505 , 477,
- 450 , 425 , 401 , 379 , 357 , 337 , 318 , 300 , 284 , 268 , 253 , 238,
- 225 , 212 , 200 , 189 , 179 , 169 , 159 , 150 , 142 , 134 , 126 , 119,
- 112 , 106 , 100 , 94 , 89 , 84 , 79 , 75 , 71 , 67 , 63 , 59 },
- {1788, 1688, 1592, 1504, 1418, 1340, 1264, 1194, 1126, 1064, 1004, 948,
- 894 , 844 , 796 , 752 , 709 , 670 , 632 , 597 , 563 , 532 , 502 , 474,
- 447 , 422 , 398 , 376 , 355 , 335 , 316 , 298 , 282 , 266 , 251 , 237,
- 223 , 211 , 199 , 188 , 177 , 167 , 158 , 149 , 141 , 133 , 125 , 118,
- 111 , 105 , 99 , 94 , 88 , 83 , 79 , 74 , 70 , 66 , 62 , 59 },
- {1774, 1676, 1582, 1492, 1408, 1330, 1256, 1184, 1118, 1056, 996 , 940,
- 887 , 838 , 791 , 746 , 704 , 665 , 628 , 592 , 559 , 528 , 498 , 470,
- 444 , 419 , 395 , 373 , 352 , 332 , 314 , 296 , 280 , 264 , 249 , 235,
- 222 , 209 , 198 , 187 , 176 , 166 , 157 , 148 , 140 , 132 , 125 , 118,
- 111 , 104 , 99 , 93 , 88 , 83 , 78 , 74 , 70 , 66 , 62 , 59 },
- {1762, 1664, 1570, 1482, 1398, 1320, 1246, 1176, 1110, 1048, 988 , 934,
- 881 , 832 , 785 , 741 , 699 , 660 , 623 , 588 , 555 , 524 , 494 , 467,
- 441 , 416 , 392 , 370 , 350 , 330 , 312 , 294 , 278 , 262 , 247 , 233,
- 220 , 208 , 196 , 185 , 175 , 165 , 156 , 147 , 139 , 131 , 123 , 117,
- 110 , 104 , 98 , 92 , 87 , 82 , 78 , 73 , 69 , 65 , 61 , 58 },
- {1750, 1652, 1558, 1472, 1388, 1310, 1238, 1168, 1102, 1040, 982 , 926,
- 875 , 826 , 779 , 736 , 694 , 655 , 619 , 584 , 551 , 520 , 491 , 463,
- 437 , 413 , 390 , 368 , 347 , 328 , 309 , 292 , 276 , 260 , 245 , 232,
- 219 , 206 , 195 , 184 , 174 , 164 , 155 , 146 , 138 , 130 , 123 , 116,
- 109 , 103 , 97 , 92 , 87 , 82 , 77 , 73 , 69 , 65 , 61 , 58 },
- {1736, 1640, 1548, 1460, 1378, 1302, 1228, 1160, 1094, 1032, 974 , 920,
- 868 , 820 , 774 , 730 , 689 , 651 , 614 , 580 , 547 , 516 , 487 , 460,
- 434 , 410 , 387 , 365 , 345 , 325 , 307 , 290 , 274 , 258 , 244 , 230,
- 217 , 205 , 193 , 183 , 172 , 163 , 154 , 145 , 137 , 129 , 122 , 115,
- 108 , 102 , 96 , 91 , 86 , 81 , 77 , 72 , 68 , 64 , 61 , 57 },
- {1724, 1628, 1536, 1450, 1368, 1292, 1220, 1150, 1086, 1026, 968 , 914,
- 862 , 814 , 768 , 725 , 684 , 646 , 610 , 575 , 543 , 513 , 484 , 457,
- 431 , 407 , 384 , 363 , 342 , 323 , 305 , 288 , 272 , 256 , 242 , 228,
- 216 , 203 , 192 , 181 , 171 , 161 , 152 , 144 , 136 , 128 , 121 , 114,
- 108 , 101 , 96 , 90 , 85 , 80 , 76 , 72 , 68 , 64 , 60 , 57 }};
-
-const uint32 Module::signatures[] = {
- MKID_BE('M.K.'), MKID_BE('M!K!'), MKID_BE('FLT4')
-};
-
-bool Module::load(Common::SeekableReadStream &st, int offs) {
- if (offs) {
- // Load the module with the common sample data
- load(st, 0);
- }
-
- st.seek(offs);
- st.read(songname, 20);
- songname[20] = '\0';
-
- for (int i = 0; i < NUM_SAMPLES; ++i) {
- st.read(sample[i].name, 22);
- sample[i].name[22] = '\0';
- sample[i].len = 2 * st.readUint16BE();
-
- sample[i].finetune = st.readByte();
- assert(sample[i].finetune < 0x10);
-
- sample[i].vol = st.readByte();
- sample[i].repeat = 2 * st.readUint16BE();
- sample[i].replen = 2 * st.readUint16BE();
- }
-
- songlen = st.readByte();
- undef = st.readByte();
-
- st.read(songpos, 128);
-
- sig = st.readUint32BE();
-
- bool foundSig = false;
- for (int i = 0; i < ARRAYSIZE(signatures); i++) {
- if (sig == signatures[i]) {
- foundSig = true;
- break;
- }
- }
-
- if (!foundSig) {
- warning("No known signature found in protracker module");
- return false;
- }
-
- int maxpattern = 0;
- for (int i = 0; i < 128; ++i)
- if (maxpattern < songpos[i])
- maxpattern = songpos[i];
-
- pattern = new pattern_t[maxpattern + 1];
-
- for (int i = 0; i <= maxpattern; ++i) {
- for (int j = 0; j < 64; ++j) {
- for (int k = 0; k < 4; ++k) {
- uint32 note = st.readUint32BE();
- pattern[i][j][k].sample = (note & 0xf0000000) >> 24 | (note & 0x0000f000) >> 12;
- pattern[i][j][k].period = (note >> 16) & 0xfff;
- pattern[i][j][k].effect = note & 0xfff;
- pattern[i][j][k].note = periodToNote((note >> 16) & 0xfff);
- }
- }
- }
-
- for (int i = 0; i < NUM_SAMPLES; ++i) {
- if (offs) {
- // Restore information for modules that use common sample data
- for (int j = 0; j < NUM_SAMPLES; ++j) {
- if (!scumm_stricmp((const char *)commonSamples[j].name, (const char *)sample[i].name)) {
- sample[i].len = commonSamples[j].len;
- st.seek(commonSamples[j].offs);
- break;
- }
- }
- } else {
- // Store information for modules that use common sample data
- memcpy(commonSamples[i].name, sample[i].name, 22);
- commonSamples[i].len = sample[i].len;
- commonSamples[i].offs = st.pos();
-
- }
-
- if (!sample[i].len) {
- sample[i].data = 0;
- } else {
- sample[i].data = new int8[sample[i].len];
- st.read((byte *)sample[i].data, sample[i].len);
- }
- }
-
- return true;
-}
-
-Module::Module() {
- pattern = 0;
- for (int i = 0; i < NUM_SAMPLES; ++i) {
- sample[i].data = 0;
- }
-}
-
-Module::~Module() {
- delete[] pattern;
- for (int i = 0; i < NUM_SAMPLES; ++i) {
- delete[] sample[i].data;
- }
-}
-
-byte Module::periodToNote(int16 period, byte finetune) {
- int16 diff1;
- int16 diff2;
-
- diff1 = ABS(periods[finetune][0] - period);
- if (diff1 == 0)
- return 0;
-
- for (int i = 1; i < 60; i++) {
- diff2 = ABS(periods[finetune][i] - period);
- if (diff2 == 0)
- return i;
- else if (diff2 > diff1)
- return i-1;
- diff1 = diff2;
- }
- return 59;
-}
-
-int16 Module::noteToPeriod(byte note, byte finetune) {
- if (finetune > 15)
- finetune = 15;
- if (note > 59)
- note = 59;
-
- return periods[finetune][note];
-}
-
-} // End of namespace Modules
diff --git a/sound/mods/module.h b/sound/mods/module.h
deleted file mode 100644
index 550b63617e..0000000000
--- a/sound/mods/module.h
+++ /dev/null
@@ -1,90 +0,0 @@
-/* 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_MODS_MODULE_H
-#define SOUND_MODS_MODULE_H
-
-#include "common/stream.h"
-
-namespace Modules {
-
-#include "common/pack-start.h" // START STRUCT PACKING
-
-struct note_t {
- byte sample;
- byte note;
- uint16 period;
- uint16 effect;
-} PACKED_STRUCT;
-
-#include "common/pack-end.h" // END STRUCT PACKING
-
-typedef note_t pattern_t[64][4];
-
-struct sample_t {
- byte name[23];
- uint16 len;
- byte finetune;
- byte vol;
- uint16 repeat;
- uint16 replen;
- int8 *data;
-};
-
-struct sample_offs {
- byte name[23];
- uint16 len;
- uint32 offs;
-};
-
-class Module {
-public:
- byte songname[21];
-
- static const int NUM_SAMPLES = 31;
- sample_t sample[NUM_SAMPLES];
- sample_offs commonSamples[NUM_SAMPLES];
-
- byte songlen;
- byte undef;
- byte songpos[128];
- uint32 sig;
- pattern_t *pattern;
-
- Module();
- ~Module();
-
- bool load(Common::SeekableReadStream &stream, int offs);
- static byte periodToNote(int16 period, byte finetune = 0);
- static int16 noteToPeriod(byte note, byte finetune = 0);
-
-private:
- static const int16 periods[16][60];
- static const uint32 signatures[];
-};
-
-} // End of namespace Modules
-
-#endif
diff --git a/sound/mods/paula.cpp b/sound/mods/paula.cpp
deleted file mode 100644
index c39b37f83d..0000000000
--- a/sound/mods/paula.cpp
+++ /dev/null
@@ -1,212 +0,0 @@
-/* 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/mods/paula.h"
-#include "sound/null.h"
-
-namespace Audio {
-
-Paula::Paula(bool stereo, int rate, uint interruptFreq) :
- _stereo(stereo), _rate(rate), _periodScale((double)kPalPaulaClock / rate), _intFreq(interruptFreq) {
-
- clearVoices();
- _voice[0].panning = 191;
- _voice[1].panning = 63;
- _voice[2].panning = 63;
- _voice[3].panning = 191;
-
- if (_intFreq == 0)
- _intFreq = _rate;
-
- _curInt = 0;
- _timerBase = 1;
- _playing = false;
- _end = true;
-}
-
-Paula::~Paula() {
-}
-
-void Paula::clearVoice(byte voice) {
- assert(voice < NUM_VOICES);
-
- _voice[voice].data = 0;
- _voice[voice].dataRepeat = 0;
- _voice[voice].length = 0;
- _voice[voice].lengthRepeat = 0;
- _voice[voice].period = 0;
- _voice[voice].volume = 0;
- _voice[voice].offset = Offset(0);
- _voice[voice].dmaCount = 0;
-}
-
-int Paula::readBuffer(int16 *buffer, const int numSamples) {
- Common::StackLock lock(_mutex);
-
- memset(buffer, 0, numSamples * 2);
- if (!_playing) {
- return numSamples;
- }
-
- if (_stereo)
- return readBufferIntern<true>(buffer, numSamples);
- else
- return readBufferIntern<false>(buffer, numSamples);
-}
-
-
-template<bool stereo>
-inline int mixBuffer(int16 *&buf, const int8 *data, Paula::Offset &offset, frac_t rate, int neededSamples, uint bufSize, byte volume, byte panning) {
- int samples;
- for (samples = 0; samples < neededSamples && offset.int_off < bufSize; ++samples) {
- const int32 tmp = ((int32) data[offset.int_off]) * volume;
- if (stereo) {
- *buf++ += (tmp * (255 - panning)) >> 7;
- *buf++ += (tmp * (panning)) >> 7;
- } else
- *buf++ += tmp;
-
- // Step to next source sample
- offset.rem_off += rate;
- if (offset.rem_off >= (frac_t)FRAC_ONE) {
- offset.int_off += fracToInt(offset.rem_off);
- offset.rem_off &= FRAC_LO_MASK;
- }
- }
-
- return samples;
-}
-
-template<bool stereo>
-int Paula::readBufferIntern(int16 *buffer, const int numSamples) {
- int samples = _stereo ? numSamples / 2 : numSamples;
- while (samples > 0) {
-
- // Handle 'interrupts'. This gives subclasses the chance to adjust the channel data
- // (e.g. insert new samples, do pitch bending, whatever).
- if (_curInt == 0) {
- _curInt = _intFreq;
- interrupt();
- }
-
- // Compute how many samples to generate: at most the requested number of samples,
- // of course, but we may stop earlier when an 'interrupt' is expected.
- const uint nSamples = MIN((uint)samples, _curInt);
-
- // Loop over the four channels of the emulated Paula chip
- for (int voice = 0; voice < NUM_VOICES; voice++) {
- // No data, or paused -> skip channel
- if (!_voice[voice].data || (_voice[voice].period <= 0))
- continue;
-
- // The Paula chip apparently run at 7.0937892 MHz in the PAL
- // version and at 7.1590905 MHz in the NTSC version. We divide this
- // by the requested the requested output sampling rate _rate
- // (typically 44.1 kHz or 22.05 kHz) obtaining the value _periodScale.
- // This is then divided by the "period" of the channel we are
- // processing, to obtain the correct output 'rate'.
- frac_t rate = doubleToFrac(_periodScale / _voice[voice].period);
- // Cap the volume
- _voice[voice].volume = MIN((byte) 0x40, _voice[voice].volume);
-
-
- Channel &ch = _voice[voice];
- int16 *p = buffer;
- int neededSamples = nSamples;
- assert(ch.offset.int_off < ch.length);
-
- // Mix the generated samples into the output buffer
- neededSamples -= mixBuffer<stereo>(p, ch.data, ch.offset, rate, neededSamples, ch.length, ch.volume, ch.panning);
-
- // Wrap around if necessary
- if (ch.offset.int_off >= ch.length) {
- // Important: Wrap around the offset *before* updating the voice length.
- // Otherwise, if length != lengthRepeat we would wrap incorrectly.
- // Note: If offset >= 2*len ever occurs, the following would be wrong;
- // instead of subtracting, we then should compute the modulus using "%=".
- // Since that requires a division and is slow, and shouldn't be necessary
- // in practice anyway, we only use subtraction.
- ch.offset.int_off -= ch.length;
- ch.dmaCount++;
-
- ch.data = ch.dataRepeat;
- ch.length = ch.lengthRepeat;
- }
-
- // If we have not yet generated enough samples, and looping is active: loop!
- if (neededSamples > 0 && ch.length > 2) {
- // Repeat as long as necessary.
- while (neededSamples > 0) {
- // Mix the generated samples into the output buffer
- neededSamples -= mixBuffer<stereo>(p, ch.data, ch.offset, rate, neededSamples, ch.length, ch.volume, ch.panning);
-
- if (ch.offset.int_off >= ch.length) {
- // Wrap around. See also the note above.
- ch.offset.int_off -= ch.length;
- ch.dmaCount++;
- }
- }
- }
-
- }
- buffer += _stereo ? nSamples * 2 : nSamples;
- _curInt -= nSamples;
- samples -= nSamples;
- }
- return numSamples;
-}
-
-} // End of namespace Audio
-
-
-// Plugin interface
-// (This can only create a null driver since apple II gs support seeems not to be implemented
-// and also is not part of the midi driver architecture. But we need the plugin for the options
-// menu in the launcher and for MidiDriver::detectDevice() which is more or less used by all engines.)
-
-class AmigaMusicPlugin : public NullMusicPlugin {
-public:
- const char *getName() const {
- return _s("Amiga Audio Emulator");
- }
-
- const char *getId() const {
- return "amiga";
- }
-
- MusicDevices getDevices() const;
-};
-
-MusicDevices AmigaMusicPlugin::getDevices() const {
- MusicDevices devices;
- devices.push_back(MusicDevice(this, "", MT_AMIGA));
- return devices;
-}
-
-//#if PLUGIN_ENABLED_DYNAMIC(AMIGA)
- //REGISTER_PLUGIN_DYNAMIC(AMIGA, PLUGIN_TYPE_MUSIC, AmigaMusicPlugin);
-//#else
- REGISTER_PLUGIN_STATIC(AMIGA, PLUGIN_TYPE_MUSIC, AmigaMusicPlugin);
-//#endif
diff --git a/sound/mods/paula.h b/sound/mods/paula.h
deleted file mode 100644
index aa3d5b4ab9..0000000000
--- a/sound/mods/paula.h
+++ /dev/null
@@ -1,210 +0,0 @@
-/* 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_MODS_PAULA_H
-#define SOUND_MODS_PAULA_H
-
-#include "sound/audiostream.h"
-#include "common/frac.h"
-#include "common/mutex.h"
-
-namespace Audio {
-
-/**
- * Emulation of the "Paula" Amiga music chip
- * The interrupt frequency specifies the number of mixed wavesamples between
- * calls of the interrupt method
- */
-class Paula : public AudioStream {
-public:
- static const int NUM_VOICES = 4;
- enum {
- kPalSystemClock = 7093790,
- kNtscSystemClock = 7159090,
- kPalCiaClock = kPalSystemClock / 10,
- kNtscCiaClock = kNtscSystemClock / 10,
- kPalPaulaClock = kPalSystemClock / 2,
- kNtscPauleClock = kNtscSystemClock / 2
- };
-
- /* TODO: Document this */
- struct Offset {
- uint int_off; // integral part of the offset
- frac_t rem_off; // fractional part of the offset, at least 0 and less than 1
-
- explicit Offset(int off = 0) : int_off(off), rem_off(0) {}
- };
-
- Paula(bool stereo = false, int rate = 44100, uint interruptFreq = 0);
- ~Paula();
-
- bool playing() const { return _playing; }
- void setTimerBaseValue( uint32 ticksPerSecond ) { _timerBase = ticksPerSecond; }
- uint32 getTimerBaseValue() { return _timerBase; }
- void setSingleInterrupt(uint sampleDelay) { assert(sampleDelay < _intFreq); _curInt = sampleDelay; }
- void setSingleInterruptUnscaled(uint timerDelay) {
- setSingleInterrupt((uint)(((double)timerDelay * getRate()) / _timerBase));
- }
- void setInterruptFreq(uint sampleDelay) { _intFreq = sampleDelay; _curInt = 0; }
- void setInterruptFreqUnscaled(uint timerDelay) {
- setInterruptFreq((uint)(((double)timerDelay * getRate()) / _timerBase));
- }
- void clearVoice(byte voice);
- void clearVoices() { for (int i = 0; i < NUM_VOICES; ++i) clearVoice(i); }
- void startPlay() { _playing = true; }
- void stopPlay() { _playing = false; }
- void pausePlay(bool pause) { _playing = !pause; }
-
-// AudioStream API
- int readBuffer(int16 *buffer, const int numSamples);
- bool isStereo() const { return _stereo; }
- bool endOfData() const { return _end; }
- int getRate() const { return _rate; }
-
-protected:
- struct Channel {
- const int8 *data;
- const int8 *dataRepeat;
- uint32 length;
- uint32 lengthRepeat;
- int16 period;
- byte volume;
- Offset offset;
- byte panning; // For stereo mixing: 0 = far left, 255 = far right
- int dmaCount;
- };
-
- bool _end;
- Common::Mutex _mutex;
-
- virtual void interrupt() = 0;
-
- void startPaula() {
- _playing = true;
- _end = false;
- }
-
- void stopPaula() {
- _playing = false;
- _end = true;
- }
-
- void setChannelPanning(byte channel, byte panning) {
- assert(channel < NUM_VOICES);
- _voice[channel].panning = panning;
- }
-
- void disableChannel(byte channel) {
- assert(channel < NUM_VOICES);
- _voice[channel].data = 0;
- }
-
- void enableChannel(byte channel) {
- assert(channel < NUM_VOICES);
- Channel &ch = _voice[channel];
- ch.data = ch.dataRepeat;
- ch.length = ch.lengthRepeat;
- // actually first 2 bytes are dropped?
- ch.offset = Offset(0);
- // ch.period = ch.periodRepeat;
- }
-
- void setChannelPeriod(byte channel, int16 period) {
- assert(channel < NUM_VOICES);
- _voice[channel].period = period;
- }
-
- void setChannelVolume(byte channel, byte volume) {
- assert(channel < NUM_VOICES);
- _voice[channel].volume = volume;
- }
-
- void setChannelSampleStart(byte channel, const int8 *data) {
- assert(channel < NUM_VOICES);
- _voice[channel].dataRepeat = data;
- }
-
- void setChannelSampleLen(byte channel, uint32 length) {
- assert(channel < NUM_VOICES);
- assert(length < 32768/2);
- _voice[channel].lengthRepeat = 2 * length;
- }
-
- void setChannelData(uint8 channel, const int8 *data, const int8 *dataRepeat, uint32 length, uint32 lengthRepeat, int32 offset = 0) {
- assert(channel < NUM_VOICES);
-
- Channel &ch = _voice[channel];
-
- ch.dataRepeat = data;
- ch.lengthRepeat = length;
- enableChannel(channel);
- ch.offset = Offset(offset);
-
- ch.dataRepeat = dataRepeat;
- ch.lengthRepeat = lengthRepeat;
- }
-
- void setChannelOffset(byte channel, Offset offset) {
- assert(channel < NUM_VOICES);
- _voice[channel].offset = offset;
- }
-
- Offset getChannelOffset(byte channel) {
- assert(channel < NUM_VOICES);
- return _voice[channel].offset;
- }
-
- int getChannelDmaCount(byte channel) {
- assert(channel < NUM_VOICES);
- return _voice[channel].dmaCount;
- }
-
- void setChannelDmaCount(byte channel, int dmaVal = 0) {
- assert(channel < NUM_VOICES);
- _voice[channel].dmaCount = dmaVal;
- }
-
- void setAudioFilter(bool enable) {
- // TODO: implement
- }
-
-private:
- Channel _voice[NUM_VOICES];
-
- const bool _stereo;
- const int _rate;
- const double _periodScale;
- uint _intFreq;
- uint _curInt;
- uint32 _timerBase;
- bool _playing;
-
- template<bool stereo>
- int readBufferIntern(int16 *buffer, const int numSamples);
-};
-
-} // End of namespace Audio
-
-#endif
diff --git a/sound/mods/protracker.cpp b/sound/mods/protracker.cpp
deleted file mode 100644
index 797b4c417d..0000000000
--- a/sound/mods/protracker.cpp
+++ /dev/null
@@ -1,466 +0,0 @@
-/* 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/mods/protracker.h"
-#include "sound/mods/paula.h"
-#include "sound/mods/module.h"
-
-#include "sound/audiostream.h"
-
-namespace Modules {
-
-class ProtrackerStream : public ::Audio::Paula {
-private:
- Module _module;
-
- int _tick;
- int _row;
- int _pos;
-
- int _speed;
- int _bpm;
-
- // For effect 0xB - Jump To Pattern;
- bool _hasJumpToPattern;
- int _jumpToPattern;
-
- // For effect 0xD - PatternBreak;
- bool _hasPatternBreak;
- int _skipRow;
-
- // For effect 0xE6 - Pattern Loop
- bool _hasPatternLoop;
- int _patternLoopCount;
- int _patternLoopRow;
-
- // For effect 0xEE - Pattern Delay
- byte _patternDelay;
-
- static const int16 sinetable[];
-
- struct {
- byte sample;
- uint16 period;
- Offset offset;
-
- byte vol;
- byte finetune;
-
- // For effect 0x0 - Arpeggio
- bool arpeggio;
- byte arpeggioNotes[3];
-
- // For effect 0x3 - Porta to note
- uint16 portaToNote;
- byte portaToNoteSpeed;
-
- // For effect 0x4 - Vibrato
- int vibrato;
- byte vibratoPos;
- byte vibratoSpeed;
- byte vibratoDepth;
-
- // For effect 0xED - Delay sample
- byte delaySample;
- byte delaySampleTick;
- } _track[4];
-
-public:
- ProtrackerStream(Common::SeekableReadStream *stream, int offs, int rate, bool stereo);
-
-private:
- void interrupt();
-
- void doPorta(int track) {
- if (_track[track].portaToNote && _track[track].portaToNoteSpeed) {
- if (_track[track].period < _track[track].portaToNote) {
- _track[track].period += _track[track].portaToNoteSpeed;
- if (_track[track].period > _track[track].portaToNote)
- _track[track].period = _track[track].portaToNote;
- } else if (_track[track].period > _track[track].portaToNote) {
- _track[track].period -= _track[track].portaToNoteSpeed;
- if (_track[track].period < _track[track].portaToNote)
- _track[track].period = _track[track].portaToNote;
- }
- }
- }
- void doVibrato(int track) {
- _track[track].vibrato =
- (_track[track].vibratoDepth * sinetable[_track[track].vibratoPos]) / 128;
- _track[track].vibratoPos += _track[track].vibratoSpeed;
- _track[track].vibratoPos %= 64;
- }
- void doVolSlide(int track, byte ex, byte ey) {
- int vol = _track[track].vol;
- if (ex == 0)
- vol -= ey;
- else if (ey == 0)
- vol += ex;
-
- if (vol < 0)
- vol = 0;
- else if (vol > 64)
- vol = 64;
-
- _track[track].vol = vol;
- }
-
- void updateRow();
- void updateEffects();
-
-};
-
-const int16 ProtrackerStream::sinetable[64] = {
- 0, 24, 49, 74, 97, 120, 141, 161,
- 180, 197, 212, 224, 235, 244, 250, 253,
- 255, 253, 250, 244, 235, 224, 212, 197,
- 180, 161, 141, 120, 97, 74, 49, 24,
- 0, -24, -49, -74, -97, -120, -141, -161,
- -180, -197, -212, -224, -235, -244, -250, -253,
- -255, -253, -250, -244, -235, -224, -212, -197,
- -180, -161, -141, -120, -97, -74, -49, -24
-};
-
-ProtrackerStream::ProtrackerStream(Common::SeekableReadStream *stream, int offs, int rate, bool stereo) :
- Paula(stereo, rate, rate/50) {
- bool result = _module.load(*stream, offs);
- assert(result);
-
- _tick = _row = _pos = 0;
-
- _speed = 6;
- _bpm = 125;
-
- _hasJumpToPattern = false;
- _jumpToPattern = 0;
-
- _hasPatternBreak = false;
- _skipRow = 0;
-
- _hasPatternLoop = false;
- _patternLoopCount = 0;
- _patternLoopRow = 0;
-
- _patternDelay = 0;
-
- memset(_track, 0, sizeof(_track));
-
- startPaula();
-}
-
-void ProtrackerStream::updateRow() {
- for (int track = 0; track < 4; track++) {
- _track[track].arpeggio = false;
- _track[track].vibrato = 0;
- _track[track].delaySampleTick = 0;
- const note_t note =
- _module.pattern[_module.songpos[_pos]][_row][track];
-
- const int effect = note.effect >> 8;
-
- if (note.sample) {
- if (_track[track].sample != note.sample) {
- _track[track].vibratoPos = 0;
- }
- _track[track].sample = note.sample;
- _track[track].finetune = _module.sample[note.sample - 1].finetune;
- _track[track].vol = _module.sample[note.sample - 1].vol;
- }
-
- if (note.period) {
- if (effect != 3 && effect != 5) {
- if (_track[track].finetune)
- _track[track].period = _module.noteToPeriod(note.note, _track[track].finetune);
- else
- _track[track].period = note.period;
- _track[track].offset = Offset(0);
- }
- }
-
- const byte exy = note.effect & 0xff;
- const byte ex = (note.effect >> 4) & 0xf;
- const byte ey = note.effect & 0xf;
-
- int vol;
- switch (effect) {
- case 0x0:
- if (exy) {
- _track[track].arpeggio = true;
- if (note.period) {
- _track[track].arpeggioNotes[0] = note.note;
- _track[track].arpeggioNotes[1] = note.note + ex;
- _track[track].arpeggioNotes[2] = note.note + ey;
- }
- }
- break;
- case 0x1:
- break;
- case 0x2:
- break;
- case 0x3:
- if (note.period)
- _track[track].portaToNote = note.period;
- if (exy)
- _track[track].portaToNoteSpeed = exy;
- break;
- case 0x4:
- if (exy) {
- _track[track].vibratoSpeed = ex;
- _track[track].vibratoDepth = ey;
- }
- break;
- case 0x5:
- doPorta(track);
- doVolSlide(track, ex, ey);
- break;
- case 0x6:
- doVibrato(track);
- doVolSlide(track, ex, ey);
- break;
- case 0x9: // Set sample offset
- if (exy) {
- _track[track].offset = Offset(exy * 256);
- setChannelOffset(track, _track[track].offset);
- }
- break;
- case 0xA:
- break;
- case 0xB:
- _hasJumpToPattern = true;
- _jumpToPattern = exy;
- break;
- case 0xC:
- _track[track].vol = exy;
- break;
- case 0xD:
- _hasPatternBreak = true;
- _skipRow = ex * 10 + ey;
- break;
- case 0xE:
- switch (ex) {
- case 0x0: // Switch filters off
- break;
- case 0x1: // Fine slide up
- _track[track].period -= exy;
- break;
- case 0x2: // Fine slide down
- _track[track].period += exy;
- break;
- case 0x5: // Set finetune
- _track[track].finetune = ey;
- _module.sample[_track[track].sample].finetune = ey;
- if (note.period) {
- if (ey)
- _track[track].period = _module.noteToPeriod(note.note, ey);
- else
- _track[track].period = note.period;
- }
- break;
- case 0x6:
- if (ey == 0) {
- _patternLoopRow = _row;
- } else {
- _patternLoopCount++;
- if (_patternLoopCount <= ey)
- _hasPatternLoop = true;
- else
- _patternLoopCount = 0;
- }
- break;
- case 0x9:
- break; // Retrigger note
- case 0xA: // Fine volume slide up
- vol = _track[track].vol + ey;
- if (vol > 64)
- vol = 64;
- _track[track].vol = vol;
- break;
- case 0xB: // Fine volume slide down
- vol = _track[track].vol - ey;
- if (vol < 0)
- vol = 0;
- _track[track].vol = vol;
- break;
- case 0xD: // Delay sample
- _track[track].delaySampleTick = ey;
- _track[track].delaySample = _track[track].sample;
- _track[track].sample = 0;
- _track[track].vol = 0;
- break;
- case 0xE: // Pattern delay
- _patternDelay = ey;
- break;
- default:
- warning("Unimplemented effect %X", note.effect);
- }
- break;
-
- case 0xF:
- if (exy < 0x20) {
- _speed = exy;
- } else {
- _bpm = exy;
- setInterruptFreq((int) (getRate() / (_bpm * 0.4)));
- }
- break;
- default:
- warning("Unimplemented effect %X", note.effect);
- }
- }
-}
-
-void ProtrackerStream::updateEffects() {
- for (int track = 0; track < 4; track++) {
- _track[track].vibrato = 0;
-
- const note_t note =
- _module.pattern[_module.songpos[_pos]][_row][track];
-
- const int effect = note.effect >> 8;
-
- const int exy = note.effect & 0xff;
- const int ex = (note.effect >> 4) & 0xf;
- const int ey = (note.effect) & 0xf;
-
- switch (effect) {
- case 0x0:
- if (exy) {
- const int idx = (_tick == 1) ? 0 : (_tick % 3);
- _track[track].period =
- _module.noteToPeriod(_track[track].arpeggioNotes[idx],
- _track[track].finetune);
- }
- break;
- case 0x1:
- _track[track].period -= exy;
- break;
- case 0x2:
- _track[track].period += exy;
- break;
- case 0x3:
- doPorta(track);
- break;
- case 0x4:
- doVibrato(track);
- break;
- case 0x5:
- doPorta(track);
- doVolSlide(track, ex, ey);
- break;
- case 0x6:
- doVibrato(track);
- doVolSlide(track, ex, ey);
- break;
- case 0xA:
- doVolSlide(track, ex, ey);
- break;
- case 0xE:
- switch (ex) {
- case 0x6:
- break; // Pattern loop
- case 0x9: // Retrigger note
- if (ey && (_tick % ey) == 0)
- _track[track].offset = Offset(0);
- break;
- case 0xD: // Delay sample
- if (_tick == _track[track].delaySampleTick) {
- _track[track].sample = _track[track].delaySample;
- _track[track].offset = Offset(0);
- if (_track[track].sample)
- _track[track].vol = _module.sample[_track[track].sample - 1].vol;
- }
- break;
- }
- break;
- }
- }
-}
-
-void ProtrackerStream::interrupt() {
- int track;
-
- for (track = 0; track < 4; track++) {
- _track[track].offset = getChannelOffset(track);
- if (_tick == 0 && _track[track].arpeggio) {
- _track[track].period = _module.noteToPeriod(_track[track].arpeggioNotes[0],
- _track[track].finetune);
- }
- }
-
- if (_tick == 0) {
- if (_hasJumpToPattern) {
- _hasJumpToPattern = false;
- _pos = _jumpToPattern;
- _row = 0;
- } else if (_hasPatternBreak) {
- _hasPatternBreak = false;
- _row = _skipRow;
- _pos = (_pos + 1) % _module.songlen;
- _patternLoopRow = 0;
- } else if (_hasPatternLoop) {
- _hasPatternLoop = false;
- _row = _patternLoopRow;
- }
- if (_row >= 64) {
- _row = 0;
- _pos = (_pos + 1) % _module.songlen;
- _patternLoopRow = 0;
- }
-
- updateRow();
- } else
- updateEffects();
-
- _tick = (_tick + 1) % (_speed + _patternDelay * _speed);
- if (_tick == 0) {
- _row++;
- _patternDelay = 0;
- }
-
- for (track = 0; track < 4; track++) {
- setChannelVolume(track, _track[track].vol);
- setChannelPeriod(track, _track[track].period + _track[track].vibrato);
- if (_track[track].sample) {
- sample_t &sample = _module.sample[_track[track].sample - 1];
- setChannelData(track,
- sample.data,
- sample.replen > 2 ? sample.data + sample.repeat : 0,
- sample.len,
- sample.replen);
- setChannelOffset(track, _track[track].offset);
- _track[track].sample = 0;
- }
- }
-}
-
-} // End of namespace Modules
-
-namespace Audio {
-
-AudioStream *makeProtrackerStream(Common::SeekableReadStream *stream, int offs, int rate, bool stereo) {
- return new Modules::ProtrackerStream(stream, offs, rate, stereo);
-}
-
-} // End of namespace Audio
diff --git a/sound/mods/protracker.h b/sound/mods/protracker.h
deleted file mode 100644
index af722637c7..0000000000
--- a/sound/mods/protracker.h
+++ /dev/null
@@ -1,57 +0,0 @@
-/* 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$
- *
- */
-
-/**
- * @file
- * Sound decoder used in engines:
- * - agos
- * - parallaction
- */
-
-#ifndef SOUND_MODS_PROTRACKER_H
-#define SOUND_MODS_PROTRACKER_H
-
-#include "common/stream.h"
-
-namespace Audio {
-
-class AudioStream;
-
-/*
- * Factory function for ProTracker streams. Reads all data from the
- * given ReadStream and creates an AudioStream from this. No reference
- * to the 'stream' object is kept, so you can safely delete it after
- * invoking this factory.
- *
- * @param stream the ReadStream from which to read the ProTracker data
- * @param rate TODO
- * @param stereo TODO
- * @return a new AudioStream, or NULL, if an error occurred
- */
-AudioStream *makeProtrackerStream(Common::SeekableReadStream *stream, int offs = 0, int rate = 44100, bool stereo = true);
-
-} // End of namespace Audio
-
-#endif
diff --git a/sound/mods/rjp1.cpp b/sound/mods/rjp1.cpp
deleted file mode 100644
index be376d61a4..0000000000
--- a/sound/mods/rjp1.cpp
+++ /dev/null
@@ -1,582 +0,0 @@
-/* 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 "common/debug.h"
-#include "common/endian.h"
-
-#include "sound/mods/paula.h"
-#include "sound/mods/rjp1.h"
-#include "sound/audiostream.h"
-
-namespace Audio {
-
-struct Rjp1Channel {
- const int8 *waveData;
- const int8 *modulatePeriodData;
- const int8 *modulateVolumeData;
- const int8 *envelopeData;
- uint16 volumeScale;
- int16 volume;
- uint16 modulatePeriodBase;
- uint32 modulatePeriodLimit;
- uint32 modulatePeriodIndex;
- uint16 modulateVolumeBase;
- uint32 modulateVolumeLimit;
- uint32 modulateVolumeIndex;
- uint8 freqStep;
- uint32 freqInc;
- uint32 freqInit;
- const uint8 *noteData;
- const uint8 *sequenceOffsets;
- const uint8 *sequenceData;
- uint8 loopSeqCount;
- uint8 loopSeqCur;
- uint8 loopSeq2Count;
- uint8 loopSeq2Cur;
- bool active;
- int16 modulatePeriodInit;
- int16 modulatePeriodNext;
- bool setupNewNote;
- int8 envelopeMode;
- int8 envelopeScale;
- int8 envelopeEnd1;
- int8 envelopeEnd2;
- int8 envelopeStart;
- int8 envelopeVolume;
- uint8 currentInstrument;
- const int8 *data;
- uint16 pos;
- uint16 len;
- uint16 repeatPos;
- uint16 repeatLen;
- bool isSfx;
-};
-
-class Rjp1 : public Paula {
-public:
-
- struct Vars {
- int8 *instData;
- uint8 *songData[7];
- uint8 activeChannelsMask;
- uint8 currentChannel;
- int subsongsCount;
- int instrumentsCount;
- };
-
- Rjp1(int rate, bool stereo);
- virtual ~Rjp1();
-
- bool load(Common::SeekableReadStream *songData, Common::SeekableReadStream *instrumentsData);
- void unload();
-
- void startPattern(int ch, int pat);
- void startSong(int song);
-
-protected:
-
- void startSequence(uint8 channelNum, uint8 seqNum);
- void turnOffChannel(Rjp1Channel *channel);
- void playChannel(Rjp1Channel *channel);
- void turnOnChannel(Rjp1Channel *channel);
- bool executeSfxSequenceOp(Rjp1Channel *channel, uint8 code, const uint8 *&p);
- bool executeSongSequenceOp(Rjp1Channel *channel, uint8 code, const uint8 *&p);
- void playSongSequence(Rjp1Channel *channel);
- void modulateVolume(Rjp1Channel *channel);
- void modulatePeriod(Rjp1Channel *channel);
- void setupNote(Rjp1Channel *channel, int16 freq);
- void setupInstrument(Rjp1Channel *channel, uint8 num);
- void setRelease(Rjp1Channel *channel);
- void modulateVolumeEnvelope(Rjp1Channel *channel);
- void setSustain(Rjp1Channel *channel);
- void setDecay(Rjp1Channel *channel);
- void modulateVolumeWaveform(Rjp1Channel *channel);
- void setVolume(Rjp1Channel *channel);
-
- void stopPaulaChannel(uint8 channel);
- void setupPaulaChannel(uint8 channel, const int8 *waveData, uint16 offset, uint16 len, uint16 repeatPos, uint16 repeatLen);
-
- virtual void interrupt();
-
- Vars _vars;
- Rjp1Channel _channelsTable[4];
-
- static const int16 _periodsTable[];
- static const int _periodsCount;
-};
-
-Rjp1::Rjp1(int rate, bool stereo)
- : Paula(stereo, rate, rate / 50) {
- memset(&_vars, 0, sizeof(_vars));
- memset(_channelsTable, 0, sizeof(_channelsTable));
-}
-
-Rjp1::~Rjp1() {
- unload();
-}
-
-bool Rjp1::load(Common::SeekableReadStream *songData, Common::SeekableReadStream *instrumentsData) {
- if (songData->readUint32BE() == MKID_BE('RJP1') && songData->readUint32BE() == MKID_BE('SMOD')) {
- for (int i = 0; i < 7; ++i) {
- uint32 size = songData->readUint32BE();
- _vars.songData[i] = (uint8 *)malloc(size);
- if (!_vars.songData[i])
- return false;
-
- songData->read(_vars.songData[i], size);
- switch (i) {
- case 0:
- _vars.instrumentsCount = size / 32;
- break;
- case 1:
- break;
- case 2:
- // sequence index to offsets, 1 per channel
- _vars.subsongsCount = size / 4;
- break;
- case 3:
- case 4:
- // sequence offsets
- break;
- case 5:
- case 6:
- // sequence data
- break;
- }
- }
-
- if (instrumentsData->readUint32BE() == MKID_BE('RJP1')) {
- uint32 size = instrumentsData->size() - 4;
- _vars.instData = (int8 *)malloc(size);
- if (!_vars.instData)
- return false;
-
- instrumentsData->read(_vars.instData, size);
-
- }
- }
-
- debug(5, "Rjp1::load() _instrumentsCount = %d _subsongsCount = %d", _vars.instrumentsCount, _vars.subsongsCount);
- return true;
-}
-
-void Rjp1::unload() {
- for (int i = 0; i < 7; ++i) {
- free(_vars.songData[i]);
- }
- free(_vars.instData);
- memset(&_vars, 0, sizeof(_vars));
- memset(_channelsTable, 0, sizeof(_channelsTable));
-}
-
-void Rjp1::startPattern(int ch, int pat) {
- Rjp1Channel *channel = &_channelsTable[ch];
- _vars.activeChannelsMask |= 1 << ch;
- channel->sequenceData = READ_BE_UINT32(_vars.songData[4] + pat * 4) + _vars.songData[6];
- channel->loopSeqCount = 6;
- channel->loopSeqCur = channel->loopSeq2Cur = 1;
- channel->active = true;
- channel->isSfx = true;
- // "start" Paula audiostream
- startPaula();
-}
-
-void Rjp1::startSong(int song) {
- if (song == 0 || song >= _vars.subsongsCount) {
- warning("Invalid subsong number %d, defaulting to 1", song);
- song = 1;
- }
- const uint8 *p = _vars.songData[2] + (song & 0x3F) * 4;
- for (int i = 0; i < 4; ++i) {
- uint8 seq = *p++;
- if (seq) {
- startSequence(i, seq);
- }
- }
- // "start" Paula audiostream
- startPaula();
-}
-
-void Rjp1::startSequence(uint8 channelNum, uint8 seqNum) {
- Rjp1Channel *channel = &_channelsTable[channelNum];
- _vars.activeChannelsMask |= 1 << channelNum;
- if (seqNum != 0) {
- const uint8 *p = READ_BE_UINT32(_vars.songData[3] + seqNum * 4) + _vars.songData[5];
- uint8 seq = *p++;
- channel->sequenceOffsets = p;
- channel->sequenceData = READ_BE_UINT32(_vars.songData[4] + seq * 4) + _vars.songData[6];
- channel->loopSeqCount = 6;
- channel->loopSeqCur = channel->loopSeq2Cur = 1;
- channel->active = true;
- } else {
- channel->active = false;
- turnOffChannel(channel);
- }
-}
-
-void Rjp1::turnOffChannel(Rjp1Channel *channel) {
- stopPaulaChannel(channel - _channelsTable);
-}
-
-void Rjp1::playChannel(Rjp1Channel *channel) {
- if (channel->active) {
- turnOnChannel(channel);
- if (channel->sequenceData) {
- playSongSequence(channel);
- }
- modulateVolume(channel);
- modulatePeriod(channel);
- }
-}
-
-void Rjp1::turnOnChannel(Rjp1Channel *channel) {
- if (channel->setupNewNote) {
- channel->setupNewNote = false;
- setupPaulaChannel(channel - _channelsTable, channel->data, channel->pos, channel->len, channel->repeatPos, channel->repeatLen);
- }
-}
-
-bool Rjp1::executeSfxSequenceOp(Rjp1Channel *channel, uint8 code, const uint8 *&p) {
- bool loop = true;
- switch (code & 7) {
- case 0:
- _vars.activeChannelsMask &= ~(1 << _vars.currentChannel);
- loop = false;
- stopPaula();
- break;
- case 1:
- setRelease(channel);
- loop = false;
- break;
- case 2:
- channel->loopSeqCount = *p++;
- break;
- case 3:
- channel->loopSeq2Count = *p++;
- break;
- case 4:
- code = *p++;
- if (code != 0) {
- setupInstrument(channel, code);
- }
- break;
- case 7:
- loop = false;
- break;
- }
- return loop;
-}
-
-bool Rjp1::executeSongSequenceOp(Rjp1Channel *channel, uint8 code, const uint8 *&p) {
- bool loop = true;
- const uint8 *offs;
- switch (code & 7) {
- case 0:
- offs = channel->sequenceOffsets;
- channel->loopSeq2Count = 1;
- while (1) {
- code = *offs++;
- if (code != 0) {
- channel->sequenceOffsets = offs;
- p = READ_BE_UINT32(_vars.songData[4] + code * 4) + _vars.songData[6];
- break;
- } else {
- code = offs[0];
- if (code == 0) {
- p = 0;
- channel->active = false;
- _vars.activeChannelsMask &= ~(1 << _vars.currentChannel);
- loop = false;
- break;
- } else if (code & 0x80) {
- code = offs[1];
- offs = READ_BE_UINT32(_vars.songData[3] + code * 4) + _vars.songData[5];
- } else {
- offs -= code;
- }
- }
- }
- break;
- case 1:
- setRelease(channel);
- loop = false;
- break;
- case 2:
- channel->loopSeqCount = *p++;
- break;
- case 3:
- channel->loopSeq2Count = *p++;
- break;
- case 4:
- code = *p++;
- if (code != 0) {
- setupInstrument(channel, code);
- }
- break;
- case 5:
- channel->volumeScale = *p++;
- break;
- case 6:
- channel->freqStep = *p++;
- channel->freqInc = READ_BE_UINT32(p); p += 4;
- channel->freqInit = 0;
- break;
- case 7:
- loop = false;
- break;
- }
- return loop;
-}
-
-void Rjp1::playSongSequence(Rjp1Channel *channel) {
- const uint8 *p = channel->sequenceData;
- --channel->loopSeqCur;
- if (channel->loopSeqCur == 0) {
- --channel->loopSeq2Cur;
- if (channel->loopSeq2Cur == 0) {
- bool loop = true;
- do {
- uint8 code = *p++;
- if (code & 0x80) {
- if (channel->isSfx) {
- loop = executeSfxSequenceOp(channel, code, p);
- } else {
- loop = executeSongSequenceOp(channel, code, p);
- }
- } else {
- code >>= 1;
- if (code < _periodsCount) {
- setupNote(channel, _periodsTable[code]);
- }
- loop = false;
- }
- } while (loop);
- channel->sequenceData = p;
- channel->loopSeq2Cur = channel->loopSeq2Count;
- }
- channel->loopSeqCur = channel->loopSeqCount;
- }
-}
-
-void Rjp1::modulateVolume(Rjp1Channel *channel) {
- modulateVolumeEnvelope(channel);
- modulateVolumeWaveform(channel);
- setVolume(channel);
-}
-
-void Rjp1::modulatePeriod(Rjp1Channel *channel) {
- if (channel->modulatePeriodData) {
- uint32 per = channel->modulatePeriodIndex;
- int period = (channel->modulatePeriodData[per] * channel->modulatePeriodInit) / 128;
- period = -period;
- if (period < 0) {
- period /= 2;
- }
- channel->modulatePeriodNext = period + channel->modulatePeriodInit;
- ++per;
- if (per == channel->modulatePeriodLimit) {
- per = channel->modulatePeriodBase * 2;
- }
- channel->modulatePeriodIndex = per;
- }
- if (channel->freqStep != 0) {
- channel->freqInit += channel->freqInc;
- --channel->freqStep;
- }
- setChannelPeriod(channel - _channelsTable, channel->freqInit + channel->modulatePeriodNext);
-}
-
-void Rjp1::setupNote(Rjp1Channel *channel, int16 period) {
- const uint8 *note = channel->noteData;
- if (note) {
- channel->modulatePeriodInit = channel->modulatePeriodNext = period;
- channel->freqInit = 0;
- const int8 *e = (const int8 *)_vars.songData[1] + READ_BE_UINT16(note + 12);
- channel->envelopeData = e;
- channel->envelopeStart = e[1];
- channel->envelopeScale = e[1] - e[0];
- channel->envelopeEnd2 = e[2];
- channel->envelopeEnd1 = e[2];
- channel->envelopeMode = 4;
- channel->data = channel->waveData;
- channel->pos = READ_BE_UINT16(note + 16);
- channel->len = channel->pos + READ_BE_UINT16(note + 18);
- channel->setupNewNote = true;
- }
-}
-
-void Rjp1::setupInstrument(Rjp1Channel *channel, uint8 num) {
- if (channel->currentInstrument != num) {
- channel->currentInstrument = num;
- const uint8 *p = _vars.songData[0] + num * 32;
- channel->noteData = p;
- channel->repeatPos = READ_BE_UINT16(p + 20);
- channel->repeatLen = READ_BE_UINT16(p + 22);
- channel->volumeScale = READ_BE_UINT16(p + 14);
- channel->modulatePeriodBase = READ_BE_UINT16(p + 24);
- channel->modulatePeriodIndex = 0;
- channel->modulatePeriodLimit = READ_BE_UINT16(p + 26) * 2;
- channel->modulateVolumeBase = READ_BE_UINT16(p + 28);
- channel->modulateVolumeIndex = 0;
- channel->modulateVolumeLimit = READ_BE_UINT16(p + 30) * 2;
- channel->waveData = _vars.instData + READ_BE_UINT32(p);
- uint32 off = READ_BE_UINT32(p + 4);
- if (off) {
- channel->modulatePeriodData = _vars.instData + off;
- }
- off = READ_BE_UINT32(p + 8);
- if (off) {
- channel->modulateVolumeData = _vars.instData + off;
- }
- }
-}
-
-void Rjp1::setRelease(Rjp1Channel *channel) {
- const int8 *e = channel->envelopeData;
- if (e) {
- channel->envelopeStart = 0;
- channel->envelopeScale = -channel->envelopeVolume;
- channel->envelopeEnd2 = e[5];
- channel->envelopeEnd1 = e[5];
- channel->envelopeMode = -1;
- }
-}
-
-void Rjp1::modulateVolumeEnvelope(Rjp1Channel *channel) {
- if (channel->envelopeMode) {
- int16 es = channel->envelopeScale;
- if (es) {
- int8 m = channel->envelopeEnd1;
- if (m == 0) {
- es = 0;
- } else {
- es *= m;
- m = channel->envelopeEnd2;
- if (m == 0) {
- es = 0;
- } else {
- es /= m;
- }
- }
- }
- channel->envelopeVolume = channel->envelopeStart - es;
- --channel->envelopeEnd1;
- if (channel->envelopeEnd1 == -1) {
- switch (channel->envelopeMode) {
- case 0:
- break;
- case 2:
- setSustain(channel);
- break;
- case 4:
- setDecay(channel);
- break;
- case -1:
- setSustain(channel);
- break;
- default:
- error("Unhandled envelope mode %d", channel->envelopeMode);
- break;
- }
- return;
- }
- }
- channel->volume = channel->envelopeVolume;
-}
-
-void Rjp1::setSustain(Rjp1Channel *channel) {
- channel->envelopeMode = 0;
-}
-
-void Rjp1::setDecay(Rjp1Channel *channel) {
- const int8 *e = channel->envelopeData;
- if (e) {
- channel->envelopeStart = e[3];
- channel->envelopeScale = e[3] - e[1];
- channel->envelopeEnd2 = e[4];
- channel->envelopeEnd1 = e[4];
- channel->envelopeMode = 2;
- }
-}
-
-void Rjp1::modulateVolumeWaveform(Rjp1Channel *channel) {
- if (channel->modulateVolumeData) {
- uint32 i = channel->modulateVolumeIndex;
- channel->volume += channel->modulateVolumeData[i] * channel->volume / 128;
- ++i;
- if (i == channel->modulateVolumeLimit) {
- i = channel->modulateVolumeBase * 2;
- }
- channel->modulateVolumeIndex = i;
- }
-}
-
-void Rjp1::setVolume(Rjp1Channel *channel) {
- channel->volume = (channel->volume * channel->volumeScale) / 64;
- channel->volume = CLIP<int16>(channel->volume, 0, 64);
- setChannelVolume(channel - _channelsTable, channel->volume);
-}
-
-void Rjp1::stopPaulaChannel(uint8 channel) {
- clearVoice(channel);
-}
-
-void Rjp1::setupPaulaChannel(uint8 channel, const int8 *waveData, uint16 offset, uint16 len, uint16 repeatPos, uint16 repeatLen) {
- if (waveData) {
- setChannelData(channel, waveData, waveData + repeatPos * 2, len * 2, repeatLen * 2, offset * 2);
- }
-}
-
-void Rjp1::interrupt() {
- for (int i = 0; i < 4; ++i) {
- _vars.currentChannel = i;
- playChannel(&_channelsTable[i]);
- }
-}
-
-const int16 Rjp1::_periodsTable[] = {
- 0x01C5, 0x01E0, 0x01FC, 0x021A, 0x023A, 0x025C, 0x0280, 0x02A6, 0x02D0,
- 0x02FA, 0x0328, 0x0358, 0x00E2, 0x00F0, 0x00FE, 0x010D, 0x011D, 0x012E,
- 0x0140, 0x0153, 0x0168, 0x017D, 0x0194, 0x01AC, 0x0071, 0x0078, 0x007F,
- 0x0087, 0x008F, 0x0097, 0x00A0, 0x00AA, 0x00B4, 0x00BE, 0x00CA, 0x00D6
-};
-
-const int Rjp1::_periodsCount = ARRAYSIZE(_periodsTable);
-
-AudioStream *makeRjp1Stream(Common::SeekableReadStream *songData, Common::SeekableReadStream *instrumentsData, int num, int rate, bool stereo) {
- Rjp1 *stream = new Rjp1(rate, stereo);
- if (stream->load(songData, instrumentsData)) {
- if (num < 0) {
- stream->startPattern(3, -num);
- } else {
- stream->startSong(num);
- }
- return stream;
- }
- delete stream;
- return 0;
-}
-
-} // End of namespace Audio
diff --git a/sound/mods/rjp1.h b/sound/mods/rjp1.h
deleted file mode 100644
index e1960921b2..0000000000
--- a/sound/mods/rjp1.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/* 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$
- *
- */
-
-/**
- * @file
- * Sound decoder used in engines:
- * - queen
- */
-
-#ifndef SOUND_MODS_RJP1_H
-#define SOUND_MODS_RJP1_H
-
-#include "common/stream.h"
-
-namespace Audio {
-
-class AudioStream;
-
-/*
- * Factory function for RichardJoseph1 modules. Reads all data from the
- * given songData and instrumentsData streams and creates an AudioStream
- * from this. No references to these stream objects are kept.
- */
-AudioStream *makeRjp1Stream(Common::SeekableReadStream *songData, Common::SeekableReadStream *instrumentsData, int num, int rate = 44100, bool stereo = true);
-
-} // End of namespace Audio
-
-#endif
diff --git a/sound/mods/soundfx.cpp b/sound/mods/soundfx.cpp
deleted file mode 100644
index 3af8ca19c6..0000000000
--- a/sound/mods/soundfx.cpp
+++ /dev/null
@@ -1,275 +0,0 @@
-/* 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 "common/endian.h"
-
-#include "sound/mods/paula.h"
-#include "sound/mods/soundfx.h"
-#include "sound/audiostream.h"
-
-namespace Audio {
-
-struct SoundFxInstrument {
- char name[23];
- uint16 len;
- uint8 finetune;
- uint8 volume;
- uint16 repeatPos;
- uint16 repeatLen;
- int8 *data;
-};
-
-class SoundFx : public Paula {
-public:
-
- enum {
- NUM_CHANNELS = 4,
- NUM_INSTRUMENTS = 15
- };
-
- SoundFx(int rate, bool stereo);
- virtual ~SoundFx();
-
- bool load(Common::SeekableReadStream *data, LoadSoundFxInstrumentCallback loadCb);
- void play();
-
-protected:
-
- void handlePattern(int ch, uint32 pat);
- void updateEffects(int ch);
- void handleTick();
-
- void disablePaulaChannel(uint8 channel);
- void setupPaulaChannel(uint8 channel, const int8 *data, uint16 len, uint16 repeatPos, uint16 repeatLen);
-
- virtual void interrupt();
-
- uint8 _ticks;
- uint16 _delay;
- SoundFxInstrument _instruments[NUM_INSTRUMENTS];
- uint8 _numOrders;
- uint8 _curOrder;
- uint16 _curPos;
- uint8 _ordersTable[128];
- uint8 *_patternData;
- uint16 _effects[NUM_CHANNELS];
-};
-
-SoundFx::SoundFx(int rate, bool stereo)
- : Paula(stereo, rate) {
- setTimerBaseValue(kPalCiaClock);
- _ticks = 0;
- _delay = 0;
- memset(_instruments, 0, sizeof(_instruments));
- _numOrders = 0;
- _curOrder = 0;
- _curPos = 0;
- memset(_ordersTable, 0, sizeof(_ordersTable));
- _patternData = 0;
- memset(_effects, 0, sizeof(_effects));
-}
-
-SoundFx::~SoundFx() {
- free(_patternData);
- for (int i = 0; i < NUM_INSTRUMENTS; ++i) {
- free(_instruments[i].data);
- }
-}
-
-bool SoundFx::load(Common::SeekableReadStream *data, LoadSoundFxInstrumentCallback loadCb) {
- int instrumentsSize[15];
- if (!loadCb) {
- for (int i = 0; i < NUM_INSTRUMENTS; ++i) {
- instrumentsSize[i] = data->readUint32BE();
- }
- }
- uint8 tag[4];
- data->read(tag, 4);
- if (memcmp(tag, "SONG", 4) != 0) {
- return false;
- }
- _delay = data->readUint16BE();
- data->skip(7 * 2);
- for (int i = 0; i < NUM_INSTRUMENTS; ++i) {
- SoundFxInstrument *ins = &_instruments[i];
- data->read(ins->name, 22); ins->name[22] = 0;
- ins->len = data->readUint16BE();
- ins->finetune = data->readByte();
- ins->volume = data->readByte();
- ins->repeatPos = data->readUint16BE();
- ins->repeatLen = data->readUint16BE();
- }
- _numOrders = data->readByte();
- data->skip(1);
- data->read(_ordersTable, 128);
- int maxOrder = 0;
- for (int i = 0; i < _numOrders; ++i) {
- if (_ordersTable[i] > maxOrder) {
- maxOrder = _ordersTable[i];
- }
- }
- int patternSize = (maxOrder + 1) * 4 * 4 * 64;
- _patternData = (uint8 *)malloc(patternSize);
- if (!_patternData) {
- return false;
- }
- data->read(_patternData, patternSize);
- for (int i = 0; i < NUM_INSTRUMENTS; ++i) {
- SoundFxInstrument *ins = &_instruments[i];
- if (!loadCb) {
- if (instrumentsSize[i] != 0) {
- assert(ins->len <= 1 || ins->len * 2 <= instrumentsSize[i]);
- assert(ins->repeatLen <= 1 || (ins->repeatPos + ins->repeatLen) * 2 <= instrumentsSize[i]);
- ins->data = (int8 *)malloc(instrumentsSize[i]);
- if (!ins->data) {
- return false;
- }
- data->read(ins->data, instrumentsSize[i]);
- }
- } else {
- if (ins->name[0]) {
- ins->name[8] = '\0';
- ins->data = (int8 *)(*loadCb)(ins->name, 0);
- if (!ins->data) {
- return false;
- }
- }
- }
- }
- return true;
-}
-
-void SoundFx::play() {
- _curPos = 0;
- _curOrder = 0;
- _ticks = 0;
- setInterruptFreqUnscaled(_delay);
- startPaula();
-}
-
-void SoundFx::handlePattern(int ch, uint32 pat) {
- uint16 note1 = pat >> 16;
- uint16 note2 = pat & 0xFFFF;
- if (note1 == 0xFFFD) { // PIC
- _effects[ch] = 0;
- return;
- }
- _effects[ch] = note2;
- if (note1 == 0xFFFE) { // STP
- disablePaulaChannel(ch);
- return;
- }
- int ins = (note2 & 0xF000) >> 12;
- if (ins != 0) {
- SoundFxInstrument *i = &_instruments[ins - 1];
- setupPaulaChannel(ch, i->data, i->len, i->repeatPos, i->repeatLen);
- int effect = (note2 & 0xF00) >> 8;
- int volume = i->volume;
- switch (effect) {
- case 5: // volume up
- volume += (note2 & 0xFF);
- if (volume > 63) {
- volume = 63;
- }
- break;
- case 6: // volume down
- volume -= (note2 & 0xFF);
- if (volume < 0) {
- volume = 0;
- }
- break;
- }
- setChannelVolume(ch, volume);
- }
- if (note1 != 0) {
- setChannelPeriod(ch, note1);
- }
-}
-
-void SoundFx::updateEffects(int ch) {
- // updateEffects() is a no-op in all Delphine Software games using SoundFx : FW,OS,Cruise,AW
- if (_effects[ch] != 0) {
- switch (_effects[ch]) {
- case 1: // appreggiato
- case 2: // pitchbend
- case 3: // ledon, enable low-pass filter
- case 4: // ledoff, disable low-pass filter
- case 7: // set step up
- case 8: // set step down
- warning("Unhandled effect %d", _effects[ch]);
- break;
- }
- }
-}
-
-void SoundFx::handleTick() {
- ++_ticks;
- if (_ticks != 6) {
- for (int ch = 0; ch < 4; ++ch) {
- updateEffects(ch);
- }
- } else {
- _ticks = 0;
- const uint8 *patternData = _patternData + _ordersTable[_curOrder] * 1024 + _curPos;
- for (int ch = 0; ch < 4; ++ch) {
- handlePattern(ch, READ_BE_UINT32(patternData));
- patternData += 4;
- }
- _curPos += 4 * 4;
- if (_curPos >= 1024) {
- _curPos = 0;
- ++_curOrder;
- if (_curOrder == _numOrders) {
- stopPaula();
- }
- }
- }
-}
-
-void SoundFx::disablePaulaChannel(uint8 channel) {
- disableChannel(channel);
-}
-
-void SoundFx::setupPaulaChannel(uint8 channel, const int8 *data, uint16 len, uint16 repeatPos, uint16 repeatLen) {
- if (data && len > 1) {
- setChannelData(channel, data, data + repeatPos * 2, len * 2, repeatLen * 2);
- }
-}
-
-void SoundFx::interrupt() {
- handleTick();
-}
-
-AudioStream *makeSoundFxStream(Common::SeekableReadStream *data, LoadSoundFxInstrumentCallback loadCb, int rate, bool stereo) {
- SoundFx *stream = new SoundFx(rate, stereo);
- if (stream->load(data, loadCb)) {
- stream->play();
- return stream;
- }
- delete stream;
- return 0;
-}
-
-} // End of namespace Audio
diff --git a/sound/mods/soundfx.h b/sound/mods/soundfx.h
deleted file mode 100644
index 089c19d292..0000000000
--- a/sound/mods/soundfx.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/* 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$
- *
- */
-
-/**
- * @file
- * Sound decoder used in engines:
- * - cine
- */
-
-#ifndef SOUND_MODS_SOUNDFX_H
-#define SOUND_MODS_SOUNDFX_H
-
-#include "common/stream.h"
-
-namespace Audio {
-
-class AudioStream;
-
-typedef byte *(*LoadSoundFxInstrumentCallback)(const char *name, uint32 *size);
-
-/*
- * Factory function for SoundFX modules. Reads all data from the
- * given data stream and creates an AudioStream from this (no references to the
- * stream object is kept). If loadCb is non 0, then instruments are loaded using
- * it, buffers returned are free'd at the end of playback.
- */
-AudioStream *makeSoundFxStream(Common::SeekableReadStream *data, LoadSoundFxInstrumentCallback loadCb, int rate = 44100, bool stereo = true);
-
-} // End of namespace Audio
-
-#endif
diff --git a/sound/mods/tfmx.cpp b/sound/mods/tfmx.cpp
deleted file mode 100644
index 6ed1abcfb5..0000000000
--- a/sound/mods/tfmx.cpp
+++ /dev/null
@@ -1,1193 +0,0 @@
-/* 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 "common/scummsys.h"
-#include "common/endian.h"
-#include "common/stream.h"
-#include "common/util.h"
-#include "common/debug.h"
-
-#include "sound/mods/tfmx.h"
-
-// test for engines using this class.
-#if defined(SOUND_MODS_TFMX_H)
-
-// couple debug-functions
-namespace {
-
-#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
-};
-
-} // End of anonymous namespace
-
-namespace Audio {
-
-Tfmx::Tfmx(int rate, bool stereo)
- : Paula(stereo, rate),
- _resource(),
- _resourceSample(),
- _playerCtx(),
- _deleteResource(false) {
-
- _playerCtx.stopWithLastPattern = false;
-
- for (int i = 0; i < kNumVoices; ++i)
- _channelCtx[i].paulaChannel = (byte)i;
-
- _playerCtx.volume = 0x40;
- _playerCtx.patternSkip = 6;
- stopSongImpl();
-
- setTimerBaseValue(kPalCiaClock);
- setInterruptFreqUnscaled(kPalDefaultCiaVal);
-}
-
-Tfmx::~Tfmx() {
- freeResourceDataImpl();
-}
-
-void Tfmx::interrupt() {
- assert(!_end);
- ++_playerCtx.tickCount;
-
- for (int i = 0; i < kNumVoices; ++i) {
- if (_channelCtx[i].dmaIntCount) {
- // wait for DMA Interupts to happen
- int doneDma = getChannelDmaCount(i);
- if (doneDma >= _channelCtx[i].dmaIntCount) {
- _channelCtx[i].dmaIntCount = 0;
- _channelCtx[i].macroRun = true;
- }
- }
- }
-
- for (int i = 0; i < kNumVoices; ++i) {
- ChannelContext &channel = _channelCtx[i];
-
- if (channel.sfxLockTime >= 0)
- --channel.sfxLockTime;
- else {
- channel.sfxLocked = false;
- channel.customMacroPrio = 0;
- }
-
- // externally queued macros
- if (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;
- channel.sfxLocked = (channel.customMacroPrio != 0);
- }
-
- // apply timebased effects on Parameters
- if (channel.macroSfxRun > 0)
- effects(channel);
-
- // see if we have to run the macro-program
- if (channel.macroRun) {
- if (!channel.macroWait)
- macroRun(channel);
- else
- --channel.macroWait;
- }
-
- Paula::setChannelPeriod(i, channel.period);
- if (channel.macroSfxRun >= 0)
- channel.macroSfxRun = 1;
-
- // TODO: handling pending DMAOff?
- }
-
- // Patterns are only processed each _playerCtx.timerCount + 1 tick
- if (_playerCtx.song >= 0 && !_playerCtx.patternCount--) {
- _playerCtx.patternCount = _playerCtx.patternSkip;
- advancePatterns();
- }
-}
-
-void Tfmx::effects(ChannelContext &channel) {
- // addBegin
- if (channel.addBeginLength) {
- channel.sampleStart += channel.addBeginDelta;
- Paula::setChannelSampleStart(channel.paulaChannel, getSamplePtr(channel.sampleStart));
- if (!(--channel.addBeginCount)) {
- channel.addBeginCount = channel.addBeginLength;
- channel.addBeginDelta = -channel.addBeginDelta;
- }
- }
-
- // vibrato
- if (channel.vibLength) {
- channel.vibValue += channel.vibDelta;
- if (--channel.vibCount == 0) {
- channel.vibCount = channel.vibLength;
- channel.vibDelta = -channel.vibDelta;
- }
- if (!channel.portaDelta) {
- // 16x16 bit multiplication, casts needed for the right results
- channel.period = (uint16)(((uint32)channel.refPeriod * (uint16)((1 << 11) + channel.vibValue)) >> 11);
- }
- }
-
- // portamento
- if (channel.portaDelta && !(--channel.portaCount)) {
- channel.portaCount = channel.portaSkip;
-
- bool resetPorta = true;
- const uint16 period = channel.refPeriod;
- uint16 portaVal = channel.portaValue;
-
- if (period > portaVal) {
- portaVal = ((uint32)portaVal * (uint16)((1 << 8) + channel.portaDelta)) >> 8;
- resetPorta = (period <= portaVal);
-
- } else if (period < portaVal) {
- portaVal = ((uint32)portaVal * (uint16)((1 << 8) - channel.portaDelta)) >> 8;
- resetPorta = (period >= portaVal);
- }
-
- if (resetPorta) {
- channel.portaDelta = 0;
- channel.portaValue = period & 0x7FF;
- } else
- channel.period = channel.portaValue = portaVal & 0x7FF;
- }
-
- // envelope
- if (channel.envSkip && !channel.envCount--) {
- channel.envCount = channel.envSkip;
-
- const int8 endVol = channel.envEndVolume;
- int8 volume = channel.volume;
- bool resetEnv = true;
-
- if (endVol > volume) {
- volume += channel.envDelta;
- resetEnv = endVol <= volume;
- } else {
- volume -= channel.envDelta;
- resetEnv = volume <= 0 || endVol >= volume;
- }
-
- if (resetEnv) {
- channel.envSkip = 0;
- volume = endVol;
- }
- channel.volume = volume;
- }
-
- // Fade
- if (_playerCtx.fadeDelta && !(--_playerCtx.fadeCount)) {
- _playerCtx.fadeCount = _playerCtx.fadeSkip;
-
- _playerCtx.volume += _playerCtx.fadeDelta;
- if (_playerCtx.volume == _playerCtx.fadeEndVolume)
- _playerCtx.fadeDelta = 0;
- }
-
- // Volume
- const uint8 finVol = _playerCtx.volume * channel.volume >> 6;
- Paula::setChannelVolume(channel.paulaChannel, finVol);
-}
-
-void Tfmx::macroRun(ChannelContext &channel) {
- bool deferWait = channel.deferWait;
- for (;;) {
- const byte *const macroPtr = (const byte *)(getMacroPtr(channel.macroOffset) + channel.macroStep);
- ++channel.macroStep;
-
- switch (macroPtr[0]) {
- case 0x00: // Reset + DMA Off. Parameters: deferWait, addset, vol
- clearEffects(channel);
- // FT
- case 0x13: // DMA Off. Parameters: deferWait, addset, vol
- // TODO: implement PArameters
- Paula::disableChannel(channel.paulaChannel);
- channel.deferWait = deferWait = (macroPtr[1] != 0);
- if (deferWait) {
- // if set, then we expect a DMA On in the same tick.
- channel.period = 4;
- //Paula::setChannelPeriod(channel.paulaChannel, channel.period);
- Paula::setChannelSampleLen(channel.paulaChannel, 1);
- // in this state we then need to allow some commands that normally
- // would halt the macroprogamm to continue instead.
- // those commands are: Wait, WaitDMA, AddPrevNote, AddNote, SetNote, <unknown Cmd>
- // DMA On is affected aswell
- // TODO remember time disabled, remember pending dmaoff?.
- }
-
- if (macroPtr[2] || macroPtr[3]) {
- channel.volume = (macroPtr[2] ? 0 : channel.relVol * 3) + macroPtr[3];
- Paula::setChannelVolume(channel.paulaChannel, channel.volume);
- }
- continue;
-
- case 0x01: // DMA On
- // TODO: Parameter macroPtr[1] - en-/disable effects
- channel.dmaIntCount = 0;
- if (deferWait) {
- // TODO
- // there is actually a small delay in the player, but I think that
- // only allows to clear DMA-State on real Hardware
- }
- Paula::setChannelPeriod(channel.paulaChannel, channel.period);
- Paula::enableChannel(channel.paulaChannel);
- channel.deferWait = deferWait = false;
- continue;
-
- case 0x02: // Set Beginn. Parameters: SampleOffset(L)
- channel.addBeginLength = 0;
- channel.sampleStart = READ_BE_UINT32(macroPtr) & 0xFFFFFF;
- Paula::setChannelSampleStart(channel.paulaChannel, getSamplePtr(channel.sampleStart));
- continue;
-
- case 0x03: // SetLength. Parameters: SampleLength(W)
- channel.sampleLen = READ_BE_UINT16(&macroPtr[2]);
- Paula::setChannelSampleLen(channel.paulaChannel, channel.sampleLen);
- continue;
-
- case 0x04: // Wait. Parameters: Ticks to wait(W).
- // TODO: some unknown Parameter? (macroPtr[1] & 1)
- channel.macroWait = READ_BE_UINT16(&macroPtr[2]);
- break;
-
- case 0x10: // Loop Key Up. Parameters: Loopcount, MacroStep(W)
- if (channel.keyUp)
- continue;
- // FT
- case 0x05: // Loop. Parameters: Loopcount, MacroStep(W)
- if (channel.macroLoopCount != 0) {
- if (channel.macroLoopCount == 0xFF)
- channel.macroLoopCount = macroPtr[1];
- channel.macroStep = READ_BE_UINT16(&macroPtr[2]);
- }
- --channel.macroLoopCount;
- continue;
-
- case 0x06: // Jump. Parameters: MacroIndex, MacroStep(W)
- // channel.macroIndex = macroPtr[1] & (kMaxMacroOffsets - 1);
- channel.macroOffset = _resource->macroOffset[macroPtr[1] & (kMaxMacroOffsets - 1)];
- channel.macroStep = READ_BE_UINT16(&macroPtr[2]);
- channel.macroLoopCount = 0xFF;
- continue;
-
- case 0x07: // Stop Macro
- channel.macroRun = false;
- --channel.macroStep;
- return;
-
- case 0x08: // AddNote. Parameters: Note, Finetune(W)
- setNoteMacro(channel, channel.note + macroPtr[1], READ_BE_UINT16(&macroPtr[2]));
- break;
-
- case 0x09: // SetNote. Parameters: Note, Finetune(W)
- setNoteMacro(channel, macroPtr[1], READ_BE_UINT16(&macroPtr[2]));
- break;
-
- case 0x0A: // Clear Effects
- clearEffects(channel);
- continue;
-
- case 0x0B: // Portamento. Parameters: count, speed
- channel.portaSkip = macroPtr[1];
- channel.portaCount = 1;
- // if porta is already running, then keep using old value
- if (!channel.portaDelta)
- channel.portaValue = channel.refPeriod;
- channel.portaDelta = READ_BE_UINT16(&macroPtr[2]);
- continue;
-
- case 0x0C: // Vibrato. Parameters: Speed, intensity
- channel.vibLength = macroPtr[1];
- channel.vibCount = macroPtr[1] / 2;
- channel.vibDelta = macroPtr[3];
- // TODO: Perhaps a bug, vibValue could be left uninitialised
- if (!channel.portaDelta) {
- channel.period = channel.refPeriod;
- channel.vibValue = 0;
- }
- continue;
-
- case 0x0D: // Add Volume. Parameters: note, addNoteFlag, volume
- if (macroPtr[2] == 0xFE)
- setNoteMacro(channel, channel.note + macroPtr[1], 0);
- channel.volume = channel.relVol * 3 + macroPtr[3];
- continue;
-
- case 0x0E: // Set Volume. Parameters: note, addNoteFlag, volume
- if (macroPtr[2] == 0xFE)
- setNoteMacro(channel, channel.note + macroPtr[1], 0);
- channel.volume = macroPtr[3];
- continue;
-
- case 0x0F: // Envelope. Parameters: speed, count, endvol
- channel.envDelta = macroPtr[1];
- channel.envCount = channel.envSkip = macroPtr[2];
- channel.envEndVolume = macroPtr[3];
- continue;
-
- case 0x11: // Add Beginn. Parameters: times, Offset(W)
- channel.addBeginLength = channel.addBeginCount = macroPtr[1];
- channel.addBeginDelta = (int16)READ_BE_UINT16(&macroPtr[2]);
- channel.sampleStart += channel.addBeginDelta;
- Paula::setChannelSampleStart(channel.paulaChannel, getSamplePtr(channel.sampleStart));
- continue;
-
- case 0x12: // Add Length. Parameters: added Length(W)
- channel.sampleLen += (int16)READ_BE_UINT16(&macroPtr[2]);
- Paula::setChannelSampleLen(channel.paulaChannel, channel.sampleLen);
- continue;
-
- case 0x14: // Wait key up. Parameters: wait cycles
- if (channel.keyUp || channel.macroLoopCount == 0) {
- channel.macroLoopCount = 0xFF;
- continue;
- } else if (channel.macroLoopCount == 0xFF)
- channel.macroLoopCount = macroPtr[3];
- --channel.macroLoopCount;
- --channel.macroStep;
- return;
-
- case 0x15: // Subroutine. Parameters: MacroIndex, Macrostep(W)
- channel.macroReturnOffset = channel.macroOffset;
- channel.macroReturnStep = channel.macroStep;
-
- channel.macroOffset = _resource->macroOffset[macroPtr[1] & (kMaxMacroOffsets - 1)];
- channel.macroStep = READ_BE_UINT16(&macroPtr[2]);
- // TODO: MI does some weird stuff there. Figure out which varioables need to be set
- continue;
-
- case 0x16: // Return from Sub.
- channel.macroOffset = channel.macroReturnOffset;
- channel.macroStep = channel.macroReturnStep;
- continue;
-
- case 0x17: // Set Period. Parameters: Period(W)
- channel.refPeriod = READ_BE_UINT16(&macroPtr[2]);
- if (!channel.portaDelta) {
- channel.period = channel.refPeriod;
- //Paula::setChannelPeriod(channel.paulaChannel, channel.period);
- }
- continue;
-
- case 0x18: { // Sampleloop. Parameters: Offset from Samplestart(W)
- // TODO: MI loads 24 bit, but thats useless?
- const uint16 temp = /* ((int8)macroPtr[1] << 16) | */ READ_BE_UINT16(&macroPtr[2]);
- if (macroPtr[1] || (temp & 1))
- warning("Tfmx: Problematic value for sampleloop: %06X", (macroPtr[1] << 16) | temp);
- channel.sampleStart += temp & 0xFFFE;
- channel.sampleLen -= (temp / 2) /* & 0x7FFF */;
- Paula::setChannelSampleStart(channel.paulaChannel, getSamplePtr(channel.sampleStart));
- Paula::setChannelSampleLen(channel.paulaChannel, channel.sampleLen);
- continue;
- }
- case 0x19: // Set One-Shot Sample
- channel.addBeginLength = 0;
- channel.sampleStart = 0;
- channel.sampleLen = 1;
- Paula::setChannelSampleStart(channel.paulaChannel, getSamplePtr(0));
- Paula::setChannelSampleLen(channel.paulaChannel, 1);
- continue;
-
- case 0x1A: // Wait on DMA. Parameters: Cycles-1(W) to wait
- channel.dmaIntCount = READ_BE_UINT16(&macroPtr[2]) + 1;
- channel.macroRun = false;
- Paula::setChannelDmaCount(channel.paulaChannel);
- break;
-
-/* case 0x1B: // Random play. Parameters: macro/speed/mode
- warnMacroUnimplemented(macroPtr, 0);
- continue;*/
-
- case 0x1C: // Branch on Note. Parameters: note/macrostep(W)
- if (channel.note > macroPtr[1])
- channel.macroStep = READ_BE_UINT16(&macroPtr[2]);
- continue;
-
- case 0x1D: // Branch on Volume. Parameters: volume/macrostep(W)
- if (channel.volume > macroPtr[1])
- channel.macroStep = READ_BE_UINT16(&macroPtr[2]);
- continue;
-
-/* case 0x1E: // Addvol+note. Parameters: note/CONST./volume
- warnMacroUnimplemented(macroPtr, 0);
- continue;*/
-
- case 0x1F: // AddPrevNote. Parameters: Note, Finetune(W)
- setNoteMacro(channel, channel.prevNote + macroPtr[1], READ_BE_UINT16(&macroPtr[2]));
- break;
-
- case 0x20: // Signal. Parameters: signalnumber, value(W)
- if (_playerCtx.numSignals > macroPtr[1])
- _playerCtx.signal[macroPtr[1]] = READ_BE_UINT16(&macroPtr[2]);
- continue;
-
- case 0x21: // Play macro. Parameters: macro, chan, detune
- noteCommand(channel.note, macroPtr[1], (channel.relVol << 4) | macroPtr[2], macroPtr[3]);
- continue;
-
- // 0x22 - 0x29 are used by Gem`X
- // 0x30 - 0x34 are used by Carribean Disaster
-
- default:
- debug(3, "Tfmx: Macro %02X not supported", macroPtr[0]);
- }
- if (!deferWait)
- return;
- }
-}
-
-void Tfmx::advancePatterns() {
-startPatterns:
- int runningPatterns = 0;
-
- for (int i = 0; i < kNumChannels; ++i) {
- PatternContext &pattern = _patternCtx[i];
- const uint8 pattCmd = pattern.command;
- if (pattCmd < 0x90) { // execute Patternstep
- ++runningPatterns;
- if (!pattern.wait) {
- // issue all Steps for this tick
- if (patternRun(pattern)) {
- // we load the next Trackstep Command and then process all Channels again
- if (trackRun(true))
- goto startPatterns;
- else
- break;
- }
-
- } else
- --pattern.wait;
-
- } else if (pattCmd == 0xFE) { // Stop voice in pattern.expose
- pattern.command = 0xFF;
- ChannelContext &channel = _channelCtx[pattern.expose & (kNumVoices - 1)];
- if (!channel.sfxLocked) {
- haltMacroProgramm(channel);
- Paula::disableChannel(channel.paulaChannel);
- }
- } // else this pattern-Channel is stopped
- }
- if (_playerCtx.stopWithLastPattern && !runningPatterns) {
- stopPaula();
- }
-}
-
-bool Tfmx::patternRun(PatternContext &pattern) {
- for (;;) {
- const byte *const patternPtr = (const byte *)(getPatternPtr(pattern.offset) + pattern.step);
- ++pattern.step;
- const byte pattCmd = patternPtr[0];
-
- if (pattCmd < 0xF0) { // Playnote
- bool doWait = false;
- byte noteCmd = pattCmd + pattern.expose;
- byte param3 = patternPtr[3];
- if (pattCmd < 0xC0) { // Note
- if (pattCmd >= 0x80) { // Wait
- pattern.wait = param3;
- param3 = 0;
- doWait = true;
- }
- noteCmd &= 0x3F;
- } // else Portamento
- noteCommand(noteCmd, patternPtr[1], patternPtr[2], param3);
- if (doWait)
- return false;
-
- } else { // Patterncommand
- switch (pattCmd & 0xF) {
- case 0: // End Pattern + Next Trackstep
- pattern.command = 0xFF;
- --pattern.step;
- return true;
-
- case 1: // Loop Pattern. Parameters: Loopcount, PatternStep(W)
- if (pattern.loopCount != 0) {
- if (pattern.loopCount == 0xFF)
- pattern.loopCount = patternPtr[1];
- pattern.step = READ_BE_UINT16(&patternPtr[2]);
- }
- --pattern.loopCount;
- continue;
-
- case 2: // Jump. Parameters: PatternIndex, PatternStep(W)
- pattern.offset = _resource->patternOffset[patternPtr[1] & (kMaxPatternOffsets - 1)];
- pattern.step = READ_BE_UINT16(&patternPtr[2]);
- continue;
-
- case 3: // Wait. Paramters: ticks to wait
- pattern.wait = patternPtr[1];
- return false;
-
- case 14: // Stop custompattern
- // TODO apparently toggles on/off pattern channel 7
- debug(3, "Tfmx: Encountered 'Stop custompattern' command");
- // FT
- case 4: // Stop this pattern
- pattern.command = 0xFF;
- --pattern.step;
- // TODO: try figuring out if this was the last Channel?
- return false;
-
- case 5: // Key Up Signal. Paramters: channel
- if (!_channelCtx[patternPtr[2] & (kNumVoices - 1)].sfxLocked)
- _channelCtx[patternPtr[2] & (kNumVoices - 1)].keyUp = true;
- continue;
-
- case 6: // Vibrato. Parameters: length, channel, rate
- case 7: // Envelope. Parameters: rate, tempo | channel, endVol
- noteCommand(pattCmd, patternPtr[1], patternPtr[2], patternPtr[3]);
- continue;
-
- case 8: // Subroutine. Parameters: pattern, patternstep(W)
- pattern.savedOffset = pattern.offset;
- pattern.savedStep = pattern.step;
-
- pattern.offset = _resource->patternOffset[patternPtr[1] & (kMaxPatternOffsets - 1)];
- pattern.step = READ_BE_UINT16(&patternPtr[2]);
- continue;
-
- case 9: // Return from Subroutine
- pattern.offset = pattern.savedOffset;
- pattern.step = pattern.savedStep;
- continue;
-
- case 10: // fade. Parameters: tempo, endVol
- initFadeCommand((uint8)patternPtr[1], (int8)patternPtr[3]);
- continue;
-
- case 11: // play pattern. Parameters: patternCmd, channel, expose
- initPattern(_patternCtx[patternPtr[2] & (kNumChannels - 1)], patternPtr[1], patternPtr[3], _resource->patternOffset[patternPtr[1] & (kMaxPatternOffsets - 1)]);
- continue;
-
- case 12: // Lock. Parameters: lockFlag, channel, lockTime
- _channelCtx[patternPtr[2] & (kNumVoices - 1)].sfxLocked = (patternPtr[1] != 0);
- _channelCtx[patternPtr[2] & (kNumVoices - 1)].sfxLockTime = patternPtr[3];
- continue;
-
- case 13: // Cue. Parameters: signalnumber, value(W)
- if (_playerCtx.numSignals > patternPtr[1])
- _playerCtx.signal[patternPtr[1]] = READ_BE_UINT16(&patternPtr[2]);
- continue;
-
- case 15: // NOP
- continue;
- }
- }
- }
-}
-
-bool Tfmx::trackRun(const bool incStep) {
- assert(_playerCtx.song >= 0);
- if (incStep) {
- // TODO Optionally disable looping
- if (_trackCtx.posInd == _trackCtx.stopInd)
- _trackCtx.posInd = _trackCtx.startInd;
- else
- ++_trackCtx.posInd;
- }
- for (;;) {
- const uint16 *const trackData = getTrackPtr(_trackCtx.posInd);
-
- if (trackData[0] != FROM_BE_16(0xEFFE)) {
- // 8 commands for Patterns
- for (int i = 0; i < 8; ++i) {
- const uint8 *patCmd = (const uint8 *)&trackData[i];
- // First byte is pattern number
- const uint8 patNum = patCmd[0];
- // if highest bit is set then keep previous pattern
- if (patNum < 0x80) {
- initPattern(_patternCtx[i], patNum, patCmd[1], _resource->patternOffset[patNum]);
- } else {
- _patternCtx[i].command = patNum;
- _patternCtx[i].expose = (int8)patCmd[1];
- }
- }
- return true;
-
- } else {
- // 16 byte Trackstep Command
- switch (READ_BE_UINT16(&trackData[1])) {
- case 0: // Stop Player. No Parameters
- stopPaula();
- return false;
-
- case 1: // Branch/Loop section of tracksteps. Parameters: branch target, loopcount
- if (_trackCtx.loopCount != 0) {
- if (_trackCtx.loopCount < 0)
- _trackCtx.loopCount = READ_BE_UINT16(&trackData[3]);
- _trackCtx.posInd = READ_BE_UINT16(&trackData[2]);
- continue;
- }
- --_trackCtx.loopCount;
- break;
-
- case 2: { // Set Tempo. Parameters: tempo, divisor
- _playerCtx.patternCount = _playerCtx.patternSkip = READ_BE_UINT16(&trackData[2]); // tempo
- const uint16 temp = READ_BE_UINT16(&trackData[3]); // divisor
-
- if (!(temp & 0x8000) && (temp & 0x1FF))
- setInterruptFreqUnscaled(temp & 0x1FF);
- break;
- }
- case 4: // Fade. Parameters: tempo, endVol
- // load the LSB of the 16bit words
- initFadeCommand(((const uint8 *)&trackData[2])[1], ((const int8 *)&trackData[3])[1]);
- break;
-
- case 3: // Unknown, stops player aswell
- default:
- debug(3, "Tfmx: Unknown Trackstep Command: %02X", READ_BE_UINT16(&trackData[1]));
- // MI-Player handles this by stopping the player, we just continue
- }
- }
-
- if (_trackCtx.posInd == _trackCtx.stopInd) {
- warning("Tfmx: Reached invalid Song-Position");
- return false;
- }
- ++_trackCtx.posInd;
- }
-}
-
-void Tfmx::noteCommand(const uint8 note, const uint8 param1, const uint8 param2, const uint8 param3) {
- ChannelContext &channel = _channelCtx[param2 & (kNumVoices - 1)];
-
- if (note == 0xFC) { // Lock command
- channel.sfxLocked = (param1 != 0);
- channel.sfxLockTime = param3; // only 1 byte read!
-
- } else if (channel.sfxLocked) { // Channel still locked, do nothing
-
- } else if (note < 0xC0) { // Play Note - Parameters: note, macro, relVol | channel, finetune
-
- channel.prevNote = channel.note;
- channel.note = note;
- // channel.macroIndex = param1 & (kMaxMacroOffsets - 1);
- channel.macroOffset = _resource->macroOffset[param1 & (kMaxMacroOffsets - 1)];
- channel.relVol = param2 >> 4;
- channel.fineTune = (int8)param3;
-
- // TODO: the point where the channel gets initialised varies with the games, needs more research.
- initMacroProgramm(channel);
- channel.keyUp = false; // key down = playing a Note
-
- } else if (note < 0xF0) { // Portamento - Parameters: note, tempo, channel, rate
- channel.portaSkip = param1;
- channel.portaCount = 1;
- if (!channel.portaDelta)
- channel.portaValue = channel.refPeriod;
- channel.portaDelta = param3;
-
- channel.note = note & 0x3F;
- channel.refPeriod = noteIntervalls[channel.note];
-
- } else switch (note) { // Command
-
- case 0xF5: // Key Up Signal
- channel.keyUp = true;
- break;
-
- case 0xF6: // Vibratio - Parameters: length, channel, rate
- channel.vibLength = param1 & 0xFE;
- channel.vibCount = param1 / 2;
- channel.vibDelta = param3;
- channel.vibValue = 0;
- break;
-
- case 0xF7: // Envelope - Parameters: rate, tempo | channel, endVol
- channel.envDelta = param1;
- channel.envCount = channel.envSkip = (param2 >> 4) + 1;
- channel.envEndVolume = param3;
- break;
- }
-}
-
-void Tfmx::initMacroProgramm(ChannelContext &channel) {
- channel.macroStep = 0;
- channel.macroWait = 0;
- channel.macroRun = true;
- channel.macroSfxRun = 0;
- channel.macroLoopCount = 0xFF;
- channel.dmaIntCount = 0;
- channel.deferWait = false;
-
- channel.macroReturnOffset = 0;
- channel.macroReturnStep = 0;
-}
-
-void Tfmx::clearEffects(ChannelContext &channel) {
- channel.addBeginLength = 0;
- channel.envSkip = 0;
- channel.vibLength = 0;
- channel.portaDelta = 0;
-}
-
-void Tfmx::haltMacroProgramm(ChannelContext &channel) {
- channel.macroRun = false;
- channel.dmaIntCount = 0;
-}
-
-void Tfmx::unlockMacroChannel(ChannelContext &channel) {
- channel.customMacro = 0;
- channel.customMacroIndex = 0;
- channel.customMacroPrio = 0;
- channel.sfxLocked = false;
- channel.sfxLockTime = -1;
-}
-
-void Tfmx::initPattern(PatternContext &pattern, uint8 cmd, int8 expose, uint32 offset) {
- pattern.command = cmd;
- pattern.offset = offset;
- pattern.expose = expose;
- pattern.step = 0;
- pattern.wait = 0;
- pattern.loopCount = 0xFF;
-
- pattern.savedOffset = 0;
- pattern.savedStep = 0;
-}
-
-void Tfmx::stopSongImpl(bool stopAudio) {
- _playerCtx.song = -1;
- for (int i = 0; i < kNumChannels; ++i) {
- _patternCtx[i].command = 0xFF;
- _patternCtx[i].expose = 0;
- }
- if (stopAudio) {
- stopPaula();
- for (int i = 0; i < kNumVoices; ++i) {
- clearEffects(_channelCtx[i]);
- unlockMacroChannel(_channelCtx[i]);
- haltMacroProgramm(_channelCtx[i]);
- _channelCtx[i].note = 0;
- _channelCtx[i].volume = 0;
- _channelCtx[i].macroSfxRun = -1;
- _channelCtx[i].vibValue = 0;
-
- _channelCtx[i].sampleStart = 0;
- _channelCtx[i].sampleLen = 2;
- _channelCtx[i].refPeriod = 4;
- _channelCtx[i].period = 4;
- Paula::disableChannel(i);
- }
- }
-}
-
-void Tfmx::setNoteMacro(ChannelContext &channel, uint note, int fineTune) {
- const uint16 noteInt = noteIntervalls[note & 0x3F];
- const uint16 finetune = (uint16)(fineTune + channel.fineTune + (1 << 8));
- channel.refPeriod = ((uint32)noteInt * finetune >> 8);
- if (!channel.portaDelta)
- channel.period = channel.refPeriod;
-}
-
-void Tfmx::initFadeCommand(const uint8 fadeTempo, const int8 endVol) {
- _playerCtx.fadeCount = _playerCtx.fadeSkip = fadeTempo;
- _playerCtx.fadeEndVolume = endVol;
-
- if (fadeTempo) {
- const int diff = _playerCtx.fadeEndVolume - _playerCtx.volume;
- _playerCtx.fadeDelta = (diff != 0) ? ((diff > 0) ? 1 : -1) : 0;
- } else {
- _playerCtx.volume = endVol;
- _playerCtx.fadeDelta = 0;
- }
-}
-
-void Tfmx::setModuleData(Tfmx &otherPlayer) {
- setModuleData(otherPlayer._resource, otherPlayer._resourceSample.sampleData, otherPlayer._resourceSample.sampleLen, false);
-}
-
-bool Tfmx::load(Common::SeekableReadStream &musicData, Common::SeekableReadStream &sampleData, bool autoDelete) {
- const MdatResource *mdat = loadMdatFile(musicData);
- if (mdat) {
- uint32 sampleLen = 0;
- const int8 *sampleDat = loadSampleFile(sampleLen, sampleData);
- if (sampleDat) {
- setModuleData(mdat, sampleDat, sampleLen, autoDelete);
- return true;
- }
- delete[] mdat->mdatAlloc;
- delete mdat;
- }
- return false;
-}
-
-void Tfmx::freeResourceDataImpl() {
- if (_deleteResource) {
- if (_resource) {
- delete[] _resource->mdatAlloc;
- delete _resource;
- }
- delete[] _resourceSample.sampleData;
- }
- _resource = 0;
- _resourceSample.sampleData = 0;
- _resourceSample.sampleLen = 0;
- _deleteResource = false;
-}
-
-void Tfmx::setModuleData(const MdatResource *resource, const int8 *sampleData, uint32 sampleLen, bool autoDelete) {
- Common::StackLock lock(_mutex);
- stopSongImpl(true);
- freeResourceDataImpl();
- _resource = resource;
- _resourceSample.sampleData = sampleData;
- _resourceSample.sampleLen = sampleData ? sampleLen : 0;
- _deleteResource = autoDelete;
-}
-
-const int8 *Tfmx::loadSampleFile(uint32 &sampleLen, Common::SeekableReadStream &sampleStream) {
- sampleLen = 0;
-
- const int32 sampleSize = sampleStream.size();
- if (sampleSize < 4) {
- warning("Tfmx: Cant load Samplefile");
- return false;
- }
-
- int8 *sampleAlloc = new int8[sampleSize];
- if (!sampleAlloc) {
- warning("Tfmx: Could not allocate Memory: %dKB", sampleSize / 1024);
- return 0;
- }
-
- if (sampleStream.read(sampleAlloc, sampleSize) == (uint32)sampleSize) {
- sampleAlloc[0] = sampleAlloc[1] = sampleAlloc[2] = sampleAlloc[3] = 0;
- sampleLen = sampleSize;
- } else {
- delete[] sampleAlloc;
- warning("Tfmx: Encountered IO-Error");
- return 0;
- }
- return sampleAlloc;
-}
-
-const Tfmx::MdatResource *Tfmx::loadMdatFile(Common::SeekableReadStream &musicData) {
- bool hasHeader = false;
- const int32 mdatSize = musicData.size();
- if (mdatSize >= 0x200) {
- byte buf[16] = { 0 };
- // 0x0000: 10 Bytes Header "TFMX-SONG "
- musicData.read(buf, 10);
- hasHeader = memcmp(buf, "TFMX-SONG ", 10) == 0;
- }
-
- if (!hasHeader) {
- warning("Tfmx: File is not a Tfmx Module");
- return 0;
- }
-
- MdatResource *resource = new MdatResource;
-
- resource->mdatAlloc = 0;
- resource->mdatData = 0;
- resource->mdatLen = 0;
-
- // 0x000A: int16 flags
- resource->headerFlags = musicData.readUint16BE();
- // 0x000C: int32 ?
- // 0x0010: 6*40 Textfield
- musicData.skip(4 + 6 * 40);
-
- /* 0x0100: Songstart x 32*/
- for (int i = 0; i < kNumSubsongs; ++i)
- resource->subsong[i].songstart = musicData.readUint16BE();
- /* 0x0140: Songend x 32*/
- for (int i = 0; i < kNumSubsongs; ++i)
- resource->subsong[i].songend = musicData.readUint16BE();
- /* 0x0180: Tempo x 32*/
- for (int i = 0; i < kNumSubsongs; ++i)
- resource->subsong[i].tempo = musicData.readUint16BE();
-
- /* 0x01c0: unused ? */
- musicData.skip(16);
-
- /* 0x01d0: trackstep, pattern data p, macro data p */
- const uint32 offTrackstep = musicData.readUint32BE();
- uint32 offPatternP, offMacroP;
-
- // This is how MI`s TFMX-Player tests for unpacked Modules.
- if (offTrackstep == 0) { // unpacked File
- resource->trackstepOffset = 0x600 + 0x200;
- offPatternP = 0x200 + 0x200;
- offMacroP = 0x400 + 0x200;
- } else { // packed File
- resource->trackstepOffset = offTrackstep;
- offPatternP = musicData.readUint32BE();
- offMacroP = musicData.readUint32BE();
- }
-
- // End of basic header, check if everything worked ok
- if (musicData.err()) {
- warning("Tfmx: Encountered IO-Error");
- delete resource;
- return 0;
- }
-
- // TODO: if a File is packed it could have for Ex only 2 Patterns/Macros
- // the following loops could then read beyond EOF.
- // To correctly handle this it would be necessary to sort the pointers and
- // figure out the number of Macros/Patterns
- // We could also analyze pointers if they are correct offsets,
- // so that accesses can be unchecked later
-
- // Read in pattern starting offsets
- musicData.seek(offPatternP);
- for (int i = 0; i < kMaxPatternOffsets; ++i)
- resource->patternOffset[i] = musicData.readUint32BE();
-
- // use last PatternOffset (stored at 0x5FC in mdat) if unpacked File
- // or fixed offset 0x200 if packed
- resource->sfxTableOffset = offTrackstep ? 0x200 : resource->patternOffset[127];
-
- // Read in macro starting offsets
- musicData.seek(offMacroP);
- for (int i = 0; i < kMaxMacroOffsets; ++i)
- resource->macroOffset[i] = musicData.readUint32BE();
-
- // Read in mdat-file
- // TODO: we can skip everything thats already stored in the resource-structure.
- const int32 mdatOffset = offTrackstep ? 0x200 : 0x600; // 0x200 is very conservative
- const uint32 allocSize = (uint32)mdatSize - mdatOffset;
-
- byte *mdatAlloc = new byte[allocSize];
- if (!mdatAlloc) {
- warning("Tfmx: Could not allocate Memory: %dKB", allocSize / 1024);
- delete resource;
- return 0;
- }
- musicData.seek(mdatOffset);
- if (musicData.read(mdatAlloc, allocSize) == allocSize) {
- resource->mdatAlloc = mdatAlloc;
- resource->mdatData = mdatAlloc - mdatOffset;
- resource->mdatLen = mdatSize;
- } else {
- delete[] mdatAlloc;
- warning("Tfmx: Encountered IO-Error");
- delete resource;
- return 0;
- }
-
- return resource;
-}
-
-void Tfmx::doMacro(int note, int macro, int relVol, int finetune, int channelNo) {
- assert(0 <= macro && macro < kMaxMacroOffsets);
- assert(0 <= note && note < 0xC0);
- Common::StackLock lock(_mutex);
-
- if (!hasResources())
- return;
- channelNo &= (kNumVoices - 1);
- ChannelContext &channel = _channelCtx[channelNo];
- unlockMacroChannel(channel);
-
- noteCommand((uint8)note, (uint8)macro, (uint8)((relVol << 4) | channelNo), (uint8)finetune);
- startPaula();
-}
-
-void Tfmx::stopMacroEffect(int channel) {
- assert(0 <= channel && channel < kNumVoices);
- Common::StackLock lock(_mutex);
- unlockMacroChannel(_channelCtx[channel]);
- haltMacroProgramm(_channelCtx[channel]);
- Paula::disableChannel(_channelCtx[channel].paulaChannel);
-}
-
-void Tfmx::doSong(int songPos, bool stopAudio) {
- assert(0 <= songPos && songPos < kNumSubsongs);
- Common::StackLock lock(_mutex);
-
- stopSongImpl(stopAudio);
-
- if (!hasResources())
- return;
-
- _trackCtx.loopCount = -1;
- _trackCtx.startInd = _trackCtx.posInd = _resource->subsong[songPos].songstart;
- _trackCtx.stopInd = _resource->subsong[songPos].songend;
- _playerCtx.song = (int8)songPos;
-
- const bool palFlag = (_resource->headerFlags & 2) != 0;
- const uint16 tempo = _resource->subsong[songPos].tempo;
- uint16 ciaIntervall;
- if (tempo >= 0x10) {
- ciaIntervall = (uint16)(kCiaBaseInterval / tempo);
- _playerCtx.patternSkip = 0;
- } else {
- ciaIntervall = palFlag ? (uint16)kPalDefaultCiaVal : (uint16)kNtscDefaultCiaVal;
- _playerCtx.patternSkip = tempo;
- }
- setInterruptFreqUnscaled(ciaIntervall);
- Paula::setAudioFilter(true);
-
- _playerCtx.patternCount = 0;
- if (trackRun())
- startPaula();
-}
-
-int Tfmx::doSfx(uint16 sfxIndex, bool unlockChannel) {
- assert(sfxIndex < 128);
- Common::StackLock lock(_mutex);
-
- if (!hasResources())
- return -1;
- const byte *sfxEntry = getSfxPtr(sfxIndex);
- if (sfxEntry[0] == 0xFB) {
- warning("Tfmx: custom patterns are not supported");
- // custompattern
- /* const uint8 patCmd = sfxEntry[2];
- const int8 patExp = (int8)sfxEntry[3]; */
- } else {
- // custommacro
- const byte channelNo = ((_playerCtx.song >= 0) ? sfxEntry[2] : sfxEntry[4]) & (kNumVoices - 1);
- const byte priority = sfxEntry[5] & 0x7F;
-
- ChannelContext &channel = _channelCtx[channelNo];
- if (unlockChannel)
- unlockMacroChannel(channel);
-
- const int16 sfxLocktime = channel.sfxLockTime;
- if (priority >= channel.customMacroPrio || sfxLocktime < 0) {
- if (sfxIndex != channel.customMacroIndex || sfxLocktime < 0 || (sfxEntry[5] < 0x80)) {
- channel.customMacro = READ_UINT32(sfxEntry); // intentionally not "endian-correct"
- channel.customMacroPrio = priority;
- channel.customMacroIndex = (uint8)sfxIndex;
- debug(3, "Tfmx: running Macro %08X on channel %i - priority: %02X", TO_BE_32(channel.customMacro), channelNo, priority);
- return channelNo;
- }
- }
- }
- return -1;
-}
-
-} // End of namespace Audio
-
-// some debugging functions
-#if 0
-namespace {
-
-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",
- "SetLen ..xxxx sample-length ",
- "Wait ..xxxx count (VBI''s) ",
- "Loop xx/xxxx count/step ",
- "Cont xx/xxxx macro-number/step ",
- "-------------STOP----------------------",
- "AddNote xx/xxxx note/detune ",
- "SetNote xx/xxxx note/detune ",
- "Reset Vibrato-Portamento-Envelope ",
- "Portamento xx/../xx count/speed ",
- "Vibrato xx/../xx speed/intensity ",
- "AddVolume ....xx volume 00-3F ",
- "SetVolume ....xx volume 00-3F ",
- "Envelope xx/xx/xx speed/count/endvol",
- "Loop key up xx/xxxx count/step ",
- "AddBegin xx/xxxx count/add to start",
- "AddLen ..xxxx add to sample-len ",
- "DMAoff stop sample but no clear ",
- "Wait key up ....xx count (VBI''s) ",
- "Go submacro xx/xxxx macro-number/step ",
- "--------Return to old macro------------",
- "Setperiod ..xxxx DMA period ",
- "Sampleloop ..xxxx relative adress ",
- "-------Set one shot sample-------------",
- "Wait on DMA ..xxxx count (Wavecycles)",
- "Random play xx/xx/xx macro/speed/mode ",
- "Splitkey xx/xxxx key/macrostep ",
- "Splitvolume xx/xxxx volume/macrostep ",
- "Addvol+note xx/fe/xx note/CONST./volume",
- "SetPrevNote xx/xxxx note/detune ",
- "Signal xx/xxxx signalnumber/value",
- "Play macro xx/.x/xx macro/chan/detune ",
- "SID setbeg xxxxxx sample-startadress",
- "SID setlen xx/xxxx buflen/sourcelen ",
- "SID op3 ofs xxxxxx offset ",
- "SID op3 frq xx/xxxx speed/amplitude ",
- "SID op2 ofs xxxxxx offset ",
- "SID op2 frq xx/xxxx speed/amplitude ",
- "SID op1 xx/xx/xx speed/amplitude/TC",
- "SID stop xx.... flag (1=clear all)"
- };
-
- 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("Unknown Macro #%02X %02X%02X%02X", macroData[0], macroData[1], macroData[2], macroData[3]);
-}
-
-void displayPatternstep(const void * const vptr) {
- static const char *tablePatterns[] = {
- "End --Next track step--",
- "Loop[count / step.w]",
- "Cont[patternno./ step.w]",
- "Wait[count 00-FF--------",
- "Stop--Stop this pattern-",
- "Kup^-Set key up/channel]",
- "Vibr[speed / rate.b]",
- "Enve[speed /endvolume.b]",
- "GsPt[patternno./ step.w]",
- "RoPt-Return old pattern-",
- "Fade[speed /endvolume.b]",
- "PPat[patt./track+transp]",
- "Lock---------ch./time.b]",
- "Cue [number.b/ value.w]",
- "Stop-Stop custompattern-",
- "NOP!-no operation-------"
- };
-
- 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?
- const char *flagsSt[] = { "Note ", "Note ", "Wait ", "Porta" };
- debug("%s %02X%02X%02X%02X", flagsSt[flags], patData[0], patData[1], patData[2], patData[3]);
- } else
- debug("%s %02X%02X%02X",tablePatterns[command & 0xF], patData[1], patData[2], patData[3]);
-}
-
-} // End of anonymous namespace
-#endif
-
-#endif // #if defined(SOUND_MODS_TFMX_H)
diff --git a/sound/mods/tfmx.h b/sound/mods/tfmx.h
deleted file mode 100644
index b24df494cd..0000000000
--- a/sound/mods/tfmx.h
+++ /dev/null
@@ -1,284 +0,0 @@
-/* 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$
- *
- */
-
-// see if all engines using this class are DISABLED
-#if !defined(ENABLE_SCUMM)
-
-// normal Header Guard
-#elif !defined(SOUND_MODS_TFMX_H)
-#define SOUND_MODS_TFMX_H
-
-#include "sound/mods/paula.h"
-
-namespace Audio {
-
-class Tfmx : public Paula {
-public:
- Tfmx(int rate, bool stereo);
- virtual ~Tfmx();
-
- /**
- * Stops a playing Song (but leaves macros running) and optionally also stops the player
- *
- * @param stopAudio stops player and audio output
- * @param dataSize number of bytes to be written
- * @return the number of bytes which were actually written.
- */
- void stopSong(bool stopAudio = true) { Common::StackLock lock(_mutex); stopSongImpl(stopAudio); }
- /**
- * Stops currently playing Song (if any) and cues up a new one.
- * if stopAudio is specified, the player gets reset before starting the new song
- *
- * @param songPos index of Song to play
- * @param stopAudio stops player and audio output
- * @param dataSize number of bytes to be written
- * @return the number of bytes which were actually written.
- */
- void doSong(int songPos, bool stopAudio = false);
- /**
- * plays an effect from the sfx-table, does not start audio-playback.
- *
- * @param sfxIndex index of effect to play
- * @param unlockChannel overwrite higher priority effects
- * @return index of the channel which now queued up the effect.
- * -1 in case the effect couldnt be queued up
- */
- int doSfx(uint16 sfxIndex, bool unlockChannel = false);
- /**
- * stop a running macro channel
- *
- * @param channel index of effect to stop
- */
- void stopMacroEffect(int channel);
-
- void doMacro(int note, int macro, int relVol = 0, int finetune = 0, int channelNo = 0);
- int getTicks() const { return _playerCtx.tickCount; }
- int getSongIndex() const { return _playerCtx.song; }
- void setSignalPtr(uint16 *ptr, uint16 numSignals) { _playerCtx.signal = ptr; _playerCtx.numSignals = numSignals; }
- void freeResources() { _deleteResource = true; freeResourceDataImpl(); }
- bool load(Common::SeekableReadStream &musicData, Common::SeekableReadStream &sampleData, bool autoDelete = true);
- void setModuleData(Tfmx &otherPlayer);
-
-protected:
- void interrupt();
-
-private:
- enum { kPalDefaultCiaVal = 11822, kNtscDefaultCiaVal = 14320, kCiaBaseInterval = 0x1B51F8 };
- enum { kNumVoices = 4, kNumChannels = 8, kNumSubsongs = 32, kMaxPatternOffsets = 128, kMaxMacroOffsets = 128 };
-
- struct MdatResource {
- const byte *mdatAlloc; ///< allocated Block of Memory
- const byte *mdatData; ///< Start of mdat-File, might point before mdatAlloc to correct Offset
- uint32 mdatLen;
-
- uint16 headerFlags;
-// uint32 headerUnknown;
-// char textField[6 * 40];
-
- struct Subsong {
- uint16 songstart; ///< Index in Trackstep-Table
- uint16 songend; ///< Last index in Trackstep-Table
- uint16 tempo;
- } subsong[kNumSubsongs];
-
- uint32 trackstepOffset; ///< Offset in mdat
- uint32 sfxTableOffset;
-
- uint32 patternOffset[kMaxPatternOffsets]; ///< Offset in mdat
- uint32 macroOffset[kMaxMacroOffsets]; ///< Offset in mdat
-
- void boundaryCheck(const void *address, size_t accessLen = 1) const {
- assert(mdatAlloc <= address && (const byte *)address + accessLen <= (const byte *)mdatData + mdatLen);
- }
- } const *_resource;
-
- struct SampleResource {
- const int8 *sampleData; ///< The whole sample-File
- uint32 sampleLen;
-
- void boundaryCheck(const void *address, size_t accessLen = 2) const {
- assert(sampleData <= address && (const byte *)address + accessLen <= (const byte *)sampleData + sampleLen);
- }
- } _resourceSample;
-
- bool _deleteResource;
-
- bool hasResources() {
- return _resource && _resource->mdatLen && _resourceSample.sampleLen;
- }
-
- struct ChannelContext {
- byte paulaChannel;
-
-// byte macroIndex;
- uint16 macroWait;
- uint32 macroOffset;
- uint32 macroReturnOffset;
- uint16 macroStep;
- uint16 macroReturnStep;
- uint8 macroLoopCount;
- bool macroRun;
- int8 macroSfxRun; ///< values are the folowing: -1 macro disabled, 0 macro init, 1 macro running
-
- uint32 customMacro;
- uint8 customMacroIndex;
- uint8 customMacroPrio;
-
- bool sfxLocked;
- int16 sfxLockTime;
- bool keyUp;
-
- bool deferWait;
- uint16 dmaIntCount;
-
- uint32 sampleStart;
- uint16 sampleLen;
- uint16 refPeriod;
- uint16 period;
-
- int8 volume;
- uint8 relVol;
- uint8 note;
- uint8 prevNote;
- int16 fineTune; // always a signextended byte
-
- uint8 portaSkip;
- uint8 portaCount;
- uint16 portaDelta;
- uint16 portaValue;
-
- uint8 envSkip;
- uint8 envCount;
- uint8 envDelta;
- int8 envEndVolume;
-
- uint8 vibLength;
- uint8 vibCount;
- int16 vibValue;
- int8 vibDelta;
-
- uint8 addBeginLength;
- uint8 addBeginCount;
- int32 addBeginDelta;
- } _channelCtx[kNumVoices];
-
- struct PatternContext {
- uint32 offset; // patternStart, Offset from mdat
- uint32 savedOffset; // for subroutine calls
- uint16 step; // distance from patternStart
- uint16 savedStep;
-
- uint8 command;
- int8 expose;
- uint8 loopCount;
- uint8 wait; ///< how many ticks to wait before next Command
- } _patternCtx[kNumChannels];
-
- struct TrackStepContext {
- uint16 startInd;
- uint16 stopInd;
- uint16 posInd;
- int16 loopCount;
- } _trackCtx;
-
- struct PlayerContext {
- int8 song; ///< >= 0 if Song is running (means process Patterns)
-
- uint16 patternCount;
- uint16 patternSkip; ///< skip that amount of CIA-Interrupts
-
- int8 volume; ///< Master Volume
-
- uint8 fadeSkip;
- uint8 fadeCount;
- int8 fadeEndVolume;
- int8 fadeDelta;
-
- int tickCount;
-
- uint16 *signal;
- uint16 numSignals;
-
- bool stopWithLastPattern; ///< hack to automatically stop the whole player if no Pattern is running
- } _playerCtx;
-
- const byte *getSfxPtr(uint16 index = 0) const {
- const byte *sfxPtr = (const byte *)(_resource->mdatData + _resource->sfxTableOffset + index * 8);
-
- _resource->boundaryCheck(sfxPtr, 8);
- return sfxPtr;
- }
-
- const uint16 *getTrackPtr(uint16 trackstep = 0) const {
- const uint16 *trackData = (const uint16 *)(_resource->mdatData + _resource->trackstepOffset + 16 * trackstep);
-
- _resource->boundaryCheck(trackData, 16);
- return trackData;
- }
-
- const uint32 *getPatternPtr(uint32 offset) const {
- const uint32 *pattData = (const uint32 *)(_resource->mdatData + offset);
-
- _resource->boundaryCheck(pattData, 4);
- return pattData;
- }
-
- const uint32 *getMacroPtr(uint32 offset) const {
- const uint32 *macroData = (const uint32 *)(_resource->mdatData + offset);
-
- _resource->boundaryCheck(macroData, 4);
- return macroData;
- }
-
- const int8 *getSamplePtr(const uint32 offset) const {
- const int8 *sample = _resourceSample.sampleData + offset;
-
- _resourceSample.boundaryCheck(sample, 2);
- return sample;
- }
-
- static inline void initMacroProgramm(ChannelContext &channel);
- static inline void clearEffects(ChannelContext &channel);
- static inline void haltMacroProgramm(ChannelContext &channel);
- static inline void unlockMacroChannel(ChannelContext &channel);
- static inline void initPattern(PatternContext &pattern, uint8 cmd, int8 expose, uint32 offset);
- void stopSongImpl(bool stopAudio = true);
- static inline void setNoteMacro(ChannelContext &channel, uint note, int fineTune);
- void initFadeCommand(const uint8 fadeTempo, const int8 endVol);
- void setModuleData(const MdatResource *resource, const int8 *sampleData, uint32 sampleLen, bool autoDelete = true);
- static const MdatResource *loadMdatFile(Common::SeekableReadStream &musicData);
- static const int8 *loadSampleFile(uint32 &sampleLen, Common::SeekableReadStream &sampleStream);
- void freeResourceDataImpl();
- void effects(ChannelContext &channel);
- void macroRun(ChannelContext &channel);
- void advancePatterns();
- bool patternRun(PatternContext &pattern);
- bool trackRun(bool incStep = false);
- void noteCommand(uint8 note, uint8 param1, uint8 param2, uint8 param3);
-};
-
-} // End of namespace Audio
-
-#endif // !defined(SOUND_MODS_TFMX_H)
diff --git a/sound/module.mk b/sound/module.mk
deleted file mode 100644
index 6cfa165a95..0000000000
--- a/sound/module.mk
+++ /dev/null
@@ -1,61 +0,0 @@
-MODULE := sound
-
-MODULE_OBJS := \
- audiostream.o \
- fmopl.o \
- mididrv.o \
- midiparser_smf.o \
- midiparser_xmidi.o \
- midiparser.o \
- mixer.o \
- mpu401.o \
- musicplugin.o \
- null.o \
- timestamp.o \
- decoders/adpcm.o \
- decoders/aiff.o \
- decoders/flac.o \
- decoders/iff_sound.o \
- decoders/mac_snd.o \
- decoders/mp3.o \
- decoders/raw.o \
- decoders/vag.o \
- decoders/voc.o \
- decoders/vorbis.o \
- decoders/wave.o \
- mods/infogrames.o \
- mods/maxtrax.o \
- mods/module.o \
- mods/protracker.o \
- mods/paula.o \
- mods/rjp1.o \
- mods/soundfx.o \
- mods/tfmx.o \
- softsynth/adlib.o \
- softsynth/cms.o \
- softsynth/opl/dbopl.o \
- softsynth/opl/dosbox.o \
- softsynth/opl/mame.o \
- softsynth/fmtowns_pc98/towns_audio.o \
- softsynth/fmtowns_pc98/towns_euphony.o \
- softsynth/fmtowns_pc98/towns_pc98_driver.o \
- softsynth/fmtowns_pc98/towns_pc98_fmsynth.o \
- softsynth/appleiigs.o \
- softsynth/ym2612.o \
- softsynth/fluidsynth.o \
- softsynth/mt32.o \
- softsynth/pcspk.o \
- softsynth/sid.o \
- softsynth/wave6581.o
-
-ifndef USE_ARM_SOUND_ASM
-MODULE_OBJS += \
- rate.o
-else
-MODULE_OBJS += \
- rate_arm.o \
- rate_arm_asm.o
-endif
-
-# Include common rules
-include $(srcdir)/rules.mk
diff --git a/sound/mpu401.cpp b/sound/mpu401.cpp
deleted file mode 100644
index fe18a3ee85..0000000000
--- a/sound/mpu401.cpp
+++ /dev/null
@@ -1,145 +0,0 @@
-/* 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/mpu401.h"
-#include "common/system.h"
-#include "common/timer.h"
-#include "common/util.h" // for ARRAYSIZE
-
-void MidiChannel_MPU401::init(MidiDriver *owner, byte channel) {
- _owner = owner;
- _channel = channel;
- _allocated = false;
-}
-
-bool MidiChannel_MPU401::allocate() {
- if (_allocated)
- return false;
- return (_allocated = true);
-}
-
-MidiDriver *MidiChannel_MPU401::device() {
- return _owner;
-}
-
-void MidiChannel_MPU401::send(uint32 b) {
- _owner->send((b & 0xFFFFFFF0) | (_channel & 0xF));
-}
-
-void MidiChannel_MPU401::noteOff(byte note) {
- _owner->send(note << 8 | 0x80 | _channel);
-}
-
-void MidiChannel_MPU401::noteOn(byte note, byte velocity) {
- _owner->send(velocity << 16 | note << 8 | 0x90 | _channel);
-}
-
-void MidiChannel_MPU401::programChange(byte program) {
- _owner->send(program << 8 | 0xC0 | _channel);
-}
-
-void MidiChannel_MPU401::pitchBend(int16 bend) {
- _owner->send((((bend + 0x2000) >> 7) & 0x7F) << 16 | ((bend + 0x2000) & 0x7F) << 8 | 0xE0 | _channel);
-}
-
-void MidiChannel_MPU401::controlChange(byte control, byte value) {
- _owner->send(value << 16 | control << 8 | 0xB0 | _channel);
-}
-
-void MidiChannel_MPU401::pitchBendFactor(byte value) {
- _owner->setPitchBendRange(_channel, value);
-}
-
-void MidiChannel_MPU401::sysEx_customInstrument(uint32 type, const byte *instr) {
- _owner->sysEx_customInstrument(_channel, type, instr);
-}
-
-const char *MidiDriver::getErrorName(int error_code) {
- static const char *const midi_errors[] = {
- "No error",
- "Cannot connect",
- "Streaming not available",
- "Device not available",
- "Driver already open"
- };
-
- if ((uint)error_code >= ARRAYSIZE(midi_errors))
- return "Unknown Error";
- return midi_errors[error_code];
-}
-
-MidiDriver_MPU401::MidiDriver_MPU401() :
- MidiDriver(),
- _timer_proc(0),
- _channel_mask(0xFFFF) // Permit all 16 channels by default
-{
-
- uint i;
- for (i = 0; i < ARRAYSIZE(_midi_channels); ++i) {
- _midi_channels[i].init(this, i);
- }
-}
-
-void MidiDriver_MPU401::close() {
- if (_timer_proc)
- g_system->getTimerManager()->removeTimerProc(_timer_proc);
- _timer_proc = 0;
- for (int i = 0; i < 16; ++i)
- send(0x7B << 8 | 0xB0 | i);
-}
-
-uint32 MidiDriver_MPU401::property(int prop, uint32 param) {
- switch (prop) {
- case PROP_CHANNEL_MASK:
- _channel_mask = param & 0xFFFF;
- return 1;
- }
-
- return 0;
-}
-
-MidiChannel *MidiDriver_MPU401::allocateChannel() {
- MidiChannel_MPU401 *chan;
- uint i;
-
- for (i = 0; i < ARRAYSIZE(_midi_channels); ++i) {
- if (i == 9 || !(_channel_mask & (1 << i)))
- continue;
- chan = &_midi_channels[i];
- if (chan->allocate()) {
- return chan;
- }
- }
- return NULL;
-}
-
-void MidiDriver_MPU401::setTimerCallback(void *timer_param, Common::TimerManager::TimerProc timer_proc) {
- if (!_timer_proc || !timer_proc) {
- if (_timer_proc)
- g_system->getTimerManager()->removeTimerProc(_timer_proc);
- _timer_proc = timer_proc;
- if (timer_proc)
- g_system->getTimerManager()->installTimerProc(timer_proc, 10000, timer_param);
- }
-}
diff --git a/sound/mpu401.h b/sound/mpu401.h
deleted file mode 100644
index 2253ab429c..0000000000
--- a/sound/mpu401.h
+++ /dev/null
@@ -1,92 +0,0 @@
-/* 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_MPU401_H
-#define SOUND_MPU401_H
-
-#include "sound/mididrv.h"
-
-////////////////////////////////////////
-//
-// Common MPU401 implementation methods
-//
-////////////////////////////////////////
-
-class MidiDriver_MPU401;
-
-class MidiChannel_MPU401 : public MidiChannel {
-
-private:
- MidiDriver *_owner;
- bool _allocated;
- byte _channel;
-
-public:
- MidiDriver *device();
- byte getNumber() { return _channel; }
- void release() { _allocated = false; }
-
- void send(uint32 b);
-
- // Regular messages
- void noteOff(byte note);
- void noteOn(byte note, byte velocity);
- void programChange(byte program);
- void pitchBend(int16 bend);
-
- // Control Change messages
- void controlChange(byte control, byte value);
- void pitchBendFactor(byte value);
-
- // SysEx messages
- void sysEx_customInstrument(uint32 type, const byte *instr);
-
- // Only to be called by the owner
- void init(MidiDriver *owner, byte channel);
- bool allocate();
-};
-
-
-
-class MidiDriver_MPU401 : public MidiDriver {
-private:
- MidiChannel_MPU401 _midi_channels[16];
- Common::TimerManager::TimerProc _timer_proc;
- uint16 _channel_mask;
-
-public:
- MidiDriver_MPU401();
-
- virtual void close();
- void setTimerCallback(void *timer_param, Common::TimerManager::TimerProc timer_proc);
- uint32 getBaseTempo(void) { return 10000; }
- uint32 property(int prop, uint32 param);
-
- MidiChannel *allocateChannel();
- MidiChannel *getPercussionChannel() { return &_midi_channels[9]; }
-};
-
-
-#endif
diff --git a/sound/musicplugin.cpp b/sound/musicplugin.cpp
deleted file mode 100644
index 8078094616..0000000000
--- a/sound/musicplugin.cpp
+++ /dev/null
@@ -1,64 +0,0 @@
-/* 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/musicplugin.h"
-#include "common/hash-str.h"
-#include "common/translation.h"
-
-MusicDevice::MusicDevice(MusicPluginObject const *musicPlugin, Common::String name, MusicType mt) :
- _musicDriverName(_(musicPlugin->getName())), _musicDriverId(musicPlugin->getId()),
- _name(_(name)), _type(mt) {
-}
-
-Common::String MusicDevice::getCompleteName() {
- Common::String name;
-
- if (_name.empty()) {
- // Default device, just show the driver name
- name = _musicDriverName;
- } else {
- // Show both device and driver names
- name = _name;
- name += " [";
- name += _musicDriverName;
- name += "]";
- }
-
- return name;
-}
-
-Common::String MusicDevice::getCompleteId() {
- Common::String id = _musicDriverId;
- if (!_name.empty()) {
- id += "_";
- id += _name;
- }
-
- return id;
-}
-
-MidiDriver::DeviceHandle MusicDevice::getHandle() {
- return (MidiDriver::DeviceHandle)Common::hashit(getCompleteId().c_str());
-}
diff --git a/sound/musicplugin.h b/sound/musicplugin.h
deleted file mode 100644
index bbb4ed778c..0000000000
--- a/sound/musicplugin.h
+++ /dev/null
@@ -1,125 +0,0 @@
-/* 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_MUSICPLUGIN_H
-#define SOUND_MUSICPLUGIN_H
-
-#include "base/plugins.h"
-#include "sound/mididrv.h"
-#include "common/list.h"
-
-class MusicPluginObject;
-
-/**
- * Description of a Music device. Used to list the devices a Music driver
- * can manage and their capabilities.
- * A device with an empty name means the default device.
- */
-class MusicDevice {
-public:
- MusicDevice(MusicPluginObject const *musicPlugin, Common::String name, MusicType mt);
-
- Common::String &getName() { return _name; }
- Common::String &getMusicDriverName() { return _musicDriverName; }
- Common::String &getMusicDriverId() { return _musicDriverId; }
- MusicType getMusicType() { return _type; }
-
- /**
- * Returns a user readable string that contains the name of the current
- * device name (if it isn't the default one) and the name of the driver.
- */
- Common::String getCompleteName();
-
- /**
- * Returns a user readable string that contains the name of the current
- * device name (if it isn't the default one) and the id of the driver.
- */
- Common::String getCompleteId();
-
- MidiDriver::DeviceHandle getHandle();
-
-private:
- Common::String _name;
- Common::String _musicDriverName;
- Common::String _musicDriverId;
- MusicType _type;
-};
-
-/** List of music devices. */
-typedef Common::List<MusicDevice> MusicDevices;
-
-/**
- * A MusicPluginObject is essentially a factory for MidiDriver instances with
- * the added ability of listing the available devices and their capabilities.
- */
-class MusicPluginObject : public PluginObject {
-public:
- virtual ~MusicPluginObject() {}
-
- /**
- * Returns a unique string identifier which will be used to save the
- * selected MIDI driver to the config file.
- */
- virtual const char *getId() const = 0;
-
- /**
- * Returns a list of the available devices.
- */
- virtual MusicDevices getDevices() const = 0;
-
- /**
- * Tries to instantiate a MIDI Driver instance based on the device
- * previously detected via MidiDriver::detectDevice()
- *
- * @param mididriver Pointer to a pointer which the MusicPluginObject sets
- * to the newly create MidiDriver, or 0 in case of an error
- *
- * @param dev Pointer to a device to be used then creating the driver instance.
- * Default value of zero for driver types without devices.
- *
- * @return a Common::Error describing the error which occurred, or kNoError
- */
- virtual Common::Error createInstance(MidiDriver **mididriver, MidiDriver::DeviceHandle = 0) const = 0;
-};
-
-
-// Music plugins
-
-typedef PluginSubclass<MusicPluginObject> MusicPlugin;
-
-/**
- * Singleton class which manages all Music plugins.
- */
-class MusicManager : public Common::Singleton<MusicManager> {
-private:
- friend class Common::Singleton<SingletonBaseType>;
-
-public:
- const MusicPlugin::List &getPlugins() const;
-};
-
-/** Convenience shortcut for accessing the Music manager. */
-#define MusicMan MusicManager::instance()
-
-#endif
diff --git a/sound/null.cpp b/sound/null.cpp
deleted file mode 100644
index 556b96c14c..0000000000
--- a/sound/null.cpp
+++ /dev/null
@@ -1,62 +0,0 @@
-/* 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/null.h"
-
-Common::Error NullMusicPlugin::createInstance(MidiDriver **mididriver, MidiDriver::DeviceHandle) const {
- *mididriver = new MidiDriver_NULL();
-
- return Common::kNoError;
-}
-
-MusicDevices NullMusicPlugin::getDevices() const {
- MusicDevices devices;
- devices.push_back(MusicDevice(this, "", MT_NULL));
- return devices;
-}
-
-class AutoMusicPlugin : public NullMusicPlugin {
-public:
- const char *getName() const {
- return _s("<default>");
- }
-
- const char *getId() const {
- return "auto";
- }
- MusicDevices getDevices() const;
-};
-
-MusicDevices AutoMusicPlugin::getDevices() const {
- MusicDevices devices;
- devices.push_back(MusicDevice(this, "", MT_AUTO));
- return devices;
-}
-
-//#if PLUGIN_ENABLED_DYNAMIC(NULL)
- //REGISTER_PLUGIN_DYNAMIC(NULL, PLUGIN_TYPE_MUSIC, NullMusicPlugin);
-//#else
- REGISTER_PLUGIN_STATIC(AUTO, PLUGIN_TYPE_MUSIC, AutoMusicPlugin);
- REGISTER_PLUGIN_STATIC(NULL, PLUGIN_TYPE_MUSIC, NullMusicPlugin);
-//#endif
diff --git a/sound/null.h b/sound/null.h
deleted file mode 100644
index d9343701fa..0000000000
--- a/sound/null.h
+++ /dev/null
@@ -1,56 +0,0 @@
-/* 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_NULL_H
-#define SOUND_NULL_H
-
-#include "sound/musicplugin.h"
-#include "sound/mpu401.h"
-#include "common/translation.h"
-
-/* NULL driver */
-class MidiDriver_NULL : public MidiDriver_MPU401 {
-public:
- int open() { return 0; }
- void send(uint32 b) { }
-};
-
-
-// Plugin interface
-
-class NullMusicPlugin : public MusicPluginObject {
-public:
- virtual const char *getName() const {
- return _s("No music");
- }
-
- virtual const char *getId() const {
- return "null";
- }
-
- virtual MusicDevices getDevices() const;
- Common::Error createInstance(MidiDriver **mididriver, MidiDriver::DeviceHandle = 0) const;
-};
-
-#endif
diff --git a/sound/rate.cpp b/sound/rate.cpp
deleted file mode 100644
index 97521da3e0..0000000000
--- a/sound/rate.cpp
+++ /dev/null
@@ -1,358 +0,0 @@
-/* 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$
- *
- */
-
-/*
- * The code in this file is based on code with Copyright 1998 Fabrice Bellard
- * Fabrice original code is part of SoX (http://sox.sourceforge.net).
- * Max Horn adapted that code to the needs of ScummVM and rewrote it partial,
- * in the process removing any use of floating point arithmetic. Various other
- * improvements over the original code were made.
- */
-
-#include "sound/audiostream.h"
-#include "sound/rate.h"
-#include "sound/mixer.h"
-#include "common/frac.h"
-#include "common/util.h"
-
-namespace Audio {
-
-
-/**
- * The size of the intermediate input cache. Bigger values may increase
- * performance, but only until some point (depends largely on cache size,
- * target processor and various other factors), at which it will decrease
- * again.
- */
-#define INTERMEDIATE_BUFFER_SIZE 512
-
-
-/**
- * Audio rate converter based on simple resampling. Used when no
- * interpolation is required.
- *
- * Limited to sampling frequency <= 65535 Hz.
- */
-template<bool stereo, bool reverseStereo>
-class SimpleRateConverter : public RateConverter {
-protected:
- st_sample_t inBuf[INTERMEDIATE_BUFFER_SIZE];
- const st_sample_t *inPtr;
- int inLen;
-
- /** position of how far output is ahead of input */
- /** Holds what would have been opos-ipos */
- long opos;
-
- /** fractional position increment in the output stream */
- long opos_inc;
-
-public:
- SimpleRateConverter(st_rate_t inrate, st_rate_t outrate);
- int flow(AudioStream &input, st_sample_t *obuf, st_size_t osamp, st_volume_t vol_l, st_volume_t vol_r);
- int drain(st_sample_t *obuf, st_size_t osamp, st_volume_t vol) {
- return ST_SUCCESS;
- }
-};
-
-
-/*
- * Prepare processing.
- */
-template<bool stereo, bool reverseStereo>
-SimpleRateConverter<stereo, reverseStereo>::SimpleRateConverter(st_rate_t inrate, st_rate_t outrate) {
- if ((inrate % outrate) != 0) {
- error("Input rate must be a multiple of output rate to use rate effect");
- }
-
- if (inrate >= 65536 || outrate >= 65536) {
- error("rate effect can only handle rates < 65536");
- }
-
- opos = 1;
-
- /* increment */
- opos_inc = inrate / outrate;
-
- inLen = 0;
-}
-
-/*
- * Processed signed long samples from ibuf to obuf.
- * Return number of sample pairs processed.
- */
-template<bool stereo, bool reverseStereo>
-int SimpleRateConverter<stereo, reverseStereo>::flow(AudioStream &input, st_sample_t *obuf, st_size_t osamp, st_volume_t vol_l, st_volume_t vol_r) {
- st_sample_t *ostart, *oend;
-
- ostart = obuf;
- oend = obuf + osamp * 2;
-
- while (obuf < oend) {
-
- // read enough input samples so that opos >= 0
- do {
- // Check if we have to refill the buffer
- if (inLen == 0) {
- inPtr = inBuf;
- inLen = input.readBuffer(inBuf, ARRAYSIZE(inBuf));
- if (inLen <= 0)
- return (obuf - ostart) / 2;
- }
- inLen -= (stereo ? 2 : 1);
- opos--;
- if (opos >= 0) {
- inPtr += (stereo ? 2 : 1);
- }
- } while (opos >= 0);
-
- st_sample_t out0, out1;
- out0 = *inPtr++;
- out1 = (stereo ? *inPtr++ : out0);
-
- // Increment output position
- opos += opos_inc;
-
- // output left channel
- clampedAdd(obuf[reverseStereo ], (out0 * (int)vol_l) / Audio::Mixer::kMaxMixerVolume);
-
- // output right channel
- clampedAdd(obuf[reverseStereo ^ 1], (out1 * (int)vol_r) / Audio::Mixer::kMaxMixerVolume);
-
- obuf += 2;
- }
- return (obuf - ostart) / 2;
-}
-
-/**
- * Audio rate converter based on simple linear Interpolation.
- *
- * The use of fractional increment allows us to use no buffer. It
- * avoid the problems at the end of the buffer we had with the old
- * method which stored a possibly big buffer of size
- * lcm(in_rate,out_rate).
- *
- * Limited to sampling frequency <= 65535 Hz.
- */
-
-template<bool stereo, bool reverseStereo>
-class LinearRateConverter : public RateConverter {
-protected:
- st_sample_t inBuf[INTERMEDIATE_BUFFER_SIZE];
- const st_sample_t *inPtr;
- int inLen;
-
- /** fractional position of the output stream in input stream unit */
- frac_t opos;
-
- /** fractional position increment in the output stream */
- frac_t opos_inc;
-
- /** last sample(s) in the input stream (left/right channel) */
- st_sample_t ilast0, ilast1;
- /** current sample(s) in the input stream (left/right channel) */
- st_sample_t icur0, icur1;
-
-public:
- LinearRateConverter(st_rate_t inrate, st_rate_t outrate);
- int flow(AudioStream &input, st_sample_t *obuf, st_size_t osamp, st_volume_t vol_l, st_volume_t vol_r);
- int drain(st_sample_t *obuf, st_size_t osamp, st_volume_t vol) {
- return ST_SUCCESS;
- }
-};
-
-
-/*
- * Prepare processing.
- */
-template<bool stereo, bool reverseStereo>
-LinearRateConverter<stereo, reverseStereo>::LinearRateConverter(st_rate_t inrate, st_rate_t outrate) {
- if (inrate >= 65536 || outrate >= 65536) {
- error("rate effect can only handle rates < 65536");
- }
-
- opos = FRAC_ONE;
-
- // Compute the linear interpolation increment.
- // This will overflow if inrate >= 2^16, and underflow if outrate >= 2^16.
- // Also, if the quotient of the two rate becomes too small / too big, that
- // would cause problems, but since we rarely scale from 1 to 65536 Hz or vice
- // versa, I think we can live with that limitation ;-).
- opos_inc = (inrate << FRAC_BITS) / outrate;
-
- ilast0 = ilast1 = 0;
- icur0 = icur1 = 0;
-
- inLen = 0;
-}
-
-/*
- * Processed signed long samples from ibuf to obuf.
- * Return number of sample pairs processed.
- */
-template<bool stereo, bool reverseStereo>
-int LinearRateConverter<stereo, reverseStereo>::flow(AudioStream &input, st_sample_t *obuf, st_size_t osamp, st_volume_t vol_l, st_volume_t vol_r) {
- st_sample_t *ostart, *oend;
-
- ostart = obuf;
- oend = obuf + osamp * 2;
-
- while (obuf < oend) {
-
- // read enough input samples so that opos < 0
- while ((frac_t)FRAC_ONE <= opos) {
- // Check if we have to refill the buffer
- if (inLen == 0) {
- inPtr = inBuf;
- inLen = input.readBuffer(inBuf, ARRAYSIZE(inBuf));
- if (inLen <= 0)
- return (obuf - ostart) / 2;
- }
- inLen -= (stereo ? 2 : 1);
- ilast0 = icur0;
- icur0 = *inPtr++;
- if (stereo) {
- ilast1 = icur1;
- icur1 = *inPtr++;
- }
- opos -= FRAC_ONE;
- }
-
- // Loop as long as the outpos trails behind, and as long as there is
- // still space in the output buffer.
- while (opos < (frac_t)FRAC_ONE && obuf < oend) {
- // interpolate
- st_sample_t out0, out1;
- out0 = (st_sample_t)(ilast0 + (((icur0 - ilast0) * opos + FRAC_HALF) >> FRAC_BITS));
- out1 = (stereo ?
- (st_sample_t)(ilast1 + (((icur1 - ilast1) * opos + FRAC_HALF) >> FRAC_BITS)) :
- out0);
-
- // output left channel
- clampedAdd(obuf[reverseStereo ], (out0 * (int)vol_l) / Audio::Mixer::kMaxMixerVolume);
-
- // output right channel
- clampedAdd(obuf[reverseStereo ^ 1], (out1 * (int)vol_r) / Audio::Mixer::kMaxMixerVolume);
-
- obuf += 2;
-
- // Increment output position
- opos += opos_inc;
- }
- }
- return (obuf - ostart) / 2;
-}
-
-
-#pragma mark -
-
-
-/**
- * Simple audio rate converter for the case that the inrate equals the outrate.
- */
-template<bool stereo, bool reverseStereo>
-class CopyRateConverter : public RateConverter {
- st_sample_t *_buffer;
- st_size_t _bufferSize;
-public:
- CopyRateConverter() : _buffer(0), _bufferSize(0) {}
- ~CopyRateConverter() {
- free(_buffer);
- }
-
- virtual int flow(AudioStream &input, st_sample_t *obuf, st_size_t osamp, st_volume_t vol_l, st_volume_t vol_r) {
- assert(input.isStereo() == stereo);
-
- st_sample_t *ptr;
- st_size_t len;
-
- st_sample_t *ostart = obuf;
-
- if (stereo)
- osamp *= 2;
-
- // Reallocate temp buffer, if necessary
- if (osamp > _bufferSize) {
- free(_buffer);
- _buffer = (st_sample_t *)malloc(osamp * 2);
- _bufferSize = osamp;
- }
-
- // Read up to 'osamp' samples into our temporary buffer
- len = input.readBuffer(_buffer, osamp);
-
- // Mix the data into the output buffer
- ptr = _buffer;
- for (; len > 0; len -= (stereo ? 2 : 1)) {
- st_sample_t out0, out1;
- out0 = *ptr++;
- out1 = (stereo ? *ptr++ : out0);
-
- // output left channel
- clampedAdd(obuf[reverseStereo ], (out0 * (int)vol_l) / Audio::Mixer::kMaxMixerVolume);
-
- // output right channel
- clampedAdd(obuf[reverseStereo ^ 1], (out1 * (int)vol_r) / Audio::Mixer::kMaxMixerVolume);
-
- obuf += 2;
- }
- return (obuf - ostart) / 2;
- }
-
- virtual int drain(st_sample_t *obuf, st_size_t osamp, st_volume_t vol) {
- return ST_SUCCESS;
- }
-};
-
-
-#pragma mark -
-
-template<bool stereo, bool reverseStereo>
-RateConverter *makeRateConverter(st_rate_t inrate, st_rate_t outrate) {
- if (inrate != outrate) {
- if ((inrate % outrate) == 0) {
- return new SimpleRateConverter<stereo, reverseStereo>(inrate, outrate);
- } else {
- return new LinearRateConverter<stereo, reverseStereo>(inrate, outrate);
- }
- } else {
- return new CopyRateConverter<stereo, reverseStereo>();
- }
-}
-
-/**
- * Create and return a RateConverter object for the specified input and output rates.
- */
-RateConverter *makeRateConverter(st_rate_t inrate, st_rate_t outrate, bool stereo, bool reverseStereo) {
- if (stereo) {
- if (reverseStereo)
- return makeRateConverter<true, true>(inrate, outrate);
- else
- return makeRateConverter<true, false>(inrate, outrate);
- } else
- return makeRateConverter<false, false>(inrate, outrate);
-}
-
-} // End of namespace Audio
diff --git a/sound/rate.h b/sound/rate.h
deleted file mode 100644
index fb231e4c4a..0000000000
--- a/sound/rate.h
+++ /dev/null
@@ -1,90 +0,0 @@
-/* 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_RATE_H
-#define SOUND_RATE_H
-
-#include "common/scummsys.h"
-#include "engines/engine.h"
-
-class AudioStream;
-
-
-namespace Audio {
-
-typedef int16 st_sample_t;
-typedef uint16 st_volume_t;
-typedef uint32 st_size_t;
-typedef uint32 st_rate_t;
-
-/* Minimum and maximum values a sample can hold. */
-enum {
- ST_SAMPLE_MAX = 0x7fffL,
- ST_SAMPLE_MIN = (-ST_SAMPLE_MAX - 1L)
-};
-
-enum {
- ST_EOF = -1,
- ST_SUCCESS = 0
-};
-
-static inline void clampedAdd(int16& a, int b) {
- register int val;
-#ifdef OUTPUT_UNSIGNED_AUDIO
- val = (a ^ 0x8000) + b;
-#else
- val = a + b;
-#endif
-
- if (val > ST_SAMPLE_MAX)
- val = ST_SAMPLE_MAX;
- else if (val < ST_SAMPLE_MIN)
- val = ST_SAMPLE_MIN;
-
-#ifdef OUTPUT_UNSIGNED_AUDIO
- a = ((int16)val) ^ 0x8000;
-#else
- a = val;
-#endif
-}
-
-class RateConverter {
-public:
- RateConverter() {}
- virtual ~RateConverter() {}
-
- /**
- * @return Number of sample pairs written into the buffer.
- */
- virtual int flow(AudioStream &input, st_sample_t *obuf, st_size_t osamp, st_volume_t vol_l, st_volume_t vol_r) = 0;
-
- virtual int drain(st_sample_t *obuf, st_size_t osamp, st_volume_t vol) = 0;
-};
-
-RateConverter *makeRateConverter(st_rate_t inrate, st_rate_t outrate, bool stereo, bool reverseStereo = false);
-
-} // End of namespace Audio
-
-#endif
diff --git a/sound/rate_arm.cpp b/sound/rate_arm.cpp
deleted file mode 100644
index 63008fcb87..0000000000
--- a/sound/rate_arm.cpp
+++ /dev/null
@@ -1,465 +0,0 @@
-/* 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$
- *
- */
-
-/*
- * The code in this file, together with the rate_arm_asm.s file offers
- * an ARM optimised version of the code in rate.cpp. The operation of this
- * code should be identical to that of rate.cpp, but faster. The heavy
- * lifting is done in the assembler file.
- *
- * To be as portable as possible we implement the core routines with C
- * linkage in assembly, and implement the C++ routines that call into
- * the C here. The C++ symbol mangling varies wildly between compilers,
- * so this is the simplest way to ensure that the C/C++ combination should
- * work on as many ARM based platforms as possible.
- *
- * Essentially the algorithm herein is the same as that in rate.cpp, so
- * anyone seeking to understand this should attempt to understand that
- * first. That code was based in turn on code with Copyright 1998 Fabrice
- * Bellard - part of SoX (http://sox.sourceforge.net).
- * Max Horn adapted that code to the needs of ScummVM and partially rewrote
- * it, in the process removing any use of floating point arithmetic. Various
- * other improvments over the original code were made.
- */
-
-#include "sound/audiostream.h"
-#include "sound/rate.h"
-#include "sound/mixer.h"
-#include "common/util.h"
-
-//#define DEBUG_RATECONV
-
-namespace Audio {
-
-/**
- * The precision of the fractional computations used by the rate converter.
- * Normally you should never have to modify this value.
- * This stuff is defined in common/frac.h, but we redefine it here as the
- * ARM routine we call doesn't respect those definitions.
- */
-#define FRAC_BITS 16
-#define FRAC_ONE (1<<FRAC_BITS)
-
-/**
- * The size of the intermediate input cache. Bigger values may increase
- * performance, but only until some point (depends largely on cache size,
- * target processor and various other factors), at which it will decrease
- * again.
- */
-#define INTERMEDIATE_BUFFER_SIZE 512
-
-
-/**
- * Audio rate converter based on simple resampling. Used when no
- * interpolation is required.
- *
- * Limited to sampling frequency <= 65535 Hz.
- */
-typedef struct {
- const st_sample_t *inPtr;
- int inLen;
-
- /** position of how far output is ahead of input */
- /** Holds what would have been opos-ipos */
- long opos;
-
- /** fractional position increment in the output stream */
- long opos_inc;
-
- st_sample_t inBuf[INTERMEDIATE_BUFFER_SIZE];
-} SimpleRateDetails;
-
-template<bool stereo, bool reverseStereo>
-class SimpleRateConverter : public RateConverter {
-protected:
- SimpleRateDetails sr;
-public:
- SimpleRateConverter(st_rate_t inrate, st_rate_t outrate);
- int flow(AudioStream &input, st_sample_t *obuf, st_size_t osamp, st_volume_t vol_l, st_volume_t vol_r);
- int drain(st_sample_t *obuf, st_size_t osamp, st_volume_t vol) {
- return (ST_SUCCESS);
- }
-};
-
-
-/*
- * Prepare processing.
- */
-template<bool stereo, bool reverseStereo>
-SimpleRateConverter<stereo, reverseStereo>::SimpleRateConverter(st_rate_t inrate, st_rate_t outrate) {
- if (inrate == outrate) {
- error("Input and Output rates must be different to use rate effect");
- }
-
- if ((inrate % outrate) != 0) {
- error("Input rate must be a multiple of Output rate to use rate effect");
- }
-
- if (inrate >= 65536 || outrate >= 65536) {
- error("rate effect can only handle rates < 65536");
- }
-
- sr.opos = 1;
-
- /* increment */
- sr.opos_inc = inrate / outrate;
-
- sr.inLen = 0;
-}
-
-extern "C" {
-#ifndef IPHONE
-#define ARM_SimpleRate_M _ARM_SimpleRate_M
-#define ARM_SimpleRate_S _ARM_SimpleRate_S
-#define ARM_SimpleRate_R _ARM_SimpleRate_R
-#endif
-}
-
-extern "C" st_sample_t *ARM_SimpleRate_M(
- AudioStream &input,
- int (*fn)(Audio::AudioStream&,int16*,int),
- SimpleRateDetails *sr,
- st_sample_t *obuf,
- st_size_t osamp,
- st_volume_t vol_l,
- st_volume_t vol_r);
-
-extern "C" st_sample_t *ARM_SimpleRate_S(
- AudioStream &input,
- int (*fn)(Audio::AudioStream&,int16*,int),
- SimpleRateDetails *sr,
- st_sample_t *obuf,
- st_size_t osamp,
- st_volume_t vol_l,
- st_volume_t vol_r);
-
-extern "C" st_sample_t *ARM_SimpleRate_R(
- AudioStream &input,
- int (*fn)(Audio::AudioStream&,int16*,int),
- SimpleRateDetails *sr,
- st_sample_t *obuf,
- st_size_t osamp,
- st_volume_t vol_l,
- st_volume_t vol_r);
-
-extern "C" int SimpleRate_readFudge(Audio::AudioStream &input,
- int16 *a, int b)
-{
-#ifdef DEBUG_RATECONV
- debug("Reading ptr=%x n%d", a, b);
-#endif
- return input.readBuffer(a, b);
-}
-
-template<bool stereo, bool reverseStereo>
-int SimpleRateConverter<stereo, reverseStereo>::flow(AudioStream &input, st_sample_t *obuf, st_size_t osamp, st_volume_t vol_l, st_volume_t vol_r) {
-
-#ifdef DEBUG_RATECONV
- debug("Simple st=%d rev=%d", stereo, reverseStereo);
-#endif
- st_sample_t *ostart = obuf;
-
- if (!stereo) {
- obuf = ARM_SimpleRate_M(input,
- &SimpleRate_readFudge,
- &sr,
- obuf, osamp, vol_l, vol_r);
- } else if (reverseStereo) {
- obuf = ARM_SimpleRate_R(input,
- &SimpleRate_readFudge,
- &sr,
- obuf, osamp, vol_l, vol_r);
- } else {
- obuf = ARM_SimpleRate_S(input,
- &SimpleRate_readFudge,
- &sr,
- obuf, osamp, vol_l, vol_r);
- }
- return (obuf-ostart)/2;
-}
-
-/**
- * Audio rate converter based on simple linear Interpolation.
- *
- * The use of fractional increment allows us to use no buffer. It
- * avoid the problems at the end of the buffer we had with the old
- * method which stored a possibly big buffer of size
- * lcm(in_rate,out_rate).
- *
- * Limited to sampling frequency <= 65535 Hz.
- */
-
-typedef struct {
- const st_sample_t *inPtr;
- int inLen;
-
- /** position of how far output is ahead of input */
- /** Holds what would have been opos-ipos<<16 + opos_frac */
- long opos;
-
- /** integer position increment in the output stream */
- long opos_inc;
-
- /** current sample(s) in the input stream (left/right channel) */
- st_sample_t icur[2];
- /** last sample(s) in the input stream (left/right channel) */
- /** Note, these are deliberately ints, not st_sample_t's */
- int32 ilast[2];
-
- st_sample_t inBuf[INTERMEDIATE_BUFFER_SIZE];
-} LinearRateDetails;
-
-extern "C" {
-#ifndef IPHONE
-#define ARM_LinearRate_M _ARM_LinearRate_M
-#define ARM_LinearRate_S _ARM_LinearRate_S
-#define ARM_LinearRate_R _ARM_LinearRate_R
-#endif
-}
-
-extern "C" st_sample_t *ARM_LinearRate_M(
- AudioStream &input,
- int (*fn)(Audio::AudioStream&,int16*,int),
- LinearRateDetails *lr,
- st_sample_t *obuf,
- st_size_t osamp,
- st_volume_t vol_l,
- st_volume_t vol_r);
-
-extern "C" st_sample_t *ARM_LinearRate_S(
- AudioStream &input,
- int (*fn)(Audio::AudioStream&,int16*,int),
- LinearRateDetails *lr,
- st_sample_t *obuf,
- st_size_t osamp,
- st_volume_t vol_l,
- st_volume_t vol_r);
-
-extern "C" st_sample_t *ARM_LinearRate_R(
- AudioStream &input,
- int (*fn)(Audio::AudioStream&,int16*,int),
- LinearRateDetails *lr,
- st_sample_t *obuf,
- st_size_t osamp,
- st_volume_t vol_l,
- st_volume_t vol_r);
-
-template<bool stereo, bool reverseStereo>
-class LinearRateConverter : public RateConverter {
-protected:
- LinearRateDetails lr;
-
-public:
- LinearRateConverter(st_rate_t inrate, st_rate_t outrate);
- int flow(AudioStream &input, st_sample_t *obuf, st_size_t osamp, st_volume_t vol_l, st_volume_t vol_r);
- int drain(st_sample_t *obuf, st_size_t osamp, st_volume_t vol) {
- return (ST_SUCCESS);
- }
-};
-
-
-/*
- * Prepare processing.
- */
-template<bool stereo, bool reverseStereo>
-LinearRateConverter<stereo, reverseStereo>::LinearRateConverter(st_rate_t inrate, st_rate_t outrate) {
- unsigned long incr;
-
- if (inrate == outrate) {
- error("Input and Output rates must be different to use rate effect");
- }
-
- if (inrate >= 65536 || outrate >= 65536) {
- error("rate effect can only handle rates < 65536");
- }
-
- lr.opos = FRAC_ONE;
-
- /* increment */
- incr = (inrate << FRAC_BITS) / outrate;
-
- lr.opos_inc = incr;
-
- lr.ilast[0] = lr.ilast[1] = 32768;
- lr.icur[0] = lr.icur[1] = 0;
-
- lr.inLen = 0;
-}
-
-/*
- * Processed signed long samples from ibuf to obuf.
- * Return number of sample pairs processed.
- */
-template<bool stereo, bool reverseStereo>
-int LinearRateConverter<stereo, reverseStereo>::flow(AudioStream &input, st_sample_t *obuf, st_size_t osamp, st_volume_t vol_l, st_volume_t vol_r) {
-
-#ifdef DEBUG_RATECONV
- debug("Linear st=%d rev=%d", stereo, reverseStereo);
-#endif
- st_sample_t *ostart = obuf;
-
- if (!stereo) {
- obuf = ARM_LinearRate_M(input,
- &SimpleRate_readFudge,
- &lr,
- obuf, osamp, vol_l, vol_r);
- } else if (reverseStereo) {
- obuf = ARM_LinearRate_R(input,
- &SimpleRate_readFudge,
- &lr,
- obuf, osamp, vol_l, vol_r);
- } else {
- obuf = ARM_LinearRate_S(input,
- &SimpleRate_readFudge,
- &lr,
- obuf, osamp, vol_l, vol_r);
- }
- return (obuf-ostart)/2;
-}
-
-
-#pragma mark -
-
-
-/**
- * Simple audio rate converter for the case that the inrate equals the outrate.
- */
-extern "C" {
-#ifndef IPHONE
-#define ARM_CopyRate_M _ARM_CopyRate_M
-#define ARM_CopyRate_S _ARM_CopyRate_S
-#define ARM_CopyRate_R _ARM_CopyRate_R
-#endif
-}
-
-extern "C" st_sample_t *ARM_CopyRate_M(
- st_size_t len,
- st_sample_t *obuf,
- st_volume_t vol_l,
- st_volume_t vol_r,
- st_sample_t *_buffer);
-
-extern "C" st_sample_t *ARM_CopyRate_S(
- st_size_t len,
- st_sample_t *obuf,
- st_volume_t vol_l,
- st_volume_t vol_r,
- st_sample_t *_buffer);
-
-extern "C" st_sample_t *ARM_CopyRate_R(
- st_size_t len,
- st_sample_t *obuf,
- st_volume_t vol_l,
- st_volume_t vol_r,
- st_sample_t *_buffer);
-
-
-template<bool stereo, bool reverseStereo>
-class CopyRateConverter : public RateConverter {
- st_sample_t *_buffer;
- st_size_t _bufferSize;
-public:
- CopyRateConverter() : _buffer(0), _bufferSize(0) {}
- ~CopyRateConverter() {
- free(_buffer);
- }
-
- virtual int flow(AudioStream &input, st_sample_t *obuf, st_size_t osamp, st_volume_t vol_l, st_volume_t vol_r) {
- assert(input.isStereo() == stereo);
-
-#ifdef DEBUG_RATECONV
- debug("Copy st=%d rev=%d", stereo, reverseStereo);
-#endif
- st_size_t len;
- st_sample_t *ostart = obuf;
-
- if (stereo)
- osamp *= 2;
-
- // Reallocate temp buffer, if necessary
- if (osamp > _bufferSize) {
- free(_buffer);
- _buffer = (st_sample_t *)malloc(osamp * 2);
- _bufferSize = osamp;
- }
-
- // Read up to 'osamp' samples into our temporary buffer
- len = input.readBuffer(_buffer, osamp);
- if (len <= 0)
- return 0;
-
- // Mix the data into the output buffer
- if (stereo && reverseStereo)
- obuf = ARM_CopyRate_R(len, obuf, vol_l, vol_r, _buffer);
- else if (stereo)
- obuf = ARM_CopyRate_S(len, obuf, vol_l, vol_r, _buffer);
- else
- obuf = ARM_CopyRate_M(len, obuf, vol_l, vol_r, _buffer);
-
- return (obuf-ostart)/2;
- }
- virtual int drain(st_sample_t *obuf, st_size_t osamp, st_volume_t vol) {
- return (ST_SUCCESS);
- }
-};
-
-
-#pragma mark -
-
-
-/**
- * Create and return a RateConverter object for the specified input and output rates.
- */
-RateConverter *makeRateConverter(st_rate_t inrate, st_rate_t outrate, bool stereo, bool reverseStereo) {
- if (inrate != outrate) {
- if ((inrate % outrate) == 0) {
- if (stereo) {
- if (reverseStereo)
- return new SimpleRateConverter<true, true>(inrate, outrate);
- else
- return new SimpleRateConverter<true, false>(inrate, outrate);
- } else
- return new SimpleRateConverter<false, false>(inrate, outrate);
- } else {
- if (stereo) {
- if (reverseStereo)
- return new LinearRateConverter<true, true>(inrate, outrate);
- else
- return new LinearRateConverter<true, false>(inrate, outrate);
- } else
- return new LinearRateConverter<false, false>(inrate, outrate);
- }
- } else {
- if (stereo) {
- if (reverseStereo)
- return new CopyRateConverter<true, true>();
- else
- return new CopyRateConverter<true, false>();
- } else
- return new CopyRateConverter<false, false>();
- }
-}
-
-} // End of namespace Audio
diff --git a/sound/rate_arm_asm.s b/sound/rate_arm_asm.s
deleted file mode 100644
index 9431ae0649..0000000000
--- a/sound/rate_arm_asm.s
+++ /dev/null
@@ -1,687 +0,0 @@
-@ 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$
-@
-@ @author Robin Watts (robin@wss.co.uk)
-@
-@ This file, together with rate_arm.cpp, provides an ARM optimised version
-@ of rate.cpp. The algorithm is essentially the same as that within rate.cpp
-@ so to understand this file you should understand rate.cpp first.
-
- .text
-
- .global _ARM_CopyRate_M
- .global _ARM_CopyRate_S
- .global _ARM_CopyRate_R
- .global _ARM_SimpleRate_M
- .global _ARM_SimpleRate_S
- .global _ARM_SimpleRate_R
- .global _ARM_LinearRate_M
- .global _ARM_LinearRate_S
- .global _ARM_LinearRate_R
-
-_ARM_CopyRate_M:
- @ r0 = len
- @ r1 = obuf
- @ r2 = vol_l
- @ r3 = vol_r
- @ <> = ptr
- LDR r12,[r13]
- STMFD r13!,{r4-r7,r14}
-
- MOV r14,#0 @ r14= 0
- ORR r2, r2, r2, LSL #8 @ r2 = vol_l as 16 bits
- ORR r3, r3, r3, LSL #8 @ r3 = vol_r as 16 bits
-CopyRate_M_loop:
- LDRSH r5, [r12], #2 @ r5 = tmp0 = tmp1 = *ptr++
- LDRSH r6, [r1] @ r6 = obuf[0]
- LDRSH r7, [r1, #2] @ r7 = obuf[1]
- MUL r4, r2, r5 @ r4 = tmp0*vol_l
- MUL r5, r3, r5 @ r5 = tmp1*vol_r
-
- ADDS r6, r4, r6, LSL #16 @ r6 = obuf[0]<<16 + tmp0*vol_l
- RSCVS r6, r14,#0x80000000 @ Clamp r6
- ADDS r7, r5, r7, LSL #16 @ r7 = obuf[1]<<16 + tmp1*vol_r
- RSCVS r7, r14,#0x80000000 @ Clamp r7
-
- MOV r6, r6, LSR #16 @ Shift back to halfword
- MOV r7, r7, LSR #16 @ Shift back to halfword
-
- STRH r6, [r1], #2 @ Store output value
- STRH r7, [r1], #2 @ Store output value
-
- SUBS r0,r0,#1 @ len--
- BGT CopyRate_M_loop @ and loop
-
- MOV r0, r1 @ return obuf
-
- LDMFD r13!,{r4-r7,PC}
-
-_ARM_CopyRate_S:
- @ r0 = len
- @ r1 = obuf
- @ r2 = vol_l
- @ r3 = vol_r
- @ <> = ptr
- LDR r12,[r13]
- STMFD r13!,{r4-r7,r14}
-
- MOV r14,#0 @ r14= 0
- ORR r2, r2, r2, LSL #8 @ r2 = vol_l as 16 bits
- ORR r3, r3, r3, LSL #8 @ r3 = vol_r as 16 bits
-CopyRate_S_loop:
- LDRSH r4, [r12],#2 @ r4 = tmp0 = *ptr++
- LDRSH r5, [r12],#2 @ r5 = tmp1 = *ptr++
- LDRSH r6, [r1] @ r6 = obuf[0]
- LDRSH r7, [r1,#2] @ r7 = obuf[1]
- MUL r4, r2, r4 @ r5 = tmp0*vol_l
- MUL r5, r3, r5 @ r6 = tmp1*vol_r
-
- ADDS r6, r4, r6, LSL #16 @ r6 = obuf[0]<<16 + tmp0*vol_l
- RSCVS r6, r14,#0x80000000 @ Clamp r6
- ADDS r7, r5, r7, LSL #16 @ r7 = obuf[1]<<16 + tmp1*vol_r
- RSCVS r7, r14,#0x80000000 @ Clamp r7
-
- MOV r6, r6, LSR #16 @ Shift back to halfword
- MOV r7, r7, LSR #16 @ Shift back to halfword
-
- STRH r6, [r1],#2 @ Store output value
- STRH r7, [r1],#2 @ Store output value
-
- SUBS r0,r0,#2 @ len -= 2
- BGT CopyRate_S_loop @ and loop
-
- MOV r0, r1 @ return obuf
-
- LDMFD r13!,{r4-r7,PC}
-
-_ARM_CopyRate_R:
- @ r0 = len
- @ r1 = obuf
- @ r2 = vol_l
- @ r3 = vol_r
- @ <> = ptr
- LDR r12,[r13]
- STMFD r13!,{r4-r7,r14}
-
- MOV r14,#0 @ r14= 0
- ORR r2, r2, r2, LSL #8 @ r2 = vol_l as 16 bits
- ORR r3, r3, r3, LSL #8 @ r3 = vol_r as 16 bits
-CopyRate_R_loop:
- LDRSH r5, [r12],#2 @ r5 = tmp1 = *ptr++
- LDRSH r4, [r12],#2 @ r4 = tmp0 = *ptr++
- LDRSH r6, [r1] @ r6 = obuf[0]
- LDRSH r7, [r1,#2] @ r7 = obuf[1]
- MUL r4, r2, r4 @ r4 = tmp0*vol_l
- MUL r5, r3, r5 @ r5 = tmp1*vol_r
-
- ADDS r6, r4, r6, LSL #16 @ r6 = obuf[0]<<16 + tmp0*vol_l
- RSCVS r6, r14,#0x80000000 @ Clamp r6
- ADDS r7, r5, r7, LSL #16 @ r7 = obuf[1]<<16 + tmp1*vol_r
- RSCVS r7, r14,#0x80000000 @ Clamp r7
-
- MOV r6, r6, LSR #16 @ Shift back to halfword
- MOV r7, r7, LSR #16 @ Shift back to halfword
-
- STRH r6, [r1],#2 @ Store output value
- STRH r7, [r1],#2 @ Store output value
-
- SUBS r0,r0,#2 @ len -= 2
- BGT CopyRate_R_loop @ and loop
-
- MOV r0, r1 @ return obuf
-
- LDMFD r13!,{r4-r7,PC}
-
-_ARM_SimpleRate_M:
- @ r0 = AudioStream &input
- @ r1 = input.readBuffer
- @ r2 = input->sr
- @ r3 = obuf
- @ <> = osamp
- @ <> = vol_l
- @ <> = vol_r
- MOV r12,r13
- STMFD r13!,{r0-r2,r4-r8,r10-r11,r14}
- LDMFD r12,{r11,r12,r14} @ r11= osamp
- @ r12= vol_l
- @ r14= vol_r
- LDMIA r2,{r0,r1,r2,r8} @ r0 = inPtr
- @ r1 = inLen
- @ r2 = opos
- @ r8 = opos_inc
- CMP r11,#0 @ if (osamp <= 0)
- BLE SimpleRate_M_end @ bale
- MOV r10,#0
- ORR r12,r12,r12,LSL #8 @ r12= vol_l as 16 bits
- ORR r14,r14,r14,LSL #8 @ r14= vol_r as 16 bits
-SimpleRate_M_loop:
- SUBS r1, r1, #1 @ r1 = inLen -= 1
- BLT SimpleRate_M_read
- SUBS r2, r2, #1 @ r2 = opos--
- ADDGE r0, r0, #2 @ if (r2 >= 0) { sr.inPtr++
- BGE SimpleRate_M_loop @ and loop }
-SimpleRate_M_read_return:
- LDRSH r5, [r0],#2 @ r5 = tmp1 = *inPtr++
- LDRSH r6, [r3] @ r6 = obuf[0]
- LDRSH r7, [r3,#2] @ r7 = obuf[1]
- ADD r2, r2, r8 @ r2 = opos += opos_inc
- MUL r4, r12,r5 @ r4 = tmp0*vol_l
- MUL r5, r14,r5 @ r5 = tmp1*vol_r
-
- ADDS r6, r4, r6, LSL #16 @ r6 = obuf[0]<<16 + tmp0*vol_l
- RSCVS r6, r10,#0x80000000 @ Clamp r6
- ADDS r7, r5, r7, LSL #16 @ r7 = obuf[1]<<16 + tmp1*vol_r
- RSCVS r7, r10,#0x80000000 @ Clamp r7
-
- MOV r6, r6, LSR #16 @ Shift back to halfword
- MOV r7, r7, LSR #16 @ Shift back to halfword
-
- STRH r6, [r3],#2 @ Store output value
- STRH r7, [r3],#2 @ Store output value
-
- SUBS r11,r11,#1 @ len--
- BGT SimpleRate_M_loop @ and loop
-SimpleRate_M_end:
- LDR r14,[r13,#8] @ r14 = sr
- ADD r13,r13,#12 @ Skip over r0-r2 on stack
- STMIA r14,{r0,r1,r2} @ Store back updated values
-
- MOV r0, r3 @ return obuf
-
- LDMFD r13!,{r4-r8,r10-r11,PC}
-SimpleRate_M_read:
- LDR r0, [r13,#8] @ r0 = sr (8 = 4*2)
- ADD r0, r0, #16 @ r0 = inPtr = inBuf
- STMFD r13!,{r0,r2-r3,r12,r14}
-
- MOV r1, r0 @ r1 = inBuf
- LDR r0, [r13,#20] @ r0 = AudioStream & input (20 = 4*5)
- MOV r2, #512 @ r2 = ARRAYSIZE(inBuf)
-
- @ Calling back into C++ here. WinCE is fairly easy about such things
- @ but other OS are more awkward. r9 is preserved for Symbian, and
- @ we have 3+8+5 = 16 things on the stack (an even number).
- MOV r14,PC
- LDR PC,[r13,#24] @ inLen = input.readBuffer(inBuf,512) (24 = 4*6)
- SUBS r1, r0, #1 @ r1 = inLen-1
- LDMFD r13!,{r0,r2-r3,r12,r14}
- BLT SimpleRate_M_end
- SUBS r2, r2, #1 @ r2 = opos--
- ADDGE r0, r0, #2 @ if (r2 >= 0) { sr.inPtr++
- BGE SimpleRate_M_loop @ and loop }
- B SimpleRate_M_read_return
-
-
-_ARM_SimpleRate_S:
- @ r0 = AudioStream &input
- @ r1 = input.readBuffer
- @ r2 = input->sr
- @ r3 = obuf
- @ <> = osamp
- @ <> = vol_l
- @ <> = vol_r
- MOV r12,r13
- STMFD r13!,{r0-r2,r4-r8,r10-r11,r14}
- LDMFD r12,{r11,r12,r14} @ r11= osamp
- @ r12= vol_l
- @ r14= vol_r
- LDMIA r2,{r0,r1,r2,r8} @ r0 = inPtr
- @ r1 = inLen
- @ r2 = opos
- @ r8 = opos_inc
- CMP r11,#0 @ if (osamp <= 0)
- BLE SimpleRate_S_end @ bale
- MOV r10,#0
- ORR r12,r12,r12,LSL #8 @ r12= vol_l as 16 bits
- ORR r14,r14,r14,LSL #8 @ r14= vol_r as 16 bits
-SimpleRate_S_loop:
- SUBS r1, r1, #2 @ r1 = inLen -= 2
- BLT SimpleRate_S_read
- SUBS r2, r2, #1 @ r2 = opos--
- ADDGE r0, r0, #4 @ if (r2 >= 0) { sr.inPtr += 2
- BGE SimpleRate_S_loop @ and loop }
-SimpleRate_S_read_return:
- LDRSH r4, [r0],#2 @ r4 = tmp0 = *inPtr++
- LDRSH r5, [r0],#2 @ r5 = tmp1 = *inPtr++
- LDRSH r6, [r3] @ r6 = obuf[0]
- LDRSH r7, [r3,#2] @ r7 = obuf[1]
- ADD r2, r2, r8 @ r2 = opos += opos_inc
- MUL r4, r12,r4 @ r5 = tmp0*vol_l
- MUL r5, r14,r5 @ r6 = tmp1*vol_r
-
- ADDS r6, r4, r6, LSL #16 @ r6 = obuf[0]<<16 + tmp0*vol_l
- RSCVS r6, r10,#0x80000000 @ Clamp r6
- ADDS r7, r5, r7, LSL #16 @ r7 = obuf[1]<<16 + tmp1*vol_r
- RSCVS r7, r10,#0x80000000 @ Clamp r7
-
- MOV r6, r6, LSR #16 @ Shift back to halfword
- MOV r7, r7, LSR #16 @ Shift back to halfword
-
- STRH r6, [r3],#2 @ Store output value
- STRH r7, [r3],#2 @ Store output value
-
- SUBS r11,r11,#1 @ osamp--
- BGT SimpleRate_S_loop @ and loop
-SimpleRate_S_end:
- LDR r14,[r13,#8] @ r14 = sr
- ADD r13,r13,#12 @ skip over r0-r2 on stack
- STMIA r14,{r0,r1,r2} @ store back updated values
- MOV r0, r3 @ return obuf
- LDMFD r13!,{r4-r8,r10-r11,PC}
-SimpleRate_S_read:
- LDR r0, [r13,#8] @ r0 = sr (8 = 4*2)
- ADD r0, r0, #16 @ r0 = inPtr = inBuf
- STMFD r13!,{r0,r2-r3,r12,r14}
- MOV r1, r0 @ r1 = inBuf
- LDR r0, [r13,#20] @ r0 = AudioStream & input (20 = 4*5)
- MOV r2, #512 @ r2 = ARRAYSIZE(inBuf)
-
- @ Calling back into C++ here. WinCE is fairly easy about such things
- @ but other OS are more awkward. r9 is preserved for Symbian, and
- @ we have 3+8+5 = 16 things on the stack (an even number).
- MOV r14,PC
- LDR PC,[r13,#24] @ inLen = input.readBuffer(inBuf,512) (24 = 4*6)
- SUBS r1, r0, #2 @ r1 = inLen-2
- LDMFD r13!,{r0,r2-r3,r12,r14}
- BLT SimpleRate_S_end
- SUBS r2, r2, #1 @ r2 = opos--
- ADDGE r0, r0, #4 @ if (r2 >= 0) { sr.inPtr += 2
- BGE SimpleRate_S_loop @ and loop }
- B SimpleRate_S_read_return
-
-
-
-_ARM_SimpleRate_R:
- @ r0 = AudioStream &input
- @ r1 = input.readBuffer
- @ r2 = input->sr
- @ r3 = obuf
- @ <> = osamp
- @ <> = vol_l
- @ <> = vol_r
- MOV r12,r13
- STMFD r13!,{r0-r2,r4-r8,r10-r11,r14}
- LDMFD r12,{r11,r12,r14} @ r11= osamp
- @ r12= vol_l
- @ r14= vol_r
- LDMIA r2,{r0,r1,r2,r8} @ r0 = inPtr
- @ r1 = inLen
- @ r2 = opos
- @ r8 = opos_inc
- CMP r11,#0 @ if (osamp <= 0)
- BLE SimpleRate_R_end @ bale
- MOV r10,#0
- ORR r12,r12,r12,LSL #8 @ r12= vol_l as 16 bits
- ORR r14,r14,r14,LSL #8 @ r14= vol_r as 16 bits
-SimpleRate_R_loop:
- SUBS r1, r1, #2 @ r1 = inLen -= 2
- BLT SimpleRate_R_read
- SUBS r2, r2, #1 @ r2 = opos--
- ADDGE r0, r0, #4 @ if (r2 >= 0) { sr.inPtr += 2
- BGE SimpleRate_R_loop @ and loop }
-SimpleRate_R_read_return:
- LDRSH r5, [r0],#2 @ r5 = tmp0 = *inPtr++
- LDRSH r4, [r0],#2 @ r4 = tmp1 = *inPtr++
- LDRSH r6, [r3] @ r6 = obuf[0]
- LDRSH r7, [r3,#2] @ r7 = obuf[1]
- ADD r2, r2, r8 @ r2 = opos += opos_inc
- MUL r4, r12,r4 @ r5 = tmp0*vol_l
- MUL r5, r14,r5 @ r6 = tmp1*vol_r
-
- ADDS r6, r4, r6, LSL #16 @ r6 = obuf[0]<<16 + tmp0*vol_l
- RSCVS r6, r10,#0x80000000 @ Clamp r6
- ADDS r7, r5, r7, LSL #16 @ r7 = obuf[1]<<16 + tmp1*vol_r
- RSCVS r7, r10,#0x80000000 @ Clamp r7
-
- MOV r6, r6, LSR #16 @ Shift back to halfword
- MOV r7, r7, LSR #16 @ Shift back to halfword
-
- STRH r6, [r3],#2 @ Store output value
- STRH r7, [r3],#2 @ Store output value
-
- SUBS r11,r11,#1 @ osamp--
- BGT SimpleRate_R_loop @ and loop
-SimpleRate_R_end:
- LDR r14,[r13,#8] @ r14 = sr
- ADD r13,r13,#12 @ Skip over r0-r2 on stack
- STMIA r14,{r0,r1,r2} @ Store back updated values
- MOV r0, r3 @ return obuf
- LDMFD r13!,{r4-r8,r10-r11,PC}
-SimpleRate_R_read:
- LDR r0, [r13,#8] @ r0 = sr (8 = 4*2)
- ADD r0, r0, #16 @ r0 = inPtr = inBuf
- STMFD r13!,{r0,r2-r3,r12,r14}
-
- MOV r1, r0 @ r1 = inBuf
- LDR r0, [r13,#20] @ r0 = AudioStream & input (20 = 4*5)
- MOV r2, #512 @ r2 = ARRAYSIZE(inBuf)
-
- @ Calling back into C++ here. WinCE is fairly easy about such things
- @ but other OS are more awkward. r9 is preserved for Symbian, and
- @ we have 3+8+5 = 16 things on the stack (an even number).
- MOV r14,PC
- LDR PC,[r13,#24] @ inLen = input.readBuffer(inBuf,512) (24 = 4*6)
- SUBS r1, r0, #2 @ r1 = inLen-2
- LDMFD r13!,{r0,r2-r3,r12,r14}
- BLT SimpleRate_R_end
- SUBS r2, r2, #1 @ r2 = opos--
- ADDGE r0, r0, #4 @ if (r2 >= 0) { sr.inPtr += 2
- BGE SimpleRate_R_loop @ and loop }
- B SimpleRate_R_read_return
-
-
-_ARM_LinearRate_M:
- @ r0 = AudioStream &input
- @ r1 = input.readBuffer
- @ r2 = input->sr
- @ r3 = obuf
- @ <> = osamp
- @ <> = vol_l
- @ <> = vol_r
- MOV r12,r13
- STMFD r13!,{r0-r1,r4-r11,r14}
- LDMFD r12,{r11,r12,r14} @ r11= osamp
- @ r12= vol_l
- @ r14= vol_r
- LDMIA r2,{r0,r1,r8} @ r0 = inPtr
- @ r1 = inLen
- @ r8 = opos
- MOV r10,#0
- CMP r11,#0 @ if (osamp <= 0)
- BLE LinearRate_M_end @ bale
- ORR r12,r12,r12,LSL #8 @ r12= vol_l as 16 bits
- ORR r14,r14,r14,LSL #8 @ r14= vol_r as 16 bits
- CMP r1,#0
- BGT LinearRate_M_part2
-
- @ part1 - read input samples
-LinearRate_M_loop:
- SUBS r1, r1, #1 @ r1 = inLen -= 1
- BLT LinearRate_M_read
-LinearRate_M_read_return:
- LDRH r4, [r2, #16] @ r4 = icur[0]
- LDRSH r5, [r0],#2 @ r5 = tmp1 = *inPtr++
- SUBS r8, r8, #65536 @ r8 = opos--
- STRH r4, [r2,#22] @ ilast[0] = icur[0]
- STRH r5, [r2,#16] @ icur[0] = tmp1
- BGE LinearRate_M_loop
-
- @ part2 - form output samples
-LinearRate_M_part2:
- @ We are guaranteed that opos < 0 here
- LDR r6, [r2,#20] @ r6 = ilast[0]<<16 + 32768
- LDRSH r5, [r2,#16] @ r5 = icur[0]
- MOV r4, r8, LSL #16
- MOV r4, r4, LSR #16
- SUB r5, r5, r6, ASR #16 @ r5 = icur[0] - ilast[0]
- MLA r6, r4, r5, r6 @ r6 = (icur[0]-ilast[0])*opos_frac+ilast[0]
-
- LDRSH r4, [r3] @ r4 = obuf[0]
- LDRSH r5, [r3,#2] @ r5 = obuf[1]
- MOV r6, r6, ASR #16 @ r6 = tmp0 = tmp1 >>= 16
- MUL r7, r12,r6 @ r7 = tmp0*vol_l
- MUL r6, r14,r6 @ r6 = tmp1*vol_r
-
- ADDS r7, r7, r4, LSL #16 @ r7 = obuf[0]<<16 + tmp0*vol_l
- RSCVS r7, r10, #0x80000000 @ Clamp r7
- ADDS r6, r6, r5, LSL #16 @ r6 = obuf[1]<<16 + tmp1*vol_r
- RSCVS r6, r10, #0x80000000 @ Clamp r6
-
- MOV r7, r7, LSR #16 @ Shift back to halfword
- MOV r6, r6, LSR #16 @ Shift back to halfword
-
- LDR r5, [r2,#12] @ r5 = opos_inc
- STRH r7, [r3],#2 @ Store output value
- STRH r6, [r3],#2 @ Store output value
- SUBS r11, r11,#1 @ osamp--
- BLE LinearRate_M_end @ end if needed
-
- ADDS r8, r8, r5 @ r8 = opos += opos_inc
- BLT LinearRate_M_part2
- B LinearRate_M_loop
-LinearRate_M_end:
- ADD r13,r13,#8
- STMIA r2,{r0,r1,r8}
- MOV r0, r3 @ return obuf
- LDMFD r13!,{r4-r11,PC}
-LinearRate_M_read:
- ADD r0, r2, #28 @ r0 = inPtr = inBuf
- STMFD r13!,{r0,r2-r3,r12,r14}
-
- MOV r1, r0 @ r1 = inBuf
- LDR r0, [r13,#20] @ r0 = AudioStream & input (20 = 4*5)
- MOV r2, #512 @ r2 = ARRAYSIZE(inBuf)
-
- @ Calling back into C++ here. WinCE is fairly easy about such things
- @ but other OS are more awkward. r9 is preserved for Symbian, and
- @ we have 2+9+5 = 16 things on the stack (an even number).
- MOV r14,PC
- LDR PC,[r13,#24] @ inLen = input.readBuffer(inBuf,512) (24 = 4*6)
- SUBS r1, r0, #1 @ r1 = inLen-1
- LDMFD r13!,{r0,r2-r3,r12,r14}
- BLT LinearRate_M_end
- B LinearRate_M_read_return
-
-_ARM_LinearRate_S:
- @ r0 = AudioStream &input
- @ r1 = input.readBuffer
- @ r2 = input->sr
- @ r3 = obuf
- @ <> = osamp
- @ <> = vol_l
- @ <> = vol_r
- MOV r12,r13
- STMFD r13!,{r0-r1,r4-r11,r14}
- LDMFD r12,{r11,r12,r14} @ r11= osamp
- @ r12= vol_l
- @ r14= vol_r
- LDMIA r2,{r0,r1,r8} @ r0 = inPtr
- @ r1 = inLen
- @ r8 = opos
- CMP r11,#0 @ if (osamp <= 0)
- BLE LinearRate_S_end @ bale
- ORR r12,r12,r12,LSL #8 @ r12= vol_l as 16 bits
- ORR r14,r14,r14,LSL #8 @ r14= vol_r as 16 bits
- CMP r1,#0
- BGT LinearRate_S_part2
-
- @ part1 - read input samples
-LinearRate_S_loop:
- SUBS r1, r1, #2 @ r1 = inLen -= 2
- BLT LinearRate_S_read
-LinearRate_S_read_return:
- LDR r10,[r2, #16] @ r10= icur[0,1]
- LDRSH r5, [r0],#2 @ r5 = tmp0 = *inPtr++
- LDRSH r6, [r0],#2 @ r5 = tmp1 = *inPtr++
- SUBS r8, r8, #65536 @ r8 = opos--
- STRH r10,[r2,#22] @ ilast[0] = icur[0]
- MOV r10,r10,LSR #16
- STRH r10,[r2,#26] @ ilast[1] = icur[1]
- STRH r5, [r2,#16] @ icur[0] = tmp0
- STRH r6, [r2,#18] @ icur[1] = tmp1
- BGE LinearRate_S_loop
-
- @ part2 - form output samples
-LinearRate_S_part2:
- @ We are guaranteed that opos < 0 here
- LDR r6, [r2,#20] @ r6 = ilast[0]<<16 + 32768
- LDRSH r5, [r2,#16] @ r5 = icur[0]
- MOV r4, r8, LSL #16
- MOV r4, r4, LSR #16
- SUB r5, r5, r6, ASR #16 @ r5 = icur[0] - ilast[0]
- MLA r6, r4, r5, r6 @ r6 = (icur[0]-ilast[0])*opos_frac+ilast[0]
-
- LDR r7, [r2,#24] @ r7 = ilast[1]<<16 + 32768
- LDRSH r5, [r2,#18] @ r5 = icur[1]
- LDRSH r10,[r3] @ r10= obuf[0]
- MOV r6, r6, ASR #16 @ r6 = tmp1 >>= 16
- SUB r5, r5, r7, ASR #16 @ r5 = icur[1] - ilast[1]
- MLA r7, r4, r5, r7 @ r7 = (icur[1]-ilast[1])*opos_frac+ilast[1]
-
- LDRSH r5, [r3,#2] @ r5 = obuf[1]
- MOV r7, r7, ASR #16 @ r7 = tmp0 >>= 16
- MUL r7, r12,r7 @ r7 = tmp0*vol_l
- MUL r6, r14,r6 @ r6 = tmp1*vol_r
-
- ADDS r7, r7, r10, LSL #16 @ r7 = obuf[0]<<16 + tmp0*vol_l
- MOV r4, #0
- RSCVS r7, r4, #0x80000000 @ Clamp r7
- ADDS r6, r6, r5, LSL #16 @ r6 = obuf[1]<<16 + tmp1*vol_r
- RSCVS r6, r4, #0x80000000 @ Clamp r6
-
- MOV r7, r7, LSR #16 @ Shift back to halfword
- MOV r6, r6, LSR #16 @ Shift back to halfword
-
- LDR r5, [r2,#12] @ r5 = opos_inc
- STRH r7, [r3],#2 @ Store output value
- STRH r6, [r3],#2 @ Store output value
- SUBS r11, r11,#1 @ osamp--
- BLE LinearRate_S_end @ and loop
-
- ADDS r8, r8, r5 @ r8 = opos += opos_inc
- BLT LinearRate_S_part2
- B LinearRate_S_loop
-LinearRate_S_end:
- ADD r13,r13,#8
- STMIA r2,{r0,r1,r8}
- MOV r0, r3 @ return obuf
- LDMFD r13!,{r4-r11,PC}
-LinearRate_S_read:
- ADD r0, r2, #28 @ r0 = inPtr = inBuf
- STMFD r13!,{r0,r2-r3,r12,r14}
-
- MOV r1, r0 @ r1 = inBuf
- LDR r0, [r13,#20] @ r0 = AudioStream & input (20 = 4*5)
- MOV r2, #512 @ r2 = ARRAYSIZE(inBuf)
-
- @ Calling back into C++ here. WinCE is fairly easy about such things
- @ but other OS are more awkward. r9 is preserved for Symbian, and
- @ we have 2+9+5 = 16 things on the stack (an even number).
- MOV r14,PC
- LDR PC,[r13,#24] @ inLen = input.readBuffer(inBuf,512) (24 = 4*6)
- SUBS r1, r0, #2 @ r1 = inLen-2
- LDMFD r13!,{r0,r2-r3,r12,r14}
- BLT LinearRate_S_end
- B LinearRate_S_read_return
-
-_ARM_LinearRate_R:
- @ r0 = AudioStream &input
- @ r1 = input.readBuffer
- @ r2 = input->sr
- @ r3 = obuf
- @ <> = osamp
- @ <> = vol_l
- @ <> = vol_r
- MOV r12,r13
- STMFD r13!,{r0-r1,r4-r11,r14}
- LDMFD r12,{r11,r12,r14} @ r11= osamp
- @ r12= vol_l
- @ r14= vol_r
- LDMIA r2,{r0,r1,r8} @ r0 = inPtr
- @ r1 = inLen
- @ r8 = opos
- CMP r11,#0 @ if (osamp <= 0)
- BLE LinearRate_R_end @ bale
- ORR r12,r12,r12,LSL #8 @ r12= vol_l as 16 bits
- ORR r14,r14,r14,LSL #8 @ r14= vol_r as 16 bits
- CMP r1,#0
- BGT LinearRate_R_part2
-
- @ part1 - read input samples
-LinearRate_R_loop:
- SUBS r1, r1, #2 @ r1 = inLen -= 2
- BLT LinearRate_R_read
-LinearRate_R_read_return:
- LDR r10,[r2, #16] @ r10= icur[0,1]
- LDRSH r5, [r0],#2 @ r5 = tmp0 = *inPtr++
- LDRSH r6, [r0],#2 @ r5 = tmp1 = *inPtr++
- SUBS r8, r8, #65536 @ r8 = opos--
- STRH r10,[r2,#22] @ ilast[0] = icur[0]
- MOV r10,r10,LSR #16
- STRH r10,[r2,#22] @ ilast[1] = icur[1]
- STRH r5, [r2,#16] @ icur[0] = tmp0
- STRH r6, [r2,#18] @ icur[1] = tmp1
- BGE LinearRate_R_loop
-
- @ part2 - form output samples
-LinearRate_R_part2:
- @ We are guaranteed that opos < 0 here
- LDR r6, [r2,#20] @ r6 = ilast[0]
- LDRSH r5, [r2,#16] @ r5 = icur[0]
- MOV r4, r8, LSL #16
- MOV r4, r4, LSR #16
- SUB r5, r5, r6, ASR #16 @ r5 = icur[0] - ilast[0]
- MLA r6, r4, r5, r6 @ r6 = (icur[0]-ilast[0])*opos_frac+ilast[0]
-
- LDR r7, [r2,#24] @ r7 = ilast[1]
- LDRSH r5, [r2,#18] @ r5 = icur[1]
- LDR r10,[r3] @ r10= obuf[0]
- MOV r6, r6, ASR #16 @ r6 = tmp1 >>= 16
- SUB r5, r5, r7, ASR #16 @ r5 = icur[1] - ilast[1]
- MLA r7, r4, r5, r7 @ r7 = (icur[1]-ilast[1])*opos_frac+ilast[1]
-
- LDRSH r5, [r3,#2] @ r5 = obuf[1]
- MOV r7, r7, ASR #16 @ r7 = tmp0 >>= 16
- MUL r7, r12,r7 @ r7 = tmp0*vol_l
- MUL r6, r14,r6 @ r6 = tmp1*vol_r
-
- ADDS r7, r7, r10, LSL #16 @ r7 = obuf[0]<<16 + tmp0*vol_l
- MOV r4, #0
- RSCVS r7, r4, #0x80000000 @ Clamp r7
- ADDS r6, r6, r5, LSL #16 @ r6 = obuf[1]<<16 + tmp1*vol_r
- RSCVS r6, r4, #0x80000000 @ Clamp r6
-
- MOV r7, r7, LSR #16 @ Shift back to halfword
- MOV r6, r6, LSR #16 @ Shift back to halfword
-
- LDR r5, [r2,#12] @ r5 = opos_inc
- STRH r6, [r3],#2 @ Store output value
- STRH r7, [r3],#2 @ Store output value
- SUBS r11, r11,#1 @ osamp--
- BLE LinearRate_R_end @ and loop
-
- ADDS r8, r8, r5 @ r8 = opos += opos_inc
- BLT LinearRate_R_part2
- B LinearRate_R_loop
-LinearRate_R_end:
- ADD r13,r13,#8
- STMIA r2,{r0,r1,r8}
- MOV r0, r3 @ return obuf
- LDMFD r13!,{r4-r11,PC}
-LinearRate_R_read:
- ADD r0, r2, #28 @ r0 = inPtr = inBuf
- STMFD r13!,{r0,r2-r3,r12,r14}
-
- MOV r1, r0 @ r1 = inBuf
- LDR r0, [r13,#20] @ r0 = AudioStream & input (20 = 4*5)
- MOV r2, #512 @ r2 = ARRAYSIZE(inBuf)
-
- @ Calling back into C++ here. WinCE is fairly easy about such things
- @ but other OS are more awkward. r9 is preserved for Symbian, and
- @ we have 2+9+5 = 16 things on the stack (an even number).
- MOV r14,PC
- LDR PC,[r13,#24] @ inLen = input.readBuffer(inBuf,512) (24 = 4*6)
- SUBS r1, r0, #2 @ r1 = inLen-2
- LDMFD r13!,{r0,r2-r3,r12,r14}
- BLT LinearRate_R_end
- B LinearRate_R_read_return
diff --git a/sound/softsynth/adlib.cpp b/sound/softsynth/adlib.cpp
deleted file mode 100644
index ffb359e816..0000000000
--- a/sound/softsynth/adlib.cpp
+++ /dev/null
@@ -1,1617 +0,0 @@
-/* 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/emumidi.h"
-#include "common/debug.h"
-#include "common/util.h"
-#include "sound/fmopl.h"
-#include "sound/musicplugin.h"
-#include "common/translation.h"
-
-#ifdef DEBUG_ADLIB
-static int tick;
-#endif
-
-class MidiDriver_ADLIB;
-struct AdLibVoice;
-
-// We use packing for the following two structs, because the code
-// does simply copy them over from byte streams, without any
-// serialization. Check AdLibPart::sysEx_customInstrument for an
-// example of this.
-//
-// It might be very well possible, that none of the compilers we support
-// add any padding bytes at all, since the structs contain only variables
-// of the type 'byte'. But better safe than sorry.
-#include "common/pack-start.h"
-struct InstrumentExtra {
- byte a, b, c, d, e, f, g, h;
-} PACKED_STRUCT;
-
-struct AdLibInstrument {
- byte mod_characteristic;
- byte mod_scalingOutputLevel;
- byte mod_attackDecay;
- byte mod_sustainRelease;
- byte mod_waveformSelect;
- byte car_characteristic;
- byte car_scalingOutputLevel;
- byte car_attackDecay;
- byte car_sustainRelease;
- byte car_waveformSelect;
- byte feedback;
- byte flags_a;
- InstrumentExtra extra_a;
- byte flags_b;
- InstrumentExtra extra_b;
- byte duration;
-
- AdLibInstrument() { memset(this, 0, sizeof(AdLibInstrument)); }
-} PACKED_STRUCT;
-#include "common/pack-end.h"
-
-class AdLibPart : public MidiChannel {
- friend class MidiDriver_ADLIB;
-
-protected:
-// AdLibPart *_prev, *_next;
- AdLibVoice *_voice;
- int16 _pitchbend;
- byte _pitchbend_factor;
- int8 _transpose_eff;
- byte _vol_eff;
- int8 _detune_eff;
- byte _modwheel;
- bool _pedal;
- byte _program;
- byte _pri_eff;
- AdLibInstrument _part_instr;
-
-protected:
- MidiDriver_ADLIB *_owner;
- bool _allocated;
- byte _channel;
-
- void init(MidiDriver_ADLIB *owner, byte channel);
- void allocate() { _allocated = true; }
-
-public:
- AdLibPart() {
- _voice = 0;
- _pitchbend = 0;
- _pitchbend_factor = 2;
- _transpose_eff = 0;
- _vol_eff = 0;
- _detune_eff = 0;
- _modwheel = 0;
- _pedal = 0;
- _program = 0;
- _pri_eff = 0;
-
- _owner = 0;
- _allocated = false;
- _channel = 0;
- }
-
- MidiDriver *device();
- byte getNumber() { return _channel; }
- void release() { _allocated = false; }
-
- void send (uint32 b);
-
- // Regular messages
- void noteOff(byte note);
- void noteOn(byte note, byte velocity);
- void programChange(byte program);
- void pitchBend(int16 bend);
-
- // Control Change messages
- void controlChange(byte control, byte value);
- void modulationWheel(byte value);
- void volume(byte value);
- void panPosition(byte value) { return; } // Not supported
- void pitchBendFactor(byte value);
- void detune(byte value);
- void priority(byte value);
- void sustain(bool value);
- void effectLevel(byte value) { return; } // Not supported
- void chorusLevel(byte value) { return; } // Not supported
- void allNotesOff();
-
- // SysEx messages
- void sysEx_customInstrument(uint32 type, const byte *instr);
-};
-
-// FYI (Jamieson630)
-// It is assumed that any invocation to AdLibPercussionChannel
-// will be done through the MidiChannel base class as opposed to the
-// AdLibPart base class. If this were NOT the case, all the functions
-// listed below would need to be virtual in AdLibPart as well as MidiChannel.
-class AdLibPercussionChannel : public AdLibPart {
- friend class MidiDriver_ADLIB;
-
-protected:
- void init(MidiDriver_ADLIB *owner, byte channel);
-
-public:
- ~AdLibPercussionChannel();
-
- void noteOff(byte note);
- void noteOn(byte note, byte velocity);
- void programChange(byte program) { }
- void pitchBend(int16 bend) { }
-
- // Control Change messages
- void modulationWheel(byte value) { }
- void pitchBendFactor(byte value) { }
- void detune(byte value) { }
- void priority(byte value) { }
- void sustain(bool value) { }
-
- // SysEx messages
- void sysEx_customInstrument(uint32 type, const byte *instr);
-
-private:
- byte _notes[256];
- AdLibInstrument *_customInstruments[256];
-};
-
-struct Struct10 {
- byte active;
- int16 cur_val;
- int16 count;
- uint16 max_value;
- int16 start_value;
- byte loop;
- byte table_a[4];
- byte table_b[4];
- int8 unk3;
- int8 modwheel;
- int8 modwheel_last;
- uint16 speed_lo_max;
- uint16 num_steps;
- int16 speed_hi;
- int8 direction;
- uint16 speed_lo;
- uint16 speed_lo_counter;
-};
-
-struct Struct11 {
- int16 modify_val;
- byte param, flag0x40, flag0x10;
- Struct10 *s10;
-};
-
-struct AdLibVoice {
- AdLibPart *_part;
- AdLibVoice *_next, *_prev;
- byte _waitforpedal;
- byte _note;
- byte _channel;
- byte _twochan;
- byte _vol_1, _vol_2;
- int16 _duration;
-
- Struct10 _s10a;
- Struct11 _s11a;
- Struct10 _s10b;
- Struct11 _s11b;
-
- AdLibVoice() { memset(this, 0, sizeof(AdLibVoice)); }
-};
-
-struct AdLibSetParams {
- byte a, b, c, d;
-};
-
-static const byte channel_mappings[9] = {
- 0, 1, 2, 8,
- 9, 10, 16, 17,
- 18
-};
-
-static const byte channel_mappings_2[9] = {
- 3, 4, 5, 11,
- 12, 13, 19, 20,
- 21
-};
-
-static const AdLibSetParams adlib_setparam_table[] = {
- {0x40, 0, 63, 63}, // level
- {0xE0, 2, 0, 0}, // unused
- {0x40, 6, 192, 0}, // level key scaling
- {0x20, 0, 15, 0}, // modulator frequency multiple
- {0x60, 4, 240, 15}, // attack rate
- {0x60, 0, 15, 15}, // decay rate
- {0x80, 4, 240, 15}, // sustain level
- {0x80, 0, 15, 15}, // release rate
- {0xE0, 0, 3, 0}, // waveformSelect select
- {0x20, 7, 128, 0}, // amp mod
- {0x20, 6, 64, 0}, // vib
- {0x20, 5, 32, 0}, // eg typ
- {0x20, 4, 16, 0}, // ksr
- {0xC0, 0, 1, 0}, // decay alg
- {0xC0, 1, 14, 0} // feedback
-};
-
-static const byte param_table_1[16] = {
- 29, 28, 27, 0,
- 3, 4, 7, 8,
- 13, 16, 17, 20,
- 21, 30, 31, 0
-};
-
-static const uint16 maxval_table[16] = {
- 0x2FF, 0x1F, 0x7, 0x3F,
- 0x0F, 0x0F, 0x0F, 0x3,
- 0x3F, 0x0F, 0x0F, 0x0F,
- 0x3, 0x3E, 0x1F, 0
-};
-
-static const uint16 num_steps_table[] = {
- 1, 2, 4, 5,
- 6, 7, 8, 9,
- 10, 12, 14, 16,
- 18, 21, 24, 30,
- 36, 50, 64, 82,
- 100, 136, 160, 192,
- 240, 276, 340, 460,
- 600, 860, 1200, 1600
-};
-
-static const byte note_to_f_num[] = {
- 90, 91, 92, 92, 93, 94, 94, 95,
- 96, 96, 97, 98, 98, 99, 100, 101,
- 101, 102, 103, 104, 104, 105, 106, 107,
- 107, 108, 109, 110, 111, 111, 112, 113,
- 114, 115, 115, 116, 117, 118, 119, 120,
- 121, 121, 122, 123, 124, 125, 126, 127,
- 128, 129, 130, 131, 132, 132, 133, 134,
- 135, 136, 137, 138, 139, 140, 141, 142,
- 143, 145, 146, 147, 148, 149, 150, 151,
- 152, 153, 154, 155, 157, 158, 159, 160,
- 161, 162, 163, 165, 166, 167, 168, 169,
- 171, 172, 173, 174, 176, 177, 178, 180,
- 181, 182, 184, 185, 186, 188, 189, 190,
- 192, 193, 194, 196, 197, 199, 200, 202,
- 203, 205, 206, 208, 209, 211, 212, 214,
- 215, 217, 218, 220, 222, 223, 225, 226,
- 228, 230, 231, 233, 235, 236, 238, 240,
- 242, 243, 245, 247, 249, 251, 252, 254
-};
-
-static const byte map_gm_to_fm[128][30] = {
- // 0x00
-{ 0xC2, 0xC5, 0x2B, 0x99, 0x58, 0xC2, 0x1F, 0x1E, 0xC8, 0x7C, 0x0A, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x23 },
-{ 0x22, 0x53, 0x0E, 0x8A, 0x30, 0x14, 0x06, 0x1D, 0x7A, 0x5C, 0x06, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0x06, 0x00, 0x1C, 0x79, 0x40, 0x02, 0x00, 0x4B, 0x79, 0x58, 0x08, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0xC2, 0x89, 0x2A, 0x89, 0x49, 0xC2, 0x16, 0x1C, 0xB8, 0x7C, 0x04, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x23 },
-{ 0xC2, 0x17, 0x3D, 0x6A, 0x00, 0xC4, 0x2E, 0x2D, 0xC9, 0x20, 0x00, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0x06, 0x1E, 0x1C, 0x99, 0x00, 0x02, 0x3A, 0x4C, 0x79, 0x00, 0x0C, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0x84, 0x40, 0x3B, 0x5A, 0x6F, 0x81, 0x0E, 0x3B, 0x5A, 0x7F, 0x0B, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0x84, 0x40, 0x3B, 0x5A, 0x63, 0x81, 0x00, 0x3B, 0x5A, 0x7F, 0x01, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0x8C, 0x80, 0x05, 0xEA, 0x59, 0x82, 0x0A, 0x3C, 0xAA, 0x64, 0x07, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0x85, 0x40, 0x0D, 0xEC, 0x71, 0x84, 0x58, 0x3E, 0xCB, 0x7C, 0x01, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0x8A, 0xC0, 0x0C, 0xDC, 0x50, 0x88, 0x58, 0x3D, 0xDA, 0x7C, 0x01, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0xC9, 0x40, 0x2B, 0x78, 0x42, 0xC2, 0x04, 0x4C, 0x8A, 0x7C, 0x00, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x1A },
-{ 0x2A, 0x0E, 0x17, 0x89, 0x28, 0x22, 0x0C, 0x1B, 0x09, 0x70, 0x0A, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0xE7, 0x9B, 0x08, 0x08, 0x26, 0xE2, 0x06, 0x0A, 0x08, 0x70, 0x0A, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0xC5, 0x05, 0x00, 0xFC, 0x40, 0x84, 0x00, 0x00, 0xDC, 0x50, 0x08, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0x86, 0x40, 0x5D, 0x5A, 0x41, 0x81, 0x00, 0x0B, 0x5A, 0x7F, 0x00, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
- // 0x10
-{ 0xED, 0x00, 0x7B, 0xC8, 0x40, 0xE1, 0x99, 0x4A, 0xE9, 0x7E, 0x07, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0xE8, 0x4F, 0x3A, 0xD7, 0x7C, 0xE2, 0x97, 0x49, 0xF9, 0x7D, 0x05, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0xE1, 0x10, 0x2F, 0xF7, 0x7D, 0xF3, 0x45, 0x8F, 0xC7, 0x62, 0x07, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0x01, 0x8C, 0x9F, 0xDA, 0x70, 0xE4, 0x50, 0x9F, 0xDA, 0x6A, 0x09, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0x08, 0xD5, 0x9D, 0xA5, 0x45, 0xE2, 0x3F, 0x9F, 0xD6, 0x49, 0x07, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0xE5, 0x0F, 0x7D, 0xB8, 0x2E, 0xA2, 0x0F, 0x7C, 0xC7, 0x61, 0x04, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0xF2, 0x2A, 0x9F, 0xDB, 0x01, 0xE1, 0x04, 0x8F, 0xD7, 0x62, 0x0A, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0xE4, 0x88, 0x9C, 0x50, 0x64, 0xE2, 0x18, 0x70, 0xC4, 0x7C, 0x0B, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0x02, 0xA3, 0x0D, 0xDA, 0x01, 0xC2, 0x35, 0x5D, 0x58, 0x00, 0x06, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x18 },
-{ 0x42, 0x55, 0x3E, 0xEB, 0x24, 0xD4, 0x08, 0x0D, 0xA9, 0x71, 0x04, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x18 },
-{ 0xC2, 0x00, 0x2B, 0x17, 0x51, 0xC2, 0x1E, 0x4D, 0x97, 0x7C, 0x00, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x19 },
-{ 0xC6, 0x01, 0x2D, 0xA7, 0x44, 0xC2, 0x06, 0x0E, 0xA7, 0x79, 0x06, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0xC2, 0x0C, 0x06, 0x06, 0x55, 0xC2, 0x3F, 0x09, 0x86, 0x7D, 0x0A, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x0A },
-{ 0xC2, 0x2E, 0x4F, 0x77, 0x00, 0xC4, 0x08, 0x0E, 0x98, 0x59, 0x0A, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0xC2, 0x30, 0x4F, 0xCA, 0x01, 0xC4, 0x0D, 0x0E, 0xB8, 0x7F, 0x08, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0xC4, 0x29, 0x4F, 0xCA, 0x03, 0xC8, 0x0D, 0x0C, 0xB7, 0x7D, 0x00, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x0B },
- // 0x20
-{ 0xC2, 0x40, 0x3C, 0x96, 0x58, 0xC4, 0xDE, 0x0E, 0xC7, 0x7C, 0x00, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x20 },
-{ 0x31, 0x13, 0x2D, 0xD7, 0x3C, 0xE2, 0x18, 0x2E, 0xB8, 0x7C, 0x08, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0x22, 0x86, 0x0D, 0xD7, 0x50, 0xE4, 0x18, 0x5E, 0xB8, 0x7C, 0x06, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x28 },
-{ 0xF2, 0x0A, 0x0D, 0xD7, 0x40, 0xE4, 0x1F, 0x5E, 0xB8, 0x7C, 0x0A, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0xF2, 0x09, 0x4B, 0xD6, 0x48, 0xE4, 0x1F, 0x1C, 0xB8, 0x7C, 0x0A, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x28 },
-{ 0x62, 0x11, 0x0C, 0xE6, 0x3C, 0xE4, 0x1F, 0x0C, 0xC8, 0x7C, 0x0A, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0xE2, 0x12, 0x3D, 0xE6, 0x34, 0xE4, 0x1F, 0x7D, 0xB8, 0x7C, 0x0A, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0xE2, 0x13, 0x3D, 0xE6, 0x34, 0xE4, 0x1F, 0x5D, 0xB8, 0x7D, 0x08, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0xA2, 0x40, 0x5D, 0xBA, 0x3F, 0xE2, 0x00, 0x8F, 0xD8, 0x79, 0x00, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0xE2, 0x40, 0x3D, 0xDA, 0x3B, 0xE1, 0x00, 0x7E, 0xD8, 0x7A, 0x04, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0x62, 0x00, 0x6D, 0xFA, 0x5D, 0xE2, 0x00, 0x8F, 0xC8, 0x79, 0x04, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0xE1, 0x00, 0x4E, 0xDB, 0x4A, 0xE3, 0x18, 0x6F, 0xE9, 0x7E, 0x00, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0xE1, 0x00, 0x4E, 0xDB, 0x66, 0xE2, 0x00, 0x7F, 0xE9, 0x7E, 0x06, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0x02, 0x0F, 0x66, 0xAA, 0x51, 0x02, 0x64, 0x29, 0xF9, 0x7C, 0x08, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x04 },
-{ 0x16, 0x4A, 0x04, 0xBA, 0x39, 0xC2, 0x58, 0x2D, 0xCA, 0x7C, 0x0A, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x03 },
-{ 0x02, 0x00, 0x01, 0x7A, 0x79, 0x02, 0x3F, 0x28, 0xEA, 0x7C, 0x08, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x02 },
- // 0x30
-{ 0x62, 0x53, 0x9C, 0xBA, 0x31, 0x62, 0x5B, 0xAD, 0xC9, 0x55, 0x04, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0xF2, 0x40, 0x6E, 0xDA, 0x49, 0xE2, 0x13, 0x8F, 0xF9, 0x7D, 0x08, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0xE2, 0x40, 0x8F, 0xFA, 0x50, 0xF2, 0x04, 0x7F, 0xFA, 0x7D, 0x0A, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0xE4, 0xA0, 0xCE, 0x5B, 0x02, 0xE2, 0x32, 0x7F, 0xFB, 0x3D, 0x04, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0xE6, 0x80, 0x9C, 0x99, 0x42, 0xE2, 0x04, 0x7D, 0x78, 0x60, 0x04, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0xEA, 0xA0, 0xAC, 0x67, 0x02, 0xE2, 0x00, 0x7C, 0x7A, 0x7C, 0x06, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0xE7, 0x94, 0xAD, 0xB7, 0x03, 0xE2, 0x00, 0x7C, 0xBA, 0x7C, 0x00, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0xC3, 0x3F, 0x4B, 0xE9, 0x7E, 0xC1, 0x3F, 0x9B, 0xF9, 0x7F, 0x0B, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x06 },
-{ 0xB2, 0x20, 0xAD, 0xE9, 0x00, 0x62, 0x05, 0x8F, 0xC8, 0x68, 0x0E, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0xF2, 0x00, 0x8F, 0xFB, 0x50, 0xF6, 0x47, 0x8F, 0xE9, 0x68, 0x08, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0xF2, 0x00, 0xAF, 0x88, 0x58, 0xF2, 0x54, 0x6E, 0xC9, 0x7C, 0x0A, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0xF2, 0x2A, 0x9F, 0x98, 0x01, 0xE2, 0x84, 0x4E, 0x78, 0x6C, 0x0E, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0xE2, 0x02, 0x9F, 0xB8, 0x48, 0x22, 0x89, 0x9F, 0xE8, 0x7C, 0x00, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0xE2, 0x2A, 0x7F, 0xB8, 0x01, 0xE4, 0x00, 0x0D, 0xC5, 0x7C, 0x0C, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0xE4, 0x28, 0x8E, 0xE8, 0x01, 0xF2, 0x00, 0x4D, 0xD6, 0x7D, 0x0C, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0x62, 0x23, 0x8F, 0xEA, 0x00, 0xF2, 0x00, 0x5E, 0xD9, 0x7C, 0x0C, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
- // 0x40
-{ 0xB4, 0x26, 0x6E, 0x98, 0x01, 0x62, 0x00, 0x7D, 0xC8, 0x7D, 0x00, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0xE2, 0x2E, 0x20, 0xD9, 0x01, 0xF2, 0x0F, 0x90, 0xF8, 0x78, 0x0E, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0xE4, 0x28, 0x7E, 0xF8, 0x01, 0xE2, 0x23, 0x8E, 0xE8, 0x7D, 0x08, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0xB8, 0x28, 0x9E, 0x98, 0x01, 0x62, 0x00, 0x3D, 0xC8, 0x7D, 0x08, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0x62, 0x00, 0x8E, 0xC9, 0x3D, 0xE6, 0x00, 0x7E, 0xD8, 0x68, 0x0A, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0xE2, 0x00, 0x5F, 0xF9, 0x48, 0xE6, 0x98, 0x8F, 0xF8, 0x7D, 0x08, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0x62, 0x0C, 0x6E, 0xD8, 0x3D, 0x2A, 0x06, 0x7D, 0xD8, 0x58, 0x04, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0xE4, 0x00, 0x7E, 0x89, 0x38, 0xE6, 0x84, 0x80, 0xF8, 0x68, 0x0C, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0xE4, 0x80, 0x6C, 0xD9, 0x30, 0xE2, 0x00, 0x8D, 0xC8, 0x7C, 0x00, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0xE2, 0x80, 0x88, 0x48, 0x40, 0xE2, 0x0A, 0x7D, 0xA8, 0x7C, 0x08, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0xE4, 0x00, 0x77, 0xC5, 0x54, 0xE2, 0x00, 0x9E, 0xD7, 0x70, 0x06, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0xE4, 0x80, 0x86, 0xB9, 0x64, 0xE2, 0x05, 0x9F, 0xD7, 0x78, 0x0A, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0xE2, 0x00, 0x68, 0x68, 0x56, 0xE2, 0x08, 0x9B, 0xB3, 0x7C, 0x08, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0xE4, 0x00, 0xA6, 0x87, 0x41, 0xE2, 0x0A, 0x7E, 0xC9, 0x7C, 0x06, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0xE4, 0x80, 0x9A, 0xB8, 0x48, 0xE2, 0x00, 0x9E, 0xF9, 0x60, 0x09, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0xE2, 0x80, 0x8E, 0x64, 0x68, 0xE2, 0x28, 0x6F, 0x73, 0x7C, 0x01, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
- // 0x50
-{ 0xE8, 0x00, 0x7D, 0x99, 0x54, 0xE6, 0x80, 0x80, 0xF8, 0x7C, 0x0C, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0xE6, 0x00, 0x9F, 0xB9, 0x6D, 0xE1, 0x00, 0x8F, 0xC8, 0x7D, 0x02, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0xE4, 0x00, 0x09, 0x68, 0x4A, 0xE2, 0x2B, 0x9E, 0xF3, 0x7C, 0x0E, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0xC4, 0x00, 0x99, 0xE8, 0x3B, 0xE2, 0x25, 0x6F, 0x93, 0x7C, 0x0E, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0xE6, 0x00, 0x6F, 0xDA, 0x69, 0xE2, 0x05, 0x2F, 0xD8, 0x6A, 0x08, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0xEC, 0x60, 0x9D, 0xC7, 0x00, 0xE2, 0x21, 0x7F, 0xC9, 0x7C, 0x06, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0xE3, 0x00, 0x0F, 0xF7, 0x7D, 0xE1, 0x3F, 0x0F, 0xA7, 0x01, 0x0D, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0xE4, 0xA9, 0x0F, 0xA8, 0x02, 0xE2, 0x3C, 0x5F, 0xDA, 0x3C, 0x0E, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0xE8, 0x40, 0x0D, 0x89, 0x7D, 0xE2, 0x17, 0x7E, 0xD9, 0x7C, 0x07, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0xE1, 0x00, 0xDF, 0x8A, 0x56, 0xE2, 0x5E, 0xCF, 0xBA, 0x7E, 0x08, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0xE2, 0x00, 0x0B, 0x68, 0x60, 0xE2, 0x01, 0x9E, 0xB8, 0x7C, 0x0A, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0xEA, 0x00, 0xAE, 0xAB, 0x49, 0xE2, 0x00, 0xAE, 0xBA, 0x6C, 0x08, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0xEB, 0x80, 0x8C, 0xCB, 0x3A, 0xE2, 0x86, 0xAF, 0xCA, 0x7C, 0x08, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0xE5, 0x40, 0xDB, 0x3B, 0x3C, 0xE2, 0x80, 0xBE, 0xCA, 0x71, 0x00, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0xE4, 0x00, 0x9E, 0xAA, 0x3D, 0xE1, 0x43, 0x0F, 0xBA, 0x7E, 0x04, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0xE7, 0x40, 0xEC, 0xCA, 0x44, 0xE2, 0x03, 0xBF, 0xBA, 0x66, 0x02, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
- // 0x60
-{ 0xEA, 0x00, 0x68, 0xB8, 0x48, 0xE2, 0x0A, 0x8E, 0xB8, 0x7C, 0x0C, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0x61, 0x00, 0xBE, 0x99, 0x7E, 0xE3, 0x40, 0xCF, 0xCA, 0x7D, 0x09, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0xCD, 0x00, 0x0B, 0x00, 0x48, 0xC2, 0x58, 0x0C, 0x00, 0x7C, 0x0C, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x1C },
-{ 0xE2, 0x00, 0x0E, 0x00, 0x52, 0xE2, 0x58, 0x5F, 0xD0, 0x7D, 0x08, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0xCC, 0x00, 0x7D, 0xDA, 0x40, 0xC2, 0x00, 0x5E, 0x9B, 0x58, 0x0C, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0xE9, 0xC0, 0xEE, 0xD8, 0x43, 0xE2, 0x05, 0xDD, 0xAA, 0x70, 0x06, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0xDA, 0x00, 0x8F, 0xAC, 0x4A, 0x22, 0x05, 0x8D, 0x8A, 0x75, 0x02, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0x62, 0x8A, 0xCB, 0x7A, 0x74, 0xE6, 0x56, 0xAF, 0xDB, 0x70, 0x02, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0xC2, 0x41, 0xAC, 0x5B, 0x5B, 0xC2, 0x80, 0x0D, 0xCB, 0x7D, 0x0A, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x12 },
-{ 0x75, 0x00, 0x0E, 0xCB, 0x5A, 0xE2, 0x1E, 0x0A, 0xC9, 0x7D, 0x0A, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x10 },
-{ 0x41, 0x00, 0x0E, 0xEA, 0x53, 0xC2, 0x00, 0x08, 0xCA, 0x7C, 0x08, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x07 },
-{ 0xC1, 0x40, 0x0C, 0x59, 0x6A, 0xC2, 0x80, 0x3C, 0xAB, 0x7C, 0x08, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x0D },
-{ 0x4B, 0x00, 0x0A, 0xF5, 0x61, 0xC2, 0x19, 0x0C, 0xE9, 0x7C, 0x08, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x07 },
-{ 0x62, 0x00, 0x7F, 0xD8, 0x54, 0xEA, 0x00, 0x8F, 0xD8, 0x7D, 0x0A, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0xE1, 0x00, 0x7F, 0xD9, 0x56, 0xE1, 0x00, 0x8F, 0xD8, 0x7E, 0x06, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0xE1, 0x00, 0x7F, 0xD9, 0x56, 0xE1, 0x00, 0x8F, 0xD8, 0x7E, 0x06, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
- // 0x70
-{ 0xCF, 0x40, 0x09, 0xEA, 0x54, 0xC4, 0x00, 0x0C, 0xDB, 0x64, 0x08, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x02 },
-{ 0xCF, 0x40, 0x0C, 0xAA, 0x54, 0xC4, 0x00, 0x18, 0xF9, 0x64, 0x0C, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x02 },
-{ 0xC9, 0x0E, 0x88, 0xD9, 0x3E, 0xC2, 0x08, 0x1A, 0xEA, 0x6C, 0x0C, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x05 },
-{ 0x03, 0x00, 0x15, 0x00, 0x64, 0x02, 0x00, 0x08, 0x00, 0x7C, 0x09, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x02 },
-{ 0x01, 0x00, 0x47, 0xD7, 0x6C, 0x01, 0x3F, 0x0C, 0xFB, 0x7C, 0x0A, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x04 },
-{ 0x00, 0x00, 0x36, 0x67, 0x7C, 0x01, 0x3F, 0x0E, 0xFA, 0x7C, 0x00, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x05 },
-{ 0x02, 0x00, 0x36, 0x68, 0x7C, 0x01, 0x3F, 0x0E, 0xFA, 0x7C, 0x00, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x05 },
-{ 0xCB, 0x00, 0xAF, 0x00, 0x7E, 0xC0, 0x00, 0xC0, 0x06, 0x7F, 0x0E, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x0F },
-{ 0x05, 0x0D, 0x80, 0xA6, 0x7F, 0x0B, 0x38, 0xA9, 0xD8, 0x00, 0x0E, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x04 },
-{ 0x0F, 0x00, 0x90, 0xFA, 0x68, 0x06, 0x00, 0xA7, 0x39, 0x54, 0x0E, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x06 },
-{ 0xC9, 0x15, 0xDD, 0xFF, 0x7C, 0x00, 0x00, 0xE7, 0xFC, 0x6C, 0x0E, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x38 },
-{ 0x48, 0x3C, 0x30, 0xF6, 0x03, 0x0A, 0x38, 0x97, 0xE8, 0x00, 0x0E, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x04 },
-{ 0x07, 0x80, 0x0B, 0xC8, 0x65, 0x02, 0x3F, 0x0C, 0xEA, 0x7C, 0x0F, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x05 },
-{ 0x00, 0x21, 0x66, 0x40, 0x03, 0x00, 0x3F, 0x47, 0x00, 0x00, 0x0E, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x02 },
-{ 0x08, 0x00, 0x0B, 0x3C, 0x7C, 0x08, 0x3F, 0x06, 0xF3, 0x00, 0x0E, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x02 },
-{ 0x00, 0x3F, 0x4C, 0xFB, 0x00, 0x00, 0x3F, 0x0A, 0xE9, 0x7C, 0x0E, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x05 }
-};
-
-static byte gm_percussion_to_fm[39][30] = {
-{ 0x1A, 0x3F, 0x15, 0x05, 0x7C, 0x02, 0x21, 0x2B, 0xE4, 0x7C, 0x0E, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x06 },
-{ 0x11, 0x12, 0x04, 0x07, 0x7C, 0x02, 0x23, 0x0B, 0xE5, 0x7C, 0x0E, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x05 },
-{ 0x0A, 0x3F, 0x0B, 0x01, 0x7C, 0x1F, 0x1C, 0x46, 0xD0, 0x7C, 0x0E, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x01 },
-{ 0x00, 0x3F, 0x0F, 0x00, 0x7C, 0x10, 0x12, 0x07, 0x00, 0x7C, 0x0E, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x02 },
-{ 0x0F, 0x3F, 0x0B, 0x00, 0x7C, 0x1F, 0x0F, 0x19, 0xD0, 0x7C, 0x0E, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x02 },
-{ 0x00, 0x3F, 0x1F, 0x00, 0x7E, 0x1F, 0x16, 0x07, 0x00, 0x7C, 0x0E, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x03 },
-{ 0x12, 0x3F, 0x05, 0x06, 0x7C, 0x03, 0x1F, 0x4A, 0xD9, 0x7C, 0x0E, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x03 },
-{ 0xCF, 0x7F, 0x08, 0xFF, 0x7E, 0x00, 0xC7, 0x2D, 0xF7, 0x73, 0x0E, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x02 },
-{ 0x12, 0x3F, 0x05, 0x06, 0x7C, 0x43, 0x21, 0x0C, 0xE9, 0x7C, 0x0E, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x03 },
-{ 0xCF, 0x7F, 0x08, 0xCF, 0x7E, 0x00, 0x45, 0x2A, 0xF8, 0x4B, 0x0E, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x0C },
-{ 0x12, 0x3F, 0x06, 0x17, 0x7C, 0x03, 0x27, 0x0B, 0xE9, 0x7C, 0x0E, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x03 },
-{ 0xCF, 0x7F, 0x08, 0xCD, 0x7E, 0x00, 0x40, 0x1A, 0x69, 0x63, 0x0E, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x0C },
-{ 0x13, 0x3F, 0x05, 0x06, 0x7C, 0x03, 0x17, 0x0A, 0xD9, 0x7C, 0x0E, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x03 },
-{ 0x15, 0x3F, 0x05, 0x06, 0x7C, 0x03, 0x21, 0x0C, 0xE9, 0x7C, 0x0E, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x03 },
-{ 0xCF, 0x3F, 0x2B, 0xFB, 0x7E, 0xC0, 0x1E, 0x1A, 0xCA, 0x7F, 0x0E, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x10 },
-{ 0x17, 0x3F, 0x04, 0x09, 0x7C, 0x03, 0x22, 0x0D, 0xE9, 0x7C, 0x0E, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x03 },
-{ 0xCF, 0x3F, 0x0F, 0x5E, 0x7C, 0xC6, 0x13, 0x00, 0xCA, 0x7F, 0x04, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x03 },
-{ 0xCF, 0x3F, 0x7E, 0x9D, 0x7C, 0xC8, 0xC0, 0x0A, 0xBA, 0x74, 0x0E, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x06 },
-{ 0xCF, 0x3F, 0x4D, 0x9F, 0x7C, 0xC6, 0x00, 0x08, 0xDA, 0x5B, 0x04, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x04 },
-{ 0xCF, 0x3F, 0x5D, 0xAA, 0x7A, 0xC0, 0xA4, 0x67, 0x99, 0x7C, 0x0A, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x02 },
-{ 0xCF, 0x3F, 0x4A, 0xFD, 0x7C, 0xCF, 0x00, 0x59, 0xEA, 0x7C, 0x0E, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x02 },
-{ 0x0F, 0x18, 0x0A, 0xFA, 0x57, 0x06, 0x07, 0x06, 0x39, 0x7C, 0x0A, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x02 },
-{ 0xCF, 0x3F, 0x2B, 0xFC, 0x7C, 0xCC, 0xC6, 0x0B, 0xEA, 0x7F, 0x0E, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x10 },
-{ 0x05, 0x1A, 0x04, 0x00, 0x7C, 0x12, 0x10, 0x0C, 0xEA, 0x7C, 0x0E, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x07 },
-{ 0x04, 0x19, 0x04, 0x00, 0x7C, 0x12, 0x10, 0x2C, 0xEA, 0x7C, 0x0E, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x04 },
-{ 0x04, 0x0A, 0x04, 0x00, 0x6C, 0x01, 0x07, 0x0D, 0xFA, 0x74, 0x0E, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x07 },
-{ 0x15, 0x14, 0x05, 0x00, 0x7D, 0x01, 0x07, 0x5C, 0xE9, 0x7C, 0x0E, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x05 },
-{ 0x10, 0x10, 0x05, 0x08, 0x7C, 0x01, 0x08, 0x0D, 0xEA, 0x7C, 0x0E, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x05 },
-{ 0x11, 0x00, 0x06, 0x87, 0x7F, 0x02, 0x40, 0x09, 0x59, 0x68, 0x0E, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x08 },
-{ 0x13, 0x26, 0x04, 0x6A, 0x7F, 0x01, 0x00, 0x08, 0x5A, 0x7C, 0x0E, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x08 },
-{ 0xCF, 0x4E, 0x0C, 0xAA, 0x50, 0xC4, 0x00, 0x18, 0xF9, 0x54, 0x04, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x02 },
-{ 0xCF, 0x4E, 0x0C, 0xAA, 0x50, 0xC3, 0x00, 0x18, 0xF8, 0x54, 0x04, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x02 },
-{ 0xCB, 0x3F, 0x8F, 0x00, 0x7E, 0xC5, 0x00, 0x98, 0xD6, 0x5F, 0x0E, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x0D },
-{ 0x0C, 0x18, 0x87, 0xB3, 0x7F, 0x19, 0x10, 0x55, 0x75, 0x7C, 0x0E, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x02 },
-{ 0x05, 0x11, 0x15, 0x00, 0x64, 0x02, 0x08, 0x08, 0x00, 0x5C, 0x09, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x02 },
-{ 0x04, 0x08, 0x15, 0x00, 0x48, 0x01, 0x08, 0x08, 0x00, 0x60, 0x08, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x02 },
-{ 0xDA, 0x00, 0x53, 0x30, 0x68, 0x07, 0x1E, 0x49, 0xC4, 0x7E, 0x03, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 },
-{ 0x1C, 0x00, 0x07, 0xBC, 0x6C, 0x0C, 0x14, 0x0B, 0x6A, 0x7E, 0x0B, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x03 },
-{ 0x0A, 0x0E, 0x7F, 0x00, 0x7D, 0x13, 0x20, 0x28, 0x03, 0x7C, 0x06, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0x00 }
-};
-
-static const byte gm_percussion_lookup[128] = {
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xFF, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C,
- 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0xFF, 0xFF, 0x17, 0x18, 0x19, 0x1A,
- 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x21, 0x22, 0x23, 0xFF, 0xFF,
- 0x24, 0x25, 0xFF, 0xFF, 0xFF, 0x26, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
-};
-
-static byte lookup_table[64][32];
-
-static const byte volume_table[] = {
- 0, 4, 7, 11,
- 13, 16, 18, 20,
- 22, 24, 26, 27,
- 29, 30, 31, 33,
- 34, 35, 36, 37,
- 38, 39, 40, 41,
- 42, 43, 44, 44,
- 45, 46, 47, 47,
- 48, 49, 49, 50,
- 51, 51, 52, 53,
- 53, 54, 54, 55,
- 55, 56, 56, 57,
- 57, 58, 58, 59,
- 59, 60, 60, 60,
- 61, 61, 62, 62,
- 62, 63, 63, 63
-};
-
-static int lookup_volume(int a, int b) {
- if (b == 0)
- return 0;
-
- if (b == 31)
- return a;
-
- if (a < -63 || a > 63) {
- return b * (a + 1) >> 5;
- }
-
- if (b < 0) {
- if (a < 0) {
- return lookup_table[-a][-b];
- } else {
- return -lookup_table[a][-b];
- }
- } else {
- if (a < 0) {
- return -lookup_table[-a][b];
- } else {
- return lookup_table[a][b];
- }
- }
-}
-
-static void create_lookup_table() {
- int i, j;
- int sum;
-
- for (i = 0; i < 64; i++) {
- sum = i;
- for (j = 0; j < 32; j++) {
- lookup_table[i][j] = sum >> 5;
- sum += i;
- }
- }
- for (i = 0; i < 64; i++)
- lookup_table[i][0] = 0;
-}
-
-////////////////////////////////////////
-//
-// AdLib MIDI driver
-//
-////////////////////////////////////////
-
-class MidiDriver_ADLIB : public MidiDriver_Emulated {
- friend class AdLibPart;
- friend class AdLibPercussionChannel;
-
-public:
- MidiDriver_ADLIB(Audio::Mixer *mixer);
-
- int open();
- void close();
- void send(uint32 b);
- void send(byte channel, uint32 b); // Supports higher than channel 15
- uint32 property(int prop, uint32 param);
-
- void setPitchBendRange(byte channel, uint range);
- void sysEx_customInstrument(byte channel, uint32 type, const byte *instr);
-
- MidiChannel *allocateChannel();
- MidiChannel *getPercussionChannel() { return &_percussion; } // Percussion partially supported
-
-
- // AudioStream API
- bool isStereo() const { return false; }
- int getRate() const { return _mixer->getOutputRate(); }
-
-private:
- bool _scummSmallHeader; // FIXME: This flag controls a special mode for SCUMM V3 games
-
- FM_OPL *_opl;
- byte *_adlib_reg_cache;
-
- int _adlib_timer_counter;
-
- uint16 channel_table_2[9];
- int _voice_index;
- int _timer_p;
- int _timer_q;
- uint16 curnote_table[9];
- AdLibVoice _voices[9];
- AdLibPart _parts[32];
- AdLibPercussionChannel _percussion;
-
- void generateSamples(int16 *buf, int len);
- void onTimer();
- void part_key_on(AdLibPart *part, AdLibInstrument *instr, byte note, byte velocity);
- void part_key_off(AdLibPart *part, byte note);
-
- void adlib_key_off(int chan);
- void adlib_note_on(int chan, byte note, int mod);
- void adlib_note_on_ex(int chan, byte note, int mod);
- int adlib_get_reg_value_param(int chan, byte data);
- void adlib_setup_channel(int chan, AdLibInstrument * instr, byte vol_1, byte vol_2);
- byte adlib_get_reg_value(byte reg) {
- return _adlib_reg_cache[reg];
- }
- void adlib_set_param(int channel, byte param, int value);
- void adlib_key_onoff(int channel);
- void adlib_write(byte reg, byte value);
- void adlib_playnote(int channel, int note);
-
- AdLibVoice *allocate_voice(byte pri);
-
- void mc_off(AdLibVoice * voice);
-
- static void link_mc(AdLibPart *part, AdLibVoice *voice);
- void mc_inc_stuff(AdLibVoice *voice, Struct10 * s10, Struct11 * s11);
- void mc_init_stuff(AdLibVoice *voice, Struct10 * s10, Struct11 * s11, byte flags,
- InstrumentExtra * ie);
-
- void struct10_init(Struct10 * s10, InstrumentExtra * ie);
- static byte struct10_ontimer(Struct10 * s10, Struct11 * s11);
- static void struct10_setup(Struct10 * s10);
- static int random_nr(int a);
- void mc_key_on(AdLibVoice *voice, AdLibInstrument *instr, byte note, byte velocity);
-};
-
-// MidiChannel method implementations
-
-void AdLibPart::init(MidiDriver_ADLIB *owner, byte channel) {
- _owner = owner;
- _channel = channel;
- _pri_eff = 127;
- programChange(0);
-}
-
-MidiDriver *AdLibPart::device() {
- return _owner;
-}
-
-void AdLibPart::send(uint32 b) {
- _owner->send(_channel, b);
-}
-
-void AdLibPart::noteOff(byte note) {
-#ifdef DEBUG_ADLIB
- debug(6, "%10d: noteOff(%d)", tick, note);
-#endif
- _owner->part_key_off(this, note);
-}
-
-void AdLibPart::noteOn(byte note, byte velocity) {
-#ifdef DEBUG_ADLIB
- debug(6, "%10d: noteOn(%d,%d)", tick, note, velocity);
-#endif
- _owner->part_key_on(this, &_part_instr, note, velocity);
-}
-
-void AdLibPart::programChange(byte program) {
- if (program > 127)
- return;
-
- uint i;
- uint count = 0;
- for (i = 0; i < ARRAYSIZE(map_gm_to_fm[0]); ++i)
- count += map_gm_to_fm[program][i];
- if (!count)
- warning("No AdLib instrument defined for GM program %d", (int) program);
- _program = program;
- memcpy(&_part_instr, &map_gm_to_fm[program], sizeof(AdLibInstrument));
-}
-
-void AdLibPart::pitchBend(int16 bend) {
- AdLibVoice *voice;
-
- _pitchbend = bend;
- for (voice = _voice; voice; voice = voice->_next) {
- _owner->adlib_note_on(voice->_channel, voice->_note + _transpose_eff,
- (_pitchbend * _pitchbend_factor >> 6) + _detune_eff);
- }
-}
-
-void AdLibPart::controlChange(byte control, byte value) {
- switch (control) {
- case 0:
- case 32:
- break; // Bank select. Not supported
- case 1: modulationWheel(value); break;
- case 7: volume(value); break;
- case 10: break; // Pan position. Not supported.
- case 16: pitchBendFactor(value); break;
- case 17: detune(value); break;
- case 18: priority(value); break;
- case 64: sustain(value > 0); break;
- case 91: break; // Effects level. Not supported.
- case 93: break; // Chorus level. Not supported.
- case 119: break; // Unknown, used in Simon the Sorcerer 2
- case 121: // reset all controllers
- modulationWheel(0);
- pitchBendFactor(0);
- detune(0);
- sustain(0);
- break;
- case 123: allNotesOff(); break;
- default:
- warning("AdLib: Unknown control change message %d (%d)", (int) control, (int)value);
- }
-}
-
-void AdLibPart::modulationWheel(byte value) {
- AdLibVoice *voice;
-
- _modwheel = value;
- for (voice = _voice; voice; voice = voice->_next) {
- if (voice->_s10a.active && voice->_s11a.flag0x40)
- voice->_s10a.modwheel = _modwheel >> 2;
- if (voice->_s10b.active && voice->_s11b.flag0x40)
- voice->_s10b.modwheel = _modwheel >> 2;
- }
-}
-
-void AdLibPart::volume(byte value) {
- AdLibVoice *voice;
-
- _vol_eff = value;
- for (voice = _voice; voice; voice = voice->_next) {
- _owner->adlib_set_param(voice->_channel, 0, volume_table[lookup_table[voice->_vol_2][_vol_eff >> 2]]);
- if (voice->_twochan) {
- _owner->adlib_set_param(voice->_channel, 13, volume_table[lookup_table[voice->_vol_1][_vol_eff >> 2]]);
- }
- }
-}
-
-void AdLibPart::pitchBendFactor(byte value) {
- AdLibVoice *voice;
-
- _pitchbend_factor = value;
- for (voice = _voice; voice; voice = voice->_next) {
- _owner->adlib_note_on(voice->_channel, voice->_note + _transpose_eff,
- (_pitchbend * _pitchbend_factor >> 6) + _detune_eff);
- }
-}
-
-void AdLibPart::detune(byte value) {
- AdLibVoice *voice;
-
- _detune_eff = value;
- for (voice = _voice; voice; voice = voice->_next) {
- _owner->adlib_note_on(voice->_channel, voice->_note + _transpose_eff,
- (_pitchbend * _pitchbend_factor >> 6) + _detune_eff);
- }
-}
-
-void AdLibPart::priority(byte value) {
- _pri_eff = value;
-}
-
-void AdLibPart::sustain(bool value) {
- AdLibVoice *voice;
-
- _pedal = value;
- if (!value) {
- for (voice = _voice; voice; voice = voice->_next) {
- if (voice->_waitforpedal)
- _owner->mc_off(voice);
- }
- }
-}
-
-void AdLibPart::allNotesOff() {
- while (_voice)
- _owner->mc_off(_voice);
-}
-
-void AdLibPart::sysEx_customInstrument(uint32 type, const byte *instr) {
- if (type == 'ADL ') {
- AdLibInstrument *i = &_part_instr;
- memcpy(i, instr, sizeof(AdLibInstrument));
- }
-}
-
-// MidiChannel method implementations for percussion
-
-AdLibPercussionChannel::~AdLibPercussionChannel() {
- for (int i = 0; i < ARRAYSIZE(_customInstruments); ++i) {
- delete _customInstruments[i];
- }
-}
-
-void AdLibPercussionChannel::init(MidiDriver_ADLIB *owner, byte channel) {
- AdLibPart::init(owner, channel);
- _pri_eff = 0;
- _vol_eff = 127;
-
- // Initialize the custom instruments data
- memset(_notes, 0, sizeof(_notes));
- memset(_customInstruments, 0, sizeof(_customInstruments));
-}
-
-void AdLibPercussionChannel::noteOff(byte note) {
- // Jamieson630: Unless I run into a specific instrument that
- // may require a key off, I'm going to ignore this message.
- // The rationale is that a percussion instrument should
- // fade out of its own accord, and the AdLib instrument
- // definitions used should follow this rule. Since
- // percussion voices are allocated at the lowest priority
- // anyway, we know that "hanging" percussion sounds will
- // not prevent later musical instruments (or even other
- // percussion sounds) from playing.
-/*
- _owner->part_key_off(this, note);
-*/
-}
-
-void AdLibPercussionChannel::noteOn(byte note, byte velocity) {
- AdLibInstrument *inst = NULL;
-
- // The custom instruments have priority over the default mapping
- inst = _customInstruments[note];
- if (inst)
- note = _notes[note];
-
- if (!inst) {
- // Use the default GM to FM mapping as a fallback as a fallback
- byte key = gm_percussion_lookup[note];
- if (key != 0xFF)
- inst = (AdLibInstrument *)&gm_percussion_to_fm[key];
- }
-
- if (!inst) {
- debug(2, "No instrument FM definition for GM percussion key %d", (int)note);
- return;
- }
-
- _owner->part_key_on(this, inst, note, velocity);
-}
-
-void AdLibPercussionChannel::sysEx_customInstrument(uint32 type, const byte *instr) {
- if (type == 'ADLP') {
- byte note = instr[0];
- _notes[note] = instr[1];
-
- // Allocate memory for the new instruments
- if (!_customInstruments[note]) {
- _customInstruments[note] = new AdLibInstrument;
- }
-
- // Save the new instrument data
- _customInstruments[note]->mod_characteristic = instr[2];
- _customInstruments[note]->mod_scalingOutputLevel = instr[3];
- _customInstruments[note]->mod_attackDecay = instr[4];
- _customInstruments[note]->mod_sustainRelease = instr[5];
- _customInstruments[note]->mod_waveformSelect = instr[6];
- _customInstruments[note]->car_characteristic = instr[7];
- _customInstruments[note]->car_scalingOutputLevel = instr[8];
- _customInstruments[note]->car_attackDecay = instr[9];
- _customInstruments[note]->car_sustainRelease = instr[10];
- _customInstruments[note]->car_waveformSelect = instr[11];
- _customInstruments[note]->feedback = instr[12];
- }
-}
-
-// MidiDriver method implementations
-
-MidiDriver_ADLIB::MidiDriver_ADLIB(Audio::Mixer *mixer)
- : MidiDriver_Emulated(mixer) {
- uint i;
-
- _scummSmallHeader = false;
-
- _adlib_reg_cache = 0;
-
- _adlib_timer_counter = 0;
- _voice_index = 0;
- for (i = 0; i < ARRAYSIZE(curnote_table); ++i) {
- curnote_table[i] = 0;
- }
-
- for (i = 0; i < ARRAYSIZE(_parts); ++i) {
- _parts[i].init(this, i + ((i >= 9) ? 1 : 0));
- }
- _percussion.init(this, 9);
- _timer_p = 0xD69;
- _timer_q = 0x411B;
-}
-
-int MidiDriver_ADLIB::open() {
- if (_isOpen)
- return MERR_ALREADY_OPEN;
-
- MidiDriver_Emulated::open();
-
- int i;
- AdLibVoice *voice;
-
- for (i = 0, voice = _voices; i != ARRAYSIZE(_voices); i++, voice++) {
- voice->_channel = i;
- voice->_s11a.s10 = &voice->_s10b;
- voice->_s11b.s10 = &voice->_s10a;
- }
-
- _adlib_reg_cache = (byte *)calloc(256, 1);
-
- _opl = makeAdLibOPL(getRate());
-
- adlib_write(1, 0x20);
- adlib_write(8, 0x40);
- adlib_write(0xBD, 0x00);
- create_lookup_table();
-
- _mixer->playStream(Audio::Mixer::kPlainSoundType, &_mixerSoundHandle, this, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO, true);
-
- return 0;
-}
-
-void MidiDriver_ADLIB::close() {
- if (!_isOpen)
- return;
- _isOpen = false;
-
- _mixer->stopHandle(_mixerSoundHandle);
-
- uint i;
- for (i = 0; i < ARRAYSIZE(_voices); ++i) {
- if (_voices[i]._part)
- mc_off(&_voices[i]);
- }
-
- // Turn off the OPL emulation
- OPLDestroy(_opl);
-// YM3812Shutdown();
-
- free(_adlib_reg_cache);
-}
-
-void MidiDriver_ADLIB::send(uint32 b) {
- send(b & 0xF, b & 0xFFFFFFF0);
-}
-
-void MidiDriver_ADLIB::send(byte chan, uint32 b) {
- //byte param3 = (byte) ((b >> 24) & 0xFF);
- byte param2 = (byte) ((b >> 16) & 0xFF);
- byte param1 = (byte) ((b >> 8) & 0xFF);
- byte cmd = (byte) (b & 0xF0);
-
- AdLibPart *part;
- if (chan == 9)
- part = &_percussion;
- else
- part = &_parts[chan];
-
- switch (cmd) {
- case 0x80:// Note Off
- part->noteOff(param1);
- break;
- case 0x90: // Note On
- part->noteOn(param1, param2);
- break;
- case 0xA0: // Aftertouch
- break; // Not supported.
- case 0xB0: // Control Change
- part->controlChange(param1, param2);
- break;
- case 0xC0: // Program Change
- part->programChange(param1);
- break;
- case 0xD0: // Channel Pressure
- break; // Not supported.
- case 0xE0: // Pitch Bend
- part->pitchBend((param1 | (param2 << 7)) - 0x2000);
- break;
- case 0xF0: // SysEx
- // We should never get here! SysEx information has to be
- // sent via high-level semantic methods.
- warning("MidiDriver_ADLIB: Receiving SysEx command on a send() call");
- break;
-
- default:
- warning("MidiDriver_ADLIB: Unknown send() command 0x%02X", cmd);
- }
-}
-
-uint32 MidiDriver_ADLIB::property(int prop, uint32 param) {
- switch (prop) {
- case PROP_OLD_ADLIB: // Older games used a different operator volume algorithm
- _scummSmallHeader = (param > 0);
- if (_scummSmallHeader) {
- _timer_p = 473;
- _timer_q = 1000;
- } else {
- _timer_p = 0xD69;
- _timer_q = 0x411B;
- }
- return 1;
- }
-
- return 0;
-}
-
-void MidiDriver_ADLIB::setPitchBendRange(byte channel, uint range) {
- AdLibVoice *voice;
- AdLibPart *part = &_parts[channel];
-
- part->_pitchbend_factor = range;
- for (voice = part->_voice; voice; voice = voice->_next) {
- adlib_note_on(voice->_channel, voice->_note + part->_transpose_eff,
- (part->_pitchbend * part->_pitchbend_factor >> 6) + part->_detune_eff);
- }
-}
-
-void MidiDriver_ADLIB::sysEx_customInstrument(byte channel, uint32 type, const byte *instr) {
- _parts[channel].sysEx_customInstrument(type, instr);
-}
-
-MidiChannel *MidiDriver_ADLIB::allocateChannel() {
- AdLibPart *part;
- uint i;
-
- for (i = 0; i < ARRAYSIZE(_parts); ++i) {
- part = &_parts[i];
- if (!part->_allocated) {
- part->allocate();
- return part;
- }
- }
- return NULL;
-}
-
-// All the code brought over from IMuseAdLib
-
-void MidiDriver_ADLIB::adlib_write(byte reg, byte value) {
- if (_adlib_reg_cache[reg] == value)
- return;
-#ifdef DEBUG_ADLIB
- debug(6, "%10d: adlib_write[%x] = %x", tick, reg, value);
-#endif
- _adlib_reg_cache[reg] = value;
-
- OPLWriteReg(_opl, reg, value);
-}
-
-void MidiDriver_ADLIB::generateSamples(int16 *data, int len) {
- memset(data, 0, sizeof(int16) * len);
- YM3812UpdateOne(_opl, data, len);
-}
-
-void MidiDriver_ADLIB::onTimer() {
- AdLibVoice *voice;
- int i;
-
- _adlib_timer_counter += _timer_p;
- while (_adlib_timer_counter >= _timer_q) {
- _adlib_timer_counter -= _timer_q;
-#ifdef DEBUG_ADLIB
- tick++;
-#endif
- voice = _voices;
- for (i = 0; i != ARRAYSIZE(_voices); i++, voice++) {
- if (!voice->_part)
- continue;
- if (voice->_duration && (voice->_duration -= 0x11) <= 0) {
- mc_off(voice);
- return;
- }
- if (voice->_s10a.active) {
- mc_inc_stuff(voice, &voice->_s10a, &voice->_s11a);
- }
- if (voice->_s10b.active) {
- mc_inc_stuff(voice, &voice->_s10b, &voice->_s11b);
- }
- }
- }
-}
-
-void MidiDriver_ADLIB::mc_off(AdLibVoice *voice) {
- AdLibVoice *tmp;
-
- adlib_key_off(voice->_channel);
-
- tmp = voice->_prev;
-
- if (voice->_next)
- voice->_next->_prev = tmp;
- if (tmp)
- tmp->_next = voice->_next;
- else
- voice->_part->_voice = voice->_next;
- voice->_part = NULL;
-}
-
-void MidiDriver_ADLIB::mc_inc_stuff(AdLibVoice *voice, Struct10 *s10, Struct11 *s11) {
- byte code;
- AdLibPart *part = voice->_part;
-
- code = struct10_ontimer(s10, s11);
-
- if (code & 1) {
- switch (s11->param) {
- case 0:
- voice->_vol_2 = s10->start_value + s11->modify_val;
- if (!_scummSmallHeader) {
- adlib_set_param(voice->_channel, 0,
- volume_table[lookup_table[voice->_vol_2]
- [part->_vol_eff >> 2]]);
- } else {
- adlib_set_param(voice->_channel, 0, voice->_vol_2);
- }
- break;
- case 13:
- voice->_vol_1 = s10->start_value + s11->modify_val;
- if (voice->_twochan && !_scummSmallHeader) {
- adlib_set_param(voice->_channel, 13,
- volume_table[lookup_table[voice->_vol_1]
- [part->_vol_eff >> 2]]);
- } else {
- adlib_set_param(voice->_channel, 13, voice->_vol_1);
- }
- break;
- case 30:
- s11->s10->modwheel = (char)s11->modify_val;
- break;
- case 31:
- s11->s10->unk3 = (char)s11->modify_val;
- break;
- default:
- adlib_set_param(voice->_channel, s11->param,
- s10->start_value + s11->modify_val);
- break;
- }
- }
-
- if (code & 2 && s11->flag0x10)
- adlib_key_onoff(voice->_channel);
-}
-
-void MidiDriver_ADLIB::adlib_key_off(int chan){
- byte reg = chan + 0xB0;
- adlib_write(reg, adlib_get_reg_value(reg) & ~0x20);
-}
-
-byte MidiDriver_ADLIB::struct10_ontimer(Struct10 *s10, Struct11 *s11) {
- byte result = 0;
- int i;
-
- if (s10->count && (s10->count -= 17) <= 0) {
- s10->active = 0;
- return 0;
- }
-
- i = s10->cur_val + s10->speed_hi;
- s10->speed_lo_counter += s10->speed_lo;
- if (s10->speed_lo_counter >= s10->speed_lo_max) {
- s10->speed_lo_counter -= s10->speed_lo_max;
- i += s10->direction;
- }
- if (s10->cur_val != i || s10->modwheel != s10->modwheel_last) {
- s10->cur_val = i;
- s10->modwheel_last = s10->modwheel;
- i = lookup_volume(i, s10->modwheel_last);
- if (i != s11->modify_val) {
- s11->modify_val = i;
- result = 1;
- }
- }
-
- if (!--s10->num_steps) {
- s10->active++;
- if (s10->active > 4) {
- if (s10->loop) {
- s10->active = 1;
- result |= 2;
- struct10_setup(s10);
- } else {
- s10->active = 0;
- }
- } else {
- struct10_setup(s10);
- }
- }
-
- return result;
-}
-
-void MidiDriver_ADLIB::adlib_set_param(int channel, byte param, int value) {
- const AdLibSetParams *as;
- byte reg;
-
- assert(channel >= 0 && channel < 9);
-
- if (param <= 12) {
- reg = channel_mappings_2[channel];
- } else if (param <= 25) {
- param -= 13;
- reg = channel_mappings[channel];
- } else if (param <= 27) {
- param -= 13;
- reg = channel;
- } else if (param == 28 || param == 29) {
- if (param == 28)
- value -= 15;
- else
- value -= 383;
- value <<= 4;
- channel_table_2[channel] = value;
- adlib_playnote(channel, curnote_table[channel] + value);
- return;
- } else {
- return;
- }
-
- as = &adlib_setparam_table[param];
- if (as->d)
- value = as->d - value;
- reg += as->a;
- adlib_write(reg, (adlib_get_reg_value(reg) & ~as->c) | (((byte)value) << as->b));
-}
-
-void MidiDriver_ADLIB::adlib_key_onoff(int channel) {
- byte val;
- byte reg = channel + 0xB0;
- assert(channel >= 0 && channel < 9);
-
- val = adlib_get_reg_value(reg);
- adlib_write(reg, val & ~0x20);
- adlib_write(reg, val | 0x20);
-}
-
-void MidiDriver_ADLIB::struct10_setup(Struct10 *s10) {
- int b, c, d, e, f, g, h;
- byte t;
-
- b = s10->unk3;
- f = s10->active - 1;
-
- t = s10->table_a[f];
- e = num_steps_table[lookup_table[t & 0x7F][b]];
- if (t & 0x80) {
- e = random_nr(e);
- }
- if (e == 0)
- e++;
-
- s10->num_steps = s10->speed_lo_max = e;
-
- if (f != 2) {
- c = s10->max_value;
- g = s10->start_value;
- t = s10->table_b[f];
- d = lookup_volume(c, (t & 0x7F) - 31);
- if (t & 0x80) {
- d = random_nr(d);
- }
- if (d + g > c) {
- h = c - g;
- } else {
- h = d;
- if (d + g < 0)
- h = -g;
- }
- h -= s10->cur_val;
- } else {
- h = 0;
- }
-
- s10->speed_hi = h / e;
- if (h < 0) {
- h = -h;
- s10->direction = -1;
- } else {
- s10->direction = 1;
- }
-
- s10->speed_lo = h % e;
- s10->speed_lo_counter = 0;
-}
-
-void MidiDriver_ADLIB::adlib_playnote(int channel, int note) {
- byte old, oct, notex;
- int note2;
- int i;
-
- note2 = (note >> 7) - 4;
- note2 = (note2 < 128) ? note2 : 0;
-
- oct = (note2 / 12);
- if (oct > 7)
- oct = 7 << 2;
- else
- oct <<= 2;
- notex = note2 % 12 + 3;
-
- old = adlib_get_reg_value(channel + 0xB0);
- if (old & 0x20) {
- old &= ~0x20;
- if (oct > old) {
- if (notex < 6) {
- notex += 12;
- oct -= 4;
- }
- } else if (oct < old) {
- if (notex > 11) {
- notex -= 12;
- oct += 4;
- }
- }
- }
-
- i = (notex << 3) + ((note >> 4) & 0x7);
- adlib_write(channel + 0xA0, note_to_f_num[i]);
- adlib_write(channel + 0xB0, oct | 0x20);
-}
-
-int MidiDriver_ADLIB::random_nr(int a) {
- static byte _rand_seed = 1;
- if (_rand_seed & 1) {
- _rand_seed >>= 1;
- _rand_seed ^= 0xB8;
- } else {
- _rand_seed >>= 1;
- }
- return _rand_seed * a >> 8;
-}
-
-void MidiDriver_ADLIB::part_key_off(AdLibPart *part, byte note) {
- AdLibVoice *voice;
-
- for (voice = part->_voice; voice; voice = voice->_next) {
- if (voice->_note == note) {
- if (part->_pedal)
- voice->_waitforpedal = true;
- else
- mc_off(voice);
- }
- }
-}
-
-void MidiDriver_ADLIB::part_key_on(AdLibPart *part, AdLibInstrument *instr, byte note, byte velocity) {
- AdLibVoice *voice;
-
- voice = allocate_voice(part->_pri_eff);
- if (!voice)
- return;
-
- link_mc(part, voice);
- mc_key_on(voice, instr, note, velocity);
-}
-
-AdLibVoice *MidiDriver_ADLIB::allocate_voice(byte pri) {
- AdLibVoice *ac, *best = NULL;
- int i;
-
- for (i = 0; i < 9; i++) {
- if (++_voice_index >= 9)
- _voice_index = 0;
- ac = &_voices[_voice_index];
- if (!ac->_part)
- return ac;
- if (!ac->_next) {
- if (ac->_part->_pri_eff <= pri) {
- pri = ac->_part->_pri_eff;
- best = ac;
- }
- }
- }
-
- /* SCUMM V3 games don't have note priorities, first comes wins. */
- if (_scummSmallHeader)
- return NULL;
-
- if (best)
- mc_off(best);
- return best;
-}
-
-void MidiDriver_ADLIB::link_mc(AdLibPart *part, AdLibVoice *voice) {
- voice->_part = part;
- voice->_next = (AdLibVoice *)part->_voice;
- part->_voice = voice;
- voice->_prev = NULL;
-
- if (voice->_next)
- voice->_next->_prev = voice;
-}
-
-void MidiDriver_ADLIB::mc_key_on(AdLibVoice *voice, AdLibInstrument *instr, byte note, byte velocity) {
- AdLibPart *part = voice->_part;
- int c;
- byte vol_1, vol_2;
-
- voice->_twochan = instr->feedback & 1;
- voice->_note = note;
- voice->_waitforpedal = false;
- voice->_duration = instr->duration;
- if (voice->_duration != 0)
- voice->_duration *= 63;
-
- if (!_scummSmallHeader)
- vol_1 = (instr->mod_scalingOutputLevel & 0x3F) + lookup_table[velocity >> 1][instr->mod_waveformSelect >> 2];
- else
- vol_1 = 0x3f - (instr->mod_scalingOutputLevel & 0x3F);
- if (vol_1 > 0x3F)
- vol_1 = 0x3F;
- voice->_vol_1 = vol_1;
-
- if (!_scummSmallHeader)
- vol_2 = (instr->car_scalingOutputLevel & 0x3F) + lookup_table[velocity >> 1][instr->car_waveformSelect >> 2];
- else
- vol_2 = 0x3f - (instr->car_scalingOutputLevel & 0x3F);
- if (vol_2 > 0x3F)
- vol_2 = 0x3F;
- voice->_vol_2 = vol_2;
-
- c = part->_vol_eff >> 2;
-
- if (!_scummSmallHeader) {
- vol_2 = volume_table[lookup_table[vol_2][c]];
- if (voice->_twochan)
- vol_1 = volume_table[lookup_table[vol_1][c]];
- }
-
- adlib_setup_channel(voice->_channel, instr, vol_1, vol_2);
- adlib_note_on_ex(voice->_channel, part->_transpose_eff + note, part->_detune_eff + (part->_pitchbend * part->_pitchbend_factor >> 6));
-
- if (instr->flags_a & 0x80) {
- mc_init_stuff(voice, &voice->_s10a, &voice->_s11a, instr->flags_a, &instr->extra_a);
- } else {
- voice->_s10a.active = 0;
- }
-
- if (instr->flags_b & 0x80) {
- mc_init_stuff(voice, &voice->_s10b, &voice->_s11b, instr->flags_b, &instr->extra_b);
- } else {
- voice->_s10b.active = 0;
- }
-}
-
-void MidiDriver_ADLIB::adlib_setup_channel(int chan, AdLibInstrument *instr, byte vol_1, byte vol_2) {
- byte channel;
-
- assert(chan >= 0 && chan < 9);
-
- channel = channel_mappings[chan];
- adlib_write(channel + 0x20, instr->mod_characteristic);
- adlib_write(channel + 0x40, (instr->mod_scalingOutputLevel | 0x3F) - vol_1 );
- adlib_write(channel + 0x60, 0xff & (~instr->mod_attackDecay));
- adlib_write(channel + 0x80, 0xff & (~instr->mod_sustainRelease));
- adlib_write(channel + 0xE0, instr->mod_waveformSelect);
-
- channel = channel_mappings_2[chan];
- adlib_write(channel + 0x20, instr->car_characteristic);
- adlib_write(channel + 0x40, (instr->car_scalingOutputLevel | 0x3F) - vol_2 );
- adlib_write(channel + 0x60, 0xff & (~instr->car_attackDecay));
- adlib_write(channel + 0x80, 0xff & (~instr->car_sustainRelease));
- adlib_write(channel + 0xE0, instr->car_waveformSelect);
-
- adlib_write((byte)chan + 0xC0, instr->feedback);
-}
-
-void MidiDriver_ADLIB::adlib_note_on_ex(int chan, byte note, int mod)
-{
- int code;
- assert(chan >= 0 && chan < 9);
- code = (note << 7) + mod;
- curnote_table[chan] = code;
- channel_table_2[chan] = 0;
- adlib_playnote(chan, code);
-}
-
-void MidiDriver_ADLIB::mc_init_stuff(AdLibVoice *voice, Struct10 * s10,
- Struct11 * s11, byte flags, InstrumentExtra * ie) {
- AdLibPart *part = voice->_part;
- s11->modify_val = 0;
- s11->flag0x40 = flags & 0x40;
- s10->loop = flags & 0x20;
- s11->flag0x10 = flags & 0x10;
- s11->param = param_table_1[flags & 0xF];
- s10->max_value = maxval_table[flags & 0xF];
- s10->unk3 = 31;
- if (s11->flag0x40) {
- s10->modwheel = part->_modwheel >> 2;
- } else {
- s10->modwheel = 31;
- }
-
- switch (s11->param) {
- case 0:
- s10->start_value = voice->_vol_2;
- break;
- case 13:
- s10->start_value = voice->_vol_1;
- break;
- case 30:
- s10->start_value = 31;
- s11->s10->modwheel = 0;
- break;
- case 31:
- s10->start_value = 0;
- s11->s10->unk3 = 0;
- break;
- default:
- s10->start_value = adlib_get_reg_value_param(voice->_channel, s11->param);
- }
-
- struct10_init(s10, ie);
-}
-
-void MidiDriver_ADLIB::struct10_init(Struct10 *s10, InstrumentExtra *ie) {
- s10->active = 1;
- if (!_scummSmallHeader) {
- s10->cur_val = 0;
- } else {
- s10->cur_val = s10->start_value;
- s10->start_value = 0;
- }
- s10->modwheel_last = 31;
- s10->count = ie->a;
- if (s10->count)
- s10->count *= 63;
- s10->table_a[0] = ie->b;
- s10->table_a[1] = ie->d;
- s10->table_a[2] = ie->f;
- s10->table_a[3] = ie->g;
-
- s10->table_b[0] = ie->c;
- s10->table_b[1] = ie->e;
- s10->table_b[2] = 0;
- s10->table_b[3] = ie->h;
-
- struct10_setup(s10);
-}
-
-int MidiDriver_ADLIB::adlib_get_reg_value_param(int chan, byte param) {
- const AdLibSetParams *as;
- byte val;
- byte channel;
-
- assert(chan >= 0 && chan < 9);
-
- if (param <= 12) {
- channel = channel_mappings_2[chan];
- } else if (param <= 25) {
- param -= 13;
- channel = channel_mappings[chan];
- } else if (param <= 27) {
- param -= 13;
- channel = chan;
- } else if (param == 28) {
- return 0xF;
- } else if (param == 29) {
- return 0x17F;
- } else {
- return 0;
- }
-
- as = &adlib_setparam_table[param];
- val = adlib_get_reg_value(channel + as->a);
- val &= as->c;
- val >>= as->b;
- if (as->d)
- val = as->d - val;
-
- return val;
-}
-
-void MidiDriver_ADLIB::adlib_note_on(int chan, byte note, int mod) {
- int code;
- assert(chan >= 0 && chan < 9);
- code = (note << 7) + mod;
- curnote_table[chan] = code;
- adlib_playnote(chan, (int16) channel_table_2[chan] + code);
-}
-
-
-// Plugin interface
-
-class AdLibEmuMusicPlugin : public MusicPluginObject {
-public:
- const char *getName() const {
- return _s("AdLib Emulator");
- }
-
- const char *getId() const {
- return "adlib";
- }
-
- MusicDevices getDevices() const;
- Common::Error createInstance(MidiDriver **mididriver, MidiDriver::DeviceHandle = 0) const;
-};
-
-MusicDevices AdLibEmuMusicPlugin::getDevices() const {
- MusicDevices devices;
- devices.push_back(MusicDevice(this, "", MT_ADLIB));
- return devices;
-}
-
-Common::Error AdLibEmuMusicPlugin::createInstance(MidiDriver **mididriver, MidiDriver::DeviceHandle) const {
- *mididriver = new MidiDriver_ADLIB(g_system->getMixer());
-
- return Common::kNoError;
-}
-
-//#if PLUGIN_ENABLED_DYNAMIC(ADLIB)
- //REGISTER_PLUGIN_DYNAMIC(ADLIB, PLUGIN_TYPE_MUSIC, AdLibEmuMusicPlugin);
-//#else
- REGISTER_PLUGIN_STATIC(ADLIB, PLUGIN_TYPE_MUSIC, AdLibEmuMusicPlugin);
-//#endif
diff --git a/sound/softsynth/appleiigs.cpp b/sound/softsynth/appleiigs.cpp
deleted file mode 100644
index 9004d1f0ab..0000000000
--- a/sound/softsynth/appleiigs.cpp
+++ /dev/null
@@ -1,57 +0,0 @@
-/* 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/null.h"
-
-// Plugin interface
-// (This can only create a null driver since apple II gs support seeems not to be implemented
-// and also is not part of the midi driver architecture. But we need the plugin for the options
-// menu in the launcher and for MidiDriver::detectDevice() which is more or less used by all engines.)
-
-class AppleIIGSMusicPlugin : public NullMusicPlugin {
-public:
- const char *getName() const {
- return _s("Apple II GS Emulator (NOT IMPLEMENTED)");
- }
-
- const char *getId() const {
- return "appleIIgs";
- }
-
- MusicDevices getDevices() const;
-};
-
-MusicDevices AppleIIGSMusicPlugin::getDevices() const {
- MusicDevices devices;
- devices.push_back(MusicDevice(this, "", MT_APPLEIIGS));
- return devices;
-}
-
-//#if PLUGIN_ENABLED_DYNAMIC(APPLEIIGS)
- //REGISTER_PLUGIN_DYNAMIC(APPLEIIGS, PLUGIN_TYPE_MUSIC, AppleIIGSMusicPlugin);
-//#else
- REGISTER_PLUGIN_STATIC(APPLEIIGS, PLUGIN_TYPE_MUSIC, AppleIIGSMusicPlugin);
-//#endif
-
diff --git a/sound/softsynth/cms.cpp b/sound/softsynth/cms.cpp
deleted file mode 100644
index b307146f14..0000000000
--- a/sound/softsynth/cms.cpp
+++ /dev/null
@@ -1,376 +0,0 @@
-/* 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 Unknown 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
deleted file mode 100644
index d5bb7f0a42..0000000000
--- a/sound/softsynth/cms.h
+++ /dev/null
@@ -1,92 +0,0 @@
-/* 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/emumidi.h b/sound/softsynth/emumidi.h
deleted file mode 100644
index 3fb2733b71..0000000000
--- a/sound/softsynth/emumidi.h
+++ /dev/null
@@ -1,116 +0,0 @@
-/* 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_EMUMIDI_H
-#define SOUND_SOFTSYNTH_EMUMIDI_H
-
-#include "sound/audiostream.h"
-#include "sound/mididrv.h"
-#include "sound/mixer.h"
-
-#define FIXP_SHIFT 16
-
-class MidiDriver_Emulated : public Audio::AudioStream, public MidiDriver {
-protected:
- bool _isOpen;
- Audio::Mixer *_mixer;
- Audio::SoundHandle _mixerSoundHandle;
-
-private:
- Common::TimerManager::TimerProc _timerProc;
- void *_timerParam;
-
- int _nextTick;
- int _samplesPerTick;
-
-protected:
- virtual void generateSamples(int16 *buf, int len) = 0;
- virtual void onTimer() {}
-
- int _baseFreq;
-
-public:
- MidiDriver_Emulated(Audio::Mixer *mixer) : _mixer(mixer) {
- _isOpen = false;
-
- _timerProc = 0;
- _timerParam = 0;
-
- _nextTick = 0;
- _samplesPerTick = 0;
-
- _baseFreq = 250;
- }
-
- int open() {
- _isOpen = true;
-
- int d = getRate() / _baseFreq;
- int r = getRate() % _baseFreq;
-
- // This is equivalent to (getRate() << FIXP_SHIFT) / BASE_FREQ
- // but less prone to arithmetic overflow.
-
- _samplesPerTick = (d << FIXP_SHIFT) + (r << FIXP_SHIFT) / _baseFreq;
- return 0;
- }
-
- void setTimerCallback(void *timer_param, Common::TimerManager::TimerProc timer_proc) {
- _timerProc = timer_proc;
- _timerParam = timer_param;
- }
-
- uint32 getBaseTempo() { return 1000000 / _baseFreq; }
-
-
- // AudioStream API
- int readBuffer(int16 *data, const int numSamples) {
- const int stereoFactor = isStereo() ? 2 : 1;
- int len = numSamples / stereoFactor;
- int step;
-
- do {
- step = len;
- if (step > (_nextTick >> FIXP_SHIFT))
- step = (_nextTick >> FIXP_SHIFT);
-
- generateSamples(data, step);
-
- _nextTick -= step << FIXP_SHIFT;
- if (!(_nextTick >> FIXP_SHIFT)) {
- if (_timerProc)
- (*_timerProc)(_timerParam);
- onTimer();
- _nextTick += _samplesPerTick;
- }
- data += step * stereoFactor;
- len -= step;
- } while (len);
-
- return numSamples;
- }
- bool endOfData() const { return false; }
-};
-
-#endif
diff --git a/sound/softsynth/fluidsynth.cpp b/sound/softsynth/fluidsynth.cpp
deleted file mode 100644
index fcb4591a20..0000000000
--- a/sound/softsynth/fluidsynth.cpp
+++ /dev/null
@@ -1,254 +0,0 @@
-/* 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 "common/scummsys.h"
-
-#ifdef USE_FLUIDSYNTH
-
-#include "common/config-manager.h"
-#include "sound/musicplugin.h"
-#include "sound/mpu401.h"
-#include "sound/softsynth/emumidi.h"
-
-#include <fluidsynth.h>
-
-class MidiDriver_FluidSynth : public MidiDriver_Emulated {
-private:
- MidiChannel_MPU401 _midiChannels[16];
- fluid_settings_t *_settings;
- fluid_synth_t *_synth;
- int _soundFont;
- int _outputRate;
- Audio::SoundHandle _handle;
-
-protected:
- // Because GCC complains about casting from const to non-const...
- void setInt(const char *name, int val);
- void setNum(const char *name, double num);
- void setStr(const char *name, const char *str);
-
- void generateSamples(int16 *buf, int len);
-
-public:
- MidiDriver_FluidSynth(Audio::Mixer *mixer);
-
- int open();
- void close();
- void send(uint32 b);
-
- MidiChannel *allocateChannel();
- MidiChannel *getPercussionChannel();
-
- // AudioStream API
- bool isStereo() const { return true; }
- int getRate() const { return _outputRate; }
-};
-
-// MidiDriver method implementations
-
-MidiDriver_FluidSynth::MidiDriver_FluidSynth(Audio::Mixer *mixer)
- : MidiDriver_Emulated(mixer) {
-
- for (int i = 0; i < ARRAYSIZE(_midiChannels); i++) {
- _midiChannels[i].init(this, i);
- }
-
- // It ought to be possible to get FluidSynth to generate samples at
- // lower
-
- _outputRate = _mixer->getOutputRate();
- if (_outputRate < 22050)
- _outputRate = 22050;
- else if (_outputRate > 96000)
- _outputRate = 96000;
-}
-
-void MidiDriver_FluidSynth::setInt(const char *name, int val) {
- char *name2 = strdup(name);
-
- fluid_settings_setint(_settings, name2, val);
- free(name2);
-}
-
-void MidiDriver_FluidSynth::setNum(const char *name, double val) {
- char *name2 = strdup(name);
-
- fluid_settings_setnum(_settings, name2, val);
- free(name2);
-}
-
-void MidiDriver_FluidSynth::setStr(const char *name, const char *val) {
- char *name2 = strdup(name);
- char *val2 = strdup(val);
-
- fluid_settings_setstr(_settings, name2, val2);
- free(name2);
- free(val2);
-}
-
-int MidiDriver_FluidSynth::open() {
- if (_isOpen)
- return MERR_ALREADY_OPEN;
-
- if (!ConfMan.hasKey("soundfont"))
- error("FluidSynth requires a 'soundfont' setting");
-
- _settings = new_fluid_settings();
-
- // The default gain setting is ridiculously low - at least for me. This
- // cannot be fixed by ScummVM's volume settings because they can only
- // soften the sound, not amplify it, so instead we add an option to
- // adjust the gain of FluidSynth itself.
-
- double gain = (double)ConfMan.getInt("midi_gain") / 100.0;
-
- setNum("synth.gain", gain);
- setNum("synth.sample-rate", _outputRate);
-
- _synth = new_fluid_synth(_settings);
-
- // In theory, this ought to reduce CPU load... but it doesn't make any
- // noticeable difference for me, so disable it for now.
-
- // fluid_synth_set_interp_method(_synth, -1, FLUID_INTERP_LINEAR);
- // fluid_synth_set_reverb_on(_synth, 0);
- // fluid_synth_set_chorus_on(_synth, 0);
-
- const char *soundfont = ConfMan.get("soundfont").c_str();
-
- _soundFont = fluid_synth_sfload(_synth, soundfont, 1);
- if (_soundFont == -1)
- error("Failed loading custom sound font '%s'", soundfont);
-
- MidiDriver_Emulated::open();
-
- // The MT-32 emulator uses kSFXSoundType here. I don't know why.
- _mixer->playStream(Audio::Mixer::kMusicSoundType, &_handle, this, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO, true);
- return 0;
-}
-
-void MidiDriver_FluidSynth::close() {
- if (!_isOpen)
- return;
- _isOpen = false;
-
- _mixer->stopHandle(_handle);
-
- if (_soundFont != -1)
- fluid_synth_sfunload(_synth, _soundFont, 1);
-
- delete_fluid_synth(_synth);
- delete_fluid_settings(_settings);
-}
-
-void MidiDriver_FluidSynth::send(uint32 b) {
- //byte param3 = (byte) ((b >> 24) & 0xFF);
- uint param2 = (byte) ((b >> 16) & 0xFF);
- uint param1 = (byte) ((b >> 8) & 0xFF);
- byte cmd = (byte) (b & 0xF0);
- byte chan = (byte) (b & 0x0F);
-
- switch (cmd) {
- case 0x80: // Note Off
- fluid_synth_noteoff(_synth, chan, param1);
- break;
- case 0x90: // Note On
- fluid_synth_noteon(_synth, chan, param1, param2);
- break;
- case 0xA0: // Aftertouch
- break;
- case 0xB0: // Control Change
- fluid_synth_cc(_synth, chan, param1, param2);
- break;
- case 0xC0: // Program Change
- fluid_synth_program_change(_synth, chan, param1);
- break;
- case 0xD0: // Channel Pressure
- break;
- case 0xE0: // Pitch Bend
- fluid_synth_pitch_bend(_synth, chan, (param2 << 7) | param1);
- break;
- case 0xF0: // SysEx
- // We should never get here! SysEx information has to be
- // sent via high-level semantic methods.
- warning("MidiDriver_FluidSynth: Receiving SysEx command on a send() call");
- break;
- default:
- warning("MidiDriver_FluidSynth: Unknown send() command 0x%02X", cmd);
- break;
- }
-}
-
-MidiChannel *MidiDriver_FluidSynth::allocateChannel() {
- for (int i = 0; i < ARRAYSIZE(_midiChannels); i++) {
- if (i != 9 && _midiChannels[i].allocate())
- return &_midiChannels[i];
- }
- return NULL;
-}
-
-MidiChannel *MidiDriver_FluidSynth::getPercussionChannel() {
- return &_midiChannels[9];
-}
-
-void MidiDriver_FluidSynth::generateSamples(int16 *data, int len) {
- fluid_synth_write_s16(_synth, len, data, 0, 2, data, 1, 2);
-}
-
-
-// Plugin interface
-
-class FluidSynthMusicPlugin : public MusicPluginObject {
-public:
- const char *getName() const {
- return "FluidSynth";
- }
-
- const char *getId() const {
- return "fluidsynth";
- }
-
- MusicDevices getDevices() const;
- Common::Error createInstance(MidiDriver **mididriver, MidiDriver::DeviceHandle = 0) const;
-};
-
-MusicDevices FluidSynthMusicPlugin::getDevices() const {
- MusicDevices devices;
- devices.push_back(MusicDevice(this, "", MT_GM));
- return devices;
-}
-
-Common::Error FluidSynthMusicPlugin::createInstance(MidiDriver **mididriver, MidiDriver::DeviceHandle) const {
- *mididriver = new MidiDriver_FluidSynth(g_system->getMixer());
-
- return Common::kNoError;
-}
-
-//#if PLUGIN_ENABLED_DYNAMIC(FLUIDSYNTH)
- //REGISTER_PLUGIN_DYNAMIC(FLUIDSYNTH, PLUGIN_TYPE_MUSIC, FluidSynthMusicPlugin);
-//#else
- REGISTER_PLUGIN_STATIC(FLUIDSYNTH, PLUGIN_TYPE_MUSIC, FluidSynthMusicPlugin);
-//#endif
-
-#endif
diff --git a/sound/softsynth/fmtowns_pc98/towns_audio.cpp b/sound/softsynth/fmtowns_pc98/towns_audio.cpp
deleted file mode 100644
index 14bc840326..0000000000
--- a/sound/softsynth/fmtowns_pc98/towns_audio.cpp
+++ /dev/null
@@ -1,1583 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * $URL$
- * $Id$
- *
- */
-
-#include "sound/softsynth/fmtowns_pc98/towns_audio.h"
-#include "common/endian.h"
-#include "backends/audiocd/audiocd.h"
-
-
-class TownsAudio_PcmChannel {
-friend class TownsAudioInterface;
-public:
- TownsAudio_PcmChannel();
- ~TownsAudio_PcmChannel();
-
-private:
- void loadExtData(uint8 *buffer, uint32 size);
- void setupLoop(uint32 start, uint32 len);
- void clear();
-
- void envAttack();
- void envDecay();
- void envSustain();
- void envRelease();
-
- uint8 *curInstrument;
- uint8 note;
- uint8 velo;
-
- int8 *data;
- int8 *dataEnd;
-
- int8 *loopEnd;
- uint32 loopLen;
-
- uint16 stepNote;
- uint16 stepPitch;
- uint16 step;
-
- uint8 panLeft;
- uint8 panRight;
-
- uint32 pos;
-
- uint8 envTotalLevel;
- uint8 envAttackRate;
- uint8 envDecayRate;
- uint8 envSustainLevel;
- uint8 envSustainRate;
- uint8 envReleaseRate;
-
- int16 envStep;
- int16 envCurrentLevel;
-
- EnvelopeState envState;
-
- int8 *extData;
-};
-
-class TownsAudio_WaveTable {
-friend class TownsAudioInterface;
-public:
- TownsAudio_WaveTable();
- ~TownsAudio_WaveTable();
-
-private:
- void readHeader(const uint8 *buffer);
- void readData(const uint8 *buffer);
- void clear();
-
- char name[9];
- int32 id;
- uint32 size;
- uint32 loopStart;
- uint32 loopLen;
- uint16 rate;
- uint16 rateOffs;
- uint16 baseNote;
- int8 *data;
-};
-
-TownsAudioInterface::TownsAudioInterface(Audio::Mixer *mixer, TownsAudioInterfacePluginDriver *driver) : TownsPC98_FmSynth(mixer, kTypeTowns),
- _fmInstruments(0), _pcmInstruments(0), _pcmChan(0), _waveTables(0), _waveTablesTotalDataSize(0),
- _baserate(55125.0f / (float)mixer->getOutputRate()), _tickLength(0), _timer(0), _drv(driver),
- _pcmSfxChanMask(0), _musicVolume(Audio::Mixer::kMaxMixerVolume), _sfxVolume(Audio::Mixer::kMaxMixerVolume),
- _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[] = {
- // 0
- INTCB(reset),
- INTCB(keyOn),
- INTCB(keyOff),
- INTCB(setPanPos),
- // 4
- INTCB(setInstrument),
- INTCB(loadInstrument),
- INTCB(notImpl),
- INTCB(setPitch),
- // 8
- INTCB(setLevel),
- INTCB(chanOff),
- INTCB(notImpl),
- INTCB(notImpl),
- // 12
- INTCB(notImpl),
- INTCB(notImpl),
- INTCB(notImpl),
- INTCB(notImpl),
- // 16
- INTCB(notImpl),
- INTCB(writeReg),
- INTCB(notImpl),
- INTCB(writeRegBuffer),
- // 20
- INTCB(readRegBuffer),
- INTCB(setTimerA),
- INTCB(setTimerB),
- INTCB(enableTimerA),
- // 24
- INTCB(enableTimerB),
- INTCB(notImpl),
- INTCB(notImpl),
- INTCB(notImpl),
- // 28
- INTCB(notImpl),
- INTCB(notImpl),
- INTCB(notImpl),
- INTCB(notImpl),
- // 32
- INTCB(loadSamples),
- INTCB(reserveEffectChannels),
- INTCB(loadWaveTable),
- INTCB(unloadWaveTable),
- // 36
- INTCB(notImpl),
- INTCB(pcmPlayEffect),
- INTCB(notImpl),
- INTCB(pcmChanOff),
- // 40
- INTCB(pcmEffectPlaying),
- INTCB(notImpl),
- INTCB(notImpl),
- INTCB(notImpl),
- // 44
- INTCB(notImpl),
- INTCB(notImpl),
- INTCB(notImpl),
- INTCB(notImpl),
- // 48
- INTCB(notImpl),
- INTCB(notImpl),
- INTCB(fmKeyOn),
- INTCB(fmKeyOff),
- // 52
- INTCB(fmSetPanPos),
- INTCB(fmSetInstrument),
- INTCB(fmLoadInstrument),
- INTCB(notImpl),
- // 56
- INTCB(fmSetPitch),
- INTCB(fmSetLevel),
- INTCB(fmReset),
- INTCB(notImpl),
- // 60
- INTCB(notImpl),
- INTCB(notImpl),
- INTCB(notImpl),
- INTCB(notImpl),
- // 64
- INTCB(notImpl),
- INTCB(notImpl),
- INTCB(notImpl),
- INTCB(setOutputVolume),
- // 68
- INTCB(resetOutputVolume),
- INTCB(notImpl),
- INTCB(updateOutputVolume),
- INTCB(notImpl),
- // 72
- INTCB(notImpl),
- INTCB(cdaToggle),
- INTCB(notImpl),
- INTCB(notImpl),
- // 76
- INTCB(notImpl),
- INTCB(notImpl),
- INTCB(notImpl),
- INTCB(notImpl),
- // 80
- INTCB(pcmUpdateEnvelopeGenerator),
- INTCB(notImpl)
- };
-#undef INTCB
-
- _intfOpcodes = intfCb;
-
- memset(_fmSaveReg, 0, sizeof(_fmSaveReg));
- memset(_outputLevel, 0, sizeof(_outputLevel));
-
- _timerBase = (uint32)(_baserate * 1000000.0f);
- _tickLength = 2 * _timerBase;
-}
-
-TownsAudioInterface::~TownsAudioInterface() {
- _ready = false;
- deinit();
-
- delete[] _fmSaveReg[0];
- delete[] _fmSaveReg[1];
- delete[] _fmInstruments;
- delete[] _pcmInstruments;
- delete[] _waveTables;
- delete[] _pcmChan;
-}
-
-bool TownsAudioInterface::init() {
- if (_ready)
- return true;
-
- if (!TownsPC98_FmSynth::init())
- return false;
-
- _fmSaveReg[0] = new uint8[256];
- _fmSaveReg[1] = new uint8[256];
- _fmInstruments = new uint8[128 * 48];
- _pcmInstruments = new uint8[32 * 128];
- _waveTables = new TownsAudio_WaveTable[128];
- _pcmChan = new TownsAudio_PcmChannel[8];
-
- _timer = 0;
-
- setVolumeChannelMasks(-1, 0);
-
- _ready = true;
- callback(0);
-
- return true;
-}
-
-int TownsAudioInterface::callback(int command, ...) {
- if (!_ready)
- return 1;
-
- va_list args;
- va_start(args, command);
-
- if (command > 81) {
- va_end(args);
- return 4;
- }
-
- int res = (this->*_intfOpcodes[command])(args);
-
- va_end(args);
- return res;
-}
-
-void TownsAudioInterface::setMusicVolume(int volume) {
- _musicVolume = CLIP<uint16>(volume, 0, Audio::Mixer::kMaxMixerVolume);
- setVolumeIntern(_musicVolume, _sfxVolume);
-}
-
-void TownsAudioInterface::setSoundEffectVolume(int volume) {
- _sfxVolume = CLIP<uint16>(volume, 0, Audio::Mixer::kMaxMixerVolume);
- setVolumeIntern(_musicVolume, _sfxVolume);
-}
-
-void TownsAudioInterface::setSoundEffectChanMask(int mask) {
- _pcmSfxChanMask = mask >> 6;
- mask &= 0x3f;
- setVolumeChannelMasks(~mask, mask);
-}
-
-void TownsAudioInterface::nextTickEx(int32 *buffer, uint32 bufferSize) {
- if (!_ready)
- return;
-
- for (uint32 i = 0; i < bufferSize; i++) {
- _timer += _tickLength;
- while (_timer > 0x514767) {
- _timer -= 0x514767;
-
- for (int ii = 0; ii < 8; ii++) {
- if ((_pcmChanKeyPlaying & _chanFlags[ii]) || (_pcmChanEffectPlaying & _chanFlags[ii])) {
- TownsAudio_PcmChannel *s = &_pcmChan[ii];
- s->pos += s->step;
-
- if (&s->data[s->pos >> 11] >= s->loopEnd) {
- if (s->loopLen) {
- s->pos -= s->loopLen;
- } else {
- s->pos = 0;
- _pcmChanEffectPlaying &= ~_chanFlags[ii];
- _pcmChanKeyPlaying &= ~_chanFlags[ii];
- }
- }
- }
- }
- }
-
- int32 finOutL = 0;
- int32 finOutR = 0;
-
- for (int ii = 0; ii < 8; ii++) {
- if (_pcmChanOut & _chanFlags[ii]) {
- int32 o = _pcmChan[ii].data[_pcmChan[ii].pos >> 11] * _pcmChan[ii].velo;
- if ((1 << ii) & (~_pcmSfxChanMask))
- o = (o * _musicVolume) / Audio::Mixer::kMaxMixerVolume;
- if ((1 << ii) & _pcmSfxChanMask)
- o = (o * _sfxVolume) / Audio::Mixer::kMaxMixerVolume;
- if (_pcmChan[ii].panLeft)
- finOutL += ((o * _pcmChan[ii].panLeft) >> 3);
- if (_pcmChan[ii].panRight)
- finOutR += ((o * _pcmChan[ii].panRight) >> 3);
- if (!((_pcmChanKeyPlaying & _chanFlags[ii]) || (_pcmChanEffectPlaying & _chanFlags[ii])))
- _pcmChanOut &= ~_chanFlags[ii];
- }
- }
-
- buffer[i << 1] += finOutL;
- buffer[(i << 1) + 1] += finOutR;
- }
-}
-
-void TownsAudioInterface::timerCallbackA() {
- Common::StackLock lock(_mutex);
- if (_drv && _ready)
- _drv->timerCallback(0);
-}
-
-void TownsAudioInterface::timerCallbackB() {
- Common::StackLock lock(_mutex);
- if (_ready) {
- if (_drv)
- _drv->timerCallback(1);
- callback(80);
- }
-}
-
-int TownsAudioInterface::intf_reset(va_list &args) {
- fmReset();
- pcmReset();
- callback(68);
- return 0;
-}
-
-int TownsAudioInterface::intf_keyOn(va_list &args) {
- int chan = va_arg(args, int);
- int note = va_arg(args, int);
- int velo = va_arg(args, int);
- return (chan & 0x40) ? pcmKeyOn(chan, note, velo) : fmKeyOn(chan, note, velo);
-}
-
-int TownsAudioInterface::intf_keyOff(va_list &args) {
- int chan = va_arg(args, int);
- return (chan & 0x40) ? pcmKeyOff(chan) : fmKeyOff(chan);
-}
-
-int TownsAudioInterface::intf_setPanPos(va_list &args) {
- int chan = va_arg(args, int);
- int mode = va_arg(args, int);
- return (chan & 0x40) ? pcmSetPanPos(chan, mode) : fmSetPanPos(chan, mode);
-}
-
-int TownsAudioInterface::intf_setInstrument(va_list &args) {
- int chan = va_arg(args, int);
- int instrId = va_arg(args, int);
- return (chan & 0x40) ? pcmSetInstrument(chan, instrId) : fmSetInstrument(chan, instrId);
-}
-
-int TownsAudioInterface::intf_loadInstrument(va_list &args) {
- int chanType = va_arg(args, int);
- int instrId = va_arg(args, int);
- uint8 *instrData = va_arg(args, uint8 *);
- return (chanType & 0x40) ? pcmLoadInstrument(instrId, instrData) : fmLoadInstrument(instrId, instrData);
-}
-
-int TownsAudioInterface::intf_setPitch(va_list &args) {
- int chan = va_arg(args, int);
- int16 pitch = (int16)(va_arg(args, int) & 0xffff);
- return (chan & 0x40) ? pcmSetPitch(chan, pitch) : fmSetPitch(chan, pitch);
-}
-
-int TownsAudioInterface::intf_setLevel(va_list &args) {
- int chan = va_arg(args, int);
- int lvl = va_arg(args, int);
- return (chan & 0x40) ? pcmSetLevel(chan, lvl) : fmSetLevel(chan, lvl);
-}
-
-int TownsAudioInterface::intf_chanOff(va_list &args) {
- int chan = va_arg(args, int);
- return (chan & 0x40) ? pcmChanOff(chan) : fmChanOff(chan);
-}
-
-int TownsAudioInterface::intf_writeReg(va_list &args) {
- int part = va_arg(args, int) ? 1 : 0;
- int reg = va_arg(args, int);
- int val = va_arg(args, int);
- if ((!part && reg < 0x20) || (part && reg < 0x30) || (reg > 0xb6))
- return 3;
-
- bufferedWriteReg(part, reg, val);
- return 0;
-}
-
-int TownsAudioInterface::intf_writeRegBuffer(va_list &args) {
- int part = va_arg(args, int) ? 1 : 0;
- int reg = va_arg(args, int);
- int val = va_arg(args, int);
-
- if ((!part && reg < 0x20) || (part && reg < 0x30) || (reg > 0xef))
- return 3;
-
- _fmSaveReg[part][reg] = val;
- return 0;
-}
-
-int TownsAudioInterface::intf_readRegBuffer(va_list &args) {
- int part = va_arg(args, int) ? 1 : 0;
- int reg = va_arg(args, int);
- uint8 *dst = va_arg(args, uint8 *);
- *dst = 0;
-
- if ((!part && reg < 0x20) || (part && reg < 0x30) || (reg > 0xef))
- return 3;
-
- *dst = _fmSaveReg[part][reg];
- return 0;
-}
-
-int TownsAudioInterface::intf_setTimerA(va_list &args) {
- int enable = va_arg(args, int);
- int tempo = va_arg(args, int);
-
- if (enable) {
- bufferedWriteReg(0, 0x25, tempo & 3);
- bufferedWriteReg(0, 0x24, (tempo >> 2) & 0xff);
- bufferedWriteReg(0, 0x27, _fmSaveReg[0][0x27] | 0x05);
- } else {
- bufferedWriteReg(0, 0x27, (_fmSaveReg[0][0x27] & 0xfa) | 0x10);
- }
-
- return 0;
-}
-
-int TownsAudioInterface::intf_setTimerB(va_list &args) {
- int enable = va_arg(args, int);
- int tempo = va_arg(args, int);
-
- if (enable) {
- bufferedWriteReg(0, 0x26, tempo & 0xff);
- bufferedWriteReg(0, 0x27, _fmSaveReg[0][0x27] | 0x0A);
- } else {
- bufferedWriteReg(0, 0x27, (_fmSaveReg[0][0x27] & 0xf5) | 0x20);
- }
-
- return 0;
-}
-
-int TownsAudioInterface::intf_enableTimerA(va_list &args) {
- bufferedWriteReg(0, 0x27, _fmSaveReg[0][0x27] | 0x15);
- return 0;
-}
-
-int TownsAudioInterface::intf_enableTimerB(va_list &args) {
- bufferedWriteReg(0, 0x27, _fmSaveReg[0][0x27] | 0x2a);
- return 0;
-}
-
-int TownsAudioInterface::intf_loadSamples(va_list &args) {
- uint32 dest = va_arg(args, uint32);
- int size = va_arg(args, int);
- uint8 *src = va_arg(args, uint8*);
-
- if (dest >= 65536 || size == 0 || size > 65536)
- return 3;
- if (size + dest > 65536)
- return 5;
-
- int dwIndex = _numWaveTables - 1;
- for (uint32 t = _waveTablesTotalDataSize; dwIndex && (dest < t); dwIndex--)
- t -= _waveTables[dwIndex].size;
-
- TownsAudio_WaveTable *s = &_waveTables[dwIndex];
- _waveTablesTotalDataSize -= s->size;
- s->size = size;
- s->readData(src);
- _waveTablesTotalDataSize += s->size;
-
- return 0;
-}
-
-int TownsAudioInterface::intf_reserveEffectChannels(va_list &args) {
- int numChan = va_arg(args, int);
- if (numChan > 8)
- return 3;
- if ((numChan << 13) + _waveTablesTotalDataSize > 65536)
- return 5;
-
- if (numChan == _numReservedChannels)
- return 0;
-
- if (numChan < _numReservedChannels) {
- int c = 8 - _numReservedChannels;
- for (int i = numChan; i; i--) {
- uint8 f = ~_chanFlags[c--];
- _pcmChanEffectPlaying &= f;
- }
- } else {
- int c = 7 - _numReservedChannels;
- for (int i = numChan - _numReservedChannels; i; i--) {
- uint8 f = ~_chanFlags[c--];
- _pcmChanKeyPressed &= f;
- _pcmChanKeyPlaying &= f;
- }
- }
-
- static const uint8 reserveChanFlags[] = { 0x00, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE, 0xFF };
- _numReservedChannels = numChan;
- _pcmChanReserved = reserveChanFlags[_numReservedChannels];
-
- return 0;
-}
-
-int TownsAudioInterface::intf_loadWaveTable(va_list &args) {
- uint8 *data = va_arg(args, uint8 *);
- if (_numWaveTables > 127)
- return 3;
-
- TownsAudio_WaveTable w;
- w.readHeader(data);
- if (!w.size)
- return 6;
-
- if (_waveTablesTotalDataSize + w.size > 65504)
- return 5;
-
- for (int i = 0; i < _numWaveTables; i++) {
- if (_waveTables[i].id == w.id)
- return 10;
- }
-
- TownsAudio_WaveTable *s = &_waveTables[_numWaveTables++];
- s->readHeader(data);
-
- _waveTablesTotalDataSize += s->size;
- callback(32, _waveTablesTotalDataSize, s->size, data + 32);
-
- return 0;
-}
-
-int TownsAudioInterface::intf_unloadWaveTable(va_list &args) {
- int id = va_arg(args, int);
-
- if (id == -1) {
- for (int i = 0; i < 128; i++)
- _waveTables[i].clear();
- _numWaveTables = 0;
- _waveTablesTotalDataSize = 0;
- } else {
- if (_waveTables) {
- for (int i = 0; i < _numWaveTables; i++) {
- if (_waveTables[i].id == id) {
- _numWaveTables--;
- _waveTablesTotalDataSize -= _waveTables[i].size;
- _waveTables[i].clear();
- for (; i < _numWaveTables; i++)
- memcpy(&_waveTables[i], &_waveTables[i + 1], sizeof(TownsAudio_WaveTable));
- return 0;
- }
- return 9;
- }
- }
- }
-
- return 0;
-}
-
-int TownsAudioInterface::intf_pcmPlayEffect(va_list &args) {
- int chan = va_arg(args, int);
- int note = va_arg(args, int);
- int velo = va_arg(args, int);
- uint8 *data = va_arg(args, uint8 *);
-
- if (chan < 0x40 || chan > 0x47)
- return 1;
-
- if (note & 0x80 || velo & 0x80)
- return 3;
-
- chan -= 0x40;
-
- if (!(_pcmChanReserved & _chanFlags[chan]))
- return 7;
-
- if ((_pcmChanEffectPlaying & _chanFlags[chan]))
- return 2;
-
- TownsAudio_WaveTable w;
- w.readHeader(data);
-
- if (w.size < (w.loopStart + w.loopLen))
- return 13;
-
- if (!w.size)
- return 6;
-
- TownsAudio_PcmChannel *p = &_pcmChan[chan];
-
- _pcmChanNote[chan] = note;
- _pcmChanVelo[chan] = velo;
-
- p->note = note;
- p->velo = velo << 1;
-
- p->loadExtData(data + 32, w.size);
- p->setupLoop(w.loopStart, w.loopLen);
-
- pcmCalcPhaseStep(p, &w);
- if (p->step > 2048)
- p->step = 2048;
-
- _pcmChanEffectPlaying |= _chanFlags[chan];
- _pcmChanOut |= _chanFlags[chan];
-
- return 0;
-}
-
-int TownsAudioInterface::intf_pcmChanOff(va_list &args) {
- int chan = va_arg(args, int);
- pcmChanOff(chan);
- return 0;
-}
-
-int TownsAudioInterface::intf_pcmEffectPlaying(va_list &args) {
- int chan = va_arg(args, int);
- if (chan < 0x40 || chan > 0x47)
- return 1;
- chan -= 0x40;
- return (_pcmChanEffectPlaying & _chanFlags[chan]) ? 1 : 0;
-}
-
-int TownsAudioInterface::intf_fmKeyOn(va_list &args) {
- int chan = va_arg(args, int);
- int note = va_arg(args, int);
- int velo = va_arg(args, int);
- return fmKeyOn(chan, note, velo);
-}
-
-int TownsAudioInterface::intf_fmKeyOff(va_list &args) {
- int chan = va_arg(args, int);
- return fmKeyOff(chan);
-}
-
-int TownsAudioInterface::intf_fmSetPanPos(va_list &args) {
- int chan = va_arg(args, int);
- int mode = va_arg(args, int);
- return fmSetPanPos(chan, mode);
-}
-
-int TownsAudioInterface::intf_fmSetInstrument(va_list &args) {
- int chan = va_arg(args, int);
- int instrId = va_arg(args, int);
- return fmSetInstrument(chan, instrId);
-}
-
-int TownsAudioInterface::intf_fmLoadInstrument(va_list &args) {
- int instrId = va_arg(args, int);
- uint8 *instrData = va_arg(args, uint8 *);
- return fmLoadInstrument(instrId, instrData);
-}
-
-int TownsAudioInterface::intf_fmSetPitch(va_list &args) {
- int chan = va_arg(args, int);
- uint16 freq = va_arg(args, int) & 0xffff;
- return fmSetPitch(chan, freq);
-}
-
-int TownsAudioInterface::intf_fmSetLevel(va_list &args) {
- int chan = va_arg(args, int);
- int lvl = va_arg(args, int);
- return fmSetLevel(chan, lvl);
-}
-
-int TownsAudioInterface::intf_fmReset(va_list &args) {
- fmReset();
- return 0;
-}
-
-int TownsAudioInterface::intf_setOutputVolume(va_list &args) {
- int chanType = va_arg(args, int);
- int left = va_arg(args, int);
- int right = va_arg(args, int);
-
- if (left & 0xff80 || right & 0xff80)
- return 3;
-
- 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
- _outputVolumeFlags &= ~flags[chanType];
-
- if (chanType > 1) {
- _outputLevel[chan + chanType] = left;
- } else {
- if (chanType == 0)
- chan -= 8;
- _outputLevel[chan] = left;
- _outputLevel[chan + 1] = right;
- }
-
- updateOutputVolume();
-
- return 0;
-}
-
-int TownsAudioInterface::intf_resetOutputVolume(va_list &args) {
- memset(_outputLevel, 0, sizeof(_outputLevel));
- _outputMuteFlags = 0;
- _outputVolumeFlags = 0;
- updateOutputVolume();
- return 0;
-}
-
-int TownsAudioInterface::intf_updateOutputVolume(va_list &args) {
- int flags = va_arg(args, int);
- _outputMuteFlags = flags & 3;
- updateOutputVolume();
- return 0;
-}
-
-int TownsAudioInterface::intf_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);
- return 0;
-}
-
-int TownsAudioInterface::intf_notImpl(va_list &args) {
- return 4;
-}
-
-void TownsAudioInterface::fmReset() {
- TownsPC98_FmSynth::reset();
-
- _fmChanPlaying = 0;
- memset(_fmChanNote, 0, sizeof(_fmChanNote));
- memset(_fmChanPitch, 0, sizeof(_fmChanPitch));
-
- memset(_fmSaveReg[0], 0, 240);
- memset(&_fmSaveReg[0][240], 0x7f, 16);
- memset(_fmSaveReg[1], 0, 256);
- memset(&_fmSaveReg[1][240], 0x7f, 16);
- _fmSaveReg[0][243] = _fmSaveReg[0][247] = _fmSaveReg[0][251] = _fmSaveReg[0][255] = _fmSaveReg[1][243] = _fmSaveReg[1][247] = _fmSaveReg[1][251] = _fmSaveReg[1][255] = 0xff;
-
- for (int i = 0; i < 128; i++)
- fmLoadInstrument(i, _fmDefaultInstrument);
-
- bufferedWriteReg(0, 0x21, 0);
- bufferedWriteReg(0, 0x2C, 0x80);
- bufferedWriteReg(0, 0x2B, 0);
- bufferedWriteReg(0, 0x27, 0x30);
-
- for (int i = 0; i < 6; i++) {
- fmKeyOff(i);
- fmSetInstrument(i, 0);
- fmSetLevel(i, 127);
- }
-}
-
-int TownsAudioInterface::fmKeyOn(int chan, int note, int velo) {
- if (chan > 5)
- return 1;
- if (note < 12 || note > 107 || (velo & 0x80))
- return 3;
- if (_fmChanPlaying & _chanFlags[chan])
- return 2;
-
- _fmChanPlaying |= _chanFlags[chan];
- note -= 12;
-
- _fmChanNote[chan] = note;
- int16 pitch = _fmChanPitch[chan];
-
- uint8 part = chan > 2 ? 1 : 0;
- if (chan > 2)
- chan -= 3;
-
- int frq = 0;
- uint8 bl = 0;
-
- if (note) {
- frq = _frequency[(note - 1) % 12];
- bl = (note - 1) / 12;
- } else {
- frq = 616;
- }
-
- frq += pitch;
-
- if (frq < 616) {
- if (!bl) {
- frq = 616;
- } else {
- frq += 616;
- --bl;
- }
- } else if (frq > 1232) {
- if (bl == 7) {
- frq = 15500;
- } else {
- frq -= 616;
- ++bl;
- }
- }
-
- frq |= (bl << 11);
-
- bufferedWriteReg(part, chan + 0xa4, (frq >> 8) & 0xff);
- bufferedWriteReg(part, chan + 0xa0, frq & 0xff);
-
- velo = (velo >> 2) + 96;
- uint16 c = _carrier[_fmSaveReg[part][0xb0 + chan] & 7];
- _fmSaveReg[part][0xe0 + chan] = velo;
-
- for (uint8 reg = 0x40 + chan; reg < 0x50; reg += 4) {
- c += c;
- if (c & 0x100) {
- c &= 0xff;
- bufferedWriteReg(part, reg, (((((((_fmSaveReg[part][0x80 + reg] ^ 0x7f) * velo) >> 7) + 1) * _fmSaveReg[part][0xd0 + chan]) >> 7) + 1) ^ 0x7f);
- }
- }
-
- uint8 v = chan;
- if (part)
- v |= 4;
-
- for (uint8 reg = 0x80 + chan; reg < 0x90; reg += 4)
- writeReg(part, reg, _fmSaveReg[part][reg] | 0x0f);
-
- writeReg(0, 0x28, v);
-
- for (uint8 reg = 0x80 + chan; reg < 0x90; reg += 4)
- writeReg(part, reg, _fmSaveReg[part][reg]);
-
- bufferedWriteReg(0, 0x28, v | 0xf0);
-
- return 0;
-}
-
-int TownsAudioInterface::fmKeyOff(int chan) {
- if (chan > 5)
- return 1;
- _fmChanPlaying &= ~_chanFlags[chan];
- if (chan > 2)
- chan++;
- bufferedWriteReg(0, 0x28, chan);
- return 0;
-}
-
-int TownsAudioInterface::fmChanOff(int chan) {
- if (chan > 5)
- return 1;
- _fmChanPlaying &= ~_chanFlags[chan];
-
- uint8 part = chan > 2 ? 1 : 0;
- if (chan > 2)
- chan -= 3;
-
- for (uint8 reg = 0x80 + chan; reg < 0x90; reg += 4)
- writeReg(part, reg, _fmSaveReg[part][reg] | 0x0f);
-
- if (part)
- chan += 4;
- writeReg(0, 0x28, chan);
- return 0;
-}
-
-int TownsAudioInterface::fmSetPanPos(int chan, int value) {
- if (chan > 5)
- return 1;
-
- uint8 part = chan > 2 ? 1 : 0;
- if (chan > 2)
- chan -= 3;
-
- if (value > 0x40)
- value = 0x40;
- else if (value < 0x40)
- value = 0x80;
- else
- value = 0xC0;
-
- bufferedWriteReg(part, 0xb4 + chan, (_fmSaveReg[part][0xb4 + chan] & 0x3f) | value);
- return 0;
-}
-
-int TownsAudioInterface::fmSetInstrument(int chan, int instrId) {
- if (chan > 5)
- return 1;
- if (instrId > 127)
- return 3;
-
- uint8 part = chan > 2 ? 1 : 0;
- if (chan > 2)
- chan -= 3;
-
- uint8 *src = &_fmInstruments[instrId * 48 + 8];
-
- uint16 c = _carrier[src[24] & 7];
- uint8 reg = 0x30 + chan;
-
- for (; reg < 0x40; reg += 4)
- bufferedWriteReg(part, reg, *src++);
-
- for (; reg < 0x50; reg += 4) {
- uint8 v = *src++;
- _fmSaveReg[part][0x80 + reg] = _fmSaveReg[part][reg] = v;
- c += c;
- if (c & 0x100) {
- c &= 0xff;
- v = 127;
- }
- writeReg(part, reg, v);
- }
-
- for (; reg < 0x90; reg += 4)
- bufferedWriteReg(part, reg, *src++);
-
- reg += 0x20;
- bufferedWriteReg(part, reg, *src++);
-
- uint8 v = *src++;
- reg += 4;
- if (v < 64)
- v |= (_fmSaveReg[part][reg] & 0xc0);
- bufferedWriteReg(part, reg, v);
-
- return 0;
-}
-
-int TownsAudioInterface::fmLoadInstrument(int instrId, const uint8 *data) {
- if (instrId > 127)
- return 3;
- assert(data);
- memcpy(&_fmInstruments[instrId * 48], data, 48);
- return 0;
-}
-
-int TownsAudioInterface::fmSetPitch(int chan, int pitch) {
- if (chan > 5)
- return 1;
-
- uint8 bl = _fmChanNote[chan];
- int frq = 0;
-
- if (pitch < 0) {
- if (bl) {
- if (pitch < -8008)
- pitch = -8008;
- pitch *= -1;
- pitch /= 13;
- frq = _frequency[(bl - 1) % 12] - pitch;
- bl = (bl - 1) / 12;
- _fmChanPitch[chan] = -pitch;
-
- if (frq < 616) {
- if (bl) {
- frq += 616;
- bl--;
- } else {
- frq = 616;
- bl = 0;
- }
- }
- } else {
- frq = 616;
- bl = 0;
- }
-
- } else if (pitch > 0) {
- if (bl < 96) {
- if (pitch > 8008)
- pitch = 8008;
- pitch /= 13;
-
- if (bl) {
- frq = _frequency[(bl - 1) % 12] + pitch;
- bl = (bl - 1) / 12;
- } else {
- frq = 616;
- bl = 0;
- }
-
- _fmChanPitch[chan] = pitch;
-
- if (frq > 1232) {
- if (bl < 7) {
- frq -= 616;
- bl++;
- } else {
- frq = 1164;
- bl = 7;
- }
- } else {
- if (bl >= 7 && frq > 1164)
- frq = 1164;
- }
-
- } else {
- frq = 1164;
- bl = 7;
- }
- } else {
- _fmChanPitch[chan] = 0;
- if (bl) {
- frq = _frequency[(bl - 1) % 12];
- bl = (bl - 1) / 12;
- } else {
- frq = 616;
- bl = 0;
- }
- }
-
- uint8 part = chan > 2 ? 1 : 0;
- if (chan > 2)
- chan -= 3;
-
- frq |= (bl << 11);
-
- bufferedWriteReg(part, chan + 0xa4, (frq >> 8));
- bufferedWriteReg(part, chan + 0xa0, (frq & 0xff));
-
- return 0;
-}
-
-int TownsAudioInterface::fmSetLevel(int chan, int lvl) {
- if (chan > 5)
- return 1;
- if (lvl > 127)
- return 3;
-
- uint8 part = chan > 2 ? 1 : 0;
- if (chan > 2)
- chan -= 3;
-
- uint16 c = _carrier[_fmSaveReg[part][0xb0 + chan] & 7];
- _fmSaveReg[part][0xd0 + chan] = lvl;
-
- for (uint8 reg = 0x40 + chan; reg < 0x50; reg += 4) {
- c += c;
- if (c & 0x100) {
- c &= 0xff;
- bufferedWriteReg(part, reg, (((((((_fmSaveReg[part][0x80 + reg] ^ 0x7f) * lvl) >> 7) + 1) * _fmSaveReg[part][0xe0 + chan]) >> 7) + 1) ^ 0x7f);
- }
- }
- return 0;
-}
-
-void TownsAudioInterface::bufferedWriteReg(uint8 part, uint8 regAddress, uint8 value) {
- _fmSaveReg[part][regAddress] = value;
- writeReg(part, regAddress, value);
-}
-
-void TownsAudioInterface::pcmReset() {
- _pcmChanOut = 0;
- _pcmChanReserved = _pcmChanKeyPressed = _pcmChanEffectPlaying = _pcmChanKeyPlaying = 0;
- _numReservedChannels = 0;
-
- memset(_pcmChanNote, 0, 8);
- memset(_pcmChanVelo, 0, 8);
- memset(_pcmChanLevel, 0, 8);
-
- for (int i = 0; i < 8; i++)
- _pcmChan[i].clear();
-
- memset(_pcmInstruments, 0, 128 * 32);
- static uint8 name[] = { 0x4E, 0x6F, 0x20, 0x44, 0x61, 0x74, 0x61, 0x21 };
- for (int i = 0; i < 32; i++)
- memcpy(_pcmInstruments + i * 128, name, 8);
-
- for (int i = 0; i < 128; i++)
- _waveTables[i].clear();
- _numWaveTables = 0;
- _waveTablesTotalDataSize = 0;
-
- for (int i = 0x40; i < 0x48; i++) {
- pcmSetInstrument(i, 0);
- pcmSetLevel(i, 127);
- }
-}
-
-int TownsAudioInterface::pcmKeyOn(int chan, int note, int velo) {
- if (chan < 0x40 || chan > 0x47)
- return 1;
-
- if (note & 0x80 || velo & 0x80)
- return 3;
-
- chan -= 0x40;
-
- if ((_pcmChanReserved & _chanFlags[chan]) || (_pcmChanKeyPressed & _chanFlags[chan]))
- return 2;
-
- _pcmChanNote[chan] = note;
- _pcmChanVelo[chan] = velo;
-
- TownsAudio_PcmChannel *p = &_pcmChan[chan];
- p->note = note;
-
- uint8 *instr = _pcmChan[chan].curInstrument;
- int i = 0;
- for (; i < 8; i++) {
- if (note <= instr[16 + 2 * i])
- break;
- }
-
- if (i == 8)
- return 8;
-
- int il = i << 3;
- p->note += instr[il + 70];
-
- p->envTotalLevel = instr[il + 64];
- p->envAttackRate = instr[il + 65];
- p->envDecayRate = instr[il + 66];
- p->envSustainLevel = instr[il + 67];
- p->envSustainRate = instr[il + 68];
- p->envReleaseRate = instr[il + 69];
- p->envStep = 0;
-
- int32 id = (int32)READ_LE_UINT32(&instr[i * 4 + 32]);
-
- for (i = 0; i < _numWaveTables; i++) {
- if (id == _waveTables[i].id)
- break;
- }
-
- if (i == _numWaveTables)
- return 9;
-
- TownsAudio_WaveTable *w = &_waveTables[i];
-
- p->data = w->data;
- p->dataEnd = w->data + w->size;
- p->setupLoop(w->loopStart, w->loopLen);
-
- pcmCalcPhaseStep(p, w);
-
- uint32 lvl = _pcmChanLevel[chan] * _pcmChanVelo[chan];
- p->envTotalLevel = ((p->envTotalLevel * lvl) >> 14) & 0xff;
- p->envSustainLevel = ((p->envSustainLevel * lvl) >> 14) & 0xff;
-
- p->envAttack();
- p->velo = (p->envCurrentLevel >> 8) << 1;
-
- _pcmChanKeyPressed |= _chanFlags[chan];
- _pcmChanKeyPlaying |= _chanFlags[chan];
- _pcmChanOut |= _chanFlags[chan];
-
- return 0;
-}
-
-int TownsAudioInterface::pcmKeyOff(int chan) {
- if (chan < 0x40 || chan > 0x47)
- return 1;
-
- chan -= 0x40;
- _pcmChanKeyPressed &= ~_chanFlags[chan];
- _pcmChan[chan].envRelease();
- return 0;
-}
-
-int TownsAudioInterface::pcmChanOff(int chan) {
- if (chan < 0x40 || chan > 0x47)
- return 1;
-
- chan -= 0x40;
-
- _pcmChanKeyPressed &= ~_chanFlags[chan];
- _pcmChanEffectPlaying &= ~_chanFlags[chan];
- _pcmChanKeyPlaying &= ~_chanFlags[chan];
- _pcmChanOut &= ~_chanFlags[chan];
-
- return 0;
-}
-
-int TownsAudioInterface::pcmSetPanPos(int chan, int mode) {
- if (chan > 0x47)
- return 1;
- if (mode & 0x80)
- return 3;
-
- chan -= 0x40;
- uint8 blc = 0x77;
-
- if (mode > 64) {
- mode -= 64;
- blc = ((blc ^ (mode >> 3)) + (mode << 4)) & 0xff;
- } else if (mode < 64) {
- mode = (mode >> 3) ^ 7;
- blc = ((119 + mode) ^ (mode << 4)) & 0xff;
- }
-
- _pcmChan[chan].panLeft = blc & 0x0f;
- _pcmChan[chan].panRight = blc >> 4;
-
- return 0;
-}
-
-int TownsAudioInterface::pcmSetInstrument(int chan, int instrId) {
- if (chan > 0x47)
- return 1;
- if (instrId > 31)
- return 3;
- chan -= 0x40;
- _pcmChan[chan].curInstrument = &_pcmInstruments[instrId * 128];
- return 0;
-}
-
-int TownsAudioInterface::pcmLoadInstrument(int instrId, const uint8 *data) {
- if (instrId > 31)
- return 3;
- assert(data);
- memcpy(&_pcmInstruments[instrId * 128], data, 128);
- return 0;
-}
-
-int TownsAudioInterface::pcmSetPitch(int chan, int pitch) {
- if (chan > 0x47)
- return 1;
-
- if (pitch < -8192 || pitch > 8191)
- return 3;
-
- chan -= 0x40;
- TownsAudio_PcmChannel *p = &_pcmChan[chan];
-
- uint32 pts = 0x4000;
-
- if (pitch < 0)
- pts = (0x20000000 / (-pitch + 0x2001)) >> 2;
- else if (pitch > 0)
- pts = (((pitch + 0x2001) << 16) / 0x2000) >> 2;
-
- p->stepPitch = pts & 0xffff;
- p->step = (p->stepNote * p->stepPitch) >> 14;
-
-// if (_pcmChanUnkFlag & _chanFlags[chan])
-// unk[chan] = (((p->step * 1000) << 11) / 98) / 20833;
-
- /*else*/
- if ((_pcmChanEffectPlaying & _chanFlags[chan]) && (p->step > 2048))
- p->step = 2048;
-
- return 0;
-}
-
-int TownsAudioInterface::pcmSetLevel(int chan, int lvl) {
- if (chan > 0x47)
- return 1;
-
- if (lvl & 0x80)
- return 3;
-
- chan -= 0x40;
- TownsAudio_PcmChannel *p = &_pcmChan[chan];
-
- if (_pcmChanReserved & _chanFlags[chan]) {
- _pcmChanVelo[chan] = lvl;
- p->velo = lvl << 1;
- } else {
- int32 t = p->envStep * lvl;
- if (_pcmChanLevel[chan])
- t /= _pcmChanLevel[chan];
- p->envStep = t;
- t = p->envCurrentLevel * lvl;
- if (_pcmChanLevel[chan])
- t /= _pcmChanLevel[chan];
- p->envCurrentLevel = t;
- _pcmChanLevel[chan] = lvl;
- p->velo = p->envCurrentLevel >> 8;
- }
-
- return 0;
-}
-
-void TownsAudioInterface::pcmUpdateEnvelopeGenerator(int chan) {
- TownsAudio_PcmChannel *p = &_pcmChan[chan];
- if (!p->envCurrentLevel) {
- _pcmChanKeyPlaying &= ~_chanFlags[chan];
- p->envState = kEnvReady;
- }
-
- if (!(_pcmChanKeyPlaying & _chanFlags[chan]))
- return;
-
- switch (p->envState) {
- case kEnvAttacking:
- if (((p->envCurrentLevel + p->envStep) >> 8) > p->envTotalLevel) {
- p->envDecay();
- return;
- } else {
- p->envCurrentLevel += p->envStep;
- }
- break;
-
- case kEnvDecaying:
- if (((p->envCurrentLevel - p->envStep) >> 8) < p->envSustainLevel) {
- p->envSustain();
- return;
- } else {
- p->envCurrentLevel -= p->envStep;
- }
- break;
-
- case kEnvSustaining:
- case kEnvReleasing:
- p->envCurrentLevel -= p->envStep;
- if (p->envCurrentLevel <= 0)
- p->envCurrentLevel = 0;
- break;
-
- default:
- break;
- }
- p->velo = (p->envCurrentLevel >> 8) << 1;
-}
-
-void TownsAudioInterface::pcmCalcPhaseStep(TownsAudio_PcmChannel *p, TownsAudio_WaveTable *w) {
- int8 diff = p->note - w->baseNote;
- uint16 r = w->rate + w->rateOffs;
- uint16 bl = 0;
- uint32 s = 0;
-
- if (diff < 0) {
- diff *= -1;
- bl = diff % 12;
- diff /= 12;
- s = (r >> diff);
- if (bl)
- s = (s * _pcmPhase2[bl]) >> 16;
-
- } else if (diff > 0) {
- bl = diff % 12;
- diff /= 12;
- s = (r << diff);
- if (bl)
- s += ((s * _pcmPhase1[bl]) >> 16);
-
- } else {
- s = r;
- }
-
- p->stepNote = s & 0xffff;
- p->step = (s * p->stepPitch) >> 14;
-}
-
-void TownsAudioInterface::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
- 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);
-}
-
-const uint8 TownsAudioInterface::_chanFlags[] = {
- 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80
-};
-
-const uint16 TownsAudioInterface::_frequency[] = {
- 0x028C, 0x02B4, 0x02DC, 0x030A, 0x0338, 0x0368, 0x039C, 0x03D4, 0x040E, 0x044A, 0x048C, 0x04D0
-};
-
-const uint8 TownsAudioInterface::_carrier[] = {
- 0x10, 0x10, 0x10, 0x10, 0x30, 0x70, 0x70, 0xF0
-};
-
-const uint8 TownsAudioInterface::_fmDefaultInstrument[] = {
- 0x45, 0x4C, 0x45, 0x50, 0x49, 0x41, 0x4E, 0x4F, 0x01, 0x0A, 0x02, 0x01,
- 0x1E, 0x32, 0x05, 0x00, 0x9C, 0xDC, 0x9C, 0xDC, 0x07, 0x03, 0x14, 0x08,
- 0x00, 0x03, 0x05, 0x05, 0x55, 0x45, 0x27, 0xA7, 0x04, 0xC0, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
-};
-
-const uint16 TownsAudioInterface::_pcmPhase1[] = {
- 0x879B, 0x0F37, 0x1F58, 0x306E, 0x4288, 0x55B6, 0x6A08, 0x7F8F, 0x965E, 0xAE88, 0xC882, 0xE341
-};
-
-const uint16 TownsAudioInterface::_pcmPhase2[] = {
- 0xFEFE, 0xF1A0, 0xE411, 0xD744, 0xCB2F, 0xBFC7, 0xB504, 0xAAE2, 0xA144, 0x9827, 0x8FAC
-};
-
-TownsAudio_PcmChannel::TownsAudio_PcmChannel() {
- extData = 0;
- clear();
-}
-
-TownsAudio_PcmChannel::~TownsAudio_PcmChannel() {
- clear();
-}
-
-void TownsAudio_PcmChannel::loadExtData(uint8 *buffer, uint32 size) {
- delete[] extData;
- extData = new int8[size];
- int8 *src = (int8 *)buffer;
- int8 *dst = extData;
- for (uint32 i = 0; i < size; i++)
- *dst++ = *src & 0x80 ? (*src++ & 0x7f) : -*src++;
-
- data = extData;
- dataEnd = extData + size;
- pos = 0;
-}
-
-void TownsAudio_PcmChannel::setupLoop(uint32 start, uint32 len) {
- loopLen = len << 11;
- loopEnd = loopLen ? &data[(start + loopLen) >> 11] : dataEnd;
- pos = start;
-}
-
-void TownsAudio_PcmChannel::clear() {
- curInstrument = 0;
- note = 0;
- velo = 0;
-
- data = 0;
- dataEnd = 0;
- loopLen = 0;
-
- pos = 0;
- loopEnd = 0;
-
- step = 0;
- stepNote = 0x4000;
- stepPitch = 0x4000;
-
- panLeft = panRight = 7;
-
- envTotalLevel = envAttackRate = envDecayRate = envSustainLevel = envSustainRate = envReleaseRate = 0;
- envStep = envCurrentLevel = 0;
-
- envState = kEnvReady;
-
- delete[] extData;
- extData = 0;
-}
-
-void TownsAudio_PcmChannel::envAttack() {
- envState = kEnvAttacking;
- int16 t = envTotalLevel << 8;
- if (envAttackRate == 127) {
- envStep = 0;
- } else if (envAttackRate) {
- envStep = t / envAttackRate;
- envCurrentLevel = 1;
- } else {
- envCurrentLevel = t;
- envDecay();
- }
-}
-
-void TownsAudio_PcmChannel::envDecay() {
- envState = kEnvDecaying;
- int16 t = envTotalLevel - envSustainLevel;
- if (t < 0 || envDecayRate == 127) {
- envStep = 0;
- } else if (envDecayRate) {
- envStep = (t << 8) / envDecayRate;
- } else {
- envCurrentLevel = envSustainLevel << 8;
- envSustain();
- }
-}
-
-void TownsAudio_PcmChannel::envSustain() {
- envState = kEnvSustaining;
- if (envSustainLevel && envSustainRate)
- envStep = (envSustainRate == 127) ? 0 : (envCurrentLevel / envSustainRate) >> 1;
- else
- envStep = envCurrentLevel = 1;
-}
-
-void TownsAudio_PcmChannel::envRelease() {
- envState = kEnvReleasing;
- if (envReleaseRate == 127)
- envStep = 0;
- else if (envReleaseRate)
- envStep = envCurrentLevel / envReleaseRate;
- else
- envStep = envCurrentLevel = 1;
-}
-
-TownsAudio_WaveTable::TownsAudio_WaveTable() {
- data = 0;
- clear();
-}
-
-TownsAudio_WaveTable::~TownsAudio_WaveTable() {
- clear();
-}
-
-void TownsAudio_WaveTable::readHeader(const uint8 *buffer) {
- memcpy(name, buffer, 8);
- name[8] = 0;
- id = READ_LE_UINT32(&buffer[8]);
- size = READ_LE_UINT32(&buffer[12]);
- loopStart = READ_LE_UINT32(&buffer[16]);
- loopLen = READ_LE_UINT32(&buffer[20]);
- rate = READ_LE_UINT16(&buffer[24]);
- rateOffs = READ_LE_UINT16(&buffer[26]);
- baseNote = READ_LE_UINT32(&buffer[28]);
-}
-
-void TownsAudio_WaveTable::readData(const uint8 *buffer) {
- if (!size)
- return;
-
- delete[] data;
- data = new int8[size];
-
- const int8 *src = (const int8 *)buffer;
- int8 *dst = data;
- for (uint32 i = 0; i < size; i++)
- *dst++ = *src & 0x80 ? (*src++ & 0x7f) : -*src++;
-}
-
-void TownsAudio_WaveTable::clear() {
- name[0] = name[8] = 0;
- id = -1;
- size = 0;
- loopStart = 0;
- loopLen = 0;
- rate = 0;
- rateOffs = 0;
- baseNote = 0;
- delete[] data;
- data = 0;
-}
-
diff --git a/sound/softsynth/fmtowns_pc98/towns_audio.h b/sound/softsynth/fmtowns_pc98/towns_audio.h
deleted file mode 100644
index 95fb1ded59..0000000000
--- a/sound/softsynth/fmtowns_pc98/towns_audio.h
+++ /dev/null
@@ -1,179 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * $URL$
- * $Id$
- *
- */
-
-#ifndef TOWNS_AUDIO_H
-#define TOWNS_AUDIO_H
-
-#include "sound/softsynth/fmtowns_pc98/towns_pc98_fmsynth.h"
-
-class TownsAudioInterfacePluginDriver {
-public:
- virtual ~TownsAudioInterfacePluginDriver() {}
- virtual void timerCallback(int timerId) = 0;
-};
-
-class TownsAudio_PcmChannel;
-class TownsAudio_WaveTable;
-
-class TownsAudioInterface : public TownsPC98_FmSynth {
-public:
- TownsAudioInterface(Audio::Mixer *mixer, TownsAudioInterfacePluginDriver *driver);
- ~TownsAudioInterface();
-
- bool init();
-
- int callback(int command, ...);
-
- void setMusicVolume(int volume);
- void setSoundEffectVolume(int volume);
- // Defines the channels used as sound effect channels for the purpose of ScummVM GUI volume control.
- // The first 6 bits are the 6 fm channels. The next 8 bits are pcm channels.
- void setSoundEffectChanMask(int mask);
-
-private:
- void nextTickEx(int32 *buffer, uint32 bufferSize);
-
- void timerCallbackA();
- void timerCallbackB();
-
- typedef int (TownsAudioInterface::*TownsAudioIntfCallback)(va_list &);
- const TownsAudioIntfCallback *_intfOpcodes;
-
- int intf_reset(va_list &args);
- int intf_keyOn(va_list &args);
- int intf_keyOff(va_list &args);
- int intf_setPanPos(va_list &args);
- int intf_setInstrument(va_list &args);
- int intf_loadInstrument(va_list &args);
- int intf_setPitch(va_list &args);
- int intf_setLevel(va_list &args);
- int intf_chanOff(va_list &args);
- int intf_writeReg(va_list &args);
- int intf_writeRegBuffer(va_list &args);
- int intf_readRegBuffer(va_list &args);
- int intf_setTimerA(va_list &args);
- int intf_setTimerB(va_list &args);
- int intf_enableTimerA(va_list &args);
- int intf_enableTimerB(va_list &args);
- int intf_loadSamples(va_list &args);
- int intf_reserveEffectChannels(va_list &args);
- int intf_loadWaveTable(va_list &args);
- int intf_unloadWaveTable(va_list &args);
- int intf_pcmPlayEffect(va_list &args);
- int intf_pcmChanOff(va_list &args);
- int intf_pcmEffectPlaying(va_list &args);
- int intf_fmKeyOn(va_list &args);
- int intf_fmKeyOff(va_list &args);
- int intf_fmSetPanPos(va_list &args);
- int intf_fmSetInstrument(va_list &args);
- int intf_fmLoadInstrument(va_list &args);
- int intf_fmSetPitch(va_list &args);
- int intf_fmSetLevel(va_list &args);
- int intf_fmReset(va_list &args);
- int intf_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);
-
- void fmReset();
- int fmKeyOn(int chan, int note, int velo);
- int fmKeyOff(int chan);
- int fmChanOff(int chan);
- int fmSetPanPos(int chan, int mode);
- int fmSetInstrument(int chan, int instrId);
- int fmLoadInstrument(int instrId, const uint8 *data);
- int fmSetPitch(int chan, int pitch);
- int fmSetLevel(int chan, int lvl);
-
- void bufferedWriteReg(uint8 part, uint8 regAddress, uint8 value);
-
- uint8 _fmChanPlaying;
- uint8 _fmChanNote[6];
- int16 _fmChanPitch[6];
-
- uint8 *_fmSaveReg[2];
- uint8 *_fmInstruments;
-
- void pcmReset();
- int pcmKeyOn(int chan, int note, int velo);
- int pcmKeyOff(int chan);
- int pcmChanOff(int chan);
- int pcmSetPanPos(int chan, int mode);
- int pcmSetInstrument(int chan, int instrId);
- int pcmLoadInstrument(int instrId, const uint8 *data);
- int pcmSetPitch(int chan, int pitch);
- int pcmSetLevel(int chan, int lvl);
- void pcmUpdateEnvelopeGenerator(int chan);
-
- TownsAudio_PcmChannel *_pcmChan;
- uint8 _pcmChanOut;
- uint8 _pcmChanReserved;
- uint8 _pcmChanKeyPressed;
- uint8 _pcmChanEffectPlaying;
- uint8 _pcmChanKeyPlaying;
-
- uint8 _pcmChanNote[8];
- uint8 _pcmChanVelo[8];
- uint8 _pcmChanLevel[8];
-
- uint8 _numReservedChannels;
- uint8 *_pcmInstruments;
-
- TownsAudio_WaveTable *_waveTables;
- uint8 _numWaveTables;
- uint32 _waveTablesTotalDataSize;
-
- void pcmCalcPhaseStep(TownsAudio_PcmChannel *p, TownsAudio_WaveTable *w);
-
- void updateOutputVolume();
- uint8 _outputVolumeFlags;
- uint8 _outputLevel[16];
- uint8 _outputMuteFlags;
-
- const float _baserate;
- uint32 _timerBase;
- uint32 _tickLength;
- uint32 _timer;
-
- uint16 _musicVolume;
- uint16 _sfxVolume;
- int _pcmSfxChanMask;
-
- TownsAudioInterfacePluginDriver *_drv;
- bool _ready;
-
- static const uint8 _chanFlags[];
- static const uint16 _frequency[];
- static const uint8 _carrier[];
- static const uint8 _fmDefaultInstrument[];
- static const uint16 _pcmPhase1[];
- static const uint16 _pcmPhase2[];
-};
-
-#endif
-
diff --git a/sound/softsynth/fmtowns_pc98/towns_euphony.cpp b/sound/softsynth/fmtowns_pc98/towns_euphony.cpp
deleted file mode 100644
index 3a691c407d..0000000000
--- a/sound/softsynth/fmtowns_pc98/towns_euphony.cpp
+++ /dev/null
@@ -1,905 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * $URL$
- * $Id$
- *
- */
-
-#include "sound/softsynth/fmtowns_pc98/towns_euphony.h"
-#include "common/endian.h"
-
-TownsEuphonyDriver::TownsEuphonyDriver(Audio::Mixer *mixer) : _activeChannels(0), _sustainChannels(0),
- _assignedChannels(0), _paraCount(0), _command(0), _tEnable(0), _tMode(0), _tOrdr(0), _tLevel(0),
- _tTranspose(0), _musicPos(0), _musicStart(0), _playing(false), _eventBuffer(0), _bufferedEventsCount(0),
- _tempoControlMode(0) {
- _para[0] = _para[1] = 0;
- _intf = new TownsAudioInterface(mixer, this);
- resetTempo();
-}
-
-TownsEuphonyDriver::~TownsEuphonyDriver() {
- delete _intf;
- delete[] _activeChannels;
- delete[] _sustainChannels;
- delete[] _assignedChannels;
- delete[] _tEnable;
- delete[] _tMode;
- delete[] _tOrdr;
- delete[] _tLevel;
- delete[] _tTranspose;
-}
-
-bool TownsEuphonyDriver::init() {
- if (!_intf->init())
- return false;
-
- _activeChannels = new int8[16];
- _sustainChannels = new int8[16];
- _assignedChannels = new ActiveChannel[128];
- _eventBuffer = new DlEvent[64];
-
- _tEnable = new uint8[32];
- _tMode = new uint8[32];
- _tOrdr = new uint8[32];
- _tLevel = new int8[32];
- _tTranspose = new int8[32];
-
- reset();
-
- return true;
-}
-
-void TownsEuphonyDriver::reset() {
- _intf->callback(0);
-
- _intf->callback(74);
- _intf->callback(70);
- _intf->callback(75, 3);
-
- setTimerA(true, 1);
- setTimerA(false, 1);
- setTimerB(true, 221);
-
- _paraCount = _command = _para[0] = _para[1] = 0;
- memset(_sustainChannels, 0, 16);
- memset(_activeChannels, -1, 16);
- for (int i = 0; i < 128; i++) {
- _assignedChannels[i].chan = _assignedChannels[i].next = -1;
- _assignedChannels[i].note = _assignedChannels[i].sub = 0;
- }
-
- int e = 0;
- for (int i = 0; i < 6; i++)
- assignChannel(i, e++);
- for (int i = 0x40; i < 0x48; i++)
- assignChannel(i, e++);
-
- resetTables();
-
- memset(_eventBuffer, 0, 64 * sizeof(DlEvent));
- _bufferedEventsCount = 0;
-
- _playing = _endOfTrack = _suspendParsing = _loop = false;
- _elapsedEvents = 0;
- _tempoDiff = 0;
-
- resetTempo();
-
- if (_tempoControlMode == 1) {
- //if (///)
- // return;
- setTempoIntern(_defaultTempo);
- } else {
- setTempoIntern(_defaultTempo);
- }
-
- resetControl();
-}
-
-void TownsEuphonyDriver::loadInstrument(int chanType, int id, const uint8 *data) {
- _intf->callback(5, chanType, id, data);
-}
-
-void TownsEuphonyDriver::loadWaveTable(const uint8 *data) {
- _intf->callback(34, data);
-}
-
-void TownsEuphonyDriver::unloadWaveTable(int id) {
- _intf->callback(35, id);
-}
-
-void TownsEuphonyDriver::reserveSoundEffectChannels(int num) {
- _intf->callback(33, num);
- uint32 volMask = 0;
-
- if (num > 8)
- return;
-
- for (uint32 v = 1 << 13; num; num--) {
- volMask |= v;
- v >>= 1;
- }
-
- _intf->setSoundEffectChanMask(volMask);
-}
-
-int TownsEuphonyDriver::setMusicTempo(int tempo) {
- if (tempo > 250)
- return 3;
- _defaultTempo = tempo;
- _trackTempo = tempo;
- setTempoIntern(tempo);
- return 0;
-}
-
-int TownsEuphonyDriver::startMusicTrack(const uint8 *data, int trackSize, int startTick) {
- if (_playing)
- return 2;
-
- _musicPos = _musicStart = data;
- _defaultBaseTickLen = _baseTickLen = startTick;
- _musicTrackSize = trackSize;
- _timeStampBase = _timeStampDest = 0;
- _tickCounter = 0;
- _playing = true;
-
- return 0;
-}
-
-void TownsEuphonyDriver::setMusicLoop(bool loop) {
- _loop = loop;
-}
-
-void TownsEuphonyDriver::stopParser() {
- if (_playing) {
- _playing = false;
- _pulseCount = 0;
- _endOfTrack = false;
- flushEventBuffer();
- resetControl();
- }
-}
-
-void TownsEuphonyDriver::continueParsing() {
- _suspendParsing = false;
-}
-
-void TownsEuphonyDriver::playSoundEffect(int chan, int note, int velo, const uint8 *data) {
- _intf->callback(37, chan, note, velo, data);
-}
-
-void TownsEuphonyDriver::stopSoundEffect(int chan) {
- _intf->callback(39, chan);
-}
-
-bool TownsEuphonyDriver::soundEffectIsPlaying(int chan) {
- return _intf->callback(40, chan) ? true : false;
-}
-
-void TownsEuphonyDriver::chanPanPos(int chan, int mode) {
- _intf->callback(3, chan, mode);
-}
-
-void TownsEuphonyDriver::chanPitch(int chan, int pitch) {
- _intf->callback(7, chan, pitch);
-}
-
-void TownsEuphonyDriver::chanVolume(int chan, int vol) {
- _intf->callback(8, chan, vol);
-}
-
-void TownsEuphonyDriver::setOutputVolume(int mode, int volLeft, int volRight) {
- _intf->callback(67, mode, volLeft, volRight);
-}
-
-int TownsEuphonyDriver::chanEnable(int tableEntry, int val) {
- if (tableEntry > 31)
- return 3;
- _tEnable[tableEntry] = val;
- return 0;
-}
-
-int TownsEuphonyDriver::chanMode(int tableEntry, int val) {
- if (tableEntry > 31)
- return 3;
- _tMode[tableEntry] = val;
- return 0;
-}
-
-int TownsEuphonyDriver::chanOrdr(int tableEntry, int val) {
- if (tableEntry > 31)
- return 3;
- if (val < 16)
- _tOrdr[tableEntry] = val;
- return 0;
-}
-
-int TownsEuphonyDriver::chanVolumeShift(int tableEntry, int val) {
- if (tableEntry > 31)
- return 3;
- if (val <= 40)
- _tLevel[tableEntry] = (int8)(val & 0xff);
- return 0;
-}
-
-int TownsEuphonyDriver::chanNoteShift(int tableEntry, int val) {
- if (tableEntry > 31)
- return 3;
- if (val <= 40)
- _tTranspose[tableEntry] = (int8)(val & 0xff);
- return 0;
-}
-
-int TownsEuphonyDriver::assignChannel(int chan, int tableEntry) {
- if (tableEntry > 15 || chan > 127 || chan < 0)
- return 3;
-
- ActiveChannel *a = &_assignedChannels[chan];
- if (a->chan == tableEntry)
- return 0;
-
- if (a->chan != -1) {
- int8 *b = &_activeChannels[a->chan];
- while (*b != chan) {
- b = &_assignedChannels[*b].next;
- if (*b == -1 && *b != chan)
- return 3;
- }
-
- *b = a->next;
-
- if (a->note)
- _intf->callback(2, chan);
-
- a->chan = a->next = -1;
- a->note = 0;
- }
-
- a->next = _activeChannels[tableEntry];
- _activeChannels[tableEntry] = chan;
- a->chan = tableEntry;
- a->note = a->sub = 0;
-
- return 0;
-}
-
-void TownsEuphonyDriver::timerCallback(int timerId) {
- switch (timerId) {
- case 0:
- updatePulseCount();
- while (_pulseCount > 0) {
- --_pulseCount;
- updateTimeStampBase();
- if (!_playing)
- continue;
- updateEventBuffer();
- updateParser();
- updateCheckEot();
- }
- break;
- default:
- break;
- }
-}
-
-void TownsEuphonyDriver::setMusicVolume(int volume) {
- _intf->setMusicVolume(volume);
-}
-
-void TownsEuphonyDriver::setSoundEffectVolume(int volume) {
- _intf->setSoundEffectVolume(volume);
-}
-
-void TownsEuphonyDriver::resetTables() {
- memset(_tEnable, 0xff, 32);
- memset(_tMode, 0xff, 16);
- memset(_tMode + 16, 0, 16);
- for (int i = 0; i < 32; i++)
- _tOrdr[i] = i & 0x0f;
- memset(_tLevel, 0, 32);
- memset(_tTranspose, 0, 32);
-}
-
-void TownsEuphonyDriver::resetTempo() {
- _defaultBaseTickLen = _baseTickLen = 0x33;
- _pulseCount = 0;
- _extraTimingControlRemainder = 0;
- _extraTimingControl = 16;
- _tempoModifier = 0;
- _timeStampDest = 0;
- _deltaTicks = 0;
- _tickCounter = 0;
- _defaultTempo = 90;
- _trackTempo = 90;
-}
-
-void TownsEuphonyDriver::setTempoIntern(int tempo) {
- tempo = CLIP(tempo + _tempoModifier, 0, 500);
- if (_tempoControlMode == 0) {
- _timerSetting = 34750 / (tempo + 30);
- _extraTimingControl = 16;
-
- while (_timerSetting < 126) {
- _timerSetting <<= 1;
- _extraTimingControl <<= 1;
- }
-
- while (_timerSetting > 383) {
- _timerSetting >>= 1;
- _extraTimingControl >>= 1;
- }
-
- setTimerA(true, -(_timerSetting - 2));
-
- } else if (_tempoControlMode == 1) {
- _timerSetting = 312500 / (tempo + 30);
- _extraTimingControl = 16;
- while (_timerSetting < 1105) {
- _timerSetting <<= 1;
- _extraTimingControl <<= 1;
- }
-
- } else if (_tempoControlMode == 2) {
- _timerSetting = 625000 / (tempo + 30);
- _extraTimingControlRemainder = 0;
- }
-}
-
-void TownsEuphonyDriver::setTimerA(bool enable, int tempo) {
- _intf->callback(21, enable ? 255 : 0, tempo);
-}
-
-void TownsEuphonyDriver::setTimerB(bool enable, int tempo) {
- _intf->callback(22, enable ? 255 : 0, tempo);
-}
-
-void TownsEuphonyDriver::updatePulseCount() {
- int tc = _extraTimingControl + _extraTimingControlRemainder;
- _extraTimingControlRemainder = tc & 0x0f;
- tc >>= 4;
- _tempoDiff -= tc;
-
- while (_tempoDiff < 0) {
- _elapsedEvents++;
- _tempoDiff += 4;
- }
-
- if (_playing && !_suspendParsing)
- _pulseCount += tc;
-}
-
-void TownsEuphonyDriver::updateTimeStampBase() {
- static const uint16 table[] = { 0x180, 0xC0, 0x80, 0x60, 0x40, 0x30, 0x20, 0x18 };
- if ((uint32)(table[_baseTickLen >> 4] * ((_baseTickLen & 0x0f) + 1)) > ++_tickCounter)
- return;
- ++_timeStampDest;
- _tickCounter = 0;
- _deltaTicks = 0;
-}
-
-void TownsEuphonyDriver::updateParser() {
- for (bool loop = true; loop;) {
- uint8 cmd = _musicPos[0];
-
- if (cmd == 0xff || cmd == 0xf7) {
- jumpNextLoop();
-
- } else if (cmd < 0x90) {
- _endOfTrack = true;
- flushEventBuffer();
- loop = false;
-
- } else if (_timeStampBase > _timeStampDest) {
- loop = false;
-
- } else {
- if (_timeStampBase == _timeStampDest) {
- uint16 timeStamp = READ_LE_UINT16(&_musicPos[2]);
- uint8 l = (timeStamp & 0xff) + (timeStamp & 0xff);
- timeStamp = ((timeStamp & 0xff00) | l) >> 1;
- if (timeStamp > _tickCounter)
- loop = false;
- }
-
- if (loop) {
- if (parseNext())
- loop = false;
- }
- }
- }
-}
-
-void TownsEuphonyDriver::updateCheckEot() {
- if (!_endOfTrack || _bufferedEventsCount)
- return;
- stopParser();
-}
-
-bool TownsEuphonyDriver::parseNext() {
-#define OPC(x) &TownsEuphonyDriver::evt##x
- static const EuphonyOpcode opcodes[] = {
- OPC(NotImpl),
- OPC(SetupNote),
- OPC(PolyphonicAftertouch),
- OPC(ControlPitch),
- OPC(InstrumentChanAftertouch),
- OPC(InstrumentChanAftertouch),
- OPC(ControlPitch)
- };
-#undef OPC
-
- uint cmd = _musicPos[0];
- if (cmd != 0xfe && cmd != 0xfd) {
- if (cmd >= 0xf0) {
- cmd &= 0x0f;
- if (cmd == 0)
- evtLoadInstrument();
- else if (cmd == 2)
- evtAdvanceTimestampOffset();
- else if (cmd == 8)
- evtTempo();
- else if (cmd == 12)
- evtModeOrdrChange();
- jumpNextLoop();
- return false;
-
- } else if (!(this->*opcodes[(cmd - 0x80) >> 4])()) {
- jumpNextLoop();
- return false;
- }
- }
-
- if (cmd == 0xfd) {
- _suspendParsing = true;
- return true;
- }
-
- if (!_loop) {
- _endOfTrack = true;
- return true;
- }
-
- _endOfTrack = false;
- _musicPos = _musicStart;
- _timeStampBase = _timeStampDest = _tickCounter = 0;
- _baseTickLen = _defaultBaseTickLen;
-
- return false;
-}
-
-void TownsEuphonyDriver::jumpNextLoop() {
- _musicPos += 6;
- if (_musicPos >= _musicStart + _musicTrackSize)
- _musicPos = _musicStart;
-}
-
-void TownsEuphonyDriver::updateEventBuffer() {
- DlEvent *e = _eventBuffer;
- for (int i = _bufferedEventsCount; i; e++) {
- if (e->evt == 0)
- continue;
- if (--e->len) {
- --i;
- continue;
- }
- processBufferNote(e->mode, e->evt, e->note, e->velo);
- e->evt = 0;
- --i;
- --_bufferedEventsCount;
- }
-}
-
-void TownsEuphonyDriver::flushEventBuffer() {
- DlEvent *e = _eventBuffer;
- for (int i = _bufferedEventsCount; i; e++) {
- if (e->evt == 0)
- continue;
- processBufferNote(e->mode, e->evt, e->note, e->velo);
- e->evt = 0;
- --i;
- --_bufferedEventsCount;
- }
-}
-
-void TownsEuphonyDriver::processBufferNote(int mode, int evt, int note, int velo) {
- if (!velo)
- evt &= 0x8f;
- sendEvent(mode, evt);
- sendEvent(mode, note);
- sendEvent(mode, velo);
-}
-
-void TownsEuphonyDriver::resetControl() {
- for (int i = 0; i < 32; i++) {
- if (_tOrdr[i] > 15) {
- for (int ii = 0; ii < 16; ii++)
- resetControlIntern(_tMode[i], ii);
- } else {
- resetControlIntern(_tMode[i], _tOrdr[i]);
- }
- }
-}
-
-void TownsEuphonyDriver::resetControlIntern(int mode, int chan) {
- sendEvent(mode, 0xb0 | chan);
- sendEvent(mode, 0x40);
- sendEvent(mode, 0);
- sendEvent(mode, 0xb0 | chan);
- sendEvent(mode, 0x7b);
- sendEvent(mode, 0);
- sendEvent(mode, 0xb0 | chan);
- sendEvent(mode, 0x79);
- sendEvent(mode, 0x40);
-}
-
-uint8 TownsEuphonyDriver::appendEvent(uint8 evt, uint8 chan) {
- if (evt >= 0x80 && evt < 0xf0 && _tOrdr[chan] < 16)
- return (evt & 0xf0) | _tOrdr[chan];
- return evt;
-}
-
-void TownsEuphonyDriver::sendEvent(uint8 mode, uint8 command) {
- if (mode == 0) {
- // warning("TownsEuphonyDriver: Mode 0 not implemented");
-
- } else if (mode == 0x10) {
- warning("TownsEuphonyDriver: Mode 0x10 not implemented");
-
- } else if (mode == 0xff) {
- if (command >= 0xf0) {
- _paraCount = 1;
- _command = 0;
- } else if (command >= 0x80) {
- _paraCount = 1;
- _command = command;
- } else if (_command >= 0x80) {
- switch ((_command - 0x80) >> 4) {
- case 0:
- if (_paraCount < 2) {
- _paraCount++;
- _para[0] = command;
- } else {
- _paraCount = 1;
- _para[1] = command;
- sendNoteOff();
- }
- break;
-
- case 1:
- if (_paraCount < 2) {
- _paraCount++;
- _para[0] = command;
- } else {
- _paraCount = 1;
- _para[1] = command;
- if (command)
- sendNoteOn();
- else
- sendNoteOff();
- }
- break;
-
- case 2:
- if (_paraCount < 2) {
- _paraCount++;
- _para[0] = command;
- } else {
- _paraCount = 1;
- }
- break;
-
- case 3:
- if (_paraCount < 2) {
- _paraCount++;
- _para[0] = command;
- } else {
- _paraCount = 1;
- _para[1] = command;
-
- if (_para[0] == 7)
- sendChanVolume();
- else if (_para[0] == 10)
- sendPanPosition();
- else if (_para[0] == 64)
- sendAllNotesOff();
- }
- break;
-
- case 4:
- _paraCount = 1;
- _para[0] = command;
- sendSetInstrument();
- break;
-
- case 5:
- _paraCount = 1;
- _para[0] = command;
- break;
-
- case 6:
- if (_paraCount < 2) {
- _paraCount++;
- _para[0] = command;
- } else {
- _paraCount = 1;
- _para[1] = command;
- sendPitch();
- }
- break;
- }
- }
- }
-}
-
-bool TownsEuphonyDriver::evtSetupNote() {
- if (_musicPos[1] > 31)
- return false;
- if (!_tEnable[_musicPos[1]]) {
- jumpNextLoop();
- return (_musicPos[0] == 0xfe || _musicPos[0] == 0xfd) ? true : false;
- }
- uint8 evt = appendEvent(_musicPos[0], _musicPos[1]);
- uint8 mode = _tMode[_musicPos[1]];
- uint8 note = _musicPos[4];
- uint8 velo = _musicPos[5];
-
- sendEvent(mode, evt);
- sendEvent(mode, applyNoteShift(note));
- sendEvent(mode, applyVolumeShift(velo));
-
- jumpNextLoop();
- if (_musicPos[0] == 0xfe || _musicPos[0] == 0xfd)
- return true;
-
- velo = _musicPos[5];
- uint16 len = ((((_musicPos[1] << 4) | (_musicPos[2] << 8)) >> 4) & 0xff) | ((((_musicPos[3] << 4) | (_musicPos[4] << 8)) >> 4) << 8);
-
- int i = 0;
- for (; i < 64; i++) {
- if (_eventBuffer[i].evt == 0)
- break;
- }
-
- if (i == 64) {
- processBufferNote(mode, evt, note, velo);
- } else {
- _eventBuffer[i].evt = evt;
- _eventBuffer[i].mode = mode;
- _eventBuffer[i].note = note;
- _eventBuffer[i].velo = velo;
- _eventBuffer[i].len = len ? len : 1;
- _bufferedEventsCount++;
- }
-
- return false;
-}
-
-bool TownsEuphonyDriver::evtPolyphonicAftertouch() {
- if (_musicPos[1] > 31)
- return false;
- if (!_tEnable[_musicPos[1]])
- return false;
-
- uint8 evt = appendEvent(_musicPos[0], _musicPos[1]);
- uint8 mode = _tMode[_musicPos[1]];
-
- sendEvent(mode, evt);
- sendEvent(mode, applyNoteShift(_musicPos[4]));
- sendEvent(mode, _musicPos[5]);
-
- return false;
-}
-
-bool TownsEuphonyDriver::evtControlPitch() {
- if (_musicPos[1] > 31)
- return false;
- if (!_tEnable[_musicPos[1]])
- return false;
-
- uint8 evt = appendEvent(_musicPos[0], _musicPos[1]);
- uint8 mode = _tMode[_musicPos[1]];
-
- sendEvent(mode, evt);
- sendEvent(mode, _musicPos[4]);
- sendEvent(mode, _musicPos[5]);
-
- return false;
-}
-
-bool TownsEuphonyDriver::evtInstrumentChanAftertouch() {
- if (_musicPos[1] > 31)
- return false;
- if (!_tEnable[_musicPos[1]])
- return false;
-
- uint8 evt = appendEvent(_musicPos[0], _musicPos[1]);
- uint8 mode = _tMode[_musicPos[1]];
-
- sendEvent(mode, evt);
- sendEvent(mode, _musicPos[4]);
-
- return false;
-}
-
-bool TownsEuphonyDriver::evtLoadInstrument() {
- return false;
-}
-
-bool TownsEuphonyDriver::evtAdvanceTimestampOffset() {
- ++_timeStampBase;
- _baseTickLen = _musicPos[1];
- return false;
-}
-
-bool TownsEuphonyDriver::evtTempo() {
- uint8 l = _musicPos[4] << 1;
- _trackTempo = (l | (_musicPos[5] << 8)) >> 1;
- setTempoIntern(_trackTempo);
- return false;
-}
-
-bool TownsEuphonyDriver::evtModeOrdrChange() {
- if (_musicPos[1] > 31)
- return false;
- if (!_tEnable[_musicPos[1]])
- return false;
-
- if (_musicPos[4] == 1)
- _tMode[_musicPos[1]] = _musicPos[5];
- else if (_musicPos[4] == 2)
- _tOrdr[_musicPos[1]] = _musicPos[5];
-
- return false;
-}
-
-uint8 TownsEuphonyDriver::applyNoteShift(uint8 in) {
- int out = _tTranspose[_musicPos[1]];
- if (!out)
- return in;
- out += (in & 0x7f);
-
- if (out > 127)
- out -= 12;
-
- if (out < 0)
- out += 12;
-
- return out & 0xff;
-}
-
-uint8 TownsEuphonyDriver::applyVolumeShift(uint8 in) {
- int out = _tLevel[_musicPos[1]];
- out += (in & 0x7f);
- out = CLIP(out, 1, 127);
-
- return out & 0xff;
-}
-
-void TownsEuphonyDriver::sendNoteOff() {
- int8 *chan = &_activeChannels[_command & 0x0f];
- if (*chan == -1)
- return;
-
- while (_assignedChannels[*chan].note != _para[0]) {
- chan = &_assignedChannels[*chan].next;
- if (*chan == -1)
- return;
- }
-
- if (_sustainChannels[_command & 0x0f]) {
- _assignedChannels[*chan].note |= 0x80;
- } else {
- _assignedChannels[*chan].note = 0;
- _intf->callback(2, *chan);
- }
-}
-
-void TownsEuphonyDriver::sendNoteOn() {
- if (!_para[0])
- return;
- int8 *chan = &_activeChannels[_command & 0x0f];
- if (*chan == -1)
- return;
-
- do {
- _assignedChannels[*chan].sub++;
- chan = &_assignedChannels[*chan].next;
- } while (*chan != -1);
-
- chan = &_activeChannels[_command & 0x0f];
-
- int d = 0;
- int c = 0;
- bool found = false;
-
- do {
- if (!_assignedChannels[*chan].note) {
- found = true;
- break;
- }
- if (d <= _assignedChannels[*chan].sub) {
- c = *chan;
- d = _assignedChannels[*chan].sub;
- }
- chan = &_assignedChannels[*chan].next;
- } while (*chan != -1);
-
- if (found)
- c = *chan;
- else
- _intf->callback(2, c);
-
- _assignedChannels[c].note = _para[0];
- _assignedChannels[c].sub = 0;
- _intf->callback(1, c, _para[0], _para[1]);
-}
-
-void TownsEuphonyDriver::sendChanVolume() {
- int8 *chan = &_activeChannels[_command & 0x0f];
- while (*chan != -1) {
- _intf->callback(8, *chan, _para[1] & 0x7f);
- chan = &_assignedChannels[*chan].next;
- }
-}
-
-void TownsEuphonyDriver::sendPanPosition() {
- int8 *chan = &_activeChannels[_command & 0x0f];
- while (*chan != -1) {
- _intf->callback(3, *chan, _para[1] & 0x7f);
- chan = &_assignedChannels[*chan].next;
- }
-}
-
-void TownsEuphonyDriver::sendAllNotesOff() {
- if (_para[1] > 63) {
- _sustainChannels[_command & 0x0f] = -1;
- return;
- }
-
- _sustainChannels[_command & 0x0f] = 0;
- int8 *chan = &_activeChannels[_command & 0x0f];
- while (*chan != -1) {
- if (_assignedChannels[*chan].note & 0x80) {
- _assignedChannels[*chan].note = 0;
- _intf->callback(2, *chan);
- }
- chan = &_assignedChannels[*chan].next;
- }
-}
-
-void TownsEuphonyDriver::sendSetInstrument() {
- int8 *chan = &_activeChannels[_command & 0x0f];
- while (*chan != -1) {
- _intf->callback(4, *chan, _para[0]);
- _intf->callback(7, *chan, 0);
- chan = &_assignedChannels[*chan].next;
- }
-}
-
-void TownsEuphonyDriver::sendPitch() {
- int8 *chan = &_activeChannels[_command & 0x0f];
- while (*chan != -1) {
- _para[0] += _para[0];
- int16 pitch = (((READ_LE_UINT16(_para)) >> 1) & 0x3fff) - 0x2000;
- _intf->callback(7, *chan, pitch);
- chan = &_assignedChannels[*chan].next;
- }
-}
diff --git a/sound/softsynth/fmtowns_pc98/towns_euphony.h b/sound/softsynth/fmtowns_pc98/towns_euphony.h
deleted file mode 100644
index fa1f8ba496..0000000000
--- a/sound/softsynth/fmtowns_pc98/towns_euphony.h
+++ /dev/null
@@ -1,187 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * $URL$
- * $Id$
- *
- */
-
-#ifndef TOWNS_EUP_H
-#define TOWNS_EUP_H
-
-#include "sound/softsynth/fmtowns_pc98/towns_audio.h"
-
-class TownsEuphonyDriver : public TownsAudioInterfacePluginDriver {
-public:
- TownsEuphonyDriver(Audio::Mixer *mixer);
- virtual ~TownsEuphonyDriver();
-
- bool init();
- void reset();
-
- void loadInstrument(int chanType, int id, const uint8 *data);
- void loadWaveTable(const uint8 *data);
- void unloadWaveTable(int id);
- void reserveSoundEffectChannels(int num);
-
- int setMusicTempo(int tempo);
- int startMusicTrack(const uint8 *data, int trackSize, int startTick);
- void setMusicLoop(bool loop);
- void stopParser();
- bool parserIsPlaying() {return _playing; }
- void continueParsing();
-
- void playSoundEffect(int chan, int note, int velo, const uint8 *data);
- void stopSoundEffect(int chan);
- bool soundEffectIsPlaying(int chan);
-
- void chanPanPos(int chan, int mode);
- void chanPitch(int chan, int pitch);
- void chanVolume(int chan, int vol);
-
- void setOutputVolume(int chanType, int volLeft, int volRight);
-
- int chanEnable(int tableEntry, int val);
- int chanMode(int tableEntry, int val);
- int chanOrdr(int tableEntry, int val);
- int chanVolumeShift(int tableEntry, int val);
- int chanNoteShift(int tableEntry, int val);
-
- int assignChannel(int chan, int tableEntry);
-
- void timerCallback(int timerId);
-
- void setMusicVolume(int volume);
- void setSoundEffectVolume(int volume);
-
- TownsAudioInterface *intf() {
- return _intf;
- }
-
-private:
- void resetTables();
-
- void resetTempo();
- void setTempoIntern(int tempo);
- void setTimerA(bool enable, int tempo);
- void setTimerB(bool enable, int tempo);
-
- void updatePulseCount();
- void updateTimeStampBase();
- void updateParser();
- void updateCheckEot();
-
- bool parseNext();
- void jumpNextLoop();
-
- void updateEventBuffer();
- void flushEventBuffer();
- void processBufferNote(int mode, int evt, int note, int velo);
-
- void resetControl();
- void resetControlIntern(int mode, int chan);
- uint8 appendEvent(uint8 evt, uint8 chan);
-
- void sendEvent(uint8 mode, uint8 command);
-
- typedef bool(TownsEuphonyDriver::*EuphonyOpcode)();
- bool evtSetupNote();
- bool evtPolyphonicAftertouch();
- bool evtControlPitch();
- bool evtInstrumentChanAftertouch();
- bool evtLoadInstrument();
- bool evtAdvanceTimestampOffset();
- bool evtTempo();
- bool evtModeOrdrChange();
- bool evtNotImpl() {
- return false;
- }
-
- uint8 applyNoteShift(uint8 in);
- uint8 applyVolumeShift(uint8 in);
-
- void sendNoteOff();
- void sendNoteOn();
- void sendChanVolume();
- void sendPanPosition();
- void sendAllNotesOff();
- void sendSetInstrument();
- void sendPitch();
-
- int8 *_activeChannels;
- int8 *_sustainChannels;
-
- struct ActiveChannel {
- int8 chan;
- int8 next;
- uint8 note;
- uint8 sub;
- } *_assignedChannels;
-
- uint8 *_tEnable;
- uint8 *_tMode;
- uint8 *_tOrdr;
- int8 *_tLevel;
- int8 *_tTranspose;
-
- struct DlEvent {
- uint8 evt;
- uint8 mode;
- uint8 note;
- uint8 velo;
- uint16 len;
- } *_eventBuffer;
- int _bufferedEventsCount;
-
- uint8 _para[2];
- uint8 _paraCount;
- uint8 _command;
-
- uint8 _defaultBaseTickLen;
- uint8 _baseTickLen;
- uint32 _pulseCount;
- int _tempoControlMode;
- int _extraTimingControlRemainder;
- int _extraTimingControl;
- int _timerSetting;
- int8 _tempoDiff;
- int _tempoModifier;
- uint32 _timeStampDest;
- uint32 _timeStampBase;
- int8 _elapsedEvents;
- uint8 _deltaTicks;
- uint32 _tickCounter;
- uint8 _defaultTempo;
- int _trackTempo;
-
- bool _loop;
- bool _playing;
- bool _endOfTrack;
- bool _suspendParsing;
-
- const uint8 *_musicStart;
- const uint8 *_musicPos;
- uint32 _musicTrackSize;
-
- TownsAudioInterface *_intf;
-};
-
-#endif
-
diff --git a/sound/softsynth/fmtowns_pc98/towns_pc98_driver.cpp b/sound/softsynth/fmtowns_pc98/towns_pc98_driver.cpp
deleted file mode 100644
index 303f08e6b1..0000000000
--- a/sound/softsynth/fmtowns_pc98/towns_pc98_driver.cpp
+++ /dev/null
@@ -1,1428 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * $URL$
- * $Id$
- *
- */
-
-#include "sound/softsynth/fmtowns_pc98/towns_pc98_driver.h"
-#include "common/endian.h"
-
-class TownsPC98_MusicChannel {
-public:
- TownsPC98_MusicChannel(TownsPC98_AudioDriver *driver, uint8 regOffs, uint8 flgs, uint8 num,
- uint8 key, uint8 prt, uint8 id);
- virtual ~TownsPC98_MusicChannel();
- virtual void init();
-
- typedef enum channelState {
- CHS_RECALCFREQ = 0x01,
- CHS_KEYOFF = 0x02,
- CHS_SSGOFF = 0x04,
- CHS_VBROFF = 0x08,
- CHS_ALLOFF = 0x0f,
- CHS_PROTECT = 0x40,
- CHS_EOT = 0x80
- } ChannelState;
-
- virtual void loadData(uint8 *data);
- virtual void processEvents();
- virtual void processFrequency();
- virtual bool processControlEvent(uint8 cmd);
-
- virtual void keyOn();
- void keyOff();
-
- void setOutputLevel();
- virtual void fadeStep();
- virtual void reset();
-
- const uint8 _idFlag;
-
-protected:
- void setupVibrato();
- bool processVibrato();
-
- bool control_dummy(uint8 para);
- bool control_f0_setPatch(uint8 para);
- bool control_f1_presetOutputLevel(uint8 para);
- bool control_f2_setKeyOffTime(uint8 para);
- bool control_f3_setFreqLSB(uint8 para);
- bool control_f4_setOutputLevel(uint8 para);
- bool control_f5_setTempo(uint8 para);
- bool control_f6_repeatSection(uint8 para);
- bool control_f7_setupVibrato(uint8 para);
- bool control_f8_toggleVibrato(uint8 para);
- bool control_fa_writeReg(uint8 para);
- virtual bool control_fb_incOutLevel(uint8 para);
- virtual bool control_fc_decOutLevel(uint8 para);
- bool control_fd_jump(uint8 para);
- virtual bool control_ff_endOfTrack(uint8 para);
-
- uint8 _ticksLeft;
- uint8 _algorithm;
- uint8 _instr;
- uint8 _totalLevel;
- uint8 _frqBlockMSB;
- int8 _frqLSB;
- uint8 _keyOffTime;
- bool _hold;
- uint8 *_dataPtr;
- uint8 _vbrInitDelayHi;
- uint8 _vbrInitDelayLo;
- int16 _vbrModInitVal;
- uint8 _vbrDuration;
- uint8 _vbrCurDelay;
- int16 _vbrModCurVal;
- uint8 _vbrDurLeft;
- uint16 _frequency;
- uint8 _block;
- uint8 _regOffset;
- uint8 _flags;
- uint8 _ssgTl;
- uint8 _ssgStep;
- uint8 _ssgTicksLeft;
- uint8 _ssgTargetLvl;
- uint8 _ssgStartLvl;
-
- const uint8 _chanNum;
- const uint8 _keyNum;
- const uint8 _part;
-
- TownsPC98_AudioDriver *_drv;
-
- typedef bool (TownsPC98_MusicChannel::*ControlEventFunc)(uint8 para);
- const ControlEventFunc *controlEvents;
-};
-
-class TownsPC98_MusicChannelSSG : public TownsPC98_MusicChannel {
-public:
- TownsPC98_MusicChannelSSG(TownsPC98_AudioDriver *driver, uint8 regOffs,
- uint8 flgs, uint8 num, uint8 key, uint8 prt, uint8 id);
- virtual ~TownsPC98_MusicChannelSSG() {}
- void init();
-
- virtual void loadData(uint8 *data);
- void processEvents();
- void processFrequency();
- bool processControlEvent(uint8 cmd);
-
- void keyOn();
- void nextShape();
-
- void protect();
- void restore();
- virtual void reset();
-
- void fadeStep();
-
-protected:
- void setOutputLevel(uint8 lvl);
-
- bool control_f0_setPatch(uint8 para);
- bool control_f1_setTotalLevel(uint8 para);
- bool control_f4_setAlgorithm(uint8 para);
- bool control_f9_loadCustomPatch(uint8 para);
- bool control_fb_incOutLevel(uint8 para);
- bool control_fc_decOutLevel(uint8 para);
- bool control_ff_endOfTrack(uint8 para);
-
- typedef bool (TownsPC98_MusicChannelSSG::*ControlEventFunc)(uint8 para);
- const ControlEventFunc *controlEvents;
-};
-
-class TownsPC98_SfxChannel : public TownsPC98_MusicChannelSSG {
-public:
- TownsPC98_SfxChannel(TownsPC98_AudioDriver *driver, uint8 regOffs,
- uint8 flgs, uint8 num, uint8 key, uint8 prt, uint8 id) :
- TownsPC98_MusicChannelSSG(driver, regOffs, flgs, num, key, prt, id) {}
- ~TownsPC98_SfxChannel() {}
-
- void loadData(uint8 *data);
- void reset();
-};
-
-#ifndef DISABLE_PC98_RHYTHM_CHANNEL
-class TownsPC98_MusicChannelPCM : public TownsPC98_MusicChannel {
-public:
- TownsPC98_MusicChannelPCM(TownsPC98_AudioDriver *driver, uint8 regOffs,
- uint8 flgs, uint8 num, uint8 key, uint8 prt, uint8 id);
- ~TownsPC98_MusicChannelPCM() {}
- void init();
-
- void loadData(uint8 *data);
- void processEvents();
- bool processControlEvent(uint8 cmd);
-
-private:
- bool control_f1_prcStart(uint8 para);
- bool control_ff_endOfTrack(uint8 para);
-
- typedef bool (TownsPC98_MusicChannelPCM::*ControlEventFunc)(uint8 para);
- const ControlEventFunc *controlEvents;
-};
-#endif
-
-TownsPC98_MusicChannel::TownsPC98_MusicChannel(TownsPC98_AudioDriver *driver, uint8 regOffs, uint8 flgs, uint8 num,
- uint8 key, uint8 prt, uint8 id) : _drv(driver), _regOffset(regOffs), _flags(flgs), _chanNum(num), _keyNum(key),
- _part(prt), _idFlag(id), controlEvents(0) {
-
- _ticksLeft = _algorithm = _instr = _totalLevel = _frqBlockMSB = _keyOffTime = 0;
- _ssgStartLvl = _ssgTl = _ssgStep = _ssgTicksLeft = _ssgTargetLvl = _block = 0;
- _vbrInitDelayHi = _vbrInitDelayLo = _vbrDuration = _vbrCurDelay = _vbrDurLeft = 0;
- _frqLSB = 0;
- _hold = false;
- _dataPtr = 0;
- _vbrModInitVal = _vbrModCurVal = 0;
- _frequency = 0;
-}
-
-TownsPC98_MusicChannel::~TownsPC98_MusicChannel() {
-}
-
-void TownsPC98_MusicChannel::init() {
-#define Control(x) &TownsPC98_MusicChannel::control_##x
- static const ControlEventFunc ctrlEvents[] = {
- Control(f0_setPatch),
- Control(f1_presetOutputLevel),
- Control(f2_setKeyOffTime),
- Control(f3_setFreqLSB),
- Control(f4_setOutputLevel),
- Control(f5_setTempo),
- Control(f6_repeatSection),
- Control(f7_setupVibrato),
- Control(f8_toggleVibrato),
- Control(dummy),
- Control(fa_writeReg),
- Control(fb_incOutLevel),
- Control(fc_decOutLevel),
- Control(fd_jump),
- Control(dummy),
- Control(ff_endOfTrack)
- };
-#undef Control
-
- controlEvents = ctrlEvents;
-}
-
-void TownsPC98_MusicChannel::keyOff() {
- // all operators off
- uint8 value = _keyNum & 0x0f;
- if (_part)
- value |= 4;
- uint8 regAddress = 0x28;
- _drv->writeReg(0, regAddress, value);
- _flags |= CHS_KEYOFF;
-}
-
-void TownsPC98_MusicChannel::keyOn() {
- // all operators on
- uint8 value = _keyNum | 0xf0;
- if (_part)
- value |= 4;
- uint8 regAddress = 0x28;
- _drv->writeReg(0, regAddress, value);
-}
-
-void TownsPC98_MusicChannel::loadData(uint8 *data) {
- _flags = (_flags & ~CHS_EOT) | CHS_ALLOFF;
- _ticksLeft = 1;
- _dataPtr = data;
- _totalLevel = 0x7F;
-
- uint8 *tmp = _dataPtr;
- for (bool loop = true; loop;) {
- uint8 cmd = *tmp++;
- if (cmd < 0xf0) {
- tmp++;
- } else if (cmd == 0xff) {
- if (READ_LE_UINT16(tmp)) {
- _drv->_looping |= _idFlag;
- tmp += _drv->_opnFxCmdLen[cmd - 240];
- } else
- loop = false;
- } else if (cmd == 0xf6) {
- // reset repeat section countdown
- tmp[0] = tmp[1];
- tmp += 4;
- } else {
- tmp += _drv->_opnFxCmdLen[cmd - 240];
- }
- }
-}
-
-void TownsPC98_MusicChannel::processEvents() {
- if (_flags & CHS_EOT)
- return;
-
- if (!_hold && _ticksLeft == _keyOffTime)
- keyOff();
-
- if (--_ticksLeft)
- return;
-
- if (!_hold)
- keyOff();
-
- uint8 cmd = 0;
- bool loop = true;
-
- while (loop) {
- cmd = *_dataPtr++;
- if (cmd < 0xf0)
- loop = false;
- else if (!processControlEvent(cmd))
- return;
- }
-
- uint8 para = *_dataPtr++;
-
- if (cmd == 0x80) {
- keyOff();
- _hold = false;
- } else {
- keyOn();
-
- if (_hold == false || cmd != _frqBlockMSB)
- _flags |= CHS_RECALCFREQ;
-
- _hold = (para & 0x80) ? true : false;
- _frqBlockMSB = cmd;
- }
-
- _ticksLeft = para & 0x7f;
-}
-
-void TownsPC98_MusicChannel::processFrequency() {
- if (_flags & CHS_RECALCFREQ) {
-
- _frequency = (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));
-
- setupVibrato();
- }
-
- if (!(_flags & CHS_VBROFF)) {
- if (!processVibrato())
- return;
-
- _drv->writeReg(_part, _regOffset + 0xa4, (_frequency >> 8));
- _drv->writeReg(_part, _regOffset + 0xa0, (_frequency & 0xff));
- }
-}
-
-void TownsPC98_MusicChannel::setupVibrato() {
- _vbrCurDelay = _vbrInitDelayHi;
- if (_flags & CHS_KEYOFF) {
- _vbrModCurVal = _vbrModInitVal;
- _vbrCurDelay += _vbrInitDelayLo;
- }
- _vbrDurLeft = (_vbrDuration >> 1);
- _flags &= ~(CHS_KEYOFF | CHS_RECALCFREQ);
-}
-
-bool TownsPC98_MusicChannel::processVibrato() {
- if (--_vbrCurDelay)
- return false;
-
- _vbrCurDelay = _vbrInitDelayHi;
- _frequency += _vbrModCurVal;
-
- if (!--_vbrDurLeft) {
- _vbrDurLeft = _vbrDuration;
- _vbrModCurVal = -_vbrModCurVal;
- }
-
- return true;
-}
-
-bool TownsPC98_MusicChannel::processControlEvent(uint8 cmd) {
- uint8 para = *_dataPtr++;
- return (this->*controlEvents[cmd & 0x0f])(para);
-}
-
-void TownsPC98_MusicChannel::setOutputLevel() {
- uint8 outopr = _drv->_opnCarrier[_algorithm];
- uint8 reg = 0x40 + _regOffset;
-
- for (int i = 0; i < 4; i++) {
- if (outopr & 1)
- _drv->writeReg(_part, reg, _totalLevel);
- outopr >>= 1;
- reg += 4;
- }
-}
-
-void TownsPC98_MusicChannel::fadeStep() {
- _totalLevel += 3;
- if (_totalLevel > 0x7f)
- _totalLevel = 0x7f;
- setOutputLevel();
-}
-
-void TownsPC98_MusicChannel::reset() {
- _hold = false;
- _keyOffTime = 0;
- _ticksLeft = 1;
-
- _flags = (_flags & ~CHS_EOT) | CHS_ALLOFF;
-
- _totalLevel = 0;
- _algorithm = 0;
- _flags = CHS_EOT;
- _algorithm = 0;
-
- _block = 0;
- _frequency = 0;
- _frqBlockMSB = 0;
- _frqLSB = 0;
-
- _ssgTl = 0;
- _ssgStartLvl = 0;
- _ssgTargetLvl = 0;
- _ssgStep = 0;
- _ssgTicksLeft = 0;
-
- _vbrInitDelayHi = 0;
- _vbrInitDelayLo = 0;
- _vbrModInitVal = 0;
- _vbrDuration = 0;
- _vbrCurDelay = 0;
- _vbrModCurVal = 0;
- _vbrDurLeft = 0;
-}
-
-bool TownsPC98_MusicChannel::control_f0_setPatch(uint8 para) {
- _instr = para;
- uint8 reg = _regOffset + 0x80;
-
- for (int i = 0; i < 4; i++) {
- // set release rate for each operator
- _drv->writeReg(_part, reg, 0x0f);
- reg += 4;
- }
-
- const uint8 *tptr = _drv->_patches + ((uint32)_instr << 5);
- reg = _regOffset + 0x30;
-
- // write registers 0x30 to 0x8f
- for (int i = 0; i < 6; i++) {
- _drv->writeReg(_part, reg, tptr[0]);
- reg += 4;
- _drv->writeReg(_part, reg, tptr[2]);
- reg += 4;
- _drv->writeReg(_part, reg, tptr[1]);
- reg += 4;
- _drv->writeReg(_part, reg, tptr[3]);
- reg += 4;
- tptr += 4;
- }
-
- reg = _regOffset + 0xB0;
- _algorithm = tptr[0] & 7;
- // set feedback and algorithm
- _drv->writeReg(_part, reg, tptr[0]);
-
- setOutputLevel();
- return true;
-}
-
-bool TownsPC98_MusicChannel::control_f1_presetOutputLevel(uint8 para) {
- if (_drv->_fading)
- return true;
-
- _totalLevel = _drv->_opnLvlPresets[para];
- setOutputLevel();
- return true;
-}
-
-bool TownsPC98_MusicChannel::control_f2_setKeyOffTime(uint8 para) {
- _keyOffTime = para;
- return true;
-}
-
-bool TownsPC98_MusicChannel::control_f3_setFreqLSB(uint8 para) {
- _frqLSB = (int8) para;
- return true;
-}
-
-bool TownsPC98_MusicChannel::control_f4_setOutputLevel(uint8 para) {
- if (_drv->_fading)
- return true;
-
- _totalLevel = para;
- setOutputLevel();
- return true;
-}
-
-bool TownsPC98_MusicChannel::control_f5_setTempo(uint8 para) {
- _drv->setMusicTempo(para);
- return true;
-}
-
-bool TownsPC98_MusicChannel::control_f6_repeatSection(uint8 para) {
- _dataPtr--;
- _dataPtr[0]--;
-
- if (*_dataPtr) {
- // repeat section until counter has reached zero
- _dataPtr = _drv->_trackPtr + READ_LE_UINT16(_dataPtr + 2);
- } else {
- // reset counter, advance to next section
- _dataPtr[0] = _dataPtr[1];
- _dataPtr += 4;
- }
- return true;
-}
-
-bool TownsPC98_MusicChannel::control_f7_setupVibrato(uint8 para) {
- _vbrInitDelayHi = _dataPtr[0];
- _vbrInitDelayLo = para;
- _vbrModInitVal = (int16) READ_LE_UINT16(_dataPtr + 1);
- _vbrDuration = _dataPtr[3];
- _dataPtr += 4;
- _flags = (_flags & ~CHS_VBROFF) | CHS_KEYOFF | CHS_RECALCFREQ;
- return true;
-}
-
-bool TownsPC98_MusicChannel::control_f8_toggleVibrato(uint8 para) {
- if (para == 0x10) {
- if (*_dataPtr++) {
- _flags = (_flags & ~CHS_VBROFF) | CHS_KEYOFF;
- } else {
- _flags |= CHS_VBROFF;
- }
- } else {
- /* NOT IMPLEMENTED
- uint8 skipChannels = para / 36;
- uint8 entry = para % 36;
- TownsPC98_AudioDriver::TownsPC98_MusicChannel *t = &chan[skipChannels];
-
- t->unnamedEntries[entry] = *_dataPtr++;*/
- }
- return true;
-}
-
-bool TownsPC98_MusicChannel::control_fa_writeReg(uint8 para) {
- _drv->writeReg(_part, para, *_dataPtr++);
- return true;
-}
-
-bool TownsPC98_MusicChannel::control_fb_incOutLevel(uint8 para) {
- _dataPtr--;
- if (_drv->_fading)
- return true;
-
- uint8 val = (_totalLevel + 3);
- if (val > 0x7f)
- val = 0x7f;
-
- _totalLevel = val;
- setOutputLevel();
- return true;
-}
-
-bool TownsPC98_MusicChannel::control_fc_decOutLevel(uint8 para) {
- _dataPtr--;
- if (_drv->_fading)
- return true;
-
- int8 val = (int8)(_totalLevel - 3);
- if (val < 0)
- val = 0;
-
- _totalLevel = (uint8) val;
- setOutputLevel();
- return true;
-}
-
-bool TownsPC98_MusicChannel::control_fd_jump(uint8 para) {
- uint8 *tmp = _drv->_trackPtr + READ_LE_UINT16(_dataPtr - 1);
- _dataPtr = (tmp[1] == 1) ? tmp : (_dataPtr + 1);
- return true;
-}
-
-bool TownsPC98_MusicChannel::control_dummy(uint8 para) {
- _dataPtr--;
- return true;
-}
-
-bool TownsPC98_MusicChannel::control_ff_endOfTrack(uint8 para) {
- uint16 val = READ_LE_UINT16(--_dataPtr);
- if (val) {
- // loop
- _dataPtr = _drv->_trackPtr + val;
- return true;
- } else {
- // quit parsing for active channel
- --_dataPtr;
- _flags |= CHS_EOT;
- _drv->_finishedChannelsFlag |= _idFlag;
- keyOff();
- return false;
- }
-}
-
-TownsPC98_MusicChannelSSG::TownsPC98_MusicChannelSSG(TownsPC98_AudioDriver *driver, uint8 regOffs,
- uint8 flgs, uint8 num, uint8 key, uint8 prt, uint8 id) :
- TownsPC98_MusicChannel(driver, regOffs, flgs, num, key, prt, id), controlEvents(0) {
-}
-
-void TownsPC98_MusicChannelSSG::init() {
- _algorithm = 0x80;
-
-#define Control(x) &TownsPC98_MusicChannelSSG::control_##x
- static const ControlEventFunc ctrlEventsSSG[] = {
- Control(f0_setPatch),
- Control(f1_setTotalLevel),
- Control(f2_setKeyOffTime),
- Control(f3_setFreqLSB),
- Control(f4_setAlgorithm),
- Control(f5_setTempo),
- Control(f6_repeatSection),
- Control(f7_setupVibrato),
- Control(f8_toggleVibrato),
- Control(f9_loadCustomPatch),
- Control(fa_writeReg),
- Control(fb_incOutLevel),
- Control(fc_decOutLevel),
- Control(fd_jump),
- Control(dummy),
- Control(ff_endOfTrack)
- };
-#undef Control
-
- controlEvents = ctrlEventsSSG;
-}
-
-void TownsPC98_MusicChannelSSG::processEvents() {
- if (_flags & CHS_EOT)
- return;
-
- _drv->toggleRegProtection(_flags & CHS_PROTECT ? true : false);
-
- if (!_hold && _ticksLeft == _keyOffTime)
- nextShape();
-
- if (!--_ticksLeft) {
-
- uint8 cmd = 0;
- bool loop = true;
-
- while (loop) {
- cmd = *_dataPtr++;
- if (cmd < 0xf0)
- loop = false;
- else if (!processControlEvent(cmd))
- return;
- }
-
- uint8 para = *_dataPtr++;
-
- if (cmd == 0x80) {
- nextShape();
- _hold = false;
- } else {
- if (!_hold) {
- _instr &= 0xf0;
- _ssgStep = _drv->_ssgPatches[_instr];
- _ssgTicksLeft = _drv->_ssgPatches[_instr + 1] & 0x7f;
- _ssgTargetLvl = _drv->_ssgPatches[_instr + 2];
- _ssgStartLvl = _drv->_ssgPatches[_instr + 3];
- _flags = (_flags & ~CHS_SSGOFF) | CHS_KEYOFF;
- }
-
- keyOn();
-
- if (_hold == false || cmd != _frqBlockMSB)
- _flags |= CHS_RECALCFREQ;
-
- _hold = (para & 0x80) ? true : false;
- _frqBlockMSB = cmd;
- }
-
- _ticksLeft = para & 0x7f;
- }
-
- if (!(_flags & CHS_SSGOFF)) {
- if (--_ssgTicksLeft) {
- if (!_drv->_fading)
- setOutputLevel(_ssgStartLvl);
- return;
- }
-
- _ssgTicksLeft = _drv->_ssgPatches[_instr + 1] & 0x7f;
-
- if (_drv->_ssgPatches[_instr + 1] & 0x80) {
- uint8 t = _ssgStartLvl - _ssgStep;
-
- if (_ssgStep <= _ssgStartLvl && _ssgTargetLvl < t) {
- if (!_drv->_fading)
- setOutputLevel(t);
- return;
- }
- } else {
- int t = _ssgStartLvl + _ssgStep;
- uint8 p = (uint8)(t & 0xff);
-
- if (t < 256 && _ssgTargetLvl > p) {
- if (!_drv->_fading)
- setOutputLevel(p);
- return;
- }
- }
-
- setOutputLevel(_ssgTargetLvl);
- if (_ssgStartLvl && !(_instr & 8)) {
- _instr += 4;
- _ssgStep = _drv->_ssgPatches[_instr];
- _ssgTicksLeft = _drv->_ssgPatches[_instr + 1] & 0x7f;
- _ssgTargetLvl = _drv->_ssgPatches[_instr + 2];
- } else {
- _flags |= CHS_SSGOFF;
- setOutputLevel(0);
- }
- }
-}
-
-void TownsPC98_MusicChannelSSG::processFrequency() {
- if (_algorithm & 0x40)
- return;
-
- if (_flags & CHS_RECALCFREQ) {
- _block = _frqBlockMSB >> 4;
- _frequency = READ_LE_UINT16(&_drv->_opnFreqTableSSG[(_frqBlockMSB & 0x0f) << 1]) + _frqLSB;
-
- uint16 f = _frequency >> _block;
- _drv->writeReg(_part, _regOffset << 1, f & 0xff);
- _drv->writeReg(_part, (_regOffset << 1) + 1, f >> 8);
-
- setupVibrato();
- }
-
- if (!(_flags & (CHS_EOT | CHS_VBROFF | CHS_SSGOFF))) {
- if (!processVibrato())
- return;
-
- uint16 f = _frequency >> _block;
- _drv->writeReg(_part, _regOffset << 1, f & 0xff);
- _drv->writeReg(_part, (_regOffset << 1) + 1, f >> 8);
- }
-}
-
-bool TownsPC98_MusicChannelSSG::processControlEvent(uint8 cmd) {
- uint8 para = *_dataPtr++;
- return (this->*controlEvents[cmd & 0x0f])(para);
-}
-
-void TownsPC98_MusicChannelSSG::nextShape() {
- _instr = (_instr & 0xf0) + 0x0c;
- _ssgStep = _drv->_ssgPatches[_instr];
- _ssgTicksLeft = _drv->_ssgPatches[_instr + 1] & 0x7f;
- _ssgTargetLvl = _drv->_ssgPatches[_instr + 2];
-}
-
-void TownsPC98_MusicChannelSSG::keyOn() {
- uint8 c = 0x7b;
- uint8 t = (_algorithm & 0xC0) << 1;
- if (_algorithm & 0x80)
- t |= 4;
-
- c = (c << (_regOffset + 1)) | (c >> (7 - _regOffset));
- t = (t << (_regOffset + 1)) | (t >> (7 - _regOffset));
-
- if (!(_algorithm & 0x80))
- _drv->writeReg(_part, 6, _algorithm & 0x7f);
-
- uint8 e = (_drv->readSSGStatus() & c) | t;
- _drv->writeReg(_part, 7, e);
-}
-
-void TownsPC98_MusicChannelSSG::protect() {
- _flags |= CHS_PROTECT;
-}
-
-void TownsPC98_MusicChannelSSG::restore() {
- _flags &= ~CHS_PROTECT;
- keyOn();
- _drv->writeReg(_part, 8 + _regOffset, _ssgTl);
- uint16 f = _frequency >> _block;
- _drv->writeReg(_part, _regOffset << 1, f & 0xff);
- _drv->writeReg(_part, (_regOffset << 1) + 1, f >> 8);
-}
-
-void TownsPC98_MusicChannelSSG::loadData(uint8 *data) {
- _drv->toggleRegProtection(_flags & CHS_PROTECT ? true : false);
- TownsPC98_MusicChannel::loadData(data);
- setOutputLevel(0);
- _algorithm = 0x80;
-}
-
-void TownsPC98_MusicChannelSSG::setOutputLevel(uint8 lvl) {
- _ssgStartLvl = lvl;
- uint16 newTl = (((uint16)_totalLevel + 1) * (uint16)lvl) >> 8;
- if (newTl == _ssgTl)
- return;
- _ssgTl = newTl;
- _drv->writeReg(_part, 8 + _regOffset, _ssgTl);
-}
-
-void TownsPC98_MusicChannelSSG::reset() {
- TownsPC98_MusicChannel::reset();
-
- // Unlike the original we restore the default patch data. This fixes a bug
- // where certain sound effects would bring each other out of tune (e.g. the
- // dragon's fire in Darm's house in Kyra 1 would sound different each time
- // you triggered another sfx by dropping an item etc.)
- uint8 i = (10 + _regOffset) << 4;
- const uint8 *src = &_drv->_drvTables[156];
- _drv->_ssgPatches[i] = src[i];
- _drv->_ssgPatches[i + 3] = src[i + 3];
- _drv->_ssgPatches[i + 4] = src[i + 4];
- _drv->_ssgPatches[i + 6] = src[i + 6];
- _drv->_ssgPatches[i + 8] = src[i + 8];
- _drv->_ssgPatches[i + 12] = src[i + 12];
-}
-
-void TownsPC98_MusicChannelSSG::fadeStep() {
- _totalLevel--;
- if ((int8)_totalLevel < 0)
- _totalLevel = 0;
- setOutputLevel(_ssgStartLvl);
-}
-
-bool TownsPC98_MusicChannelSSG::control_f0_setPatch(uint8 para) {
- _instr = para << 4;
- para = (para >> 3) & 0x1e;
- if (para)
- return control_f4_setAlgorithm(para | 0x40);
- return true;
-}
-
-bool TownsPC98_MusicChannelSSG::control_f1_setTotalLevel(uint8 para) {
- if (!_drv->_fading)
- _totalLevel = para;
- return true;
-}
-
-bool TownsPC98_MusicChannelSSG::control_f4_setAlgorithm(uint8 para) {
- _algorithm = para;
- return true;
-}
-
-bool TownsPC98_MusicChannelSSG::control_f9_loadCustomPatch(uint8 para) {
- _instr = (_drv->_sfxOffs + 10 + _regOffset) << 4;
- _drv->_ssgPatches[_instr] = *_dataPtr++;
- _drv->_ssgPatches[_instr + 3] = para;
- _drv->_ssgPatches[_instr + 4] = *_dataPtr++;
- _drv->_ssgPatches[_instr + 6] = *_dataPtr++;
- _drv->_ssgPatches[_instr + 8] = *_dataPtr++;
- _drv->_ssgPatches[_instr + 12] = *_dataPtr++;
- return true;
-}
-
-bool TownsPC98_MusicChannelSSG::control_fb_incOutLevel(uint8 para) {
- _dataPtr--;
- if (_drv->_fading)
- return true;
-
- _totalLevel--;
- if ((int8)_totalLevel < 0)
- _totalLevel = 0;
-
- return true;
-}
-
-bool TownsPC98_MusicChannelSSG::control_fc_decOutLevel(uint8 para) {
- _dataPtr--;
- if (_drv->_fading)
- return true;
-
- if (_totalLevel + 1 < 0x10)
- _totalLevel++;
-
- return true;
-}
-
-bool TownsPC98_MusicChannelSSG::control_ff_endOfTrack(uint8 para) {
- if (!_drv->_sfxOffs) {
- uint16 val = READ_LE_UINT16(--_dataPtr);
- if (val) {
- // loop
- _dataPtr = _drv->_trackPtr + val;
- return true;
- } else {
- // stop parsing
- if (!_drv->_fading)
- setOutputLevel(0);
- --_dataPtr;
- _flags |= CHS_EOT;
- _drv->_finishedSSGFlag |= _idFlag;
- }
- } else {
- // end of sfx track - restore ssg music channel
- _flags |= CHS_EOT;
- _drv->_finishedSfxFlag |= _idFlag;
- _drv->_ssgChannels[_chanNum]->restore();
- }
-
- return false;
-}
-
-void TownsPC98_SfxChannel::loadData(uint8 *data) {
- _flags = CHS_ALLOFF;
- _ticksLeft = 1;
- _dataPtr = data;
- _ssgTl = 0xff;
- _algorithm = 0x80;
-
- uint8 *tmp = _dataPtr;
- for (bool loop = true; loop;) {
- uint8 cmd = *tmp++;
- if (cmd < 0xf0) {
- tmp++;
- } else if (cmd == 0xff) {
- loop = false;
- } else if (cmd == 0xf6) {
- // reset repeat section countdown
- tmp[0] = tmp[1];
- tmp += 4;
- } else {
- tmp += _drv->_opnFxCmdLen[cmd - 240];
- }
- }
-}
-
-void TownsPC98_SfxChannel::reset() {
- TownsPC98_MusicChannel::reset();
-
- // Unlike the original we restore the default patch data. This fixes a bug
- // where certain sound effects would bring each other out of tune (e.g. the
- // dragon's fire in Darm's house in Kyra 1 would sound different each time
- // you triggered another sfx by dropping an item etc.)
- uint8 i = (13 + _regOffset) << 4;
- const uint8 *src = &_drv->_drvTables[156];
- _drv->_ssgPatches[i] = src[i];
- _drv->_ssgPatches[i + 3] = src[i + 3];
- _drv->_ssgPatches[i + 4] = src[i + 4];
- _drv->_ssgPatches[i + 6] = src[i + 6];
- _drv->_ssgPatches[i + 8] = src[i + 8];
- _drv->_ssgPatches[i + 12] = src[i + 12];
-}
-
-#ifndef DISABLE_PC98_RHYTHM_CHANNEL
-TownsPC98_MusicChannelPCM::TownsPC98_MusicChannelPCM(TownsPC98_AudioDriver *driver, uint8 regOffs,
- uint8 flgs, uint8 num, uint8 key, uint8 prt, uint8 id) :
- TownsPC98_MusicChannel(driver, regOffs, flgs, num, key, prt, id), controlEvents(0) {
-}
-
-void TownsPC98_MusicChannelPCM::init() {
- _algorithm = 0x80;
-
-#define Control(x) &TownsPC98_MusicChannelPCM::control_##x
- static const ControlEventFunc ctrlEventsPCM[] = {
- Control(dummy),
- Control(f1_prcStart),
- Control(dummy),
- Control(dummy),
- Control(dummy),
- Control(dummy),
- Control(f6_repeatSection),
- Control(dummy),
- Control(dummy),
- Control(dummy),
- Control(fa_writeReg),
- Control(dummy),
- Control(dummy),
- Control(dummy),
- Control(dummy),
- Control(ff_endOfTrack)
- };
-#undef Control
-
- controlEvents = ctrlEventsPCM;
-}
-
-void TownsPC98_MusicChannelPCM::loadData(uint8 *data) {
- _flags = (_flags & ~CHS_EOT) | CHS_ALLOFF;
- _ticksLeft = 1;
- _dataPtr = data;
- _totalLevel = 0x7F;
-}
-
-void TownsPC98_MusicChannelPCM::processEvents() {
- if (_flags & CHS_EOT)
- return;
-
- if (--_ticksLeft)
- return;
-
- uint8 cmd = 0;
- bool loop = true;
-
- while (loop) {
- cmd = *_dataPtr++;
- if (cmd == 0x80) {
- loop = false;
- } else if (cmd < 0xf0) {
- _drv->writeReg(_part, 0x10, cmd);
- } else if (!processControlEvent(cmd)) {
- return;
- }
- }
-
- _ticksLeft = *_dataPtr++;
-}
-
-bool TownsPC98_MusicChannelPCM::processControlEvent(uint8 cmd) {
- uint8 para = *_dataPtr++;
- return (this->*controlEvents[cmd & 0x0f])(para);
-}
-
-bool TownsPC98_MusicChannelPCM::control_f1_prcStart(uint8 para) {
- _totalLevel = para;
- _drv->writeReg(_part, 0x11, para);
- return true;
-}
-
-bool TownsPC98_MusicChannelPCM::control_ff_endOfTrack(uint8 para) {
- uint16 val = READ_LE_UINT16(--_dataPtr);
- if (val) {
- // loop
- _dataPtr = _drv->_trackPtr + val;
- return true;
- } else {
- // quit parsing for active channel
- --_dataPtr;
- _flags |= CHS_EOT;
- _drv->_finishedRhythmFlag |= _idFlag;
- return false;
- }
-}
-#endif // DISABLE_PC98_RHYTHM_CHANNEL
-
-TownsPC98_AudioDriver::TownsPC98_AudioDriver(Audio::Mixer *mixer, EmuType type) : TownsPC98_FmSynth(mixer, type),
- _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),
-
- _opnCarrier(_drvTables + 76), _opnFreqTable(_drvTables + 108), _opnFreqTableSSG(_drvTables + 132),
- _opnFxCmdLen(_drvTables + 36), _opnLvlPresets(_drvTables + (type == kTypeTowns ? 52 : 84)),
-
- _updateChannelsFlag(type == kType26 ? 0x07 : 0x3F), _finishedChannelsFlag(0),
- _updateSSGFlag(type == kTypeTowns ? 0x00 : 0x07), _finishedSSGFlag(0),
- _updateRhythmFlag(type == kType86 ?
-#ifndef DISABLE_PC98_RHYTHM_CHANNEL
- 0x01
-#else
- 0x00
-#endif
- : 0x00), _finishedRhythmFlag(0),
- _updateSfxFlag(0), _finishedSfxFlag(0),
-
- _musicTickCounter(0),
-
- _musicVolume(255), _sfxVolume(255),
-
- _musicPlaying(false), _sfxPlaying(false), _fading(false), _looping(0), _ready(false) {
-
- _sfxOffsets[0] = _sfxOffsets[1] = 0;
-}
-
-TownsPC98_AudioDriver::~TownsPC98_AudioDriver() {
- _ready = false;
- deinit();
-
- if (_channels) {
- for (int i = 0; i < _numChan; i++)
- delete _channels[i];
- delete[] _channels;
- }
-
- if (_ssgChannels) {
- for (int i = 0; i < _numSSG; i++)
- delete _ssgChannels[i];
- delete[] _ssgChannels;
- }
-
- if (_sfxChannels) {
- for (int i = 0; i < 2; i++)
- delete _sfxChannels[i];
- delete[] _sfxChannels;
- }
-#ifndef DISABLE_PC98_RHYTHM_CHANNEL
- delete _rhythmChannel;
-#endif
-
- delete[] _ssgPatches;
-}
-
-bool TownsPC98_AudioDriver::init() {
- if (_ready) {
- reset();
- return true;
- }
-
- TownsPC98_FmSynth::init();
-
- setVolumeChannelMasks(-1, 0);
-
- _channels = new TownsPC98_MusicChannel *[_numChan];
- for (int i = 0; i < _numChan; i++) {
- int ii = i * 6;
- _channels[i] = new TownsPC98_MusicChannel(this, _drvTables[ii], _drvTables[ii + 1],
- _drvTables[ii + 2], _drvTables[ii + 3], _drvTables[ii + 4], _drvTables[ii + 5]);
- _channels[i]->init();
- }
-
- if (_numSSG) {
- _ssgPatches = new uint8[256];
- memcpy(_ssgPatches, _drvTables + 156, 256);
-
- _ssgChannels = new TownsPC98_MusicChannelSSG *[_numSSG];
- for (int i = 0; i < _numSSG; i++) {
- int ii = i * 6;
- _ssgChannels[i] = new TownsPC98_MusicChannelSSG(this, _drvTables[ii], _drvTables[ii + 1],
- _drvTables[ii + 2], _drvTables[ii + 3], _drvTables[ii + 4], _drvTables[ii + 5]);
- _ssgChannels[i]->init();
- }
-
- _sfxChannels = new TownsPC98_SfxChannel *[2];
- for (int i = 0; i < 2; i++) {
- int ii = (i + 1) * 6;
- _sfxChannels[i] = new TownsPC98_SfxChannel(this, _drvTables[ii], _drvTables[ii + 1],
- _drvTables[ii + 2], _drvTables[ii + 3], _drvTables[ii + 4], _drvTables[ii + 5]);
- _sfxChannels[i]->init();
- }
- }
-
-#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);
-
- _ready = true;
-
- return true;
-}
-
-void TownsPC98_AudioDriver::loadMusicData(uint8 *data, bool loadPaused) {
- if (!_ready) {
- warning("TownsPC98_AudioDriver: Driver must be initialized before loading data");
- return;
- }
-
- if (!data) {
- warning("TownsPC98_AudioDriver: Invalid music file data");
- return;
- }
-
- reset();
-
- Common::StackLock lock(_mutex);
- uint8 *src_a = _trackPtr = _musicBuffer = data;
-
- for (uint8 i = 0; i < 3; i++) {
- _channels[i]->loadData(data + READ_LE_UINT16(src_a));
- src_a += 2;
- }
-
- for (int i = 0; i < _numSSG; i++) {
- _ssgChannels[i]->loadData(data + READ_LE_UINT16(src_a));
- src_a += 2;
- }
-
- for (uint8 i = 3; i < _numChan; i++) {
- _channels[i]->loadData(data + READ_LE_UINT16(src_a));
- src_a += 2;
- }
-
- if (_hasPercussion) {
-#ifndef DISABLE_PC98_RHYTHM_CHANNEL
- _rhythmChannel->loadData(data + READ_LE_UINT16(src_a));
-#endif
- src_a += 2;
- }
-
- toggleRegProtection(false);
-
- _patches = src_a + 4;
- _finishedChannelsFlag = _finishedSSGFlag = _finishedRhythmFlag = 0;
-
- _musicPlaying = (loadPaused ? false : true);
-}
-
-void TownsPC98_AudioDriver::loadSoundEffectData(uint8 *data, uint8 trackNum) {
- if (!_ready) {
- warning("TownsPC98_AudioDriver: Driver must be initialized before loading data");
- return;
- }
-
- if (!_sfxChannels) {
- warning("TownsPC98_AudioDriver: Sound effects not supported by this configuration");
- return;
- }
-
- if (!data) {
- warning("TownsPC98_AudioDriver: Invalid sound effects file data");
- return;
- }
-
- Common::StackLock lock(_mutex);
- _sfxData = _sfxBuffer = data;
- _sfxOffsets[0] = READ_LE_UINT16(&_sfxData[(trackNum << 2)]);
- _sfxOffsets[1] = READ_LE_UINT16(&_sfxData[(trackNum << 2) + 2]);
- _sfxPlaying = true;
- _finishedSfxFlag = 0;
-}
-
-void TownsPC98_AudioDriver::reset() {
- Common::StackLock lock(_mutex);
-
- _musicPlaying = false;
- _sfxPlaying = false;
- _fading = false;
- _looping = 0;
- _musicTickCounter = 0;
- _sfxData = 0;
-
- TownsPC98_FmSynth::reset();
-
- for (int i = 0; i < _numChan; i++)
- _channels[i]->reset();
- for (int i = 0; i < _numSSG; i++)
- _ssgChannels[i]->reset();
-
- if (_numSSG) {
- for (int i = 0; i < 2; i++)
- _sfxChannels[i]->reset();
-
- memcpy(_ssgPatches, _drvTables + 156, 256);
- }
-
-#ifndef DISABLE_PC98_RHYTHM_CHANNEL
- if (_rhythmChannel)
- _rhythmChannel->reset();
-#endif
-}
-
-void TownsPC98_AudioDriver::fadeStep() {
- if (!_musicPlaying)
- return;
-
- Common::StackLock lock(_mutex);
- for (int j = 0; j < _numChan; j++) {
- if (_updateChannelsFlag & _channels[j]->_idFlag)
- _channels[j]->fadeStep();
- }
-
- for (int j = 0; j < _numSSG; j++) {
- if (_updateSSGFlag & _ssgChannels[j]->_idFlag)
- _ssgChannels[j]->fadeStep();
- }
-
- if (!_fading) {
- _fading = 19;
-#ifndef DISABLE_PC98_RHYTHM_CHANNEL
- if (_hasPercussion) {
- if (_updateRhythmFlag & _rhythmChannel->_idFlag)
- _rhythmChannel->reset();
- }
-#endif
- } else {
- if (!--_fading)
- reset();
- }
-}
-
-void TownsPC98_AudioDriver::timerCallbackB() {
- _sfxOffs = 0;
-
- if (_musicPlaying) {
- _musicTickCounter++;
-
- for (int i = 0; i < _numChan; i++) {
- if (_updateChannelsFlag & _channels[i]->_idFlag) {
- _channels[i]->processEvents();
- _channels[i]->processFrequency();
- }
- }
-
- for (int i = 0; i < _numSSG; i++) {
- if (_updateSSGFlag & _ssgChannels[i]->_idFlag) {
- _ssgChannels[i]->processEvents();
- _ssgChannels[i]->processFrequency();
- }
- }
-
-#ifndef DISABLE_PC98_RHYTHM_CHANNEL
- if (_hasPercussion)
- if (_updateRhythmFlag & _rhythmChannel->_idFlag)
- _rhythmChannel->processEvents();
-#endif
- }
-
- toggleRegProtection(false);
-
- if (_finishedChannelsFlag == _updateChannelsFlag && _finishedSSGFlag == _updateSSGFlag && _finishedRhythmFlag == _updateRhythmFlag)
- _musicPlaying = false;
-}
-
-void TownsPC98_AudioDriver::timerCallbackA() {
- if (_sfxChannels && _sfxPlaying) {
- if (_sfxData)
- startSoundEffect();
-
- _sfxOffs = 3;
- _trackPtr = _sfxBuffer;
-
- for (int i = 0; i < 2; i++) {
- if (_updateSfxFlag & _sfxChannels[i]->_idFlag) {
- _sfxChannels[i]->processEvents();
- _sfxChannels[i]->processFrequency();
- }
- }
-
- _trackPtr = _musicBuffer;
- }
-
- if (_updateSfxFlag && _finishedSfxFlag == _updateSfxFlag) {
- _sfxPlaying = false;
- _updateSfxFlag = 0;
- setVolumeChannelMasks(-1, 0);
- }
-}
-
-void TownsPC98_AudioDriver::setMusicTempo(uint8 tempo) {
- writeReg(0, 0x26, tempo);
- writeReg(0, 0x27, 0x33);
-}
-
-void TownsPC98_AudioDriver::setSfxTempo(uint16 tempo) {
- writeReg(0, 0x24, tempo & 0xff);
- writeReg(0, 0x25, tempo >> 8);
- writeReg(0, 0x27, 0x33);
-}
-
-void TownsPC98_AudioDriver::startSoundEffect() {
- int volFlags = 0;
-
- for (int i = 0; i < 2; i++) {
- if (_sfxOffsets[i]) {
- _ssgChannels[i + 1]->protect();
- _sfxChannels[i]->reset();
- _sfxChannels[i]->loadData(_sfxData + _sfxOffsets[i]);
- _updateSfxFlag |= _sfxChannels[i]->_idFlag;
- volFlags |= (_sfxChannels[i]->_idFlag << _numChan);
- } else {
- _ssgChannels[i + 1]->restore();
- _updateSfxFlag &= ~_sfxChannels[i]->_idFlag;
- }
- }
-
- setVolumeChannelMasks(~volFlags, volFlags);
- _sfxData = 0;
-}
-
-const uint8 TownsPC98_AudioDriver::_drvTables[] = {
- // channel presets
- 0x00, 0x80, 0x00, 0x00, 0x00, 0x01,
- 0x01, 0x80, 0x01, 0x01, 0x00, 0x02,
- 0x02, 0x80, 0x02, 0x02, 0x00, 0x04,
- 0x00, 0x80, 0x03, 0x04, 0x01, 0x08,
- 0x01, 0x80, 0x04, 0x05, 0x01, 0x10,
- 0x02, 0x80, 0x05, 0x06, 0x01, 0x20,
-
- // control event size
- 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x04, 0x05,
- 0x02, 0x06, 0x02, 0x00, 0x00, 0x02, 0x00, 0x02,
-
- // fmt level presets
- 0x54, 0x50, 0x4C, 0x48, 0x44, 0x40, 0x3C, 0x38,
- 0x34, 0x30, 0x2C, 0x28, 0x24, 0x20, 0x1C, 0x18,
- 0x14, 0x10, 0x0C, 0x08, 0x04, 0x90, 0x90, 0x90,
-
- // carriers
- 0x08, 0x08, 0x08, 0x08, 0x0C, 0x0E, 0x0E, 0x0F,
-
- // pc98 level presets
- 0x40, 0x3B, 0x38, 0x34, 0x30, 0x2A, 0x28, 0x25,
- 0x22, 0x20, 0x1D, 0x1A, 0x18, 0x15, 0x12, 0x10,
- 0x0D, 0x0A, 0x08, 0x05, 0x02, 0x90, 0x90, 0x90,
-
- // frequencies
- 0x6A, 0x02, 0x8F, 0x02, 0xB6, 0x02, 0xDF, 0x02,
- 0x0B, 0x03, 0x39, 0x03, 0x6A, 0x03, 0x9E, 0x03,
- 0xD5, 0x03, 0x10, 0x04, 0x4E, 0x04, 0x8F, 0x04,
-
- // ssg frequencies
- 0xE8, 0x0E, 0x12, 0x0E, 0x48, 0x0D, 0x89, 0x0C,
- 0xD5, 0x0B, 0x2B, 0x0B, 0x8A, 0x0A, 0xF3, 0x09,
- 0x64, 0x09, 0xDD, 0x08, 0x5E, 0x08, 0xE6, 0x07,
-
- // ssg patch data
- 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x81, 0x00, 0x00,
- 0x00, 0x81, 0x00, 0x00, 0xFF, 0x81, 0x00, 0x00,
- 0x00, 0x01, 0xFF, 0xFF, 0x37, 0x81, 0xC8, 0x00,
- 0x00, 0x81, 0x00, 0x00, 0x0A, 0x81, 0x00, 0x00,
- 0x00, 0x01, 0xFF, 0xFF, 0x37, 0x81, 0xC8, 0x00,
- 0x01, 0x81, 0x00, 0x00, 0x0A, 0x81, 0x00, 0x00,
- 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0x81, 0xBE, 0x00,
- 0x00, 0x81, 0x00, 0x00, 0x0A, 0x81, 0x00, 0x00,
- 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0x81, 0xBE, 0x00,
- 0x01, 0x81, 0x00, 0x00, 0x0A, 0x81, 0x00, 0x00,
- 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0x81, 0xBE, 0x00,
- 0x04, 0x81, 0x00, 0x00, 0x0A, 0x81, 0x00, 0x00,
- 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0x81, 0xBE, 0x00,
- 0x0A, 0x81, 0x00, 0x00, 0x0A, 0x81, 0x00, 0x00,
- 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0x81, 0x01, 0x00,
- 0xFF, 0x81, 0x00, 0x00, 0xFF, 0x81, 0x00, 0x00,
- 0xFF, 0x01, 0xFF, 0xFF, 0xFF, 0x81, 0xFF, 0x00,
- 0x01, 0x81, 0x00, 0x00, 0x0A, 0x81, 0x00, 0x00,
- 0x64, 0x01, 0xFF, 0x64, 0xFF, 0x81, 0xFF, 0x00,
- 0x01, 0x81, 0x00, 0x00, 0x0A, 0x81, 0x00, 0x00,
-
- 0x02, 0x01, 0xFF, 0x28, 0xFF, 0x81, 0xF0, 0x00,
- 0x00, 0x81, 0x00, 0x00, 0x0A, 0x81, 0x00, 0x00,
- 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0x81, 0xC8, 0x00,
- 0x01, 0x81, 0x00, 0x00, 0x28, 0x81, 0x00, 0x00,
- 0x00, 0x01, 0xFF, 0x78, 0x5F, 0x81, 0xA0, 0x00,
- 0x05, 0x81, 0x00, 0x00, 0x28, 0x81, 0x00, 0x00,
- 0x00, 0x01, 0xFF, 0xFF, 0x00, 0x81, 0x00, 0x00,
- 0x00, 0x81, 0x00, 0x00, 0xFF, 0x81, 0x00, 0x00,
- 0x00, 0x01, 0xFF, 0xFF, 0x00, 0x81, 0x00, 0x00,
- 0x00, 0x81, 0x00, 0x00, 0xFF, 0x81, 0x00, 0x00,
- 0x00, 0x01, 0xFF, 0xFF, 0x00, 0x81, 0x00, 0x00,
- 0x00, 0x81, 0x00, 0x00, 0xFF, 0x81, 0x00, 0x00
-};
-
-#undef EUPHONY_FADEOUT_TICKS
-
diff --git a/sound/softsynth/fmtowns_pc98/towns_pc98_driver.h b/sound/softsynth/fmtowns_pc98/towns_pc98_driver.h
deleted file mode 100644
index 00fcf7c5d5..0000000000
--- a/sound/softsynth/fmtowns_pc98/towns_pc98_driver.h
+++ /dev/null
@@ -1,135 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * $URL$
- * $Id$
- *
- */
-
-#ifndef TOWNS_PC98_AUDIODRIVER_H
-#define TOWNS_PC98_AUDIODRIVER_H
-
-#include "sound/softsynth/fmtowns_pc98/towns_pc98_fmsynth.h"
-
-class TownsPC98_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();
-
- void loadMusicData(uint8 *data, bool loadPaused = false);
- void loadSoundEffectData(uint8 *data, uint8 trackNum);
- bool init();
- void reset();
-
- void fadeStep();
-
- void pause() {
- _musicPlaying = false;
- }
- void cont() {
- _musicPlaying = true;
- }
-
- void timerCallbackB();
- void timerCallbackA();
-
- bool looping() {
- return _looping == _updateChannelsFlag ? true : false;
- }
- bool musicPlaying() {
- return _musicPlaying;
- }
-
- void setMusicVolume(int volume) {
- _musicVolume = volume;
- setVolumeIntern(_musicVolume, _sfxVolume);
- }
- void setSoundEffectVolume(int volume) {
- _sfxVolume = volume;
- setVolumeIntern(_musicVolume, _sfxVolume);
- }
-
-protected:
- void startSoundEffect();
-
- void setMusicTempo(uint8 tempo);
- void setSfxTempo(uint16 tempo);
-
- TownsPC98_MusicChannel **_channels;
- TownsPC98_MusicChannelSSG **_ssgChannels;
- TownsPC98_SfxChannel **_sfxChannels;
-#ifndef DISABLE_PC98_RHYTHM_CHANNEL
- TownsPC98_MusicChannelPCM *_rhythmChannel;
-#endif
-
- const uint8 *_opnCarrier;
- const uint8 *_opnFreqTable;
- const uint8 *_opnFreqTableSSG;
- const uint8 *_opnFxCmdLen;
- const uint8 *_opnLvlPresets;
-
- uint8 *_musicBuffer;
- uint8 *_sfxBuffer;
- uint8 *_trackPtr;
- uint8 *_patches;
- uint8 *_ssgPatches;
-
- uint8 _updateChannelsFlag;
- uint8 _updateSSGFlag;
- uint8 _updateRhythmFlag;
- uint8 _updateSfxFlag;
- uint8 _finishedChannelsFlag;
- uint8 _finishedSSGFlag;
- uint8 _finishedRhythmFlag;
- uint8 _finishedSfxFlag;
-
- bool _musicPlaying;
- bool _sfxPlaying;
- uint8 _fading;
- uint8 _looping;
- uint32 _musicTickCounter;
-
- int _sfxOffs;
- uint8 *_sfxData;
- uint16 _sfxOffsets[2];
-
- uint16 _musicVolume;
- uint16 _sfxVolume;
-
- static const uint8 _drvTables[];
-
- bool _ready;
-};
-
-#endif
-
diff --git a/sound/softsynth/fmtowns_pc98/towns_pc98_fmsynth.cpp b/sound/softsynth/fmtowns_pc98/towns_pc98_fmsynth.cpp
deleted file mode 100644
index 62f7d39771..0000000000
--- a/sound/softsynth/fmtowns_pc98/towns_pc98_fmsynth.cpp
+++ /dev/null
@@ -1,1548 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * $URL$
- * $Id$
- *
- */
-
-#include "sound/softsynth/fmtowns_pc98/towns_pc98_fmsynth.h"
-#include "common/endian.h"
-
-class TownsPC98_FmSynthOperator {
-public:
- TownsPC98_FmSynthOperator(const uint32 timerbase, const uint32 rtt, const uint8 *rateTable,
- const uint8 *shiftTable, const uint8 *attackDecayTable, const uint32 *frqTable,
- const uint32 *sineTable, const int32 *tlevelOut, const int32 *detuneTable);
- ~TownsPC98_FmSynthOperator() {}
-
- void keyOn();
- void keyOff();
- void frequency(int freq);
- void updatePhaseIncrement();
- void recalculateRates();
- void generateOutput(int32 phasebuf, int32 *feedbuf, int32 &out);
-
- void feedbackLevel(int32 level) {
- _feedbackLevel = level ? level + 6 : 0;
- }
- void detune(int value) {
- _detn = &_detnTbl[value << 5];
- }
- void multiple(uint32 value) {
- _multiple = value ? (value << 1) : 1;
- }
- void attackRate(uint32 value) {
- _specifiedAttackRate = value;
- }
- bool scaleRate(uint8 value);
- void decayRate(uint32 value) {
- _specifiedDecayRate = value;
- recalculateRates();
- }
- void sustainRate(uint32 value) {
- _specifiedSustainRate = value;
- recalculateRates();
- }
- void sustainLevel(uint32 value) {
- _sustainLevel = (value == 0x0f) ? 0x3e0 : value << 5;
- }
- void releaseRate(uint32 value) {
- _specifiedReleaseRate = value;
- recalculateRates();
- }
- void totalLevel(uint32 value) {
- _totalLevel = value << 3;
- }
- void ampModulation(bool enable) {
- _ampMod = enable;
- }
- void reset();
-
-protected:
- EnvelopeState _state;
- bool _playing;
- uint32 _feedbackLevel;
- uint32 _multiple;
- uint32 _totalLevel;
- uint8 _keyScale1;
- uint8 _keyScale2;
- uint32 _specifiedAttackRate;
- uint32 _specifiedDecayRate;
- uint32 _specifiedSustainRate;
- uint32 _specifiedReleaseRate;
- uint32 _tickCount;
- uint32 _sustainLevel;
-
- bool _ampMod;
- uint32 _frequency;
- uint8 _kcode;
- uint32 _phase;
- uint32 _phaseIncrement;
- const int32 *_detn;
-
- const uint8 *_rateTbl;
- const uint8 *_rshiftTbl;
- const uint8 *_adTbl;
- const uint32 *_fTbl;
- const uint32 *_sinTbl;
- const int32 *_tLvlTbl;
- const int32 *_detnTbl;
-
- const uint32 _tickLength;
- uint32 _timer;
- const uint32 _rtt;
- int32 _currentLevel;
-
- struct EvpState {
- uint8 rate;
- uint8 shift;
- } fs_a, fs_d, fs_s, fs_r;
-};
-
-TownsPC98_FmSynthOperator::TownsPC98_FmSynthOperator(const uint32 timerbase, const uint32 rtt,
- const uint8 *rateTable, const uint8 *shiftTable, const uint8 *attackDecayTable,
- const uint32 *frqTable, const uint32 *sineTable, const int32 *tlevelOut, const int32 *detuneTable) :
- _rtt(rtt), _rateTbl(rateTable), _rshiftTbl(shiftTable), _adTbl(attackDecayTable), _fTbl(frqTable),
- _sinTbl(sineTable), _tLvlTbl(tlevelOut), _detnTbl(detuneTable), _tickLength(timerbase * 2),
- _specifiedAttackRate(0), _specifiedDecayRate(0), _specifiedReleaseRate(0), _specifiedSustainRate(0),
- _phase(0), _state(kEnvReady), _playing(false), _timer(0), _keyScale1(0),
- _keyScale2(0), _currentLevel(1023), _ampMod(false), _tickCount(0) {
-
- fs_a.rate = fs_a.shift = fs_d.rate = fs_d.shift = fs_s.rate = fs_s.shift = fs_r.rate = fs_r.shift = 0;
-
- reset();
-}
-
-void TownsPC98_FmSynthOperator::keyOn() {
- if (_playing)
- return;
-
- _playing = true;
- _state = kEnvAttacking;
- _phase = 0;
-}
-
-void TownsPC98_FmSynthOperator::keyOff() {
- if (!_playing)
- return;
-
- _playing = false;
- if (_state != kEnvReady)
- _state = kEnvReleasing;
-}
-
-void TownsPC98_FmSynthOperator::frequency(int freq) {
- uint8 block = (freq >> 11);
- uint16 pos = (freq & 0x7ff);
- uint8 c = pos >> 7;
-
- _kcode = (block << 2) | ((c < 7) ? 0 : ((c > 8) ? 3 : c - 6));
- _frequency = _fTbl[pos << 1] >> (7 - block);
-}
-
-void TownsPC98_FmSynthOperator::updatePhaseIncrement() {
- _phaseIncrement = ((_frequency + _detn[_kcode]) * _multiple) >> 1;
- uint8 keyscale = _kcode >> _keyScale1;
- if (_keyScale2 != keyscale) {
- _keyScale2 = keyscale;
- recalculateRates();
- }
-}
-
-void TownsPC98_FmSynthOperator::recalculateRates() {
- int k = _keyScale2;
- int r = _specifiedAttackRate ? (_specifiedAttackRate << 1) + 0x20 : 0;
- fs_a.rate = ((r + k) < 94) ? _rateTbl[r + k] : 136;
- fs_a.shift = ((r + k) < 94) ? _rshiftTbl[r + k] : 0;
-
- r = _specifiedDecayRate ? (_specifiedDecayRate << 1) + 0x20 : 0;
- fs_d.rate = _rateTbl[r + k];
- fs_d.shift = _rshiftTbl[r + k];
-
- r = _specifiedSustainRate ? (_specifiedSustainRate << 1) + 0x20 : 0;
- fs_s.rate = _rateTbl[r + k];
- fs_s.shift = _rshiftTbl[r + k];
-
- r = (_specifiedReleaseRate << 2) + 0x22;
- fs_r.rate = _rateTbl[r + k];
- fs_r.shift = _rshiftTbl[r + k];
-}
-
-void TownsPC98_FmSynthOperator::generateOutput(int32 phasebuf, int32 *feed, int32 &out) {
- if (_state == kEnvReady)
- return;
-
- _timer += _tickLength;
- while (_timer > _rtt) {
- _timer -= _rtt;
- ++_tickCount;
-
- int32 levelIncrement = 0;
- uint32 targetTime = 0;
- int32 targetLevel = 0;
- EnvelopeState nextState = kEnvReady;
-
- switch (_state) {
- case kEnvReady:
- return;
- case kEnvAttacking:
- targetLevel = 0;
- nextState = kEnvDecaying;
- if ((_specifiedAttackRate << 1) + _keyScale2 < 64) {
- targetTime = (1 << fs_a.shift) - 1;
- levelIncrement = (~_currentLevel * _adTbl[fs_a.rate + ((_tickCount >> fs_a.shift) & 7)]) >> 4;
- break;
- } else {
- _currentLevel = targetLevel;
- _state = nextState;
- }
- // Fall through
- case kEnvDecaying:
- targetTime = (1 << fs_d.shift) - 1;
- nextState = kEnvSustaining;
- targetLevel = _sustainLevel;
- levelIncrement = _adTbl[fs_d.rate + ((_tickCount >> fs_d.shift) & 7)];
- break;
- case kEnvSustaining:
- targetTime = (1 << fs_s.shift) - 1;
- nextState = kEnvSustaining;
- targetLevel = 1023;
- levelIncrement = _adTbl[fs_s.rate + ((_tickCount >> fs_s.shift) & 7)];
- break;
- case kEnvReleasing:
- targetTime = (1 << fs_r.shift) - 1;
- nextState = kEnvReady;
- targetLevel = 1023;
- levelIncrement = _adTbl[fs_r.rate + ((_tickCount >> fs_r.shift) & 7)];
- break;
- }
-
- if (!(_tickCount & targetTime)) {
- _currentLevel += levelIncrement;
- if ((_state == kEnvAttacking && _currentLevel <= targetLevel) || (_state != kEnvAttacking && _currentLevel >= targetLevel)) {
- if (_state != kEnvDecaying)
- _currentLevel = targetLevel;
- _state = nextState;
- }
- }
- }
-
- uint32 lvlout = _totalLevel + (uint32) _currentLevel;
-
-
- int32 outp = 0;
- int32 *i = &outp, *o = &outp;
- int phaseShift = 0;
-
- if (feed) {
- o = &feed[0];
- i = &feed[1];
- phaseShift = _feedbackLevel ? ((*o + *i) << _feedbackLevel) : 0;
- *o = *i;
- } else {
- phaseShift = phasebuf << 15;
- }
-
- if (lvlout < 832) {
- uint32 index = (lvlout << 3) + _sinTbl[(((int32)((_phase & 0xffff0000)
- + phaseShift)) >> 16) & 0x3ff];
- *i = ((index < 6656) ? _tLvlTbl[index] : 0);
- } else {
- *i = 0;
- }
-
- _phase += _phaseIncrement;
- out += *o;
-}
-
-void TownsPC98_FmSynthOperator::reset() {
- keyOff();
- _timer = 0;
- _keyScale2 = 0;
- _currentLevel = 1023;
-
- frequency(0);
- detune(0);
- scaleRate(0);
- multiple(0);
- updatePhaseIncrement();
- attackRate(0);
- decayRate(0);
- releaseRate(0);
- sustainRate(0);
- feedbackLevel(0);
- totalLevel(127);
- ampModulation(false);
-}
-
-bool TownsPC98_FmSynthOperator::scaleRate(uint8 value) {
- value = 3 - value;
- if (_keyScale1 != value) {
- _keyScale1 = value;
- return true;
- }
-
- int k = _keyScale2;
- int r = _specifiedAttackRate ? (_specifiedAttackRate << 1) + 0x20 : 0;
- fs_a.rate = ((r + k) < 94) ? _rateTbl[r + k] : 136;
- fs_a.shift = ((r + k) < 94) ? _rshiftTbl[r + k] : 0;
- return false;
-}
-
-class TownsPC98_FmSynthSquareSineSource {
-public:
- TownsPC98_FmSynthSquareSineSource(const uint32 timerbase, const uint32 rtt);
- ~TownsPC98_FmSynthSquareSineSource();
-
- void init(const int *rsTable, const int *rseTable);
- void reset();
- void writeReg(uint8 address, uint8 value, bool force = false);
-
- void nextTick(int32 *buffer, uint32 bufferSize);
-
- void setVolumeIntern(int volA, int volB) {
- _volumeA = volA;
- _volumeB = volB;
- }
- void setVolumeChannelMasks(int channelMaskA, int channelMaskB) {
- _volMaskA = channelMaskA;
- _volMaskB = channelMaskB;
- }
-
- uint8 chanEnable() const {
- return _chanEnable;
- }
-private:
- void updateRegs();
-
- uint8 _updateRequestBuf[64];
- int _updateRequest;
- int _rand;
-
- int8 _evpTimer;
- uint32 _pReslt;
- uint8 _attack;
-
- bool _evpUpdate, _cont;
-
- int _evpUpdateCnt;
- uint8 _outN;
- int _nTick;
-
- int32 *_tlTable;
- int32 *_tleTable;
-
- const uint32 _tickLength;
- uint32 _timer;
- const uint32 _rtt;
-
- struct Channel {
- int tick;
- uint8 smp;
- uint8 out;
-
- uint8 frqL;
- uint8 frqH;
- uint8 vol;
- } _channels[3];
-
- uint8 _noiseGenerator;
- uint8 _chanEnable;
-
- uint8 **_reg;
-
- uint16 _volumeA;
- uint16 _volumeB;
- int _volMaskA;
- int _volMaskB;
-
- bool _ready;
-};
-
-#ifndef DISABLE_PC98_RHYTHM_CHANNEL
-class TownsPC98_FmSynthPercussionSource {
-public:
- TownsPC98_FmSynthPercussionSource(const uint32 timerbase, const uint32 rtt);
- ~TownsPC98_FmSynthPercussionSource() {
- delete[] _reg;
- }
-
- void init(const uint8 *instrData = 0);
- void reset();
- void writeReg(uint8 address, uint8 value);
-
- void nextTick(int32 *buffer, uint32 bufferSize);
-
- void setVolumeIntern(int volA, int volB) {
- _volumeA = volA;
- _volumeB = volB;
- }
- void setVolumeChannelMasks(int channelMaskA, int channelMaskB) {
- _volMaskA = channelMaskA;
- _volMaskB = channelMaskB;
- }
-
-private:
- struct RhtChannel {
- const uint8 *data;
-
- const uint8 *start;
- const uint8 *end;
- const uint8 *pos;
- uint32 size;
- bool active;
- uint8 level;
-
- int8 decState;
- uint8 decStep;
-
- int16 samples[2];
- int out;
-
- uint8 startPosH;
- uint8 startPosL;
- uint8 endPosH;
- uint8 endPosL;
- };
-
- void recalcOuput(RhtChannel *ins);
- void advanceInput(RhtChannel *ins);
-
- RhtChannel _rhChan[6];
-
- uint8 _totalLevel;
-
- const uint32 _tickLength;
- uint32 _timer;
- const uint32 _rtt;
-
- uint8 **_reg;
-
- uint16 _volumeA;
- uint16 _volumeB;
- int _volMaskA;
- int _volMaskB;
-
- 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),
- _nTick(0), _evpUpdateCnt(0), _evpTimer(0x1f), _pReslt(0x1f), _attack(0), _cont(false), _evpUpdate(true),
- _timer(0), _noiseGenerator(0), _chanEnable(0),
- _volMaskA(0), _volMaskB(0), _volumeA(Audio::Mixer::kMaxMixerVolume), _volumeB(Audio::Mixer::kMaxMixerVolume) {
-
- memset(_channels, 0, sizeof(_channels));
- memset(_updateRequestBuf, 0, sizeof(_updateRequestBuf));
- _reg = new uint8 *[11];
-
- _reg[0] = &_channels[0].frqL;
- _reg[1] = &_channels[0].frqH;
- _reg[2] = &_channels[1].frqL;
- _reg[3] = &_channels[1].frqH;
- _reg[4] = &_channels[2].frqL;
- _reg[5] = &_channels[2].frqH;
- _reg[6] = &_noiseGenerator;
- _reg[7] = &_chanEnable;
- _reg[8] = &_channels[0].vol;
- _reg[9] = &_channels[1].vol;
- _reg[10] = &_channels[2].vol;
-
- reset();
-}
-
-TownsPC98_FmSynthSquareSineSource::~TownsPC98_FmSynthSquareSineSource() {
- delete[] _tlTable;
- delete[] _tleTable;
- delete[] _reg;
-}
-
-void TownsPC98_FmSynthSquareSineSource::init(const int *rsTable, const int *rseTable) {
- if (_ready) {
- reset();
- return;
- }
-
- delete[] _tlTable;
- delete[] _tleTable;
- _tlTable = new int32[16];
- _tleTable = new int32[32];
- float a, b, d;
- d = 801.0f;
-
- for (int i = 0; i < 16; i++) {
- b = 1.0f / rsTable[i];
- a = 1.0f / d + b + 1.0f / 1000.0f;
- float v = (b / a) * 32767.0f;
- _tlTable[i] = (int32) v;
-
- b = 1.0f / rseTable[i];
- a = 1.0f / d + b + 1.0f / 1000.0f;
- v = (b / a) * 32767.0f;
- _tleTable[i] = (int32) v;
- }
-
- for (int i = 16; i < 32; i++) {
- b = 1.0f / rseTable[i];
- a = 1.0f / d + b + 1.0f / 1000.0f;
- float v = (b / a) * 32767.0f;
- _tleTable[i] = (int32) v;
- }
-
- _ready = true;
-}
-
-void TownsPC98_FmSynthSquareSineSource::reset() {
- _rand = 1;
- _outN = 1;
- _updateRequest = -1;
- _nTick = _evpUpdateCnt = 0;
- _evpTimer = 0x1f;
- _pReslt = 0x1f;
- _attack = 0;
- _cont = false;
- _evpUpdate = true;
- _timer = 0;
-
- for (int i = 0; i < 3; i++) {
- _channels[i].tick = 0;
- _channels[i].smp = _channels[i].out = 0;
- }
-
- for (int i = 0; i < 14; i++)
- writeReg(i, 0, true);
-
- writeReg(7, 0xbf, true);
-}
-
-void TownsPC98_FmSynthSquareSineSource::writeReg(uint8 address, uint8 value, bool force) {
- if (!_ready)
- return;
-
- if (address > 10 || *_reg[address] == value) {
- if ((address == 11 || address == 12 || address == 13) && value)
- warning("TownsPC98_FmSynthSquareSineSource: unsupported reg address: %d", address);
- return;
- }
-
- if (!force) {
- if (_updateRequest >= 63) {
- warning("TownsPC98_FmSynthSquareSineSource: event buffer overflow");
- _updateRequest = -1;
- }
- _updateRequestBuf[++_updateRequest] = value;
- _updateRequestBuf[++_updateRequest] = address;
- return;
- }
-
- *_reg[address] = value;
-}
-
-void TownsPC98_FmSynthSquareSineSource::nextTick(int32 *buffer, uint32 bufferSize) {
- if (!_ready)
- return;
-
- for (uint32 i = 0; i < bufferSize; i++) {
- _timer += _tickLength;
- while (_timer > _rtt) {
- _timer -= _rtt;
-
- if (++_nTick >= (_noiseGenerator & 0x1f)) {
- if ((_rand + 1) & 2)
- _outN ^= 1;
-
- _rand = (((_rand & 1) ^ ((_rand >> 3) & 1)) << 16) | (_rand >> 1);
- _nTick = 0;
- }
-
- for (int ii = 0; ii < 3; ii++) {
- if (++_channels[ii].tick >= (((_channels[ii].frqH & 0x0f) << 8) | _channels[ii].frqL)) {
- _channels[ii].tick = 0;
- _channels[ii].smp ^= 1;
- }
- _channels[ii].out = (_channels[ii].smp | ((_chanEnable >> ii) & 1)) & (_outN | ((_chanEnable >> (ii + 3)) & 1));
- }
-
- if (_evpUpdate) {
- if (++_evpUpdateCnt >= 0) {
- _evpUpdateCnt = 0;
-
- if (--_evpTimer < 0) {
- if (_cont) {
- _evpTimer &= 0x1f;
- } else {
- _evpUpdate = false;
- _evpTimer = 0;
- }
- }
- }
- }
- _pReslt = _evpTimer ^ _attack;
- updateRegs();
- }
-
- int32 finOut = 0;
- for (int ii = 0; ii < 3; ii++) {
- int32 finOutTemp = ((_channels[ii].vol >> 4) & 1) ? _tleTable[_channels[ii].out ? _pReslt : 0] : _tlTable[_channels[ii].out ? (_channels[ii].vol & 0x0f) : 0];
-
- if ((1 << ii) & _volMaskA)
- finOutTemp = (finOutTemp * _volumeA) / Audio::Mixer::kMaxMixerVolume;
-
- if ((1 << ii) & _volMaskB)
- finOutTemp = (finOutTemp * _volumeB) / Audio::Mixer::kMaxMixerVolume;
-
- finOut += finOutTemp;
- }
-
- finOut /= 3;
-
- buffer[i << 1] += finOut;
- buffer[(i << 1) + 1] += finOut;
- }
-}
-
-void TownsPC98_FmSynthSquareSineSource::updateRegs() {
- for (int i = 0; i < _updateRequest;) {
- uint8 b = _updateRequestBuf[i++];
- uint8 a = _updateRequestBuf[i++];
- writeReg(a, b, true);
- }
- _updateRequest = -1;
-}
-
-#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) {
-
- memset(_rhChan, 0, sizeof(RhtChannel) * 6);
- _reg = new uint8 *[40];
-
- _reg[0] = _reg[1] = _reg[2] = _reg[3] = _reg[4] = _reg[5] = _reg[6] = _reg[7] = _reg[8] = _reg[9] = _reg[10] = _reg[11] = _reg[12] = _reg[13] = _reg[14] = _reg[15] = 0;
- _reg[16] = &_rhChan[0].startPosL;
- _reg[17] = &_rhChan[1].startPosL;
- _reg[18] = &_rhChan[2].startPosL;
- _reg[19] = &_rhChan[3].startPosL;
- _reg[20] = &_rhChan[4].startPosL;
- _reg[21] = &_rhChan[5].startPosL;
- _reg[22] = &_rhChan[0].startPosH;
- _reg[23] = &_rhChan[1].startPosH;
- _reg[24] = &_rhChan[2].startPosH;
- _reg[25] = &_rhChan[3].startPosH;
- _reg[26] = &_rhChan[4].startPosH;
- _reg[27] = &_rhChan[5].startPosH;
- _reg[28] = &_rhChan[0].endPosL;
- _reg[29] = &_rhChan[1].endPosL;
- _reg[30] = &_rhChan[2].endPosL;
- _reg[31] = &_rhChan[3].endPosL;
- _reg[32] = &_rhChan[4].endPosL;
- _reg[33] = &_rhChan[5].endPosL;
- _reg[34] = &_rhChan[0].endPosH;
- _reg[35] = &_rhChan[1].endPosH;
- _reg[36] = &_rhChan[2].endPosH;
- _reg[37] = &_rhChan[3].endPosH;
- _reg[38] = &_rhChan[4].endPosH;
- _reg[39] = &_rhChan[5].endPosH;
-}
-
-void TownsPC98_FmSynthPercussionSource::init(const uint8 *instrData) {
- if (_ready) {
- reset();
- return;
- }
-
- const uint8 *start = instrData;
- const uint8 *pos = start;
-
- if (instrData) {
- for (int i = 0; i < 6; i++) {
- _rhChan[i].data = start + READ_BE_UINT16(pos);
- pos += 2;
- _rhChan[i].size = READ_BE_UINT16(pos);
- pos += 2;
- }
- reset();
- _ready = true;
- } else {
- memset(_rhChan, 0, sizeof(RhtChannel) * 6);
- _ready = false;
- }
-}
-
-void TownsPC98_FmSynthPercussionSource::reset() {
- _timer = 0;
- _totalLevel = 63;
-
- for (int i = 0; i < 6; i++) {
- RhtChannel *s = &_rhChan[i];
- s->pos = s->start = s->data;
- s->end = s->data + s->size;
- s->active = false;
- s->level = 0;
- s->out = 0;
- s->decStep = 1;
- s->decState = 0;
- s->samples[0] = s->samples[1] = 0;
- s->startPosH = s->startPosL = s->endPosH = s->endPosL = 0;
- }
-}
-
-void TownsPC98_FmSynthPercussionSource::writeReg(uint8 address, uint8 value) {
- if (!_ready)
- return;
-
- uint8 h = address >> 4;
- uint8 l = address & 15;
-
- if (address > 15)
- *_reg[address] = value;
-
- if (address == 0) {
- if (value & 0x80) {
- //key off
- for (int i = 0; i < 6; i++) {
- if ((value >> i) & 1)
- _rhChan[i].active = false;
- }
- } else {
- //key on
- for (int i = 0; i < 6; i++) {
- if ((value >> i) & 1) {
- RhtChannel *s = &_rhChan[i];
- s->pos = s->start;
- s->active = true;
- s->out = 0;
- s->samples[0] = s->samples[1] = 0;
- s->decStep = 1;
- s->decState = 0;
- }
- }
- }
- } else if (address == 1) {
- // total level
- _totalLevel = (value & 63) ^ 63;
- for (int i = 0; i < 6; i++)
- recalcOuput(&_rhChan[i]);
- } else if (!h && l & 8) {
- // instrument level
- l &= 7;
- _rhChan[l].level = (value & 0x1f) ^ 0x1f;
- recalcOuput(&_rhChan[l]);
- } else if (h & 3) {
- l &= 7;
- if (h == 1) {
- // set start offset
- _rhChan[l].start = _rhChan[l].data + ((_rhChan[l].startPosH << 8 | _rhChan[l].startPosL) << 8);
- } else if (h == 2) {
- // set end offset
- _rhChan[l].end = _rhChan[l].data + ((_rhChan[l].endPosH << 8 | _rhChan[l].endPosL) << 8) + 255;
- }
- }
-}
-
-void TownsPC98_FmSynthPercussionSource::nextTick(int32 *buffer, uint32 bufferSize) {
- if (!_ready)
- return;
-
- for (uint32 i = 0; i < bufferSize; i++) {
- _timer += _tickLength;
- while (_timer > _rtt) {
- _timer -= _rtt;
-
- for (int ii = 0; ii < 6; ii++) {
- RhtChannel *s = &_rhChan[ii];
- if (s->active) {
- recalcOuput(s);
- if (s->decStep) {
- advanceInput(s);
- if (s->pos == s->end)
- s->active = false;
- }
- s->decStep ^= 1;
- }
- }
- }
-
- int32 finOut = 0;
-
- for (int ii = 0; ii < 6; ii++) {
- if (_rhChan[ii].active)
- finOut += _rhChan[ii].out;
- }
-
- finOut <<= 1;
-
- if (1 & _volMaskA)
- finOut = (finOut * _volumeA) / Audio::Mixer::kMaxMixerVolume;
-
- if (1 & _volMaskB)
- finOut = (finOut * _volumeB) / Audio::Mixer::kMaxMixerVolume;
-
- buffer[i << 1] += finOut;
- buffer[(i << 1) + 1] += finOut;
- }
-}
-
-void TownsPC98_FmSynthPercussionSource::recalcOuput(RhtChannel *ins) {
- uint32 s = _totalLevel + ins->level;
- uint32 x = s > 62 ? 0 : (1 + (s >> 3));
- int32 y = s > 62 ? 0 : (15 - (s & 7));
- ins->out = ((ins->samples[ins->decStep] * y) >> x) & ~3;
-}
-
-void TownsPC98_FmSynthPercussionSource::advanceInput(RhtChannel *ins) {
- static const int8 adjustIndex[] = { -1, -1, -1, -1, 2, 5, 7, 9 };
-
- static const int16 stepTable[] = {
- 16, 17, 19, 21, 23, 25, 28, 31, 34, 37, 41, 45, 50, 55,
- 60, 66, 73, 80, 88, 97, 107, 118, 130, 143, 157, 173, 190, 209, 230, 253, 279, 307, 337,
- 371, 408, 449, 494, 544, 598, 658, 724, 796, 876, 963, 1060, 1166, 1282, 1411, 1552
- };
-
- uint8 cur = (int8)*ins->pos++;
-
- for (int i = 0; i < 2; i++) {
- int b = (2 * (cur & 7) + 1) * stepTable[ins->decState] / 8;
- ins->samples[i] = CLIP<int16>(ins->samples[i ^ 1] + (cur & 8 ? b : -b), -2048, 2047);
- ins->decState = CLIP<int8>(ins->decState + adjustIndex[cur & 7], 0, 48);
- cur >>= 4;
- }
-}
-#endif // DISABLE_PC98_RHYTHM_CHANNEL
-
-TownsPC98_FmSynth::TownsPC98_FmSynth(Audio::Mixer *mixer, EmuType type) :
- _mixer(mixer),
- _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),
- _regProtectionFlag(false), _ready(false) {
-
- memset(&_timers[0], 0, sizeof(ChipTimer));
- memset(&_timers[1], 0, sizeof(ChipTimer));
-
- _timers[0].cb = _timers[1].cb = &TownsPC98_FmSynth::idleTimerCallback;
- _timerbase = (uint32)(_baserate * 1000000.0f);
-}
-
-TownsPC98_FmSynth::~TownsPC98_FmSynth() {
- if (_ready)
- deinit();
-
- delete _ssg;
-#ifndef DISABLE_PC98_RHYTHM_CHANNEL
- delete _prc;
-#endif
- delete[] _chanInternal;
-
- delete[] _oprRates;
- delete[] _oprRateshift;
- delete[] _oprFrq;
- delete[] _oprAttackDecay;
- delete[] _oprSinTbl;
- delete[] _oprLevelOut;
- delete[] _oprDetune;
-}
-
-bool TownsPC98_FmSynth::init() {
- if (_ready) {
- reset();
- return true;
- }
-
- generateTables();
-
- _chanInternal = new ChanInternal[_numChan];
- for (int i = 0; i < _numChan; i++) {
- memset(&_chanInternal[i], 0, sizeof(ChanInternal));
- for (int j = 0; j < 4; ++j)
- _chanInternal[i].opr[j] = new TownsPC98_FmSynthOperator(_timerbase, _rtt, _oprRates, _oprRateshift, _oprAttackDecay, _oprFrq, _oprSinTbl, _oprLevelOut, _oprDetune);
- }
-
- if (_numSSG) {
- _ssg = new TownsPC98_FmSynthSquareSineSource(_timerbase, _rtt);
- _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);
-
- _ready = true;
-
- return true;
-}
-
-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();
- memset(_chanInternal[i].feedbuf, 0, 3);
- _chanInternal[i].algorithm = 0;
- _chanInternal[i].frqTemp = 0;
- _chanInternal[i].enableLeft = _chanInternal[i].enableRight = true;
- _chanInternal[i].updateEnvelopeParameters = false;
- }
-
- writeReg(0, 0x27, 0x33);
-
- if (_ssg)
- _ssg->reset();
-
-#ifndef DISABLE_PC98_RHYTHM_CHANNEL
- if (_prc)
- _prc->reset();
-#endif
-}
-
-void TownsPC98_FmSynth::writeReg(uint8 part, uint8 regAddress, uint8 value) {
- if (_regProtectionFlag || !_ready)
- return;
-
- static const uint8 oprOrdr[] = { 0, 2, 1, 3 };
-
- Common::StackLock lock(_mutex);
-
- uint8 h = regAddress & 0xf0;
- uint8 l = (regAddress & 0x0f);
-
- ChanInternal *c = 0;
- TownsPC98_FmSynthOperator **co = 0;
- TownsPC98_FmSynthOperator *o = 0;
-
- if (regAddress > 0x2F) {
- c = &_chanInternal[(l & 3) + 3 * part];
- co = c->opr;
- o = c->opr[oprOrdr[(l - (l & 3)) >> 2]];
- } else if (regAddress == 0x28) {
- c = &_chanInternal[(value & 3) + ((value & 4) ? 3 : 0)];
- co = c->opr;
- }
-
- switch (h) {
- case 0x00:
- // ssg
- if (_ssg)
- _ssg->writeReg(l, value);
- break;
- case 0x10:
-#ifndef DISABLE_PC98_RHYTHM_CHANNEL
- // pcm rhythm channel
- if (_prc)
- _prc->writeReg(l, value);
-#endif
- break;
- case 0x20:
- if (l == 8) {
- // Key on/off
- for (int i = 0; i < 4; i++) {
- if ((value >> (4 + i)) & 1)
- co[oprOrdr[i]]->keyOn();
- else
- co[oprOrdr[i]]->keyOff();
- }
- } else if (l == 4) {
- // Timer A
- _timers[0].value = (_timers[0].value & 3) | (value << 2);
- } else if (l == 5) {
- // Timer A
- _timers[0].value = (_timers[0].value & 0x3fc) | (value & 3);
- } else if (l == 6) {
- // Timer B
- _timers[1].value = value & 0xff;
- } else if (l == 7) {
- if (value & 1) {
- float spc = (float)(0x400 - _timers[0].value) / _baserate;
- if (spc < 1) {
- warning("TownsPC98_FmSynth: Invalid Timer A setting: %d", _timers[0].value);
- spc = 1;
- }
-
- _timers[0].smpPerCb = (int32) spc;
- _timers[0].smpPerCbRem = (uint32)((spc - (float)_timers[0].smpPerCb) * 1000000.0f);
- _timers[0].smpTillCb = _timers[0].smpPerCb;
- _timers[0].smpTillCbRem = _timers[0].smpPerCbRem;
- _timers[0].enabled = true;
- } else {
- _timers[0].enabled = false;
- }
-
- if (value & 2) {
- float spc = (float)(0x100 - _timers[1].value) * 16.0f / _baserate;
- if (spc < 1) {
- warning("TownsPC98_FmSynth: Invalid Timer B setting: %d", _timers[1].value);
- spc = 1;
- }
-
- _timers[1].smpPerCb = (int32) spc;
- _timers[1].smpPerCbRem = (uint32)((spc - (float)_timers[1].smpPerCb) * 1000000.0f);
- _timers[1].smpTillCb = _timers[1].smpPerCb;
- _timers[1].smpTillCbRem = _timers[1].smpPerCbRem;
- _timers[1].enabled = true;
- } else {
- _timers[1].enabled = false;
- }
-
- if (value & 0x10) {
- _timers[0].smpTillCb = _timers[0].smpPerCb;
- _timers[0].smpTillCbRem = _timers[0].smpTillCbRem;
- }
-
- if (value & 0x20) {
- _timers[1].smpTillCb = _timers[1].smpPerCb;
- _timers[1].smpTillCbRem = _timers[1].smpTillCbRem;
- }
- } else if (l == 2) {
- // LFO
- if (value & 8)
- warning("TownsPC98_FmSynth: TRYING TO USE LFO (NOT SUPPORTED)");
- } else if (l == 10 || l == 11) {
- // DAC
- if (l == 11 && (value & 0x80))
- warning("TownsPC98_FmSynth: TRYING TO USE DAC (NOT SUPPORTED)");
- }
- break;
-
- case 0x30:
- // detune, multiple
- o->detune((value >> 4) & 7);
- o->multiple(value & 0x0f);
- c->updateEnvelopeParameters = true;
- break;
-
- case 0x40:
- // total level
- o->totalLevel(value & 0x7f);
- break;
-
- case 0x50:
- // rate scaling, attack rate
- o->attackRate(value & 0x1f);
- if (o->scaleRate(value >> 6))
- c->updateEnvelopeParameters = true;
- break;
-
- case 0x60:
- // first decay rate, amplitude modulation
- o->decayRate(value & 0x1f);
- o->ampModulation(value & 0x80 ? true : false);
- break;
-
- case 0x70:
- // secondary decay rate
- o->sustainRate(value & 0x1f);
- break;
-
- case 0x80:
- // secondary amplitude, release rate;
- o->sustainLevel(value >> 4);
- o->releaseRate(value & 0x0f);
- break;
-
- case 0x90:
- warning("TownsPC98_FmSynth: TRYING TO USE SSG ENVELOPE SHAPES (NOT SUPPORTED)");
- break;
-
- case 0xa0:
- // frequency
- l &= ~3;
- if (l == 0) {
- c->frqTemp = (c->frqTemp & 0xff00) | value;
- c->updateEnvelopeParameters = true;
- for (int i = 0; i < 4; i++)
- co[i]->frequency(c->frqTemp);
- } else if (l == 4) {
- c->frqTemp = (c->frqTemp & 0xff) | (value << 8);
- } else if (l == 8) {
- // Ch 3/6 special mode frq
- warning("TownsPC98_FmSynth: TRYING TO USE CH 3/6 SPECIAL MODE FREQ (NOT SUPPORTED)");
- } else if (l == 12) {
- // Ch 3/6 special mode frq
- warning("TownsPC98_FmSynth: TRYING TO USE CH 3/6 SPECIAL MODE FREQ (NOT SUPPORTED)");
- }
- break;
-
- case 0xb0:
- l &= ~3;
- if (l == 0) {
- // feedback, _algorithm
- co[0]->feedbackLevel((value >> 3) & 7);
- c->algorithm = value & 7;
- } else if (l == 4) {
- // stereo, LFO sensitivity
- c->enableLeft = value & 0x80 ? true : false;
- c->enableRight = value & 0x40 ? true : false;
- c->ampModSensitivity((value & 0x30) >> 4);
- c->frqModSensitivity(value & 3);
- }
- break;
-
- default:
- warning("TownsPC98_FmSynth: UNKNOWN ADDRESS %d", regAddress);
- }
-}
-
-int TownsPC98_FmSynth::readBuffer(int16 *buffer, const int numSamples) {
- Common::StackLock lock(_mutex);
-
- memset(buffer, 0, sizeof(int16) * numSamples);
- int32 *tmp = new int32[numSamples];
- int32 *tmpStart = tmp;
- memset(tmp, 0, sizeof(int32) * numSamples);
- int32 samplesLeft = numSamples >> 1;
-
- while (_ready && samplesLeft) {
- int32 render = samplesLeft;
-
- for (int i = 0; i < 2; i++) {
- if (_timers[i].enabled && _timers[i].cb) {
- if (!_timers[i].smpTillCb) {
- (this->*_timers[i].cb)();
- _timers[i].smpTillCb = _timers[i].smpPerCb;
-
- _timers[i].smpTillCbRem += _timers[i].smpPerCbRem;
- if (_timers[i].smpTillCbRem >= _timerbase) {
- _timers[i].smpTillCb++;
- _timers[i].smpTillCbRem -= _timerbase;
- }
- }
- render = MIN(render, _timers[i].smpTillCb);
- }
- }
-
- samplesLeft -= render;
-
- for (int i = 0; i < 2; i++) {
- if (_timers[i].enabled && _timers[i].cb) {
- _timers[i].smpTillCb -= render;
- }
- }
-
- nextTick(tmp, render);
-
- if (_ssg)
- _ssg->nextTick(tmp, render);
-#ifndef DISABLE_PC98_RHYTHM_CHANNEL
- if (_prc)
- _prc->nextTick(tmp, render);
-#endif
-
- nextTickEx(tmp, render);
-
- for (int i = 0; i < render; ++i) {
- int32 l = CLIP<int32>(tmp[i << 1], -32767, 32767);
- buffer[i << 1] = (int16) l;
- int32 r = CLIP<int32>(tmp[(i << 1) + 1], -32767, 32767);
- buffer[(i << 1) + 1] = (int16) r;
- }
-
- buffer += (render << 1);
- tmp += (render << 1);
- }
-
- delete[] tmpStart;
- return numSamples;
-}
-
-void TownsPC98_FmSynth::deinit() {
- _ready = false;
- _mixer->stopHandle(_soundHandle);
- _timers[0].cb = _timers[1].cb = &TownsPC98_FmSynth::idleTimerCallback;
-}
-
-uint8 TownsPC98_FmSynth::readSSGStatus() {
- return _ssg->chanEnable();
-}
-
-void TownsPC98_FmSynth::setVolumeIntern(int volA, int volB) {
- Common::StackLock lock(_mutex);
- _volumeA = CLIP<uint16>(volA, 0, Audio::Mixer::kMaxMixerVolume);
- _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) {
- Common::StackLock lock(_mutex);
- _volMaskA = channelMaskA;
- _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() {
- delete[] _oprRates;
- _oprRates = new uint8[128];
-
- WRITE_BE_UINT32(_oprRates + 32, _numChan == 6 ? 0x90900000 : 0x00081018);
- WRITE_BE_UINT32(_oprRates + 36, _numChan == 6 ? 0x00001010 : 0x00081018);
- memset(_oprRates, 0x90, 32);
- memset(_oprRates + 96, 0x80, 32);
- uint8 *dst = (uint8 *)_oprRates + 40;
- for (int i = 0; i < 40; i += 4)
- WRITE_BE_UINT32(dst + i, 0x00081018);
- for (int i = 0; i < 48; i += 4)
- WRITE_BE_UINT32(dst + i, 0x00081018);
- dst += 40;
- for (uint8 i = 0; i < 16; i ++) {
- uint8 v = (i < 12) ? i : 12;
- *dst++ = ((4 + v) << 3);
- }
-
- delete[] _oprRateshift;
- _oprRateshift = new uint8[128];
- memset(_oprRateshift, 0, 128);
- dst = (uint8 *)_oprRateshift + 32;
- for (int i = 11; i; i--) {
- memset(dst, i, 4);
- dst += 4;
- }
-
- delete[] _oprFrq;
- _oprFrq = new uint32[0x1000];
- for (uint32 i = 0; i < 0x1000; i++)
- _oprFrq[i] = (uint32)(_baserate * (float)(i << 11));
-
- delete[] _oprAttackDecay;
- _oprAttackDecay = new uint8[152];
- memset(_oprAttackDecay, 0, 152);
- for (int i = 0; i < 36; i++)
- WRITE_BE_UINT32(_oprAttackDecay + (i << 2), _adtStat[i]);
-
- delete[] _oprSinTbl;
- _oprSinTbl = new uint32[1024];
- for (int i = 0; i < 1024; i++) {
- double val = sin((double)(((i << 1) + 1) * PI / 1024.0));
- double d_dcb = log(1.0 / (double)ABS(val)) / log(2.0) * 256.0;
- int32 i_dcb = (int32)(2.0 * d_dcb);
- i_dcb = (i_dcb & 1) ? (i_dcb >> 1) + 1 : (i_dcb >> 1);
- _oprSinTbl[i] = (i_dcb << 1) + (val >= 0.0 ? 0 : 1);
- }
-
- delete[] _oprLevelOut;
- _oprLevelOut = new int32[0x1a00];
- for (int i = 0; i < 256; i++) {
- double val = floor(65536.0 / pow(2.0, 0.00390625 * (double)(1 + i)));
- int32 val_int = ((int32) val) >> 4;
- _oprLevelOut[i << 1] = (val_int & 1) ? ((val_int >> 1) + 1) << 2 : (val_int >> 1) << 2;
- _oprLevelOut[(i << 1) + 1] = -_oprLevelOut[i << 1];
- for (int ii = 1; ii < 13; ++ii) {
- _oprLevelOut[(i << 1) + (ii << 9)] = _oprLevelOut[i << 1] >> ii;
- _oprLevelOut[(i << 1) + (ii << 9) + 1] = -_oprLevelOut[(i << 1) + (ii << 9)];
- }
- }
-
- uint8 *dtt = new uint8[128];
- memset(dtt, 0, 36);
- memset(dtt + 36, 1, 8);
- memcpy(dtt + 44, _detSrc, 84);
-
- delete[] _oprDetune;
- _oprDetune = new int32[256];
- for (int i = 0; i < 128; i++) {
- _oprDetune[i] = (int32)((float)dtt[i] * _baserate * 64.0);
- _oprDetune[i + 128] = -_oprDetune[i];
- }
-
- delete[] dtt;
-}
-
-void TownsPC98_FmSynth::nextTick(int32 *buffer, uint32 bufferSize) {
- if (!_ready)
- return;
-
- for (int i = 0; i < _numChan; i++) {
- TownsPC98_FmSynthOperator **o = _chanInternal[i].opr;
-
- if (_chanInternal[i].updateEnvelopeParameters) {
- _chanInternal[i].updateEnvelopeParameters = false;
- for (int ii = 0; ii < 4 ; ii++)
- o[ii]->updatePhaseIncrement();
- }
-
- for (uint32 ii = 0; ii < bufferSize ; ii++) {
- int32 phbuf1, phbuf2, output;
- phbuf1 = phbuf2 = output = 0;
-
- int32 *leftSample = &buffer[ii * 2];
- int32 *rightSample = &buffer[ii * 2 + 1];
- int32 *del = &_chanInternal[i].feedbuf[2];
- int32 *feed = _chanInternal[i].feedbuf;
-
- switch (_chanInternal[i].algorithm) {
- case 0:
- o[0]->generateOutput(0, feed, phbuf1);
- o[2]->generateOutput(*del, 0, phbuf2);
- *del = 0;
- o[1]->generateOutput(phbuf1, 0, *del);
- o[3]->generateOutput(phbuf2, 0, output);
- break;
- case 1:
- o[0]->generateOutput(0, feed, phbuf1);
- o[2]->generateOutput(*del, 0, phbuf2);
- o[1]->generateOutput(0, 0, phbuf1);
- o[3]->generateOutput(phbuf2, 0, output);
- *del = phbuf1;
- break;
- case 2:
- o[0]->generateOutput(0, feed, phbuf2);
- o[2]->generateOutput(*del, 0, phbuf2);
- o[1]->generateOutput(0, 0, phbuf1);
- o[3]->generateOutput(phbuf2, 0, output);
- *del = phbuf1;
- break;
- case 3:
- o[0]->generateOutput(0, feed, phbuf2);
- o[2]->generateOutput(0, 0, *del);
- o[1]->generateOutput(phbuf2, 0, phbuf1);
- o[3]->generateOutput(*del, 0, output);
- *del = phbuf1;
- break;
- case 4:
- o[0]->generateOutput(0, feed, phbuf1);
- o[2]->generateOutput(0, 0, phbuf2);
- o[1]->generateOutput(phbuf1, 0, output);
- o[3]->generateOutput(phbuf2, 0, output);
- *del = 0;
- break;
- case 5:
- o[0]->generateOutput(0, feed, phbuf1);
- o[2]->generateOutput(*del, 0, output);
- o[1]->generateOutput(phbuf1, 0, output);
- o[3]->generateOutput(phbuf1, 0, output);
- *del = phbuf1;
- break;
- case 6:
- o[0]->generateOutput(0, feed, phbuf1);
- o[2]->generateOutput(0, 0, output);
- o[1]->generateOutput(phbuf1, 0, output);
- o[3]->generateOutput(0, 0, output);
- *del = 0;
- break;
- case 7:
- o[0]->generateOutput(0, feed, output);
- o[2]->generateOutput(0, 0, output);
- o[1]->generateOutput(0, 0, output);
- o[3]->generateOutput(0, 0, output);
- *del = 0;
- break;
- };
-
- int32 finOut = (output << 2) / ((_numChan + _numSSG - 3) / 3);
-
- if ((1 << i) & _volMaskA)
- finOut = (finOut * _volumeA) / Audio::Mixer::kMaxMixerVolume;
-
- if ((1 << i) & _volMaskB)
- finOut = (finOut * _volumeB) / Audio::Mixer::kMaxMixerVolume;
-
- if (_chanInternal[i].enableLeft)
- *leftSample += finOut;
-
- if (_chanInternal[i].enableRight)
- *rightSample += finOut;
- }
- }
-}
-
-const uint32 TownsPC98_FmSynth::_adtStat[] = {
- 0x00010001, 0x00010001, 0x00010001, 0x01010001,
- 0x00010101, 0x00010101, 0x00010101, 0x01010101,
- 0x01010101, 0x01010101, 0x01010102, 0x01010102,
- 0x01020102, 0x01020102, 0x01020202, 0x01020202,
- 0x02020202, 0x02020202, 0x02020204, 0x02020204,
- 0x02040204, 0x02040204, 0x02040404, 0x02040404,
- 0x04040404, 0x04040404, 0x04040408, 0x04040408,
- 0x04080408, 0x04080408, 0x04080808, 0x04080808,
- 0x08080808, 0x08080808, 0x10101010, 0x10101010
-};
-
-const uint8 TownsPC98_FmSynth::_detSrc[] = {
- 0x02, 0x02, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03,
- 0x04, 0x04, 0x04, 0x05, 0x05, 0x06, 0x06, 0x07,
- 0x08, 0x08, 0x08, 0x08, 0x01, 0x01, 0x01, 0x01,
- 0x02, 0x02, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03,
- 0x04, 0x04, 0x04, 0x05, 0x05, 0x06, 0x06, 0x07,
- 0x08, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
- 0x10, 0x10, 0x10, 0x10, 0x02, 0x02, 0x02, 0x02,
- 0x02, 0x03, 0x03, 0x03, 0x04, 0x04, 0x04, 0x05,
- 0x05, 0x06, 0x06, 0x07, 0x08, 0x08, 0x09, 0x0a,
- 0x0b, 0x0c, 0x0d, 0x0e, 0x10, 0x11, 0x13, 0x14,
- 0x16, 0x16, 0x16, 0x16
-};
-
-const int TownsPC98_FmSynth::_ssgTables[] = {
- 0x01202A, 0x0092D2, 0x006B42, 0x0053CB, 0x003DF8, 0x003053, 0x0022DA, 0x001A8C,
- 0x00129B, 0x000DC1, 0x000963, 0x0006C9, 0x000463, 0x0002FA, 0x0001B6, 0x0000FB,
- 0x0193B6, 0x01202A, 0x00CDB1, 0x0092D2, 0x007D7D, 0x006B42, 0x005ECD, 0x0053CB,
- 0x00480F, 0x003DF8, 0x0036B9, 0x003053, 0x00290A, 0x0022DA, 0x001E6B, 0x001A8C,
- 0x001639, 0x00129B, 0x000FFF, 0x000DC1, 0x000B5D, 0x000963, 0x0007FB, 0x0006C9,
- 0x000575, 0x000463, 0x00039D, 0x0002FA, 0x000242, 0x0001B6, 0x00014C, 0x0000FB
-};
-
-#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,
- 128, 155, 144, 203, 139, 0, 235, 9, 177, 172, 0, 185, 168, 138, 25, 240, 59, 211, 139, 19, 176, 90, 160, 17, 26, 132, 41, 1, 5, 25, 3, 50, 144, 115, 147, 42, 39, 152, 41, 3, 56, 193, 105, 130, 155, 66, 200, 26, 19, 218, 154, 49, 201, 171, 138, 176, 251, 139, 185, 172, 136, 189, 139, 145, 207, 41, 160, 171, 152, 186, 139,
- 186, 141, 128, 218, 171, 51, 217, 170, 56, 163, 12, 4, 155, 81, 147, 42, 37, 152, 32, 54, 136, 49, 50, 48, 37, 32, 69, 0, 17, 50, 50, 83, 2, 16, 68, 20, 8, 66, 4, 154, 84, 145, 24, 33, 24, 32, 17, 18, 145, 32, 22, 168, 49, 163, 1, 33, 50, 184, 115, 129, 25, 66, 1, 24, 67, 2, 80, 35, 40, 53, 2, 65, 51, 19, 67, 37, 0, 52, 35, 49, 37,
- 34, 49, 37, 17, 52, 17, 35, 35, 35, 34, 32, 49, 33, 152, 34, 145, 24, 24, 128, 138, 128, 184, 9, 177, 171, 168, 185, 155, 152, 172, 155, 186, 172, 185, 172, 155, 186, 173, 153, 202, 187, 185, 202, 170, 171, 202, 186, 169, 170, 170, 171, 139, 154, 171, 153, 154, 169, 10, 168, 154, 128, 168, 154, 0, 153, 152, 136, 137,
- 128, 153, 0, 152, 8, 128, 137, 0, 136, 136, 8, 9, 8, 9, 8, 24, 153, 128, 136, 153, 144, 0, 161, 138, 1, 169, 136, 128, 160, 168, 152, 153, 138, 137, 154, 153, 153, 154, 153, 170, 168, 170, 185, 168, 169, 154, 169, 171, 153, 169, 170, 153, 152, 154, 153, 137, 169, 137, 136, 144, 152, 144, 128, 128, 144, 129, 129, 0, 33,
- 0, 17, 17, 17, 33, 33, 18, 18, 34, 34, 34, 34, 34, 34, 35, 19, 35, 19, 35, 35, 18, 19, 18, 35, 18, 33, 0, 8, 8, 8, 8, 8, 8, 8, 160, 205, 65, 176, 171, 203, 16, 240, 95, 242, 120, 145, 156, 66, 177, 26, 19, 153, 9, 35, 35, 239, 56, 132, 138, 154, 50, 145, 203, 25, 32, 20, 237, 24, 130, 138, 160, 27, 39, 173, 50, 203, 64, 145, 139,
- 18, 168, 48, 146, 171, 65, 18, 176, 12, 52, 128, 25, 5, 57, 240, 104, 161, 25, 129, 18, 188, 114, 160, 26, 36, 200, 154, 18, 1, 128, 186, 73, 162, 173, 32, 184, 25, 144, 137, 234, 8, 154, 32, 160, 158, 18, 187, 81, 2, 235, 41, 36, 144, 154, 17, 67, 128, 33, 160, 114, 146, 26, 37, 33, 232, 41, 130, 41, 178, 29, 50, 251, 24,
- 1, 153, 138, 160, 76, 179, 155, 11, 0, 38, 252, 41, 146, 41, 178, 27, 193, 43, 39, 170, 136, 17, 129, 8, 49, 233, 48, 129, 11, 6, 26, 130, 136, 128, 64, 1, 248, 105, 145, 9, 16, 144, 140, 5, 25, 168, 16, 186, 48, 5, 171, 217, 57, 134, 171, 8, 34, 188, 20, 203, 41, 6, 155, 161, 89, 164, 140, 2, 136, 51, 202, 41, 131, 56, 144,
- 8, 97, 144, 146, 13, 69, 200, 42, 130, 25, 152, 57, 6, 220, 88, 177, 26, 148, 9, 168, 8, 67, 192, 156, 65, 145, 137, 10, 4, 154, 18, 157, 67, 160, 154, 1, 50, 188, 82, 170, 82, 185, 49, 220, 97, 144, 10, 8, 16, 145, 9, 136, 18, 202, 51, 184, 141, 114, 179, 139, 24, 19, 8, 250, 121, 160, 40, 160, 10, 18, 152, 168, 42, 35, 216,
- 187, 120, 145, 18, 156, 203, 84, 144, 9, 144, 26, 66, 161, 13, 1, 128, 17, 154, 18, 142, 6, 154, 65, 192, 29, 35, 186, 64, 192, 24, 9, 146, 56, 185, 16, 248, 121, 176, 40, 129, 136, 171, 96, 147, 140, 50, 203, 64, 144, 41, 128, 161, 187, 71, 200, 24, 129, 24, 217, 56, 20, 220, 24, 4, 169, 9, 1, 33, 201, 26, 134, 141, 51, 201,
- 25, 16, 33, 235, 32, 144, 33, 153, 169, 99, 160, 11, 3, 136, 58, 210, 33, 203, 48, 163, 17, 219, 128, 140, 38, 8, 184, 141, 50, 131, 159, 33, 128, 153, 25, 18, 153, 88, 242, 43, 3, 9, 136, 157, 53, 202, 40, 145, 25, 2, 204, 105, 146, 156, 66, 152, 8, 153, 33, 128, 129, 136, 153, 50, 186, 55, 188, 51, 249, 64, 178, 27, 128,
- 48, 177, 156, 18, 35, 175, 51, 189, 32, 51, 234, 155, 69, 184, 26, 2, 152, 9, 17, 136, 144, 137, 50, 235, 115, 216, 24, 2, 170, 67, 187, 49, 129, 155, 4, 27, 129, 56, 232, 43, 39, 203, 40, 3, 154, 169, 66, 184, 114, 224, 25, 2, 9, 128, 11, 35, 155, 18, 11, 202, 84, 169, 26, 5, 154, 8, 160, 98, 185, 17, 187, 50, 23, 188, 33,
- 1, 139, 4, 154, 90, 147, 12, 3, 43, 2, 170, 171, 103, 193, 28, 132, 137, 8, 129, 24, 170, 50, 201, 42, 35, 202, 169, 52, 201, 33, 218, 40, 39, 203, 0, 40, 147, 29, 163, 139, 83, 185, 1, 4, 159, 34, 160, 12, 21, 155, 40, 129, 137, 58, 151, 13, 2, 136, 144, 16, 153, 40, 17, 131, 207, 51, 144, 140, 4, 154, 17, 146, 170, 73, 163,
- 44, 164, 12, 152, 37, 203, 17, 128, 144, 139, 23, 154, 128, 138, 38, 216, 41, 1, 0, 233, 73, 131, 171, 49, 136, 9, 164, 46, 3, 171, 32, 0, 145, 157, 38, 187, 64, 176, 58, 134, 155, 18, 136, 217, 64, 1, 200, 140, 38, 153, 170, 66, 161, 8, 169, 65, 185, 98, 200, 41, 3, 155, 144, 58, 23, 187, 1, 145, 40, 147, 189, 32, 68, 249,
- 1, 112, 255, 199, 195, 19, 108, 76, 187, 247, 247, 183, 40, 168, 212, 245, 199, 227, 68, 45, 59, 10, 145, 177, 198, 24, 130, 76, 26, 193, 180, 129, 0, 162, 42, 160, 199, 162, 0, 16, 152, 137, 132, 168, 195, 130, 162, 181, 227, 163, 161, 179, 211, 180, 179, 164, 128, 162, 161, 194, 164, 179, 40, 153, 195, 213, 146, 178,
- 147, 176, 50, 186, 161, 196, 151, 58, 16, 28, 162, 160, 131, 122, 155, 33, 241, 146, 128, 40, 26, 128, 154, 36, 170, 89, 59, 9, 24, 144, 77, 161, 8, 177, 112, 139, 33, 232, 148, 24, 41, 61, 9, 26, 162, 32, 30, 58, 153, 32, 59, 73, 59, 11, 79, 137, 57, 9, 49, 30, 24, 153, 131, 25, 106, 61, 153, 73, 28, 56, 27, 41, 137, 148,
- 76, 43, 74, 58, 13, 161, 3, 171, 149, 32, 77, 10, 74, 42, 168, 16, 0, 123, 138, 129, 162, 178, 225, 50, 140, 161, 0, 147, 10, 129, 41, 244, 210, 165, 1, 152, 24, 162, 184, 166, 32, 144, 59, 216, 132, 177, 8, 145, 67, 143, 146, 160, 183, 162, 130, 24, 192, 32, 225, 146, 144, 33, 44, 73, 30, 129, 137, 32, 76, 152, 25, 161,
- 2, 154, 32, 177, 132, 232, 2, 136, 210, 128, 149, 177, 32, 58, 27, 168, 225, 133, 8, 44, 107, 136, 25, 136, 17, 26, 58, 46, 16, 11, 145, 17, 144, 79, 136, 144, 136, 145, 152, 33, 31, 162, 130, 200, 82, 153, 74, 137, 147, 26, 0, 13, 133, 170, 149, 16, 192, 0, 178, 0, 128, 152, 182, 150, 9, 16, 9, 137, 33, 59, 63, 10, 152, 32,
- 179, 192, 5, 154, 228, 182, 145, 130, 144, 42, 128, 242, 2, 136, 41, 168, 17, 76, 57, 31, 129, 136, 17, 47, 8, 41, 138, 32, 138, 123, 59, 58, 10, 136, 161, 4, 46, 25, 145, 136, 129, 25, 56, 28, 91, 41, 154, 108, 9, 16, 44, 24, 137, 48, 15, 0, 194, 162, 41, 194, 56, 241, 163, 146, 0, 139, 7, 186, 150, 129, 152, 1, 208, 33, 176,
- 136, 164, 163, 185, 7, 138, 130, 242, 162, 163, 177, 88, 136, 184, 166, 146, 0, 25, 25, 177, 199, 146, 16, 136, 9, 145, 178, 178, 0, 147, 138, 229, 18, 152, 25, 144, 163, 246, 162, 129, 129, 184, 5, 152, 178, 145, 148, 136, 146, 95, 152, 128, 144, 33, 170, 81, 11, 40, 202, 131, 0, 243, 24, 1, 11, 148, 42, 24, 163, 140,
- 120, 9, 76, 58, 153, 145, 56, 30, 72, 46, 42, 9, 8, 57, 91, 76, 59, 26, 160, 129, 41, 76, 10, 57, 192, 163, 129, 16, 225, 2, 27, 40, 200, 48, 91, 226, 40, 145, 43, 177, 177, 182, 196, 145, 33, 184, 165, 17, 192, 163, 194, 129, 211, 128, 162, 197, 129, 0, 136, 211, 146, 8, 162, 144, 0, 167, 160, 1, 176, 150, 137, 1, 24, 243,
- 0, 129, 145, 25, 123, 169, 130, 168, 132, 41, 63, 42, 136, 137, 120, 26, 136, 8, 24, 89, 29, 58, 177, 193, 147, 1, 26, 162, 176, 167, 180, 8, 49, 28, 29, 178, 162, 88, 43, 42, 57, 43, 61, 8, 29, 129, 128, 128, 123, 137, 24, 243, 16, 136, 16, 46, 0, 169, 149, 128, 1, 60, 153, 72, 154, 90, 25, 25, 25, 8, 91, 73, 12, 16, 137, 144,
- 72, 11, 8, 167, 128, 129, 9, 138, 166, 193, 147, 162, 123, 137, 145, 1, 162, 26, 1, 219, 147, 129, 210, 147, 243, 1, 243, 16, 144, 145, 160, 131, 200, 4, 59, 75, 57, 218, 2, 178, 77, 24, 60, 11, 147, 10, 50, 141, 64, 27, 185, 122, 161, 41, 128, 90, 136, 24, 46, 16, 139, 16, 24, 28, 124, 9, 41, 8, 26, 121, 10, 42, 40, 139, 129,
- 0, 201, 135, 137, 56, 176, 176, 35, 215, 145, 1, 26, 145, 144, 160, 135, 138, 1, 177, 146, 146, 161, 65, 242, 136, 164, 177, 1, 1, 186, 151, 208, 148, 129, 10, 32, 241, 145, 163, 178, 17, 168, 136, 151, 168, 2, 148, 185, 133, 176, 130, 129, 154, 163, 215, 0, 146, 136, 40, 211, 161, 131, 171, 81, 144, 170, 21, 184, 56,
- 195, 168, 133, 177, 91, 16, 187, 5, 145, 153, 66, 172, 18, 177, 42, 120, 138, 27, 134, 26, 106, 42, 138, 146, 184, 66, 75, 46, 41, 168, 0, 145, 57, 91, 75, 27, 24, 27, 48, 169, 40, 122, 9, 109, 10, 8, 177, 146, 16, 74, 30, 129, 160, 162, 146, 41, 124, 138, 24, 145, 152, 3, 1, 14, 3, 139, 1, 192, 161, 151, 177, 122, 8, 10, 0,
- 176, 130, 129, 27, 88, 225, 0, 2, 154, 129, 129, 193, 49, 203, 81, 153, 226, 33, 0, 30, 0, 176, 179, 18, 9, 96, 156, 162, 148, 160, 129, 2, 29, 195, 128, 0, 56, 156, 20, 232, 129, 128, 32, 10, 144, 74, 183, 9, 145, 162, 1, 162, 138, 23, 171, 1, 164, 224, 34, 43, 43, 177, 200, 135, 161, 91, 57, 154, 177, 148, 145, 146, 58,
- 108, 136, 170, 35, 208, 177, 34, 128, 44, 129, 155, 151, 243, 16, 1, 154, 72, 193, 144, 18, 11, 122, 160, 153, 5, 192, 24, 130, 184, 132, 226, 0, 128, 153, 131, 181, 136, 65, 154, 128, 17, 170, 39, 28, 59, 144, 168, 80, 25, 47, 24, 26, 144, 32, 47, 41, 153, 161, 148, 8, 92, 9, 9, 129, 144, 33, 26, 47, 24, 137, 108, 25, 10,
- 17, 10, 73, 75, 47, 24, 184, 48, 8, 45, 57, 138, 136, 150, 10, 48, 139, 136, 35, 203, 121, 8, 27, 179, 161, 106, 0, 29, 16, 176, 179, 3, 185, 19, 227, 41, 145, 168, 61, 197, 177, 20, 10, 57, 42, 250, 147, 196, 16, 41, 138, 24, 195, 208, 135, 137, 0, 145, 160, 2, 210, 146, 195, 177, 132, 136, 153, 167, 210, 146, 162, 40, 8,
- 138, 148, 227, 145, 17, 137, 40, 169, 179, 130, 242, 2, 196, 9, 146, 145, 169, 167, 146, 130, 137, 136, 51, 220, 17, 163, 28, 74, 10, 76, 40, 140, 5, 137, 43, 18, 12, 107, 137, 40, 8, 201, 50, 0, 143, 3, 138, 161, 134, 138, 104, 169, 16, 162, 160, 121, 25, 28, 129, 152, 32, 56, 14, 16, 184, 146, 3, 46, 25, 176, 129, 179,
- 193, 17, 130, 202, 135, 8, 57, 25, 154, 148, 184, 120, 9, 153, 211, 165, 24, 128, 26, 17, 242, 161, 18, 185, 81, 42, 11, 17, 12, 25, 181, 137, 66, 42, 47, 41, 184, 166, 129, 24, 91, 27, 136, 196, 0, 0, 74, 28, 178, 161, 149, 160, 32, 8, 225, 32, 128, 59, 8, 169, 50, 139, 47, 72, 186, 16, 132, 9, 122, 9, 160, 146, 144, 89, 153,
- 10, 149, 178, 0, 121, 11, 146, 152, 162, 48, 13, 123, 177, 24, 0, 106, 27, 9, 144, 132, 12, 17, 0, 168, 0, 181, 56, 169, 129, 242, 195, 129, 17, 154, 64, 161, 244, 16, 137, 24, 144, 144, 164, 129, 75, 42, 176, 149, 9, 179, 148, 203, 4, 166, 136, 163, 128, 227, 163, 8, 57, 11, 30, 165, 0, 74, 59, 62, 9, 208, 131, 144, 40, 76,
- 26, 27, 196, 129, 1, 25, 43, 49, 174, 67, 153, 136, 106, 152, 41, 25, 28, 2, 43, 44, 104, 45, 59, 8, 43, 128, 144, 120, 25, 12, 17, 152, 9, 130, 155, 151, 145, 74, 40, 13, 48, 192, 58, 90, 43, 43, 177, 146, 49, 31, 75, 24, 217, 131, 0, 76, 26, 152, 149, 161, 24, 74, 154, 193, 166, 145, 32, 27, 161, 164, 176, 135, 152, 24, 193,
- 162, 146, 164, 58, 227, 193, 148, 161, 128, 18, 234, 130, 180, 145, 2, 200, 1, 163, 186, 98, 184, 129, 149, 153, 49, 42, 186, 151, 242, 129, 1, 43, 8, 177, 212, 165, 8, 40, 137, 24, 8, 144, 90, 9, 25, 48, 44, 46, 24, 138, 40, 144, 108, 58, 27, 128, 181, 128, 80, 29, 42, 152, 162, 130, 25, 106, 136, 11, 148, 8, 144, 128, 136,
- 112, 139, 80, 153, 24, 136, 129, 46, 0, 60, 129, 208, 1, 3, 13, 57, 168, 144, 1, 242, 17, 9, 26, 2, 185, 27, 55, 140, 73, 137, 179, 16, 192, 3, 145, 143, 33, 9, 171, 135, 160, 17, 137, 10, 151, 168, 3, 178, 44, 17, 208, 144, 167, 0, 40, 155, 16, 167, 152, 18, 144, 26, 160, 199, 1, 136, 91, 136, 160, 178, 150, 161, 1, 10, 181,
- 145, 161, 1, 145, 161, 198, 2, 9, 90, 137, 177, 160, 150, 40, 29, 129, 144, 145, 162, 57, 77, 169, 16, 148, 42, 42, 40, 141, 34, 170, 121, 154, 210, 131, 162, 107, 8, 9, 160, 195, 40, 73, 139, 18, 224, 162, 34, 139, 0, 244, 178, 163, 24, 26, 146, 194, 166, 49, 29, 42, 137, 130, 192, 16, 93, 128, 154, 19, 59, 11, 122, 11,
- 146, 177, 120, 42, 26, 43, 164, 152, 17, 60, 63, 137, 128, 48, 10, 58, 92, 9, 59, 91, 75, 139, 32, 25, 25, 61, 74, 28, 177, 40, 130, 74, 29, 73, 168, 130, 128, 48, 14, 8, 77, 9, 25, 26, 179, 211, 32, 78, 26, 41, 152, 161, 180, 89, 59, 9, 153, 166, 160, 3, 26, 57, 106, 154, 88, 184, 40, 1, 27, 58, 73, 143, 131, 169, 3, 161, 184,
- 122, 152, 16, 181, 145, 129, 17, 15, 129, 193, 147, 145, 192, 33, 193, 162, 183, 163, 136, 178, 129, 178, 197, 2, 41, 216, 131, 168, 163, 181, 226, 163, 178, 1, 33, 187, 166, 212, 129, 1, 27, 24, 162, 184, 151, 8, 16, 160, 144, 181, 210, 72, 168, 128, 32, 42, 25, 40, 142, 5, 185, 88, 58, 11, 58, 177, 32, 129, 63, 42, 136,
- 186, 53, 29, 75, 58, 144, 144, 129, 77, 128, 11, 144, 133, 29, 40, 152, 24, 161, 129, 80, 155, 60, 3, 12, 89, 8, 60, 152, 152, 49, 136, 47, 57, 224, 129, 16, 41, 90, 139, 162, 147, 170, 51, 169, 27, 17, 95, 26, 26, 160, 5, 139, 48, 76, 10, 228, 146, 1, 136, 44, 161, 147, 209, 130, 137, 73, 224, 1, 162, 195, 32, 210, 177, 180,
- 179, 148, 145, 154, 132, 242, 146, 1, 152, 32, 192, 1, 144, 155, 7, 177, 168, 5, 138, 178, 148, 152, 150, 136, 89, 152, 9, 41, 196, 145, 40, 28, 16, 8, 10, 178, 167, 24, 1, 44, 123, 137, 136, 145, 194, 48, 27, 74, 26, 192, 179, 135, 136, 88, 27, 10, 177, 163, 164, 128, 73, 24, 31, 8, 0, 192, 149, 144, 129, 9, 106, 41, 200,
- 161, 151, 41, 138, 0, 24, 226, 162, 49, 42, 11, 90, 136, 136, 152, 17, 145, 10, 63, 40, 11, 56, 245, 162, 16, 26, 73, 11, 144, 135, 137, 58, 106, 10, 25, 8, 57, 137, 28, 33, 129, 156, 113, 10, 10, 161, 18, 8, 153, 77, 3, 217, 0, 1, 242, 128, 193, 18, 128, 75, 60, 178, 154, 37, 45, 58, 29, 144, 1, 184, 66, 41, 29, 8, 145, 10,
- 194, 33, 148, 170, 107, 89, 139, 128, 163, 178, 16, 63, 59, 176, 144, 151, 129, 42, 74, 10, 129, 192, 2, 128, 154, 97, 192, 0, 177, 128, 178, 183, 16, 16, 155, 149, 145, 184, 84, 138, 8, 192, 161, 20, 225, 0, 130, 138, 165, 0, 28, 148, 153, 18, 209, 128, 88, 153, 89, 152, 9, 17, 9, 29, 130, 43, 122, 153, 24, 32, 202, 49,
- 24, 43, 106, 154, 130, 193, 27, 51, 29, 28, 133, 138, 65, 11, 123, 25, 10, 40, 152, 44, 130, 26, 43, 148, 45, 73, 140, 33, 8, 153, 88, 128, 61, 144, 42, 59, 225, 128, 18, 155, 50, 75, 186, 20, 202, 120, 144, 42, 92, 176, 162, 165, 25, 2, 169, 152, 135, 185, 19, 152, 8, 146, 160, 123, 195, 137, 132, 209, 0, 16, 11, 2, 242,
- 146, 164, 152, 73, 193, 136, 130, 178, 1, 136, 169, 23, 169, 128, 164, 242, 129, 178, 129, 32, 138, 180, 167, 153, 132, 8, 138, 2, 209, 4, 138, 1, 128, 138, 92, 136, 44, 129, 136, 162, 33, 63, 40, 141, 2, 160, 144, 106, 137, 64, 155, 17, 129, 60, 30, 146, 26, 17, 28, 48, 46, 169, 51, 154, 91, 137, 41, 26, 32, 143, 18, 138,
- 1, 32, 28, 123, 177, 9, 181, 195, 56, 57, 14, 145, 161, 17, 17, 31, 41, 152, 145, 194, 194, 20, 153, 41, 9, 243, 129, 180, 0, 128, 45, 16, 43, 170, 135, 144, 16, 25, 42, 137, 242, 163, 194, 16, 0, 57, 14, 130, 194, 178, 16, 33, 30, 8, 59, 211, 163, 160, 5, 137, 44, 10, 17, 170, 3, 120, 9, 44, 146, 136, 131, 140, 91, 9, 171,
- 7, 161, 32, 73, 13, 8, 161, 40, 106, 11, 25, 129, 59, 0, 49, 31, 42, 28, 40, 11, 0, 81, 176, 61, 32, 138, 25, 178, 241, 148, 136, 106, 8, 136, 128, 177, 90, 8, 155, 96, 176, 9, 18, 217, 132, 129, 10, 81, 156, 40, 178, 161, 36, 169, 76, 147, 203, 150, 0, 10, 146, 200, 147, 149, 128, 144, 148, 154, 182, 24, 0, 137, 11, 134, 211,
- 24, 136, 129, 145, 209, 33, 8, 43, 163, 243, 88, 41, 13, 0, 160, 145, 33, 31, 32, 185, 145, 4, 155, 17, 32, 47, 161, 128, 73, 160, 44, 56, 176, 75, 74, 12, 35, 141, 104, 137, 9, 89, 152, 58, 56, 44, 41, 30, 41, 40, 157, 48, 128, 154, 88, 41, 42, 8, 14, 3, 184, 59, 120, 152, 9, 56, 10, 128, 41, 57, 227, 186, 52, 152, 62, 8, 56,
- 242, 0, 58, 8, 156, 34, 243, 128, 24, 176, 51, 169, 58, 183, 192, 146, 164, 177, 18, 170, 7, 177, 208, 132, 161, 24, 136, 27, 147, 243, 128, 133, 10, 24, 161, 161, 178, 214, 17, 160, 25, 16, 161, 137, 165, 192, 48, 27, 72, 58, 218, 133, 162, 26, 72, 27, 10, 197, 178, 49, 138, 89, 56, 142, 1, 24, 11, 0, 44, 105, 10, 25, 0,
- 194, 9, 3, 47, 8, 138, 147, 18, 28, 48, 202, 147, 199, 146, 25, 161, 0, 145, 194, 163, 57, 11, 146, 248, 130, 32, 57, 63, 154, 16, 48, 14, 128, 144, 209, 133, 26, 56, 154, 182, 162, 195, 18, 152, 44, 194, 180, 168, 5, 24, 137, 138, 35, 192, 232, 66, 176, 161, 24, 41, 26, 244, 129, 163, 160, 75, 129, 226, 147, 40, 145, 61,
- 13, 130, 177, 17, 137, 112, 170, 130, 0, 136, 75, 152, 177, 241, 34, 0, 59, 156, 51, 186, 178, 91, 132, 137, 137, 122, 1, 45, 28, 50, 172, 57, 108, 8, 26, 136, 32, 152, 46, 144, 131, 171, 4, 152, 18, 141, 148, 1, 216, 32, 9, 60, 169, 66, 152, 128, 72, 90, 201, 1, 17, 201, 136, 3, 195, 26, 73, 133, 200, 176, 150, 146, 169,
- 24, 33, 178, 184, 151, 73, 11, 28, 72, 44, 153, 82, 153, 17, 42, 57, 78, 153, 8, 160, 0, 1, 123, 11, 19, 171, 195, 18, 59, 31, 129, 10, 162, 2, 58, 96, 142, 130, 26, 75, 128, 176, 17, 180, 123, 9, 90, 137, 211, 145, 32, 26, 76, 43, 145, 130, 12, 90, 41, 27, 58, 160, 160, 128, 178, 7, 76, 59, 0, 203, 180, 147, 33, 62, 10, 0, 243,
- 129, 146, 73, 29, 145, 144, 0, 26, 56, 153, 185, 83, 8, 76, 27, 166, 161, 193, 146, 131, 224, 145, 165, 161, 40, 168, 149, 162, 226, 2, 136, 138, 163, 131, 211, 0, 59, 146, 218, 148, 1, 192, 16, 16, 58, 248, 88, 144, 177, 136, 1, 58, 45, 9, 195, 197, 147, 48, 29, 10, 0, 162, 176, 64, 122, 9, 10, 17, 9, 153, 56, 75, 27, 31,
- 72, 136, 9, 129, 129, 61, 45, 59, 10, 161, 18, 122, 43, 59, 41, 169, 34, 155, 130, 131, 219, 120, 162, 27, 49, 208, 160, 131, 156, 66, 12, 145, 50, 240, 16, 136, 12, 162, 40, 129, 130, 15, 129, 162, 146, 180, 83, 139, 58, 217, 129, 177, 4, 0, 169, 197, 163, 144, 242, 131, 168, 179, 179, 17, 197, 145, 178, 164, 128, 160,
- 211, 2, 244, 163, 145, 162, 129, 212, 177, 163, 17, 208, 163, 195, 180, 57, 24, 170, 182, 164, 129, 0, 60, 60, 169, 149, 162, 177, 122, 26, 24, 136, 136, 133, 43, 27, 178, 56, 77, 24, 128, 240, 0, 2, 44, 46, 8, 128, 193, 146, 64, 27, 42, 16, 193, 25, 0, 192, 148, 11, 52, 47, 153, 147, 243, 0, 24, 73, 28, 144, 161, 150, 9,
- 8, 73, 170, 2, 162, 25, 27, 147, 167, 131, 29, 1, 168, 200, 165, 16, 91, 137, 8, 162, 176, 35, 41, 31, 24, 169, 50, 168, 58, 123, 144, 48, 128, 13, 73, 169, 144, 16, 57, 123, 44, 200, 163, 56, 153, 80, 10, 176, 146, 57, 94, 8, 152, 131, 9, 168, 125, 26, 145, 177, 132, 137, 41, 60, 26, 144, 243, 32, 192, 34, 60, 43, 26, 16,
- 249, 164, 16, 58, 61, 11, 130, 243, 146, 2, 42, 44, 27, 128, 165, 137, 49, 45, 28, 16, 43, 8, 211, 48, 28, 152, 105, 9, 9, 163, 161, 169, 35, 107, 42, 232, 164, 130, 168, 72, 42, 168, 210, 148, 144, 136, 129, 3, 217, 194, 50, 27, 192, 41, 210, 147, 40, 76, 226, 1, 161, 1, 155, 132, 145, 147, 171, 67, 173, 210, 132, 161, 106,
- 137, 56, 169, 209, 131, 64, 13, 129, 9, 194, 17, 57, 61, 169, 17, 128, 40, 31, 16, 10, 162, 57, 61, 75, 139, 40, 242, 17, 58, 59, 138, 179, 144, 50, 105, 140, 179, 243, 57, 40, 26, 9, 243, 130, 24, 29, 57, 128, 210, 129, 25, 59, 91, 137, 162, 178, 72, 27, 181, 168, 19, 129, 8, 184, 231, 147, 178, 32, 28, 184, 198, 148, 144,
- 1, 26, 128, 16, 192, 2, 26, 144, 244, 129, 0, 16, 10, 197, 177, 181, 1, 41, 9, 178, 165, 211, 129, 25, 145, 137, 210, 147, 152, 210, 163, 132, 194, 17, 91, 169, 145, 181, 130, 9, 89, 137, 152, 178, 4, 128, 9, 63, 160, 128, 106, 8, 25, 43, 10, 32, 47, 26, 123, 152, 24, 40, 25, 27, 18, 186, 35, 158, 64, 42, 216, 33, 25, 58, 58,
- 45, 184, 147, 29, 72, 46, 9, 0, 178, 146, 58, 77, 26, 25, 209, 165, 128, 145, 17, 153, 128, 129, 148, 240, 129, 1, 40, 31, 0, 152, 242, 163, 16, 59, 44, 24, 243, 146, 128, 1, 26, 26, 179, 213, 145, 130, 176, 131, 40, 25, 145, 219, 179, 167, 8, 33, 59, 14, 176, 166, 16, 136, 74, 128, 176, 128, 149, 8, 8, 209, 148, 152, 0, 72,
- 153, 161, 178, 35, 62, 75, 154, 163, 153, 19, 62, 170, 133, 179, 136, 89, 12, 129, 164, 144, 3, 47, 58, 193, 177, 148, 0, 61, 43, 10, 129, 17, 41, 61, 43, 25, 8, 126, 26, 25, 137, 145, 34, 44, 45, 129, 216, 179, 1, 90, 25, 137, 32, 227, 8, 16, 9, 170, 49, 31, 32, 29, 128, 145, 148, 75, 25, 75, 153, 162, 192, 35, 12, 80, 136,
- 176, 8, 194, 24, 1, 176, 21, 154, 145, 80, 251, 130, 2, 30, 9, 8, 130, 145, 128, 98, 27, 26, 129, 136, 162, 15, 33, 168, 59, 65, 177, 77, 141, 1, 128, 168, 113, 10, 137, 178, 163, 146, 132, 74, 153, 224, 164, 33, 184, 19, 184, 228, 161, 17, 91, 152, 25, 146, 152, 44, 121, 9, 160, 145, 17, 25, 28, 93, 128, 152, 2, 25, 27, 161,
- 210, 129, 146, 45, 179, 227, 163, 162, 9, 40, 193, 148, 179, 57, 107, 140, 196, 32, 25, 57, 47, 136, 210, 130, 24, 40, 28, 152, 210, 182, 145, 40, 8, 129, 184, 147, 147, 140, 163, 166, 160, 34, 45, 144, 194, 161, 134, 41, 46, 152, 162, 162, 3, 44, 58, 75, 209, 162, 144, 57, 129, 47, 152, 130, 59, 16, 248, 129, 17, 26, 57,
- 9, 29, 167, 2, 60, 42, 138, 136, 209, 130, 90, 42, 42, 176, 146, 178, 120, 28, 8, 160, 145, 16, 33, 31, 1, 8, 160, 129, 128, 242, 164, 32, 152, 177, 146, 213, 196, 128, 40, 26, 160, 163, 180, 146, 108, 60, 144, 144, 136, 147, 137, 40, 90, 161, 3, 17, 219, 243, 33, 184, 130, 60, 136, 243, 178, 179, 132, 26, 8, 168, 212, 147,
- 16, 57, 42, 31, 145, 145, 160, 32, 43, 184, 66, 45, 180, 33, 140, 226, 1, 91, 152, 16, 144, 193, 162, 48, 77, 25, 137, 153, 17, 178, 78, 0, 0, 16, 14, 90, 152, 153, 19, 129, 13, 123, 137, 129, 160, 1, 73, 44, 9, 129, 0, 153, 120, 10, 9, 162, 195, 32, 139, 28, 151, 161, 2, 128, 26, 45, 193, 146, 48, 29, 146, 153, 194, 5, 59,
- 29, 128, 144, 195, 1, 64, 43, 208, 178, 149, 8, 9, 16, 240, 163, 129, 16, 42, 185, 181, 211, 24, 48, 45, 137, 149, 9, 24, 41, 75, 184, 177, 4, 43, 91, 128, 180, 16, 144, 29, 25, 184, 167, 1, 59, 60, 153, 148, 161, 146, 91, 42, 186, 4, 24, 145, 123, 11, 2, 178, 77, 136, 26, 25, 195, 40, 115, 61, 27, 168, 177, 3, 59, 79, 26, 25,
- 144, 1, 48, 13, 56, 154, 248, 1, 16, 9, 129, 8, 2, 178, 31, 130, 153, 162, 20, 15, 33, 170, 56, 40, 29, 28, 128, 152, 149, 144, 56, 120, 11, 162, 212, 129, 144, 145, 59, 180, 243, 147, 145, 144, 16, 152, 48, 241, 0, 161, 176, 1, 134, 10, 129, 200, 166, 144, 128, 121, 26, 24, 177, 178, 196, 48, 75, 138, 41, 180, 195, 26, 24,
- 89, 138, 24, 33, 187, 41, 84, 155, 57, 79, 136, 160, 210, 130, 0, 58, 58, 168, 243, 132, 27, 41, 75, 138, 3, 8, 61, 8, 29, 145, 179, 76, 24, 28, 146, 208, 2, 49, 140, 75, 196, 144, 0, 40, 44, 179, 208, 3, 176, 33, 15, 177, 2, 160, 106, 8, 160, 164, 164, 8, 73, 27, 226, 179, 161, 1, 57, 1, 196, 211, 128, 40, 156, 145, 166, 178,
- 131, 29, 128, 145, 162, 165, 40, 27, 216, 146, 135, 144, 40, 160, 194, 177, 145, 20, 139, 200, 151, 178, 17, 136, 40, 25, 205, 130, 17, 11, 17, 129, 156, 38, 26, 25, 137, 179, 163, 11, 79, 16, 12, 146, 147, 143, 89, 25, 136, 136, 25, 48, 26, 46, 129, 40, 29, 42, 29, 8, 145, 2, 56, 27, 62, 8, 25, 212, 161, 48, 43, 144, 129,
- 29, 145, 144, 41, 106, 10, 107, 43, 184, 131, 1, 36, 61, 13, 138, 2, 194, 1, 16, 27, 75, 186, 181, 151, 8, 1, 161, 138, 211, 129, 2, 59, 248, 129, 16, 0, 144, 63, 152, 150, 136, 24, 25, 128, 30, 161, 128, 17, 24, 225, 146, 10, 16, 0, 9, 227, 183, 129, 40, 60, 26, 162, 194, 181, 24, 90, 9, 24, 0, 176, 161, 193, 194, 35, 12, 63,
- 8, 210, 162, 1, 32, 78, 28, 152, 164, 144, 16, 48, 45, 137, 162, 147, 168, 152, 98, 27, 43, 33, 12, 160, 165, 129, 137, 63, 41, 153, 153, 151, 16, 91, 26, 8, 8, 9, 56, 10, 46, 24, 146, 57, 168, 160, 166, 241, 129, 32, 140, 16, 145, 179, 164, 137, 113, 138, 208, 131, 26, 25, 1, 42, 178, 196, 106, 24, 171, 18, 196, 8, 18, 29,
- 41, 194, 128, 3, 249, 57, 162, 152, 48, 184, 120, 160, 208, 33, 137, 74, 57, 187, 149, 129, 26, 35, 158, 72, 128, 168, 32, 26, 25, 180, 75, 2, 136, 15, 163, 161, 136, 120, 27, 41, 160, 128, 182, 56, 60, 25, 12, 178, 151, 128, 168, 72, 10, 152, 4, 177, 26, 147, 137, 113, 44, 42, 33, 220, 2, 152, 41, 82, 11, 210, 163, 184,
- 133, 162, 10, 196, 128, 3, 234, 40, 149, 152, 161, 1, 44, 129, 194, 4, 225, 16, 58, 168, 24, 194, 146, 146, 154, 49, 21, 218, 33, 152, 248, 129, 194, 147, 0, 28, 1, 195, 162, 20, 140, 42, 25, 160, 198, 1, 33, 136, 142, 3, 25, 24, 141, 16, 177, 208, 112, 0, 138, 41, 160, 130, 45, 60, 32, 170, 73, 24, 75, 59, 161, 176, 49, 159,
- 97, 26, 168, 149, 145, 32, 28, 25, 184, 211, 129, 179, 74, 73, 8, 153, 136, 193, 151, 160, 32, 48, 143, 9, 147, 181, 145, 32, 60, 9, 187, 133, 166, 144, 32, 152, 25, 136, 161, 150, 168, 145, 81, 10, 42, 0, 169, 182, 148, 136, 58, 41, 187, 182, 211, 131, 16, 137, 25, 243, 144, 129, 2, 9, 8, 202, 7, 25, 185, 21, 144, 136, 153,
- 65, 184, 137, 56, 151, 10, 153, 49, 16, 145, 14, 56, 176, 11, 192, 19, 89, 91, 44, 168, 147, 2, 8, 147, 63, 27, 1, 136, 229, 129, 73, 26, 136, 26, 137, 81, 170, 147, 77, 72, 12, 42, 42, 192, 24, 104, 91, 26, 27, 65, 177, 27, 32, 41, 60, 14, 136, 17, 170, 150, 129, 24, 58, 11, 16, 251, 162, 19, 57, 31, 0, 152, 129, 145, 17, 61,
- 14, 1, 129, 27, 129, 66, 169, 178, 74, 12, 11, 19, 198, 145, 75, 33, 138, 174, 133, 1, 184, 57, 40, 136, 169, 20, 1, 60, 174, 20, 154, 201, 67, 26, 162, 151, 42, 16, 138, 59, 130, 204, 20, 169, 59, 180, 59, 114, 184, 56, 178, 242, 128, 130, 43, 8, 194, 3, 229, 144, 33, 185, 144, 34, 181, 145, 168, 17, 149, 153, 74, 35, 220,
- 129, 128, 1, 88, 59, 75, 225, 136, 130, 168, 17, 144, 12, 151, 8, 25, 179, 8, 1, 240, 16, 8, 25, 145, 211, 41, 130, 138, 115, 169, 160, 163, 168, 84, 154, 74, 0, 170, 144, 211, 149, 2, 30, 128, 137, 9, 149, 1, 144, 58, 60, 57, 153, 178, 150, 17, 29, 27, 74, 25, 195, 152, 56, 15, 1, 25, 26, 152, 149, 80, 153, 57, 73, 140, 128,
- 160, 144, 113, 27, 56, 28, 25, 4, 42, 44, 137, 60, 171, 130, 50, 240, 8, 5, 139, 145, 1, 105, 137, 200, 80, 137, 145, 146, 178, 179, 160, 46, 16, 240, 195, 131, 128, 144, 24, 164, 198, 128, 0, 136, 137, 131, 194, 165, 177, 2, 161, 147, 11, 144, 188, 181, 148, 144, 23, 0, 28, 224, 128, 131, 192, 32, 1, 224, 1, 168, 132, 145,
- 9, 41, 208, 58, 137, 179, 151, 145, 16, 1, 30, 8, 145, 178, 1, 47, 32, 186, 72, 169, 146, 75, 8, 41, 48, 136, 89, 13, 48, 9, 10, 124, 26, 11, 42, 32, 129, 91, 77, 16, 12, 128, 42, 57, 138, 10, 60, 2, 63, 9, 0, 93, 128, 152, 90, 8, 10, 24, 40, 44, 144, 29, 49, 188, 48, 72, 25, 30, 177, 33, 128, 186, 120, 129, 186, 133, 152, 130,
- 24, 156, 51, 154, 8, 226, 2, 56, 155, 2, 179, 233, 167, 128, 24, 129, 176, 136, 151, 8, 184, 0, 33, 224, 152, 21, 177, 24, 10, 163, 16, 250, 17, 130, 171, 83, 137, 136, 37, 12, 56, 242, 154, 17, 160, 145, 82, 13, 3, 201, 128, 18, 137, 24, 162, 63, 162, 8, 107, 178, 128, 57, 158, 32, 24, 200, 18, 0, 106, 154, 73, 16, 248, 8,
- 73, 137, 57, 75, 0, 128, 12, 65, 137, 59, 75, 28, 144, 129, 122, 0, 58, 140, 160, 195, 145, 105, 56, 28, 153, 145, 164, 88, 8, 28, 25, 153, 9, 162, 113, 89, 153, 136, 33, 234, 147, 128, 41, 72, 11, 138, 151, 144, 145, 16, 43, 58, 248, 130, 178, 42, 4, 40, 10, 196, 154, 147, 216, 24, 7, 136, 10, 161, 148, 210, 161, 98, 138,
- 137, 128, 146, 176, 33, 105, 27, 43, 163, 49, 185, 6, 10, 136, 43, 67, 174, 161, 162, 151, 137, 1, 64, 200, 193, 24, 64, 200, 56, 145, 242, 24, 57, 137, 1, 128, 3, 162, 175, 80, 128, 162, 152, 25, 58, 175, 17, 17, 0, 200, 64, 168, 162, 91, 1, 154, 44, 211, 177, 35, 64, 160, 161, 144, 4, 241, 41, 209, 162, 25, 1, 3, 242, 176,
- 134, 153, 42, 41, 136, 135, 154, 2, 130, 46, 41, 161, 153, 180, 145, 34, 26, 46, 18, 242, 137, 146, 129, 25, 128, 11, 151, 161, 40, 179, 27, 122, 168, 59, 137, 181, 50, 172, 36, 56, 15, 9, 129, 137, 128, 75, 2, 58, 12, 52, 141, 8, 24, 58, 153, 157, 122, 145, 9, 1, 80, 27, 184, 32, 74, 219, 50, 57, 168, 153, 180, 48, 28, 143,
- 131, 144, 178, 65, 13, 48, 168, 162, 147, 155, 121, 9, 170, 5, 16, 153, 21, 29, 144, 161, 91, 0, 184, 57, 128, 137, 17, 159, 88, 178, 128, 105, 152, 9, 162, 33, 164, 141, 88, 178, 224, 1, 0, 16, 27, 185, 150, 161, 9, 4, 139, 16, 128, 160, 194, 144, 65, 180, 46, 40, 136, 27, 135, 160, 16, 44, 57, 145, 236, 2, 195, 40, 75, 177,
- 2, 200, 179, 146, 186, 104, 50, 141, 24, 169, 165, 148, 11, 97, 10, 11, 130, 177, 49, 57, 78, 42, 154, 128, 165, 59, 33, 28, 30, 1, 136, 16, 192, 41, 128, 152, 123, 136, 24, 1, 169, 113, 10, 11, 49, 153, 14, 147, 19, 45, 43, 8, 176, 210, 148, 8, 16, 11, 96, 144, 192, 163, 150, 10, 128, 43, 26, 150, 178, 165, 24, 41, 171, 18,
- 27, 215, 1, 8, 128, 136, 40, 35, 208, 11, 161, 193, 18, 73, 154, 133, 155, 165, 164, 10, 49, 154, 8, 199, 0, 2, 168, 64, 192, 0, 40, 162, 43, 202, 180, 150, 10, 106, 24, 185, 145, 131, 184, 113, 43, 24, 162, 187, 73, 146, 42, 81, 171, 121, 58, 155, 151, 16, 43, 32, 31, 9, 160, 146, 17, 136, 94, 10, 24, 145, 25, 9, 130, 59,
- 65, 13, 91, 25, 169, 146, 176, 112, 42, 59, 16, 217, 130, 20, 13, 25, 9, 40, 161, 138, 68, 169, 154, 18, 62, 154, 180, 145, 135, 152, 56, 58, 155, 165, 211, 8, 40, 42, 10, 198, 1, 2, 184, 57, 184, 224, 51, 154, 27, 134, 168, 19, 202, 73, 75, 184, 35, 176, 75, 24, 25, 209, 51, 157, 19, 30, 184, 179, 3, 33, 148, 45, 232, 146,
- 129, 168, 41, 32, 170, 149, 193, 35, 136, 16, 50, 191, 56, 146, 173, 149, 16, 24, 41, 30, 129, 168, 209, 3, 57, 31, 0, 16, 176, 147, 41, 152, 10, 17, 181, 14, 40, 144, 49, 170, 75, 97, 141, 25, 162, 146, 72, 177, 92, 137, 137, 19, 137, 153, 113, 154, 2, 41, 60, 129, 217, 2, 211, 152, 73, 42, 193, 197, 146, 147, 10, 59, 0,
- 192, 196, 132, 41, 160, 25, 88, 169, 16, 40, 241, 1, 153, 81, 28, 10, 147, 161, 209, 88, 75, 9, 161, 162, 180, 16, 43, 57, 235, 33, 56, 156, 129, 144, 2, 135, 31, 128, 145, 136, 163, 56, 59, 154, 57, 167, 160, 105, 137, 0, 138, 163, 3, 41, 47, 185, 211, 131, 41, 41, 60, 139, 182, 146, 16, 16, 43, 242, 144, 145, 129, 16, 179,
- 183, 1, 26, 9, 147, 240, 131, 160, 91, 74, 152, 184, 166, 178, 33, 140, 9, 4, 162, 233, 34, 136, 129, 144, 163, 60, 142, 144, 149, 128, 33, 73, 13, 161, 194, 131, 0, 26, 56, 142, 128, 163, 128, 1, 233, 56, 209, 41, 145, 194, 147, 179, 149, 64, 30, 8, 128, 216, 18, 24, 43, 43, 32, 153, 25, 74, 109, 137, 153, 48, 8, 137, 122,
- 25, 144, 26, 43, 59, 30, 33, 41, 27, 24, 96, 153, 160, 50, 76, 27, 47, 152, 145, 163, 73, 40, 14, 152, 131, 176, 74, 90, 8, 8, 200, 67, 155, 154, 50, 49, 155, 28, 124, 177, 152, 1, 2, 17, 62, 138, 180, 176, 4, 25, 9, 177, 245, 162, 129, 40, 25, 176, 164, 130, 172, 4, 8, 181, 194, 49, 11, 168, 154, 165, 133, 152, 40, 136, 226,
- 179, 19, 26, 185, 16, 167, 194, 16, 25, 57, 243, 136, 147, 1, 31, 25, 184, 132, 160, 33, 62, 138, 129, 130, 41, 121, 137, 153, 145, 26, 17, 107, 136, 179, 1, 61, 60, 26, 162, 168, 148, 64, 31, 25, 32, 168, 152, 64, 31, 137, 8, 129, 33, 62, 24, 137, 8, 16, 59, 47, 153, 33, 162, 91, 59, 41, 170, 145, 5, 43, 60, 41, 13, 178, 134,
- 57, 153, 12, 194, 227, 8, 2, 128, 57, 208, 162, 19, 216, 32, 178, 25, 128, 160, 48, 194, 195, 37, 155, 10, 33, 251, 163, 146, 16, 136, 12, 166, 195, 160, 148, 129, 176, 147, 178, 150, 160, 72, 162, 162, 193, 162, 60, 200, 145, 5, 144, 25, 122, 216, 129, 161, 130, 0, 10, 73, 1, 241, 2, 9, 168, 33, 13, 161, 165, 24, 64, 203,
- 50, 1, 14, 9, 9, 129, 161, 106, 33, 27, 13, 164, 128, 40, 41, 107, 169, 160, 33, 136, 60, 92, 168, 152, 2, 91, 57, 176, 129, 0, 144, 47, 136, 162, 164, 128, 80, 43, 154, 179, 213, 130, 74, 27, 0, 145, 145, 167, 58, 59, 160, 9, 26, 76, 8, 171, 5, 49, 28, 44, 169, 162, 183, 130, 72, 28, 144, 179, 228, 2, 25, 26, 129, 186, 151,
- 1, 75, 128, 169, 17, 178, 15, 57, 170, 16, 166, 16, 57, 8, 139, 162, 181, 1, 8, 152, 164, 181, 41, 81, 43, 10, 242, 145, 57, 139, 89, 8, 193, 18, 154, 32, 176, 10, 165, 129, 137, 147, 177, 134, 0, 25, 25, 201, 147, 227, 129, 72, 59, 185, 167, 128, 129, 160, 91, 25, 176, 130, 147, 145, 9, 160, 5, 202, 17, 16, 186, 136, 37,
- 177, 56, 76, 42, 169, 186, 48, 9, 145, 57, 24, 128, 41, 169, 134, 137, 145, 147, 28, 41, 168, 131, 228, 32, 27, 9, 60, 129, 178, 64, 60, 45, 25, 9, 24, 152, 49, 31, 136, 57, 42, 0, 25, 12, 181, 18, 153, 57, 96, 169, 177, 132, 153, 123, 9, 152, 129, 177, 17, 74, 43, 24, 169, 128, 121, 137, 25, 1, 139, 96, 42, 10, 146, 178, 18,
- 44, 29, 1, 161, 164, 146, 31, 137, 146, 177, 19, 1, 10, 26, 209, 165, 146, 43, 40, 138, 240, 130, 18, 144, 25, 40, 212, 1, 58, 11, 152, 196, 147, 10, 74, 26, 152, 225, 130, 146, 58, 60, 210, 145, 16, 148, 16, 185, 192, 18, 44, 42, 57, 199, 162, 1, 9, 87, 47, 186, 215, 231, 197, 179, 180, 195, 212, 164, 32, 59, 92, 126, 62,
- 41, 59, 76, 59, 60, 168, 179, 213, 197, 163, 72, 44, 25, 74, 126, 127, 127, 79, 26, 177, 148, 90, 27, 225, 247, 165, 0, 152, 147, 123, 138, 211, 164, 72, 126, 127, 46, 210, 196, 163, 228, 215, 64, 11, 210, 180, 1, 8, 58, 153, 1, 224, 149, 57, 76, 27, 24, 76, 42, 43, 136, 128, 243, 179, 130, 106, 60, 42, 42, 92, 28, 243, 231,
- 147, 24, 57, 44, 58, 94, 45, 8, 57, 139, 214, 148, 40, 77, 26, 9, 16, 10, 144, 64, 62, 43, 25, 123, 59, 138, 162, 48, 63, 26, 41, 92, 60, 43, 176, 3, 59, 232, 214, 164, 16, 75, 75, 76, 60, 153, 179, 33, 62, 26, 136, 40, 75, 169, 197, 163, 129, 57, 60, 59, 75, 138, 145, 64, 63, 138, 179, 1, 42, 136, 90, 43, 176, 214, 180, 1, 25,
- 152, 195, 129, 129, 106, 76, 60, 137, 145, 178, 2, 25, 10, 228, 130, 57, 59, 44, 41, 154, 165, 105, 76, 44, 144, 16, 76, 26, 41, 76, 26, 152, 1, 58, 26, 9, 193, 165, 16, 92, 26, 41, 77, 59, 76, 76, 60, 26, 136, 161, 130, 152, 195, 163, 211, 146, 0, 57, 11, 211, 130, 8, 25, 40, 62, 153, 162, 17, 109, 60, 153, 146, 40, 76, 60,
- 26, 160, 179, 211, 163, 32, 60, 42, 153, 179, 194, 199, 130, 24, 58, 43, 58, 27, 128, 161, 195, 129, 226, 196, 147, 90, 59, 75, 44, 136, 128, 145, 160, 148, 123, 59, 42, 26, 41, 26, 57, 27, 192, 215, 147, 57, 59, 27, 161, 145, 213, 130, 106, 76, 43, 9, 144, 162, 129, 177, 181, 130, 136, 194, 146, 40, 10, 129, 25, 210, 146,
- 178, 197, 196, 179, 196, 130, 8, 41, 9, 144, 178, 130, 209, 182, 17, 92, 43, 176, 147, 144, 212, 130, 136, 0, 177, 130, 73, 62, 10, 161, 130, 91, 75, 59, 43, 57, 46, 25, 41, 77, 10, 177, 164, 16, 26, 136, 210, 197, 179, 130, 128, 57, 77, 43, 25, 75, 10, 227, 179, 180, 179, 146, 128, 57, 185, 183, 163, 145, 0, 8, 8, 10, 119,
- 114, 120, 16, 210, 244, 60, 28, 41, 25, 152, 149, 56, 161, 35, 44, 89, 27, 24, 136, 24, 164, 211, 17, 233, 176, 136, 192, 129, 179, 17, 17, 25, 0, 10, 46, 160, 132, 49, 66, 24, 132, 177, 147, 193, 56, 72, 26, 29, 232, 168, 176, 12, 137, 41, 139, 147, 9, 1, 41, 15, 91, 136, 35, 148, 21, 18, 48, 40, 1, 168, 167, 144, 0, 42, 172,
- 177, 204, 193, 155, 232, 152, 152, 26, 152, 41, 146, 17, 6, 4, 65, 34, 35, 135, 4, 16, 32, 9, 24, 186, 176, 0, 250, 153, 204, 186, 173, 154, 153, 177, 3, 65, 41, 34, 145, 134, 35, 65, 98, 49, 50, 50, 2, 33, 169, 138, 155, 175, 170, 172, 204, 192, 138, 234, 136, 155, 136, 10, 32, 18, 5, 52, 48, 24, 162, 17, 67, 54, 66, 51, 34,
- 131, 184, 174, 234, 153, 10, 9, 40, 0, 152, 251, 168, 142, 154, 9, 16, 33, 49, 33, 128, 154, 170, 156, 34, 54, 54, 33, 68, 0, 1, 136, 201, 137, 26, 88, 48, 35, 99, 8, 152, 189, 189, 187, 155, 171, 16, 24, 130, 145, 188, 175, 203, 144, 49, 115, 67, 67, 50, 19, 2, 1, 0, 0, 130, 131, 1, 136, 206, 216, 188, 203, 204, 187, 187,
- 156, 153, 0, 0, 51, 17, 34, 24, 112, 20, 69, 67, 67, 34, 19, 0, 136, 169, 185, 137, 186, 232, 185, 219, 201, 203, 187, 173, 170, 154, 153, 129, 131, 6, 2, 19, 49, 49, 21, 65, 19, 53, 51, 83, 34, 16, 168, 201, 154, 172, 156, 138, 0, 1, 24, 201, 233, 186, 204, 186, 171, 137, 3, 37, 48, 24, 128, 201, 202, 202, 129, 17, 48, 21,
- 22, 20, 19, 19, 32, 16, 2, 66, 52, 68, 4, 3, 1, 203, 235, 188, 189, 186, 171, 153, 137, 153, 170, 219, 170, 140, 9, 17, 53, 115, 50, 52, 67, 51, 51, 51, 17, 130, 0, 145, 154, 169, 188, 236, 187, 190, 203, 187, 172, 171, 138, 136, 17, 33, 18, 2, 34, 98, 98, 50, 50, 52, 66, 34, 35, 2, 19, 24, 169, 203, 203, 188, 219, 169, 154,
- 9, 137, 171, 204, 188, 203, 184, 136, 34, 83, 50, 33, 153, 184, 170, 170, 152, 40, 57, 19, 36, 50, 50, 18, 35, 17, 2, 49, 49, 66, 66, 66, 34, 17, 168, 233, 202, 202, 170, 171, 170, 186, 219, 203, 188, 188, 154, 138, 25, 33, 68, 52, 68, 67, 67, 36, 51, 36, 18, 17, 17, 136, 8, 170, 176, 202, 188, 206, 202, 171, 172, 186, 169,
- 153, 8, 25, 144, 128, 1, 34, 68, 52, 68, 51, 52, 34, 49, 18, 34, 2, 144, 136, 155, 140, 187, 186, 186, 154, 154, 185, 185, 153, 9, 9, 0, 24, 0, 128, 144, 168, 169, 170, 154, 154, 153, 9, 8, 16, 8, 0, 144, 19, 35, 68, 51, 52, 67, 51, 66, 34, 50, 33, 1, 144, 185, 186, 172, 204, 187, 188, 173, 172, 186, 172, 186, 154, 138, 41,
- 33, 52, 53, 83, 50, 51, 52, 52, 37, 34, 34, 18, 16, 144, 152, 154, 187, 219, 203, 188, 173, 186, 186, 186, 170, 154, 153, 138, 144, 16, 17, 67, 82, 50, 51, 21, 34, 19, 33, 2, 18, 33, 1, 8, 153, 169, 153, 153, 136, 128, 0, 136, 154, 153, 153, 8, 8, 1, 16, 0, 169, 170, 187, 171, 171, 154, 153, 153, 152, 153, 153, 0, 16, 51, 83,
- 66, 50, 67, 50, 51, 67, 51, 52, 35, 18, 136, 186, 219, 187, 189, 186, 171, 187, 173, 187, 188, 187, 203, 138, 9, 16, 33, 50, 52, 53, 67, 67, 147, 8, 128, 128, 128, 128, 128, 128, 128, 128, 0, 240, 255, 55, 232, 23, 220, 0, 148, 1, 9, 18, 148, 10, 189, 32, 163, 62, 160, 5, 137, 12, 149, 42, 153, 144, 34, 42, 8, 1, 138, 181,
- 45, 136, 18, 144, 105, 138, 1, 160, 14, 128, 132, 145, 186, 37, 138, 41, 192, 48, 145, 46, 160, 33, 44, 24, 225, 16, 13, 132, 136, 137, 16, 148, 25, 170, 194, 82, 152, 136, 91, 24, 42, 169, 33, 233, 131, 179, 24, 185, 149, 16, 57, 172, 164, 18, 10, 211, 160, 147, 211, 33, 138, 243, 129, 16, 41, 193, 0, 43, 132, 155, 73,
- 58, 145, 244, 145, 43, 35, 9, 171, 16, 110, 25, 8, 28, 74, 162, 128, 26, 27, 82, 45, 136, 153, 18, 8, 136, 8
-};
-#endif // DISABLE_PC98_RHYTHM_CHANNEL
-
-TownsPC98_FmSynth::ChanInternal::ChanInternal() {
- memset(this, 0, sizeof(ChanInternal));
-}
-
-TownsPC98_FmSynth::ChanInternal::~ChanInternal() {
- for (uint i = 0; i < ARRAYSIZE(opr); ++i)
- delete opr[i];
-}
diff --git a/sound/softsynth/fmtowns_pc98/towns_pc98_fmsynth.h b/sound/softsynth/fmtowns_pc98/towns_pc98_fmsynth.h
deleted file mode 100644
index ddd249b1b8..0000000000
--- a/sound/softsynth/fmtowns_pc98/towns_pc98_fmsynth.h
+++ /dev/null
@@ -1,196 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * $URL$
- * $Id$
- *
- */
-
-#ifndef TOWNS_PC98_FMSYNTH_H
-#define TOWNS_PC98_FMSYNTH_H
-
-#include "sound/audiostream.h"
-#include "sound/mixer.h"
-#include "common/list.h"
-
-#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,
- kEnvAttacking,
- kEnvDecaying,
- kEnvSustaining,
- kEnvReleasing
-};
-
-class TownsPC98_FmSynth : public Audio::AudioStream {
-public:
- enum EmuType {
- kTypeTowns,
- kType26,
- kType86
- };
-
- TownsPC98_FmSynth(Audio::Mixer *mixer, EmuType type);
- virtual ~TownsPC98_FmSynth();
-
- virtual bool init();
- virtual void reset();
-
- void writeReg(uint8 part, uint8 regAddress, uint8 value);
-
- // AudioStream interface
- int readBuffer(int16 *buffer, const int numSamples);
- bool isStereo() const {
- return true;
- }
- bool endOfData() const {
- return false;
- }
- int getRate() const {
- return _mixer->getOutputRate();
- }
-
-protected:
- 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) {}
-
- void toggleRegProtection(bool prot) {
- _regProtectionFlag = prot;
- }
- uint8 readSSGStatus();
-
- virtual void timerCallbackA() = 0;
- virtual void timerCallbackB() = 0;
-
- // The audio driver can store and apply two different audio settings
- // (usually for music and sound effects). The channel mask will determine
- // which channels get effected by the setting. The first bits will be
- // the normal fm channels, the next bits the ssg channels and the final
- // bit the rhythm channel.
- void setVolumeIntern(int volA, int volB);
- void setVolumeChannelMasks(int channelMaskA, int channelMaskB);
-
- const int _numChan;
- const int _numSSG;
- const bool _hasPercussion;
-
- Common::Mutex _mutex;
-private:
- void generateTables();
- void nextTick(int32 *buffer, uint32 bufferSize);
- void generateOutput(int32 &leftSample, int32 &rightSample, int32 *del, int32 *feed);
-
- struct ChanInternal {
- ChanInternal();
- ~ChanInternal();
-
- void ampModSensitivity(uint32 value) {
- ampModSvty = (1 << (3 - value)) - (((value >> 1) & 1) | (value & 1));
- }
- void frqModSensitivity(uint32 value) {
- frqModSvty = value << 5;
- }
-
- uint16 frqTemp;
- bool enableLeft;
- bool enableRight;
- bool updateEnvelopeParameters;
- int32 feedbuf[3];
- uint8 algorithm;
-
- uint32 ampModSvty;
- uint32 frqModSvty;
-
- TownsPC98_FmSynthOperator *opr[4];
- };
-
- TownsPC98_FmSynthSquareSineSource *_ssg;
-#ifndef DISABLE_PC98_RHYTHM_CHANNEL
- TownsPC98_FmSynthPercussionSource *_prc;
-#endif
- ChanInternal *_chanInternal;
-
- uint8 *_oprRates;
- uint8 *_oprRateshift;
- uint8 *_oprAttackDecay;
- uint32 *_oprFrq;
- uint32 *_oprSinTbl;
- int32 *_oprLevelOut;
- int32 *_oprDetune;
-
- bool _regProtectionFlag;
-
- typedef void (TownsPC98_FmSynth::*ChipTimerProc)();
- void idleTimerCallback() {}
-
- struct ChipTimer {
- bool enabled;
- uint16 value;
-
- int32 smpTillCb;
- uint32 smpTillCbRem;
- int32 smpPerCb;
- uint32 smpPerCbRem;
-
- ChipTimerProc cb;
- };
-
- ChipTimer _timers[2];
-
- int _volMaskA, _volMaskB;
- uint16 _volumeA, _volumeB;
-
- const float _baserate;
- uint32 _timerbase;
- uint32 _rtt;
-
- 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[];
-
- bool _ready;
-};
-
-#endif
-
diff --git a/sound/softsynth/mt32.cpp b/sound/softsynth/mt32.cpp
deleted file mode 100644
index 09e7e48151..0000000000
--- a/sound/softsynth/mt32.cpp
+++ /dev/null
@@ -1,573 +0,0 @@
-/* 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 "common/scummsys.h"
-
-#ifdef USE_MT32EMU
-
-#include "sound/softsynth/mt32/mt32emu.h"
-
-#include "sound/softsynth/emumidi.h"
-#include "sound/musicplugin.h"
-#include "sound/mpu401.h"
-
-#include "common/config-manager.h"
-#include "common/debug.h"
-#include "common/events.h"
-#include "common/file.h"
-#include "common/system.h"
-#include "common/util.h"
-#include "common/archive.h"
-#include "common/translation.h"
-
-#include "graphics/fontman.h"
-#include "graphics/surface.h"
-
-class MidiChannel_MT32 : public MidiChannel_MPU401 {
- void effectLevel(byte value) { }
- void chorusLevel(byte value) { }
-};
-
-class MidiDriver_MT32 : public MidiDriver_Emulated {
-private:
- Audio::SoundHandle _handle;
- MidiChannel_MT32 _midiChannels[16];
- uint16 _channelMask;
- MT32Emu::Synth *_synth;
-
- int _outputRate;
-
-protected:
- void generateSamples(int16 *buf, int len);
-
-public:
- bool _initialising;
-
- MidiDriver_MT32(Audio::Mixer *mixer);
- virtual ~MidiDriver_MT32();
-
- int open();
- void close();
- void send(uint32 b);
- void setPitchBendRange (byte channel, uint range);
- void sysEx(const byte *msg, uint16 length);
-
- uint32 property(int prop, uint32 param);
- MidiChannel *allocateChannel();
- MidiChannel *getPercussionChannel();
-
- // AudioStream API
- bool isStereo() const { return true; }
- int getRate() const { return _outputRate; }
-};
-
-class MT32File : public MT32Emu::File {
- Common::File _in;
- Common::DumpFile _out;
-public:
- bool open(const char *filename, OpenMode mode) {
- if (mode == OpenMode_read)
- return _in.open(filename);
- else
- return _out.open(filename);
- }
- void close() {
- _in.close();
- _out.close();
- }
- size_t read(void *in, size_t size) {
- return _in.read(in, size);
- }
- bool readBit8u(MT32Emu::Bit8u *in) {
- byte b = _in.readByte();
- if (_in.eos())
- return false;
- *in = b;
- return true;
- }
- size_t write(const void *in, size_t size) {
- return _out.write(in, size);
- }
- bool writeBit8u(MT32Emu::Bit8u out) {
- _out.writeByte(out);
- return !_out.err();
- }
- bool isEOF() {
- return _in.isOpen() && _in.eos();
- }
-};
-
-static int eatSystemEvents() {
- Common::Event event;
- Common::EventManager *eventMan = g_system->getEventManager();
- while (eventMan->pollEvent(event)) {
- switch (event.type) {
- case Common::EVENT_QUIT:
- return 1;
- default:
- break;
- }
- }
- return 0;
-}
-
-static void drawProgress(float progress) {
- const Graphics::Font &font(*FontMan.getFontByUsage(Graphics::FontManager::kOSDFont));
- Graphics::Surface *screen = g_system->lockScreen();
-
- assert(screen);
- assert(screen->pixels);
-
- Graphics::PixelFormat screenFormat = g_system->getScreenFormat();
-
- int16 w = g_system->getWidth() / 7 * 5;
- int16 h = font.getFontHeight();
- int16 x = g_system->getWidth() / 7;
- int16 y = g_system->getHeight() / 2 - h / 2;
-
- Common::Rect r(x, y, x + w, y + h);
-
- uint32 col;
-
- if (screenFormat.bytesPerPixel > 1)
- col = screenFormat.RGBToColor(0, 171, 0);
- else
- col = 1;
-
- screen->frameRect(r, col);
-
- r.grow(-1);
- r.setWidth(uint16(progress * w));
-
- if (screenFormat.bytesPerPixel > 1)
- col = screenFormat.RGBToColor(171, 0, 0);
- else
- col = 2;
-
- screen->fillRect(r, col);
-
- g_system->unlockScreen();
- g_system->updateScreen();
-}
-
-static void drawMessage(int offset, const Common::String &text) {
- const Graphics::Font &font(*FontMan.getFontByUsage(Graphics::FontManager::kOSDFont));
- Graphics::Surface *screen = g_system->lockScreen();
-
- assert(screen);
- assert(screen->pixels);
-
- Graphics::PixelFormat screenFormat = g_system->getScreenFormat();
-
- uint16 h = font.getFontHeight();
- uint16 y = g_system->getHeight() / 2 - h / 2 + offset * (h + 1);
-
- uint32 col;
-
- if (screenFormat.bytesPerPixel > 1)
- col = screenFormat.RGBToColor(0, 0, 0);
- else
- col = 0;
-
- Common::Rect r(0, y, screen->w, y + h);
- screen->fillRect(r, col);
-
- if (screenFormat.bytesPerPixel > 1)
- col = screenFormat.RGBToColor(0, 171, 0);
- else
- col = 1;
-
- font.drawString(screen, text, 0, y, screen->w, col, Graphics::kTextAlignCenter);
-
- g_system->unlockScreen();
- g_system->updateScreen();
-}
-
-static MT32Emu::File *MT32_OpenFile(void *userData, const char *filename, MT32Emu::File::OpenMode mode) {
- MT32File *file = new MT32File();
- if (!file->open(filename, mode)) {
- delete file;
- return NULL;
- }
- return file;
-}
-
-static void MT32_PrintDebug(void *userData, const char *fmt, va_list list) {
- if (((MidiDriver_MT32 *)userData)->_initialising) {
- char buf[512];
-
- vsnprintf(buf, 512, fmt, list);
- buf[70] = 0; // Truncate to a reasonable length
-
- drawMessage(1, buf);
- }
-
- //vdebug(0, fmt, list); // FIXME: Use a higher debug level
-}
-
-static int MT32_Report(void *userData, MT32Emu::ReportType type, const void *reportData) {
- switch (type) {
- case MT32Emu::ReportType_lcdMessage:
- g_system->displayMessageOnOSD((const char *)reportData);
- break;
- case MT32Emu::ReportType_errorControlROM:
- error("Failed to load MT32_CONTROL.ROM");
- break;
- case MT32Emu::ReportType_errorPCMROM:
- error("Failed to load MT32_PCM.ROM");
- break;
- case MT32Emu::ReportType_progressInit:
- if (((MidiDriver_MT32 *)userData)->_initialising) {
- drawProgress(*((const float *)reportData));
- return eatSystemEvents();
- }
- break;
- case MT32Emu::ReportType_availableSSE:
- debug(1, "MT32emu: SSE is available");
- break;
- case MT32Emu::ReportType_usingSSE:
- debug(1, "MT32emu: using SSE");
- break;
- case MT32Emu::ReportType_available3DNow:
- debug(1, "MT32emu: 3DNow! is available");
- break;
- case MT32Emu::ReportType_using3DNow:
- debug(1, "MT32emu: using 3DNow!");
- break;
- default:
- break;
- }
- return 0;
-}
-
-////////////////////////////////////////
-//
-// MidiDriver_MT32
-//
-////////////////////////////////////////
-
-MidiDriver_MT32::MidiDriver_MT32(Audio::Mixer *mixer) : MidiDriver_Emulated(mixer) {
- _channelMask = 0xFFFF; // Permit all 16 channels by default
- uint i;
- for (i = 0; i < ARRAYSIZE(_midiChannels); ++i) {
- _midiChannels[i].init(this, i);
- }
- _synth = NULL;
- // A higher baseFreq reduces the length used in generateSamples(),
- // and means that the timer callback will be called more often.
- // That results in more accurate timing.
- _baseFreq = 10000;
- // Unfortunately bugs in the emulator cause inaccurate tuning
- // at rates other than 32KHz, thus we produce data at 32KHz and
- // rely on Mixer to convert.
- _outputRate = 32000; //_mixer->getOutputRate();
- _initialising = false;
-}
-
-MidiDriver_MT32::~MidiDriver_MT32() {
- delete _synth;
-}
-
-int MidiDriver_MT32::open() {
- MT32Emu::SynthProperties prop;
-
- if (_isOpen)
- return MERR_ALREADY_OPEN;
-
- MidiDriver_Emulated::open();
-
- memset(&prop, 0, sizeof(prop));
- prop.sampleRate = getRate();
- prop.useReverb = true;
- prop.useDefaultReverb = false;
- prop.reverbType = 0;
- prop.reverbTime = 5;
- prop.reverbLevel = 3;
- prop.userData = this;
- prop.printDebug = MT32_PrintDebug;
- prop.report = MT32_Report;
- prop.openFile = MT32_OpenFile;
-
- _synth = new MT32Emu::Synth();
-
- Graphics::PixelFormat screenFormat = g_system->getScreenFormat();
-
- if (screenFormat.bytesPerPixel == 1) {
- const byte dummy_palette[] = {
- 0, 0, 0, 0, // background
- 0, 171, 0, 0, // border, font
- 171, 0, 0, 0 // fill
- };
-
- g_system->getPaletteManager()->setPalette(dummy_palette, 0, 3);
- }
-
- _initialising = true;
- drawMessage(-1, _s("Initialising MT-32 Emulator"));
- if (!_synth->open(prop))
- return MERR_DEVICE_NOT_AVAILABLE;
- _initialising = false;
-
- if (screenFormat.bytesPerPixel > 1)
- g_system->fillScreen(screenFormat.RGBToColor(0, 0, 0));
- else
- g_system->fillScreen(0);
-
- g_system->updateScreen();
-
- _mixer->playStream(Audio::Mixer::kSFXSoundType, &_handle, this, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO, true);
-
- return 0;
-}
-
-void MidiDriver_MT32::send(uint32 b) {
- _synth->playMsg(b);
-}
-
-void MidiDriver_MT32::setPitchBendRange(byte channel, uint range) {
- if (range > 24) {
- printf("setPitchBendRange() called with range > 24: %d", range);
- }
- byte benderRangeSysex[9];
- benderRangeSysex[0] = 0x41; // Roland
- benderRangeSysex[1] = channel;
- benderRangeSysex[2] = 0x16; // MT-32
- benderRangeSysex[3] = 0x12; // Write
- benderRangeSysex[4] = 0x00;
- benderRangeSysex[5] = 0x00;
- benderRangeSysex[6] = 0x04;
- benderRangeSysex[7] = (byte)range;
- benderRangeSysex[8] = MT32Emu::Synth::calcSysexChecksum(&benderRangeSysex[4], 4, 0);
- sysEx(benderRangeSysex, 9);
-}
-
-void MidiDriver_MT32::sysEx(const byte *msg, uint16 length) {
- if (msg[0] == 0xf0) {
- _synth->playSysex(msg, length);
- } else {
- _synth->playSysexWithoutFraming(msg, length);
- }
-}
-
-void MidiDriver_MT32::close() {
- if (!_isOpen)
- return;
- _isOpen = false;
-
- // Detach the player callback handler
- setTimerCallback(NULL, NULL);
- // Detach the mixer callback handler
- _mixer->stopHandle(_handle);
-
- _synth->close();
- delete _synth;
- _synth = NULL;
-}
-
-void MidiDriver_MT32::generateSamples(int16 *data, int len) {
- _synth->render(data, len);
-}
-
-uint32 MidiDriver_MT32::property(int prop, uint32 param) {
- switch (prop) {
- case PROP_CHANNEL_MASK:
- _channelMask = param & 0xFFFF;
- return 1;
- }
-
- return 0;
-}
-
-MidiChannel *MidiDriver_MT32::allocateChannel() {
- MidiChannel_MT32 *chan;
- uint i;
-
- for (i = 0; i < ARRAYSIZE(_midiChannels); ++i) {
- if (i == 9 || !(_channelMask & (1 << i)))
- continue;
- chan = &_midiChannels[i];
- if (chan->allocate()) {
- return chan;
- }
- }
- return NULL;
-}
-
-MidiChannel *MidiDriver_MT32::getPercussionChannel() {
- return &_midiChannels[9];
-}
-
-// This code should be used when calling the timer callback from the mixer thread is undesirable.
-// Note that it results in less accurate timing.
-#if 0
-class MidiEvent_MT32 {
-public:
- MidiEvent_MT32 *_next;
- uint32 _msg; // 0xFFFFFFFF indicates a sysex message
- byte *_data;
- uint32 _len;
-
- MidiEvent_MT32(uint32 msg, byte *data, uint32 len) {
- _msg = msg;
- if (len > 0) {
- _data = new byte[len];
- memcpy(_data, data, len);
- }
- _len = len;
- _next = NULL;
- }
-
- MidiEvent_MT32() {
- if (_len > 0)
- delete _data;
- }
-};
-
-class MidiDriver_ThreadedMT32 : public MidiDriver_MT32 {
-private:
- OSystem::Mutex _eventMutex;
- MidiEvent_MT32 *_events;
- TimerManager::TimerProc _timer_proc;
-
- void pushMidiEvent(MidiEvent_MT32 *event);
- MidiEvent_MT32 *popMidiEvent();
-
-protected:
- void send(uint32 b);
- void sysEx(const byte *msg, uint16 length);
-
-public:
- MidiDriver_ThreadedMT32(Audio::Mixer *mixer);
-
- void onTimer();
- void close();
- void setTimerCallback(void *timer_param, TimerManager::TimerProc timer_proc);
-};
-
-
-MidiDriver_ThreadedMT32::MidiDriver_ThreadedMT32(Audio::Mixer *mixer) : MidiDriver_MT32(mixer) {
- _events = NULL;
- _timer_proc = NULL;
-}
-
-void MidiDriver_ThreadedMT32::close() {
- MidiDriver_MT32::close();
- while ((popMidiEvent() != NULL)) {
- // Just eat any leftover events
- }
-}
-
-void MidiDriver_ThreadedMT32::setTimerCallback(void *timer_param, TimerManager::TimerProc timer_proc) {
- if (!_timer_proc || !timer_proc) {
- if (_timer_proc)
- _vm->_timer->removeTimerProc(_timer_proc);
- _timer_proc = timer_proc;
- if (timer_proc)
- _vm->_timer->installTimerProc(timer_proc, getBaseTempo(), timer_param);
- }
-}
-
-void MidiDriver_ThreadedMT32::pushMidiEvent(MidiEvent_MT32 *event) {
- Common::StackLock lock(_eventMutex);
- if (_events == NULL) {
- _events = event;
- } else {
- MidiEvent_MT32 *last = _events;
- while (last->_next != NULL)
- last = last->_next;
- last->_next = event;
- }
-}
-
-MidiEvent_MT32 *MidiDriver_ThreadedMT32::popMidiEvent() {
- Common::StackLock lock(_eventMutex);
- MidiEvent_MT32 *event;
- event = _events;
- if (event != NULL)
- _events = event->_next;
- return event;
-}
-
-void MidiDriver_ThreadedMT32::send(uint32 b) {
- MidiEvent_MT32 *event = new MidiEvent_MT32(b, NULL, 0);
- pushMidiEvent(event);
-}
-
-void MidiDriver_ThreadedMT32::sysEx(const byte *msg, uint16 length) {
- MidiEvent_MT32 *event = new MidiEvent_MT32(0xFFFFFFFF, msg, length);
- pushMidiEvent(event);
-}
-
-void MidiDriver_ThreadedMT32::onTimer() {
- MidiEvent_MT32 *event;
- while ((event = popMidiEvent()) != NULL) {
- if (event->_msg == 0xFFFFFFFF) {
- MidiDriver_MT32::sysEx(event->_data, event->_len);
- } else {
- MidiDriver_MT32::send(event->_msg);
- }
- delete event;
- }
-}
-#endif
-
-
-// Plugin interface
-
-class MT32EmuMusicPlugin : public MusicPluginObject {
-public:
- const char *getName() const {
- return _s("MT-32 Emulator");
- }
-
- const char *getId() const {
- return "mt32";
- }
-
- MusicDevices getDevices() const;
- Common::Error createInstance(MidiDriver **mididriver, MidiDriver::DeviceHandle = 0) const;
-};
-
-MusicDevices MT32EmuMusicPlugin::getDevices() const {
- MusicDevices devices;
- devices.push_back(MusicDevice(this, "", MT_MT32));
- return devices;
-}
-
-Common::Error MT32EmuMusicPlugin::createInstance(MidiDriver **mididriver, MidiDriver::DeviceHandle) const {
- if (ConfMan.hasKey("extrapath"))
- SearchMan.addDirectory("extrapath", ConfMan.get("extrapath"));
-
- *mididriver = new MidiDriver_MT32(g_system->getMixer());
-
- return Common::kNoError;
-}
-
-//#if PLUGIN_ENABLED_DYNAMIC(MT32)
- //REGISTER_PLUGIN_DYNAMIC(MT32, PLUGIN_TYPE_MUSIC, MT32EmuMusicPlugin);
-//#else
- REGISTER_PLUGIN_STATIC(MT32, PLUGIN_TYPE_MUSIC, MT32EmuMusicPlugin);
-//#endif
-
-#endif
diff --git a/sound/softsynth/mt32/freeverb.cpp b/sound/softsynth/mt32/freeverb.cpp
deleted file mode 100644
index 4ee6e20117..0000000000
--- a/sound/softsynth/mt32/freeverb.cpp
+++ /dev/null
@@ -1,310 +0,0 @@
-/* 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$
- *
- */
-
-// Comb filter implementation
-//
-// Written by
-// http://www.dreampoint.co.uk
-// This code is public domain
-
-#include "sound/softsynth/mt32/freeverb.h"
-
-comb::comb() {
- filterstore = 0;
- bufidx = 0;
-}
-
-void comb::setbuffer(float *buf, int size) {
- buffer = buf;
- bufsize = size;
-}
-
-void comb::mute() {
- for (int i = 0; i < bufsize; i++)
- buffer[i] = 0;
-}
-
-void comb::setdamp(float val) {
- damp1 = val;
- damp2 = 1 - val;
-}
-
-float comb::getdamp() {
- return damp1;
-}
-
-void comb::setfeedback(float val) {
- feedback = val;
-}
-
-float comb::getfeedback() {
- return feedback;
-}
-
-// Allpass filter implementation
-
-allpass::allpass() {
- bufidx = 0;
-}
-
-void allpass::setbuffer(float *buf, int size) {
- buffer = buf;
- bufsize = size;
-}
-
-void allpass::mute() {
- for (int i = 0; i < bufsize; i++)
- buffer[i] = 0;
-}
-
-void allpass::setfeedback(float val) {
- feedback = val;
-}
-
-float allpass::getfeedback() {
- return feedback;
-}
-
-// Reverb model implementation
-
-revmodel::revmodel() {
- // Tie the components to their buffers
- combL[0].setbuffer(bufcombL1,combtuningL1);
- combR[0].setbuffer(bufcombR1,combtuningR1);
- combL[1].setbuffer(bufcombL2,combtuningL2);
- combR[1].setbuffer(bufcombR2,combtuningR2);
- combL[2].setbuffer(bufcombL3,combtuningL3);
- combR[2].setbuffer(bufcombR3,combtuningR3);
- combL[3].setbuffer(bufcombL4,combtuningL4);
- combR[3].setbuffer(bufcombR4,combtuningR4);
- combL[4].setbuffer(bufcombL5,combtuningL5);
- combR[4].setbuffer(bufcombR5,combtuningR5);
- combL[5].setbuffer(bufcombL6,combtuningL6);
- combR[5].setbuffer(bufcombR6,combtuningR6);
- combL[6].setbuffer(bufcombL7,combtuningL7);
- combR[6].setbuffer(bufcombR7,combtuningR7);
- combL[7].setbuffer(bufcombL8,combtuningL8);
- combR[7].setbuffer(bufcombR8,combtuningR8);
- allpassL[0].setbuffer(bufallpassL1,allpasstuningL1);
- allpassR[0].setbuffer(bufallpassR1,allpasstuningR1);
- allpassL[1].setbuffer(bufallpassL2,allpasstuningL2);
- allpassR[1].setbuffer(bufallpassR2,allpasstuningR2);
- allpassL[2].setbuffer(bufallpassL3,allpasstuningL3);
- allpassR[2].setbuffer(bufallpassR3,allpasstuningR3);
- allpassL[3].setbuffer(bufallpassL4,allpasstuningL4);
- allpassR[3].setbuffer(bufallpassR4,allpasstuningR4);
-
- // Set default values
- allpassL[0].setfeedback(0.5f);
- allpassR[0].setfeedback(0.5f);
- allpassL[1].setfeedback(0.5f);
- allpassR[1].setfeedback(0.5f);
- allpassL[2].setfeedback(0.5f);
- allpassR[2].setfeedback(0.5f);
- allpassL[3].setfeedback(0.5f);
- allpassR[3].setfeedback(0.5f);
- setmode(initialmode);
- setwet(initialwet);
- setroomsize(initialroom);
- setdry(initialdry);
- setdamp(initialdamp);
- setwidth(initialwidth);
-
- // Buffer will be full of rubbish - so we MUST mute them
- mute();
-}
-
-void revmodel::mute() {
- int i;
-
- if (getmode() >= freezemode)
- return;
-
- for (i = 0; i < numcombs; i++) {
- combL[i].mute();
- combR[i].mute();
- }
-
- for (i = 0; i < numallpasses; i++) {
- allpassL[i].mute();
- allpassR[i].mute();
- }
-}
-
-void revmodel::processreplace(float *inputL, float *inputR, float *outputL, float *outputR, long numsamples, int skip) {
- float outL, outR, input;
-
- while (numsamples-- > 0) {
- int i;
-
- outL = outR = 0;
- input = (*inputL + *inputR) * gain;
-
- // Accumulate comb filters in parallel
- for (i = 0; i < numcombs; i++) {
- outL += combL[i].process(input);
- outR += combR[i].process(input);
- }
-
- // Feed through allpasses in series
- for (i = 0; i < numallpasses; i++) {
- outL = allpassL[i].process(outL);
- outR = allpassR[i].process(outR);
- }
-
- // Calculate output REPLACING anything already there
- *outputL = outL * wet1 + outR * wet2 + *inputL * dry;
- *outputR = outR * wet1 + outL * wet2 + *inputR * dry;
-
- // Increment sample pointers, allowing for interleave (if any)
- inputL += skip;
- inputR += skip;
- outputL += skip;
- outputR += skip;
- }
-}
-
-void revmodel::processmix(float *inputL, float *inputR, float *outputL, float *outputR, long numsamples, int skip) {
- float outL, outR, input;
-
- while (numsamples-- > 0) {
- int i;
-
- outL = outR = 0;
- input = (*inputL + *inputR) * gain;
-
- // Accumulate comb filters in parallel
- for (i = 0; i < numcombs; i++) {
- outL += combL[i].process(input);
- outR += combR[i].process(input);
- }
-
- // Feed through allpasses in series
- for (i = 0; i < numallpasses; i++) {
- outL = allpassL[i].process(outL);
- outR = allpassR[i].process(outR);
- }
-
- // Calculate output MIXING with anything already there
- *outputL += outL * wet1 + outR * wet2 + *inputL * dry;
- *outputR += outR * wet1 + outL * wet2 + *inputR * dry;
-
- // Increment sample pointers, allowing for interleave (if any)
- inputL += skip;
- inputR += skip;
- outputL += skip;
- outputR += skip;
- }
-}
-
-void revmodel::update() {
- // Recalculate internal values after parameter change
-
- int i;
-
- wet1 = wet * (width / 2 + 0.5f);
- wet2 = wet * ((1 - width) / 2);
-
- if (mode >= freezemode) {
- roomsize1 = 1;
- damp1 = 0;
- gain = muted;
- } else {
- roomsize1 = roomsize;
- damp1 = damp;
- gain = fixedgain;
- }
-
- for (i = 0; i < numcombs; i++) {
- combL[i].setfeedback(roomsize1);
- combR[i].setfeedback(roomsize1);
- }
-
- for (i = 0; i < numcombs; i++) {
- combL[i].setdamp(damp1);
- combR[i].setdamp(damp1);
- }
-}
-
-// The following get/set functions are not inlined, because
-// speed is never an issue when calling them, and also
-// because as you develop the reverb model, you may
-// wish to take dynamic action when they are called.
-
-void revmodel::setroomsize(float value) {
- roomsize = (value * scaleroom) + offsetroom;
- update();
-}
-
-float revmodel::getroomsize() {
- return (roomsize - offsetroom) / scaleroom;
-}
-
-void revmodel::setdamp(float value) {
- damp = value * scaledamp;
- update();
-}
-
-float revmodel::getdamp() {
- return damp / scaledamp;
-}
-
-void revmodel::setwet(float value) {
- wet = value * scalewet;
- update();
-}
-
-float revmodel::getwet() {
- return wet / scalewet;
-}
-
-void revmodel::setdry(float value) {
- dry = value * scaledry;
-}
-
-float revmodel::getdry() {
- return dry / scaledry;
-}
-
-void revmodel::setwidth(float value) {
- width = value;
- update();
-}
-
-float revmodel::getwidth() {
- return width;
-}
-
-void revmodel::setmode(float value) {
- mode = value;
- update();
-}
-
-float revmodel::getmode() {
- if (mode >= freezemode)
- return 1;
- else
- return 0;
-}
diff --git a/sound/softsynth/mt32/freeverb.h b/sound/softsynth/mt32/freeverb.h
deleted file mode 100644
index 8310aca3e3..0000000000
--- a/sound/softsynth/mt32/freeverb.h
+++ /dev/null
@@ -1,244 +0,0 @@
-/* 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$
- *
- */
-
-// Macro for killing denormalled numbers
-//
-// Written by Jezar at Dreampoint, June 2000
-// http://www.dreampoint.co.uk
-// Based on IS_DENORMAL macro by Jon Watte
-// This code is public domain
-
-#ifndef FREEVERB_H
-#define FREEVERB_H
-
-// FIXME: Fix this really ugly hack
-inline float undenormalise(void *sample) {
- if (((*(unsigned int*)sample) & 0x7f800000) == 0)
- return 0.0f;
- return *(float*)sample;
-}
-
-// Comb filter class declaration
-
-class comb {
-public:
- comb();
- void setbuffer(float *buf, int size);
- inline float process(float inp);
- void mute();
- void setdamp(float val);
- float getdamp();
- void setfeedback(float val);
- float getfeedback();
-private:
- float feedback;
- float filterstore;
- float damp1;
- float damp2;
- float *buffer;
- int bufsize;
- int bufidx;
-};
-
-
-// Big to inline - but crucial for speed
-
-inline float comb::process(float input) {
- float output;
-
- output = buffer[bufidx];
- undenormalise(&output);
-
- filterstore = (output * damp2) + (filterstore * damp1);
- undenormalise(&filterstore);
-
- buffer[bufidx] = input + (filterstore * feedback);
-
- if (++bufidx >= bufsize)
- bufidx = 0;
-
- return output;
-}
-
-// Allpass filter declaration
-
-class allpass {
-public:
- allpass();
- void setbuffer(float *buf, int size);
- inline float process(float inp);
- void mute();
- void setfeedback(float val);
- float getfeedback();
-private:
- float feedback;
- float *buffer;
- int bufsize;
- int bufidx;
-};
-
-
-// Big to inline - but crucial for speed
-
-inline float allpass::process(float input) {
- float output;
- float bufout;
-
- bufout = buffer[bufidx];
- undenormalise(&bufout);
-
- output = -input + bufout;
- buffer[bufidx] = input + (bufout * feedback);
-
- if (++bufidx >= bufsize)
- bufidx = 0;
-
- return output;
-}
-
-
-// Reverb model tuning values
-
-const int numcombs = 8;
-const int numallpasses = 4;
-const float muted = 0;
-const float fixedgain = 0.015f;
-const float scalewet = 3;
-const float scaledry = 2;
-const float scaledamp = 0.4f;
-const float scaleroom = 0.28f;
-const float offsetroom = 0.7f;
-const float initialroom = 0.5f;
-const float initialdamp = 0.5f;
-const float initialwet = 1 / scalewet;
-const float initialdry = 0;
-const float initialwidth = 1;
-const float initialmode = 0;
-const float freezemode = 0.5f;
-const int stereospread = 23;
-
-// These values assume 44.1KHz sample rate
-// they will probably be OK for 48KHz sample rate
-// but would need scaling for 96KHz (or other) sample rates.
-// The values were obtained by listening tests.
-const int combtuningL1 = 1116;
-const int combtuningR1 = 1116 + stereospread;
-const int combtuningL2 = 1188;
-const int combtuningR2 = 1188 + stereospread;
-const int combtuningL3 = 1277;
-const int combtuningR3 = 1277 + stereospread;
-const int combtuningL4 = 1356;
-const int combtuningR4 = 1356 + stereospread;
-const int combtuningL5 = 1422;
-const int combtuningR5 = 1422 + stereospread;
-const int combtuningL6 = 1491;
-const int combtuningR6 = 1491 + stereospread;
-const int combtuningL7 = 1557;
-const int combtuningR7 = 1557 + stereospread;
-const int combtuningL8 = 1617;
-const int combtuningR8 = 1617 + stereospread;
-const int allpasstuningL1 = 556;
-const int allpasstuningR1 = 556 + stereospread;
-const int allpasstuningL2 = 441;
-const int allpasstuningR2 = 441 + stereospread;
-const int allpasstuningL3 = 341;
-const int allpasstuningR3 = 341 + stereospread;
-const int allpasstuningL4 = 225;
-const int allpasstuningR4 = 225 + stereospread;
-
-
-// Reverb model declaration
-
-class revmodel {
-public:
- revmodel();
- void mute();
- void processmix(float *inputL, float *inputR, float *outputL, float *outputR, long numsamples, int skip);
- void processreplace(float *inputL, float *inputR, float *outputL, float *outputR, long numsamples, int skip);
- void setroomsize(float value);
- float getroomsize();
- void setdamp(float value);
- float getdamp();
- void setwet(float value);
- float getwet();
- void setdry(float value);
- float getdry();
- void setwidth(float value);
- float getwidth();
- void setmode(float value);
- float getmode();
-private:
- void update();
-
- float gain;
- float roomsize, roomsize1;
- float damp, damp1;
- float wet, wet1, wet2;
- float dry;
- float width;
- float mode;
-
- // The following are all declared inline
- // to remove the need for dynamic allocation
- // with its subsequent error-checking messiness
-
- // Comb filters
- comb combL[numcombs];
- comb combR[numcombs];
-
- // Allpass filters
- allpass allpassL[numallpasses];
- allpass allpassR[numallpasses];
-
- // Buffers for the combs
- float bufcombL1[combtuningL1];
- float bufcombR1[combtuningR1];
- float bufcombL2[combtuningL2];
- float bufcombR2[combtuningR2];
- float bufcombL3[combtuningL3];
- float bufcombR3[combtuningR3];
- float bufcombL4[combtuningL4];
- float bufcombR4[combtuningR4];
- float bufcombL5[combtuningL5];
- float bufcombR5[combtuningR5];
- float bufcombL6[combtuningL6];
- float bufcombR6[combtuningR6];
- float bufcombL7[combtuningL7];
- float bufcombR7[combtuningR7];
- float bufcombL8[combtuningL8];
- float bufcombR8[combtuningR8];
-
- // Buffers for the allpasses
- float bufallpassL1[allpasstuningL1];
- float bufallpassR1[allpasstuningR1];
- float bufallpassL2[allpasstuningL2];
- float bufallpassR2[allpasstuningR2];
- float bufallpassL3[allpasstuningL3];
- float bufallpassR3[allpasstuningR3];
- float bufallpassL4[allpasstuningL4];
- float bufallpassR4[allpasstuningR4];
-};
-
-#endif
diff --git a/sound/softsynth/mt32/i386.cpp b/sound/softsynth/mt32/i386.cpp
deleted file mode 100644
index f092189d76..0000000000
--- a/sound/softsynth/mt32/i386.cpp
+++ /dev/null
@@ -1,849 +0,0 @@
-/* Copyright (c) 2003-2005 Various contributors
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- * IN THE SOFTWARE.
- */
-
-#include "mt32emu.h"
-
-#ifdef MT32EMU_HAVE_X86
-
-namespace MT32Emu {
-
-#ifndef _MSC_VER
-
-#define eflag(value) __asm__ __volatile__("pushfl \n popfl \n" : : "a"(value))
-#define cpuid_flag (1 << 21)
-
-static inline bool atti386_DetectCPUID() {
- unsigned int result;
-
- // Is there a cpuid?
- result = cpuid_flag; // set test
- eflag(result);
- if (!(result & cpuid_flag))
- return false;
-
- result = 0; // clear test
- eflag(result);
- if (result & cpuid_flag)
- return false;
-
- return true;
-}
-
-static inline bool atti386_DetectSIMD() {
- unsigned int result;
-
- if (atti386_DetectCPUID() == false)
- return false;
-
- /* check cpuid */
- __asm__ __volatile__(
- "pushl %%ebx \n" \
- "movl $1, %%eax \n" \
- "cpuid \n" \
- "movl %%edx, %0 \n" \
- "popl %%ebx \n" \
- : "=r"(result) : : "eax", "ecx", "edx");
-
- if (result & (1 << 25))
- return true;
-
- return false;
-}
-
-static inline bool atti386_Detect3DNow() {
- unsigned int result;
-
- if (atti386_DetectCPUID() == false)
- return false;
-
- // get cpuid
- __asm__ __volatile__(
- "pushl %%ebx \n" \
- "movl $0x80000001, %%eax \n" \
- "cpuid \n" \
- "movl %%edx, %0 \n" \
- "popl %%ebx \n" \
- : "=r"(result) : : "eax", "ecx", "edx");
-
- if (result & 0x80000000)
- return true;
-
- return false;
-}
-
-
-static inline float atti386_iir_filter_sse(float *output, float *hist1_ptr, float *coef_ptr) {
- __asm__ __volatile__ (
- "pushl %1 \n" \
- "pushl %2 \n" \
- "movss 0(%0), %%xmm1 \n" \
- "movups 0(%1), %%xmm2 \n" \
- "movlps 0(%2), %%xmm3 \n" \
- " \n" \
- "shufps $0x44, %%xmm3, %%xmm3 \n" \
- " \n" \
- "mulps %%xmm3, %%xmm2 \n" \
- " \n" \
- "subss %%xmm2, %%xmm1 \n" \
- "shufps $0x39, %%xmm2, %%xmm2 \n" \
- "subss %%xmm2, %%xmm1 \n" \
- " \n" \
- "movss %%xmm1, 0(%2) \n" \
- " \n" \
- "shufps $0x39, %%xmm2, %%xmm2 \n" \
- "addss %%xmm2, %%xmm1 \n" \
- " \n" \
- "shufps $0x39, %%xmm2, %%xmm2 \n" \
- "addss %%xmm2, %%xmm1 \n" \
- " \n" \
- "movss %%xmm3, 4(%2) \n" \
- " \n" \
- "addl $16, %1 \n" \
- "addl $8, %2 \n" \
- " \n" \
- "movups 0(%1), %%xmm2 \n" \
- " \n" \
- "movlps 0(%2), %%xmm3 \n" \
- "shufps $0x44, %%xmm3, %%xmm3 \n" \
- " \n" \
- "mulps %%xmm3, %%xmm2 \n" \
- " \n" \
- "subss %%xmm2, %%xmm1 \n" \
- "shufps $0x39, %%xmm2, %%xmm2 \n" \
- "subss %%xmm2, %%xmm1 \n" \
- " \n" \
- "movss %%xmm1, 0(%2) \n" \
- " \n" \
- "shufps $0x39, %%xmm2, %%xmm2 \n" \
- "addss %%xmm2, %%xmm1 \n" \
- " \n" \
- "shufps $0x39, %%xmm2, %%xmm2 \n" \
- "addss %%xmm2, %%xmm1 \n" \
- " \n" \
- "movss %%xmm3, 4(%2) \n" \
- "movss %%xmm1, 0(%0) \n" \
- "popl %2 \n" \
- "popl %1 \n" \
- : : "r"(output), "r"(coef_ptr), "r"(hist1_ptr)
- : "memory"
-#ifdef __SSE__
- , "xmm1", "xmm2", "xmm3"
-#endif
- );
-
- return *output;
-}
-
-static inline float atti386_iir_filter_3DNow(float output, float *hist1_ptr, float *coef_ptr) {
- float tmp;
-
- __asm__ __volatile__ (
- "movq %0, %%mm1 \n" \
- " \n" \
- "movl %1, %%edi \n" \
- "movq 0(%%edi), %%mm2 \n" \
- " \n" \
- "movl %2, %%eax; \n" \
- "movq 0(%%eax), %%mm3 \n" \
- " \n" \
- "pfmul %%mm3, %%mm2 \n" \
- "pfsub %%mm2, %%mm1 \n" \
- " \n" \
- "psrlq $32, %%mm2 \n" \
- "pfsub %%mm2, %%mm1 \n" \
- " \n" \
- "movd %%mm1, %3 \n" \
- " \n" \
- "addl $8, %%edi \n" \
- "movq 0(%%edi), %%mm2 \n" \
- "movq 0(%%eax), %%mm3 \n" \
- " \n" \
- "pfmul %%mm3, %%mm2 \n" \
- "pfadd %%mm2, %%mm1 \n" \
- " \n" \
- "psrlq $32, %%mm2 \n" \
- "pfadd %%mm2, %%mm1 \n" \
- " \n" \
- "pushl %3 \n" \
- "popl 0(%%eax) \n" \
- " \n" \
- "movd %%mm3, 4(%%eax) \n" \
- " \n" \
- "addl $8, %%edi \n" \
- "addl $8, %%eax \n" \
- " \n" \
- "movq 0(%%edi), %%mm2 \n" \
- "movq 0(%%eax), %%mm3 \n" \
- " \n" \
- "pfmul %%mm3, %%mm2 \n" \
- "pfsub %%mm2, %%mm1 \n" \
- " \n" \
- "psrlq $32, %%mm2 \n" \
- "pfsub %%mm2, %%mm1 \n" \
- " \n" \
- "movd %%mm1, %3 \n" \
- " \n" \
- "addl $8, %%edi \n" \
- "movq 0(%%edi), %%mm2 \n" \
- "movq 0(%%eax), %%mm3 \n" \
- " \n" \
- "pfmul %%mm3, %%mm2 \n" \
- "pfadd %%mm2, %%mm1 \n" \
- " \n" \
- "psrlq $32, %%mm2 \n" \
- "pfadd %%mm2, %%mm1 \n" \
- " \n" \
- "pushl %3 \n" \
- "popl 0(%%eax) \n" \
- "movd %%mm3, 4(%%eax) \n" \
- " \n" \
- "movd %%mm1, %0 \n" \
- "femms \n" \
- : "=m"(output) : "g"(coef_ptr), "g"(hist1_ptr), "m"(tmp)
- : "eax", "edi", "memory"
-#ifdef __MMX__
- , "mm1", "mm2", "mm3"
-#endif
- );
-
- return output;
-}
-
-static inline void atti386_produceOutput1(int tmplen, Bit16s myvolume, Bit16s *useBuf, Bit16s *snd) {
- __asm__ __volatile__(
- "movl %0, %%ecx \n" \
- "movw %1, %%ax \n" \
- "shll $16, %%eax \n" \
- "movw %1, %%ax \n" \
- "movd %%eax, %%mm3 \n" \
- "movd %%eax, %%mm2 \n" \
- "psllq $32, %%mm3 \n" \
- "por %%mm2, %%mm3 \n" \
- "movl %2, %%esi \n" \
- "movl %3, %%edi \n" \
- "1: \n" \
- "movq 0(%%esi), %%mm1 \n" \
- "movq 0(%%edi), %%mm2 \n" \
- "pmulhw %%mm3, %%mm1 \n" \
- "paddw %%mm2, %%mm1 \n" \
- "movq %%mm1, 0(%%edi) \n" \
- " \n" \
- "addl $8, %%esi \n" \
- "addl $8, %%edi \n" \
- " \n" \
- "decl %%ecx \n" \
- "cmpl $0, %%ecx \n" \
- "jg 1b \n" \
- "emms \n" \
- : : "g"(tmplen), "g"(myvolume), "g"(useBuf), "g"(snd)
- : "eax", "ecx", "edi", "esi", "memory"
-#ifdef __MMX__
- , "mm1", "mm2", "mm3"
-#endif
- );
-}
-
-static inline void atti386_produceOutput2(Bit32u len, Bit16s *snd, float *sndbufl, float *sndbufr, float *multFactor) {
- __asm__ __volatile__(
- "movl %4, %%ecx \n" \
- "shrl $1, %%ecx \n" \
- "addl $4, %%ecx \n" \
- "pushl %%ecx \n" \
- " \n" \
- "movl %0, %%esi \n" \
- "movups 0(%%esi), %%xmm1 \n" \
- " \n" \
- "movl %1, %%esi \n" \
- "movl %2, %%edi \n" \
- "1: \n" \
- "xorl %%eax, %%eax \n" \
- "movw 0(%1), %%ax \n" \
- "cwde \n" \
- "incl %1 \n" \
- "incl %1 \n" \
- "movd %%eax, %%mm1 \n" \
- "psrlq $32, %%mm1 \n" \
- "movw 0(%1), %%ax \n" \
- "incl %1 \n" \
- "incl %1 \n" \
- "movd %%eax, %%mm2 \n" \
- "por %%mm2, %%mm1 \n" \
- " \n" \
- "decl %%ecx \n" \
- "jnz 1b \n" \
- " \n" \
- "popl %%ecx \n" \
- "movl %1, %%esi \n" \
- "movl %3, %%edi \n" \
- "incl %%esi \n" \
- "2: \n" \
- "decl %%ecx \n" \
- "jnz 2b \n" \
- : : "g"(multFactor), "r"(snd), "g"(sndbufl), "g"(sndbufr), "g"(len)
- : "eax", "ecx", "edi", "esi", "mm1", "mm2", "xmm1", "memory");
-}
-
-static inline void atti386_mixBuffers(Bit16s * buf1, Bit16s *buf2, int len) {
- __asm__ __volatile__(
- "movl %0, %%ecx \n" \
- "movl %1, %%esi \n" \
- "movl %2, %%edi \n" \
- "1: \n" \
- "movq 0(%%edi), %%mm1 \n" \
- "movq 0(%%esi), %%mm2 \n" \
- "paddw %%mm2, %%mm1 \n" \
- "movq %%mm1, 0(%%esi) \n" \
- "addl $8, %%edi \n" \
- "addl $8, %%esi \n" \
- "decl %%ecx \n" \
- "cmpl $0, %%ecx \n" \
- "jg 1b \n" \
- "emms \n" \
- : : "g"(len), "g"(buf1), "g"(buf2)
- : "ecx", "edi", "esi", "memory"
-#ifdef __MMX__
- , "mm1", "mm2"
-#endif
- );
-}
-
-static inline void atti386_mixBuffersRingMix(Bit16s * buf1, Bit16s *buf2, int len) {
- __asm__ __volatile__(
- "movl %0, %%ecx \n" \
- "movl %1, %%esi \n" \
- "movl %2, %%edi \n" \
- "1: \n" \
- "movq 0(%%esi), %%mm1 \n" \
- "movq 0(%%edi), %%mm2 \n" \
- "movq %%mm1, %%mm3 \n" \
- "pmulhw %%mm2, %%mm1 \n" \
- "paddw %%mm3, %%mm1 \n" \
- "movq %%mm1, 0(%%esi) \n" \
- "addl $8, %%edi \n" \
- "addl $8, %%esi \n" \
- "decl %%ecx \n" \
- "cmpl $0, %%ecx \n" \
- "jg 1b \n" \
- "emms \n" \
- : : "g"(len), "g"(buf1), "g"(buf2)
- : "ecx", "edi", "esi", "memory"
-#ifdef __MMX__
- , "mm1", "mm2", "mm3"
-#endif
- );
-}
-
-static inline void atti386_mixBuffersRing(Bit16s * buf1, Bit16s *buf2, int len) {
- __asm__ __volatile__(
- "movl %0, %%ecx \n" \
- "movl %1, %%esi \n" \
- "movl %2, %%edi \n" \
- "1: \n" \
- "movq 0(%%esi), %%mm1 \n" \
- "movq 0(%%edi), %%mm2 \n" \
- "pmulhw %%mm2, %%mm1 \n" \
- "movq %%mm1, 0(%%esi) \n" \
- "addl $8, %%edi \n" \
- "addl $8, %%esi \n" \
- "decl %%ecx \n" \
- "cmpl $0, %%ecx \n" \
- "jg 1b \n" \
- "emms \n" \
- : : "g"(len), "g"(buf1), "g"(buf2)
- : "ecx", "edi", "esi", "memory"
-#ifdef __MMX__
- , "mm1", "mm2"
-#endif
- );
-}
-
-static inline void atti386_partialProductOutput(int quadlen, Bit16s leftvol, Bit16s rightvol, Bit16s *partialBuf, Bit16s *p1buf) {
- __asm__ __volatile__(
- "movl %0, %%ecx \n" \
- "movw %1, %%ax \n" \
- "shll $16, %%eax \n" \
- "movw %2, %%ax \n" \
- "movd %%eax, %%mm1 \n" \
- "movd %%eax, %%mm2 \n" \
- "psllq $32, %%mm1 \n" \
- "por %%mm2, %%mm1 \n" \
- "movl %3, %%edi \n" \
- "movl %4, %%esi \n" \
- "pushl %%ebx \n" \
- "1: \n" \
- "movw 0(%%esi), %%bx \n" \
- "addl $2, %%esi \n" \
- "movw 0(%%esi), %%dx \n" \
- "addl $2, %%esi \n" \
- "" \
- "movw %%dx, %%ax \n" \
- "shll $16, %%eax \n" \
- "movw %%dx, %%ax \n" \
- "movd %%eax, %%mm2 \n" \
- "psllq $32, %%mm2 \n" \
- "movw %%bx, %%ax \n" \
- "shll $16, %%eax \n" \
- "movw %%bx, %%ax \n" \
- "movd %%eax, %%mm3 \n" \
- "por %%mm3, %%mm2 \n" \
- "" \
- "pmulhw %%mm1, %%mm2 \n" \
- "movq %%mm2, 0(%%edi) \n" \
- "addl $8, %%edi \n" \
- "" \
- "decl %%ecx \n" \
- "cmpl $0, %%ecx \n" \
- "jg 1b \n" \
- "emms \n" \
- "popl %%ebx \n" \
- : : "g"(quadlen), "g"(leftvol), "g"(rightvol), "g"(partialBuf), "g"(p1buf)
- : "eax", "ecx", "edx", "edi", "esi", "memory"
-#ifdef __MMX__
- , "mm1", "mm2", "mm3"
-#endif
- );
-}
-
-#endif
-
-bool DetectSIMD() {
-#ifdef _MSC_VER
- bool found_simd;
- __asm {
- pushfd
- pop eax // get EFLAGS into eax
- mov ebx,eax // keep a copy
- xor eax,0x200000
- // toggle CPUID bit
-
- push eax
- popfd // set new EFLAGS
- pushfd
- pop eax // EFLAGS back into eax
-
- xor eax,ebx
- // have we changed the ID bit?
-
- je NO_SIMD
- // No, no CPUID instruction
-
- // we could toggle the
- // ID bit so CPUID is present
- mov eax,1
-
- cpuid // get processor features
- test edx,1<<25 // check the SIMD bit
- jz NO_SIMD
- mov found_simd,1
- jmp DONE
- NO_SIMD:
- mov found_simd,0
- DONE:
- }
- return found_simd;
-#else
- return atti386_DetectSIMD();
-#endif
-}
-
-bool Detect3DNow() {
-#ifdef _MSC_VER
- bool found3D = false;
- __asm {
- pushfd
- pop eax
- mov edx, eax
- xor eax, 00200000h
- push eax
- popfd
- pushfd
- pop eax
- xor eax, edx
- jz NO_3DNOW
-
- mov eax, 80000000h
- cpuid
-
- cmp eax, 80000000h
- jbe NO_3DNOW
-
- mov eax, 80000001h
- cpuid
- test edx, 80000000h
- jz NO_3DNOW
- mov found3D, 1
-NO_3DNOW:
-
- }
- return found3D;
-#else
- return atti386_Detect3DNow();
-#endif
-}
-
-float iir_filter_sse(float input,float *hist1_ptr, float *coef_ptr) {
- float output;
-
- // 1st number of coefficients array is overall input scale factor, or filter gain
- output = input * (*coef_ptr++);
-
-#ifdef _MSC_VER
- __asm {
-
- movss xmm1, output
-
- mov eax, coef_ptr
- movups xmm2, [eax]
-
- mov eax, hist1_ptr
- movlps xmm3, [eax]
- shufps xmm3, xmm3, 44h
- // hist1_ptr+1, hist1_ptr, hist1_ptr+1, hist1_ptr
-
- mulps xmm2, xmm3
-
- subss xmm1, xmm2
- // Rotate elements right
- shufps xmm2, xmm2, 39h
- subss xmm1, xmm2
-
- // Store new_hist
- movss DWORD PTR [eax], xmm1
-
- // Rotate elements right
- shufps xmm2, xmm2, 39h
- addss xmm1, xmm2
-
- // Rotate elements right
- shufps xmm2, xmm2, 39h
- addss xmm1, xmm2
-
- // Store previous hist
- movss DWORD PTR [eax+4], xmm3
-
- add coef_ptr, 16
- add hist1_ptr, 8
-
- mov eax, coef_ptr
- movups xmm2, [eax]
-
- mov eax, hist1_ptr
- movlps xmm3, [eax]
- shufps xmm3, xmm3, 44h
- // hist1_ptr+1, hist1_ptr, hist1_ptr+1, hist1_ptr
-
- mulps xmm2, xmm3
-
- subss xmm1, xmm2
- // Rotate elements right
- shufps xmm2, xmm2, 39h
- subss xmm1, xmm2
-
- // Store new_hist
- movss DWORD PTR [eax], xmm1
-
- // Rotate elements right
- shufps xmm2, xmm2, 39h
- addss xmm1, xmm2
-
- // Rotate elements right
- shufps xmm2, xmm2, 39h
- addss xmm1, xmm2
-
- // Store previous hist
- movss DWORD PTR [eax+4], xmm3
-
- movss output, xmm1
- }
-#else
- output = atti386_iir_filter_sse(&output, hist1_ptr, coef_ptr);
-#endif
- return output;
-}
-
-float iir_filter_3dnow(float input,float *hist1_ptr, float *coef_ptr) {
- float output;
-
- // 1st number of coefficients array is overall input scale factor, or filter gain
- output = input * (*coef_ptr++);
-
- // I find it very sad that 3DNow requires twice as many instructions as Intel's SSE
- // Intel does have the upper hand here.
-#ifdef _MSC_VER
- float tmp;
- __asm {
- movq mm1, output
- mov ebx, coef_ptr
- movq mm2, [ebx]
-
- mov eax, hist1_ptr;
- movq mm3, [eax]
-
- pfmul mm2, mm3
- pfsub mm1, mm2
-
- psrlq mm2, 32
- pfsub mm1, mm2
-
- // Store new hist
- movd tmp, mm1
-
- add ebx, 8
- movq mm2, [ebx]
- movq mm3, [eax]
-
- pfmul mm2, mm3
- pfadd mm1, mm2
-
- psrlq mm2, 32
- pfadd mm1, mm2
-
- push tmp
- pop DWORD PTR [eax]
-
- movd DWORD PTR [eax+4], mm3
-
- add ebx, 8
- add eax, 8
-
- movq mm2, [ebx]
- movq mm3, [eax]
-
- pfmul mm2, mm3
- pfsub mm1, mm2
-
- psrlq mm2, 32
- pfsub mm1, mm2
-
- // Store new hist
- movd tmp, mm1
-
- add ebx, 8
- movq mm2, [ebx]
- movq mm3, [eax]
-
- pfmul mm2, mm3
- pfadd mm1, mm2
-
- psrlq mm2, 32
- pfadd mm1, mm2
-
- push tmp
- pop DWORD PTR [eax]
- movd DWORD PTR [eax+4], mm3
-
- movd output, mm1
-
- femms
- }
-#else
- output = atti386_iir_filter_3DNow(output, hist1_ptr, coef_ptr);
-#endif
- return output;
-}
-
-#if MT32EMU_USE_MMX > 0
-
-int i386_partialProductOutput(int len, Bit16s leftvol, Bit16s rightvol, Bit16s *partialBuf, Bit16s *mixedBuf) {
- int tmplen = len >> 1;
- if (tmplen == 0) {
- return 0;
- }
-#ifdef _MSC_VER
- __asm {
- mov ecx,tmplen
- mov ax, leftvol
- shl eax,16
- mov ax, rightvol
- movd mm1, eax
- movd mm2, eax
- psllq mm1, 32
- por mm1, mm2
- mov edi, partialBuf
- mov esi, mixedBuf
-mmxloop1:
- mov bx, [esi]
- add esi,2
- mov dx, [esi]
- add esi,2
-
- mov ax, dx
- shl eax, 16
- mov ax, dx
- movd mm2,eax
- psllq mm2, 32
- mov ax, bx
- shl eax, 16
- mov ax, bx
- movd mm3,eax
- por mm2,mm3
-
- pmulhw mm2, mm1
- movq [edi], mm2
- add edi, 8
-
- dec ecx
- cmp ecx,0
- jg mmxloop1
- emms
- }
-#else
- atti386_partialProductOutput(tmplen, leftvol, rightvol, partialBuf, mixedBuf);
-#endif
- return tmplen << 1;
-}
-
-int i386_mixBuffers(Bit16s * buf1, Bit16s *buf2, int len) {
- int tmplen = len >> 2;
- if (tmplen == 0) {
- return 0;
- }
-#ifdef _MSC_VER
- __asm {
- mov ecx, tmplen
- mov esi, buf1
- mov edi, buf2
-
-mixloop1:
- movq mm1, [edi]
- movq mm2, [esi]
- paddw mm1,mm2
- movq [esi],mm1
- add edi,8
- add esi,8
-
- dec ecx
- cmp ecx,0
- jg mixloop1
- emms
- }
-#else
- atti386_mixBuffers(buf1, buf2, tmplen);
-#endif
- return tmplen << 2;
-}
-
-
-int i386_mixBuffersRingMix(Bit16s * buf1, Bit16s *buf2, int len) {
- int tmplen = len >> 2;
- if (tmplen == 0) {
- return 0;
- }
-#ifdef _MSC_VER
- __asm {
- mov ecx, tmplen
- mov esi, buf1
- mov edi, buf2
-
-mixloop2:
- movq mm1, [esi]
- movq mm2, [edi]
- movq mm3, mm1
- pmulhw mm1, mm2
- paddw mm1,mm3
- movq [esi],mm1
- add edi,8
- add esi,8
-
- dec ecx
- cmp ecx,0
- jg mixloop2
- emms
- }
-#else
- atti386_mixBuffersRingMix(buf1, buf2, tmplen);
-#endif
- return tmplen << 2;
-}
-
-int i386_mixBuffersRing(Bit16s * buf1, Bit16s *buf2, int len) {
- int tmplen = len >> 2;
- if (tmplen == 0) {
- return 0;
- }
-#ifdef _MSC_VER
- __asm {
- mov ecx, tmplen
- mov esi, buf1
- mov edi, buf2
-
-mixloop3:
- movq mm1, [esi]
- movq mm2, [edi]
- pmulhw mm1, mm2
- movq [esi],mm1
- add edi,8
- add esi,8
-
- dec ecx
- cmp ecx,0
- jg mixloop3
- emms
- }
-#else
- atti386_mixBuffersRing(buf1, buf2, tmplen);
-#endif
- return tmplen << 2;
-}
-
-int i386_produceOutput1(Bit16s *useBuf, Bit16s *stream, Bit32u len, Bit16s volume) {
- int tmplen = (len >> 1);
- if (tmplen == 0) {
- return 0;
- }
-#ifdef _MSC_VER
- __asm {
- mov ecx, tmplen
- mov ax,volume
- shl eax,16
- mov ax,volume
- movd mm3,eax
- movd mm2,eax
- psllq mm3, 32
- por mm3,mm2
- mov esi, useBuf
- mov edi, stream
-mixloop4:
- movq mm1, [esi]
- movq mm2, [edi]
- pmulhw mm1, mm3
- paddw mm1,mm2
- movq [edi], mm1
-
- add esi,8
- add edi,8
-
- dec ecx
- cmp ecx,0
- jg mixloop4
- emms
- }
-#else
- atti386_produceOutput1(tmplen, volume, useBuf, stream);
-#endif
- return tmplen << 1;
-}
-
-#endif
-
-}
-
-#endif
diff --git a/sound/softsynth/mt32/i386.h b/sound/softsynth/mt32/i386.h
deleted file mode 100644
index e8644411cd..0000000000
--- a/sound/softsynth/mt32/i386.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/* Copyright (c) 2003-2005 Various contributors
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- * IN THE SOFTWARE.
- */
-
-#ifndef MT32EMU_I386_H
-#define MT32EMU_I386_H
-
-namespace MT32Emu {
-#ifdef MT32EMU_HAVE_X86
-
-// Function that detects the availablity of SSE SIMD instructions
-bool DetectSIMD();
-// Function that detects the availablity of 3DNow instructions
-bool Detect3DNow();
-
-float iir_filter_sse(float input,float *hist1_ptr, float *coef_ptr);
-float iir_filter_3dnow(float input,float *hist1_ptr, float *coef_ptr);
-float iir_filter_normal(float input,float *hist1_ptr, float *coef_ptr);
-
-#if MT32EMU_USE_MMX > 0
-int i386_partialProductOutput(int len, Bit16s leftvol, Bit16s rightvol, Bit16s *partialBuf, Bit16s *mixedBuf);
-int i386_mixBuffers(Bit16s * buf1, Bit16s *buf2, int len);
-int i386_mixBuffersRingMix(Bit16s * buf1, Bit16s *buf2, int len);
-int i386_mixBuffersRing(Bit16s * buf1, Bit16s *buf2, int len);
-int i386_produceOutput1(Bit16s *useBuf, Bit16s *stream, Bit32u len, Bit16s volume);
-#endif
-
-#endif
-
-}
-
-#endif
diff --git a/sound/softsynth/mt32/module.mk b/sound/softsynth/mt32/module.mk
deleted file mode 100644
index 4d5d899ac3..0000000000
--- a/sound/softsynth/mt32/module.mk
+++ /dev/null
@@ -1,14 +0,0 @@
-MODULE := sound/softsynth/mt32
-
-MODULE_OBJS := \
- mt32_file.o \
- i386.o \
- part.o \
- partial.o \
- partialManager.o \
- synth.o \
- tables.o \
- freeverb.o
-
-# Include common rules
-include $(srcdir)/rules.mk
diff --git a/sound/softsynth/mt32/mt32_file.cpp b/sound/softsynth/mt32/mt32_file.cpp
deleted file mode 100644
index cdf9fa13f6..0000000000
--- a/sound/softsynth/mt32/mt32_file.cpp
+++ /dev/null
@@ -1,70 +0,0 @@
-/* Copyright (c) 2003-2005 Various contributors
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- * IN THE SOFTWARE.
- */
-
-
-#include "mt32emu.h"
-
-namespace MT32Emu {
-
-bool File::readBit16u(Bit16u *in) {
- Bit8u b[2];
- if (read(&b[0], 2) != 2)
- return false;
- *in = ((b[0] << 8) | b[1]);
- return true;
-}
-
-bool File::readBit32u(Bit32u *in) {
- Bit8u b[4];
- if (read(&b[0], 4) != 4)
- return false;
- *in = ((b[0] << 24) | (b[1] << 16) | (b[2] << 8) | b[3]);
- return true;
-}
-
-bool File::writeBit16u(Bit16u out) {
- if (!writeBit8u((Bit8u)((out & 0xFF00) >> 8))) {
- return false;
- }
- if (!writeBit8u((Bit8u)(out & 0x00FF))) {
- return false;
- }
- return true;
-}
-
-bool File::writeBit32u(Bit32u out) {
- if (!writeBit8u((Bit8u)((out & 0xFF000000) >> 24))) {
- return false;
- }
- if (!writeBit8u((Bit8u)((out & 0x00FF0000) >> 16))) {
- return false;
- }
- if (!writeBit8u((Bit8u)((out & 0x0000FF00) >> 8))) {
- return false;
- }
- if (!writeBit8u((Bit8u)(out & 0x000000FF))) {
- return false;
- }
- return true;
-}
-
-} // End of namespace MT32Emu
-
diff --git a/sound/softsynth/mt32/mt32_file.h b/sound/softsynth/mt32/mt32_file.h
deleted file mode 100644
index e6641660ee..0000000000
--- a/sound/softsynth/mt32/mt32_file.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/* Copyright (c) 2003-2005 Various contributors
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- * IN THE SOFTWARE.
- */
-
-#ifndef MT32EMU_FILE_H
-#define MT32EMU_FILE_H
-
-#include "common/scummsys.h"
-
-namespace MT32Emu {
-
-class File {
-public:
- enum OpenMode {
- OpenMode_read = 0,
- OpenMode_write = 1
- };
- virtual ~File() {}
- virtual void close() = 0;
- virtual size_t read(void *in, size_t size) = 0;
- virtual bool readBit8u(Bit8u *in) = 0;
- virtual bool readBit16u(Bit16u *in);
- virtual bool readBit32u(Bit32u *in);
- virtual size_t write(const void *out, size_t size) = 0;
- virtual bool writeBit8u(Bit8u out) = 0;
- // Note: May write a single byte to the file before failing
- virtual bool writeBit16u(Bit16u out);
- // Note: May write some (<4) bytes to the file before failing
- virtual bool writeBit32u(Bit32u out);
- virtual bool isEOF() = 0;
-};
-
-} // End of namespace MT32Emu
-
-#endif
diff --git a/sound/softsynth/mt32/mt32emu.h b/sound/softsynth/mt32/mt32emu.h
deleted file mode 100644
index 6eedf04bc0..0000000000
--- a/sound/softsynth/mt32/mt32emu.h
+++ /dev/null
@@ -1,70 +0,0 @@
-/* Copyright (c) 2003-2005 Various contributors
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- * IN THE SOFTWARE.
- */
-
-#ifndef MT32EMU_MT32EMU_H
-#define MT32EMU_MT32EMU_H
-
-// Debugging
-// Show the instruments played
-#define MT32EMU_MONITOR_INSTRUMENTS 1
-// Shows number of partials MT-32 is playing, and on which parts
-#define MT32EMU_MONITOR_PARTIALS 0
-// Determines how the waveform cache file is handled (must be regenerated after sampling rate change)
-#define MT32EMU_WAVECACHEMODE 0 // Load existing cache if possible, otherwise generate and save cache
-//#define MT32EMU_WAVECACHEMODE 1 // Load existing cache if possible, otherwise generate but don't save cache
-//#define MT32EMU_WAVECACHEMODE 2 // Ignore existing cache, generate and save cache
-//#define MT32EMU_WAVECACHEMODE 3 // Ignore existing cache, generate but don't save cache
-
-// Configuration
-// The maximum number of partials playing simultaneously
-#define MT32EMU_MAX_PARTIALS 32
-// The maximum number of notes playing simultaneously per part.
-// No point making it more than MT32EMU_MAX_PARTIALS, since each note needs at least one partial.
-#define MT32EMU_MAX_POLY 32
-// This calculates the exact frequencies of notes as they are played, instead of offsetting from pre-cached semitones. Potentially very slow.
-#define MT32EMU_ACCURATENOTES 0
-
-#if (defined (_MSC_VER) && defined(_M_IX86))
-#define MT32EMU_HAVE_X86
-#elif defined(__GNUC__)
-#if __GNUC__ >= 3 && defined(__i386__)
-#define MT32EMU_HAVE_X86
-#endif
-#endif
-
-#ifdef MT32EMU_HAVE_X86
-#define MT32EMU_USE_MMX 1
-#else
-#define MT32EMU_USE_MMX 0
-#endif
-
-#include "freeverb.h"
-
-#include "structures.h"
-#include "i386.h"
-#include "mt32_file.h"
-#include "tables.h"
-#include "partial.h"
-#include "partialManager.h"
-#include "part.h"
-#include "synth.h"
-
-#endif
diff --git a/sound/softsynth/mt32/part.cpp b/sound/softsynth/mt32/part.cpp
deleted file mode 100644
index eb087f7ea0..0000000000
--- a/sound/softsynth/mt32/part.cpp
+++ /dev/null
@@ -1,633 +0,0 @@
-/* Copyright (c) 2003-2005 Various contributors
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- * IN THE SOFTWARE.
- */
-
-#include <string.h>
-#include <math.h>
-
-#include "mt32emu.h"
-
-namespace MT32Emu {
-
-static const Bit8u PartialStruct[13] = {
- 0, 0, 2, 2, 1, 3,
- 3, 0, 3, 0, 2, 1, 3 };
-
-static const Bit8u PartialMixStruct[13] = {
- 0, 1, 0, 1, 1, 0,
- 1, 3, 3, 2, 2, 2, 2 };
-
-static const float floatKeyfollow[17] = {
- -1.0f, -1.0f/2.0f, -1.0f/4.0f, 0.0f,
- 1.0f/8.0f, 1.0f/4.0f, 3.0f/8.0f, 1.0f/2.0f, 5.0f/8.0f, 3.0f/4.0f, 7.0f/8.0f, 1.0f,
- 5.0f/4.0f, 3.0f/2.0f, 2.0f,
- 1.0009765625f, 1.0048828125f
-};
-
-//FIXME:KG: Put this dpoly stuff somewhere better
-bool dpoly::isActive() const {
- return partials[0] != NULL || partials[1] != NULL || partials[2] != NULL || partials[3] != NULL;
-}
-
-Bit32u dpoly::getAge() const {
- for (int i = 0; i < 4; i++) {
- if (partials[i] != NULL) {
- return partials[i]->age;
- }
- }
- return 0;
-}
-
-RhythmPart::RhythmPart(Synth *useSynth, unsigned int usePartNum): Part(useSynth, usePartNum) {
- strcpy(name, "Rhythm");
- rhythmTemp = &synth->mt32ram.rhythmSettings[0];
- refresh();
-}
-
-Part::Part(Synth *useSynth, unsigned int usePartNum) {
- this->synth = useSynth;
- this->partNum = usePartNum;
- patchCache[0].dirty = true;
- holdpedal = false;
- patchTemp = &synth->mt32ram.patchSettings[partNum];
- if (usePartNum == 8) {
- // Nasty hack for rhythm
- timbreTemp = NULL;
- } else {
- sprintf(name, "Part %d", partNum + 1);
- timbreTemp = &synth->mt32ram.timbreSettings[partNum];
- }
- currentInstr[0] = 0;
- currentInstr[10] = 0;
- expression = 127;
- volumeMult = 0;
- volumesetting.leftvol = 32767;
- volumesetting.rightvol = 32767;
- bend = 0.0f;
- memset(polyTable,0,sizeof(polyTable));
- memset(patchCache, 0, sizeof(patchCache));
-}
-
-void Part::setHoldPedal(bool pedalval) {
- if (holdpedal && !pedalval) {
- holdpedal = false;
- stopPedalHold();
- } else {
- holdpedal = pedalval;
- }
-}
-
-void RhythmPart::setBend(unsigned int midiBend) {
- synth->printDebug("%s: Setting bend (%d) not supported on rhythm", name, midiBend);
- return;
-}
-
-void Part::setBend(unsigned int midiBend) {
- // FIXME:KG: Slightly unbalanced increments, but I wanted min -1.0, centre 0.0 and max 1.0
- if (midiBend <= 0x2000) {
- bend = ((signed int)midiBend - 0x2000) / (float)0x2000;
- } else {
- bend = ((signed int)midiBend - 0x2000) / (float)0x1FFF;
- }
- // Loop through all partials to update their bend
- for (int i = 0; i < MT32EMU_MAX_POLY; i++) {
- for (int j = 0; j < 4; j++) {
- if (polyTable[i].partials[j] != NULL) {
- polyTable[i].partials[j]->setBend(bend);
- }
- }
- }
-}
-
-void RhythmPart::setModulation(unsigned int midiModulation) {
- synth->printDebug("%s: Setting modulation (%d) not supported on rhythm", name, midiModulation);
-}
-
-void Part::setModulation(unsigned int midiModulation) {
- // Just a bloody guess, as always, before I get things figured out
- for (int t = 0; t < 4; t++) {
- if (patchCache[t].playPartial) {
- int newrate = (patchCache[t].modsense * midiModulation) >> 7;
- //patchCache[t].lfoperiod = lfotable[newrate];
- patchCache[t].lfodepth = newrate;
- //FIXME:KG: timbreTemp->partial[t].lfo.depth =
- }
- }
-}
-
-void RhythmPart::refresh() {
- updateVolume();
- // (Re-)cache all the mapped timbres ahead of time
- for (unsigned int drumNum = 0; drumNum < synth->controlROMMap->rhythmSettingsCount; drumNum++) {
- int drumTimbreNum = rhythmTemp[drumNum].timbre;
- if (drumTimbreNum >= 127) // 94 on MT-32
- continue;
- Bit16s pan = rhythmTemp[drumNum].panpot; // They use R-L 0-14...
- // FIXME:KG: Panning cache should be backed up to partials using it, too
- if (pan < 7) {
- drumPan[drumNum].leftvol = pan * 4681;
- drumPan[drumNum].rightvol = 32767;
- } else {
- drumPan[drumNum].rightvol = (14 - pan) * 4681;
- drumPan[drumNum].leftvol = 32767;
- }
- PatchCache *cache = drumCache[drumNum];
- backupCacheToPartials(cache);
- for (int t = 0; t < 4; t++) {
- // Common parameters, stored redundantly
- cache[t].dirty = true;
- cache[t].pitchShift = 0.0f;
- cache[t].benderRange = 0.0f;
- cache[t].pansetptr = &drumPan[drumNum];
- cache[t].reverb = rhythmTemp[drumNum].reverbSwitch > 0;
- }
- }
-}
-
-void Part::refresh() {
- updateVolume();
- backupCacheToPartials(patchCache);
- for (int t = 0; t < 4; t++) {
- // Common parameters, stored redundantly
- patchCache[t].dirty = true;
- patchCache[t].pitchShift = (patchTemp->patch.keyShift - 24) + (patchTemp->patch.fineTune - 50) / 100.0f;
- patchCache[t].benderRange = patchTemp->patch.benderRange;
- patchCache[t].pansetptr = &volumesetting;
- patchCache[t].reverb = patchTemp->patch.reverbSwitch > 0;
- }
- memcpy(currentInstr, timbreTemp->common.name, 10);
-}
-
-const char *Part::getCurrentInstr() const {
- return &currentInstr[0];
-}
-
-void RhythmPart::refreshTimbre(unsigned int absTimbreNum) {
- for (int m = 0; m < 85; m++) {
- if (rhythmTemp[m].timbre == absTimbreNum - 128)
- drumCache[m][0].dirty = true;
- }
-}
-
-void Part::refreshTimbre(unsigned int absTimbreNum) {
- if (getAbsTimbreNum() == absTimbreNum) {
- memcpy(currentInstr, timbreTemp->common.name, 10);
- patchCache[0].dirty = true;
- }
-}
-
-int Part::fixBiaslevel(int srcpnt, int *dir) {
- int noteat = srcpnt & 0x3F;
- int outnote;
- if (srcpnt < 64)
- *dir = 0;
- else
- *dir = 1;
- outnote = 33 + noteat;
- //synth->printDebug("Bias note %d, dir %d", outnote, *dir);
-
- return outnote;
-}
-
-int Part::fixKeyfollow(int srckey) {
- if (srckey>=0 && srckey<=16) {
- int keyfix[17] = { -256*16, -128*16, -64*16, 0, 32*16, 64*16, 96*16, 128*16, (128+32)*16, 192*16, (192+32)*16, 256*16, (256+64)*16, (256+128)*16, (512)*16, 4100, 4116};
- return keyfix[srckey];
- } else {
- //LOG(LOG_ERROR|LOG_MISC,"Missed key: %d", srckey);
- return 256;
- }
-}
-
-void Part::abortPoly(dpoly *poly) {
- if (!poly->isPlaying) {
- return;
- }
- for (int i = 0; i < 4; i++) {
- Partial *partial = poly->partials[i];
- if (partial != NULL) {
- partial->deactivate();
- }
- }
- poly->isPlaying = false;
-}
-
-void Part::setPatch(const PatchParam *patch) {
- patchTemp->patch = *patch;
-}
-
-void RhythmPart::setTimbre(TimbreParam * /*timbre*/) {
- synth->printDebug("%s: Attempted to call setTimbre() - doesn't make sense for rhythm", name);
-}
-
-void Part::setTimbre(TimbreParam *timbre) {
- *timbreTemp = *timbre;
-}
-
-unsigned int RhythmPart::getAbsTimbreNum() const {
- synth->printDebug("%s: Attempted to call getAbsTimbreNum() - doesn't make sense for rhythm", name);
- return 0;
-}
-
-unsigned int Part::getAbsTimbreNum() const {
- return (patchTemp->patch.timbreGroup * 64) + patchTemp->patch.timbreNum;
-}
-
-void RhythmPart::setProgram(unsigned int patchNum) {
- synth->printDebug("%s: Attempt to set program (%d) on rhythm is invalid", name, patchNum);
-}
-
-void Part::setProgram(unsigned int patchNum) {
- setPatch(&synth->mt32ram.patches[patchNum]);
- setTimbre(&synth->mt32ram.timbres[getAbsTimbreNum()].timbre);
-
- refresh();
-
- allSoundOff(); //FIXME:KG: Is this correct?
-}
-
-void Part::backupCacheToPartials(PatchCache cache[4]) {
- // check if any partials are still playing with the old patch cache
- // if so then duplicate the cached data from the part to the partial so that
- // we can change the part's cache without affecting the partial.
- // We delay this until now to avoid a copy operation with every note played
- for (int m = 0; m < MT32EMU_MAX_POLY; m++) {
- for (int i = 0; i < 4; i++) {
- Partial *partial = polyTable[m].partials[i];
- if (partial != NULL && partial->patchCache == &cache[i]) {
- partial->cachebackup = cache[i];
- partial->patchCache = &partial->cachebackup;
- }
- }
- }
-}
-
-void Part::cacheTimbre(PatchCache cache[4], const TimbreParam *timbre) {
- backupCacheToPartials(cache);
- int partialCount = 0;
- for (int t = 0; t < 4; t++) {
- cache[t].PCMPartial = false;
- if (((timbre->common.pmute >> t) & 0x1) == 1) {
- cache[t].playPartial = true;
- partialCount++;
- } else {
- cache[t].playPartial = false;
- continue;
- }
-
- // Calculate and cache common parameters
-
- cache[t].pcm = timbre->partial[t].wg.pcmwave;
- cache[t].useBender = (timbre->partial[t].wg.bender == 1);
-
- switch (t) {
- case 0:
- cache[t].PCMPartial = (PartialStruct[(int)timbre->common.pstruct12] & 0x2) ? true : false;
- cache[t].structureMix = PartialMixStruct[(int)timbre->common.pstruct12];
- cache[t].structurePosition = 0;
- cache[t].structurePair = 1;
- break;
- case 1:
- cache[t].PCMPartial = (PartialStruct[(int)timbre->common.pstruct12] & 0x1) ? true : false;
- cache[t].structureMix = PartialMixStruct[(int)timbre->common.pstruct12];
- cache[t].structurePosition = 1;
- cache[t].structurePair = 0;
- break;
- case 2:
- cache[t].PCMPartial = (PartialStruct[(int)timbre->common.pstruct34] & 0x2) ? true : false;
- cache[t].structureMix = PartialMixStruct[(int)timbre->common.pstruct34];
- cache[t].structurePosition = 0;
- cache[t].structurePair = 3;
- break;
- case 3:
- cache[t].PCMPartial = (PartialStruct[(int)timbre->common.pstruct34] & 0x1) ? true : false;
- cache[t].structureMix = PartialMixStruct[(int)timbre->common.pstruct34];
- cache[t].structurePosition = 1;
- cache[t].structurePair = 2;
- break;
- default:
- break;
- }
-
- cache[t].waveform = timbre->partial[t].wg.waveform;
- cache[t].pulsewidth = timbre->partial[t].wg.pulsewid;
- cache[t].pwsens = timbre->partial[t].wg.pwvelo;
- if (timbre->partial[t].wg.keyfollow > 16) {
- synth->printDebug("Bad keyfollow value in timbre!");
- cache[t].pitchKeyfollow = 1.0f;
- } else {
- cache[t].pitchKeyfollow = floatKeyfollow[timbre->partial[t].wg.keyfollow];
- }
-
- cache[t].pitch = timbre->partial[t].wg.coarse + (timbre->partial[t].wg.fine - 50) / 100.0f + 24.0f;
- cache[t].pitchEnv = timbre->partial[t].env;
- cache[t].pitchEnv.sensitivity = (char)((float)cache[t].pitchEnv.sensitivity * 1.27f);
- cache[t].pitchsustain = cache[t].pitchEnv.level[3];
-
- // Calculate and cache TVA envelope stuff
- cache[t].ampEnv = timbre->partial[t].tva;
- cache[t].ampEnv.level = (char)((float)cache[t].ampEnv.level * 1.27f);
-
- cache[t].ampbias[0] = fixBiaslevel(cache[t].ampEnv.biaspoint1, &cache[t].ampdir[0]);
- cache[t].ampblevel[0] = 12 - cache[t].ampEnv.biaslevel1;
- cache[t].ampbias[1] = fixBiaslevel(cache[t].ampEnv.biaspoint2, &cache[t].ampdir[1]);
- cache[t].ampblevel[1] = 12 - cache[t].ampEnv.biaslevel2;
- cache[t].ampdepth = cache[t].ampEnv.envvkf * cache[t].ampEnv.envvkf;
-
- // Calculate and cache filter stuff
- cache[t].filtEnv = timbre->partial[t].tvf;
- cache[t].filtkeyfollow = fixKeyfollow(cache[t].filtEnv.keyfollow);
- cache[t].filtEnv.envdepth = (char)((float)cache[t].filtEnv.envdepth * 1.27);
- cache[t].tvfbias = fixBiaslevel(cache[t].filtEnv.biaspoint, &cache[t].tvfdir);
- cache[t].tvfblevel = cache[t].filtEnv.biaslevel;
- cache[t].filtsustain = cache[t].filtEnv.envlevel[3];
-
- // Calculate and cache LFO stuff
- cache[t].lfodepth = timbre->partial[t].lfo.depth;
- cache[t].lfoperiod = synth->tables.lfoPeriod[(int)timbre->partial[t].lfo.rate];
- cache[t].lforate = timbre->partial[t].lfo.rate;
- cache[t].modsense = timbre->partial[t].lfo.modsense;
- }
- for (int t = 0; t < 4; t++) {
- // Common parameters, stored redundantly
- cache[t].dirty = false;
- cache[t].partialCount = partialCount;
- cache[t].sustain = (timbre->common.nosustain == 0);
- }
- //synth->printDebug("Res 1: %d 2: %d 3: %d 4: %d", cache[0].waveform, cache[1].waveform, cache[2].waveform, cache[3].waveform);
-
-#if MT32EMU_MONITOR_INSTRUMENTS == 1
- synth->printDebug("%s (%s): Recached timbre", name, currentInstr);
- for (int i = 0; i < 4; i++) {
- synth->printDebug(" %d: play=%s, pcm=%s (%d), wave=%d", i, cache[i].playPartial ? "YES" : "NO", cache[i].PCMPartial ? "YES" : "NO", timbre->partial[i].wg.pcmwave, timbre->partial[i].wg.waveform);
- }
-#endif
-}
-
-const char *Part::getName() const {
- return name;
-}
-
-void Part::updateVolume() {
- volumeMult = synth->tables.volumeMult[patchTemp->outlevel * expression / 127];
-}
-
-int Part::getVolume() const {
- // FIXME: Use the mappings for this in the control ROM
- return patchTemp->outlevel * 127 / 100;
-}
-
-void Part::setVolume(int midiVolume) {
- // FIXME: Use the mappings for this in the control ROM
- patchTemp->outlevel = (Bit8u)(midiVolume * 100 / 127);
- updateVolume();
- synth->printDebug("%s (%s): Set volume to %d", name, currentInstr, midiVolume);
-}
-
-void Part::setExpression(int midiExpression) {
- expression = midiExpression;
- updateVolume();
-}
-
-void RhythmPart::setPan(unsigned int midiPan)
-{
- // FIXME:KG: This is unchangeable for drums (they always use drumPan), is that correct?
- synth->printDebug("%s: Setting pan (%d) not supported on rhythm", name, midiPan);
-}
-
-void Part::setPan(unsigned int midiPan) {
- // FIXME:KG: Tweaked this a bit so that we have a left 100%, centre and right 100%
- // (But this makes the range somewhat skewed)
- // Check against the real thing
- // NOTE: Panning is inverted compared to GM.
- if (midiPan < 64) {
- volumesetting.leftvol = (Bit16s)(midiPan * 512);
- volumesetting.rightvol = 32767;
- } else if (midiPan == 64) {
- volumesetting.leftvol = 32767;
- volumesetting.rightvol = 32767;
- } else {
- volumesetting.rightvol = (Bit16s)((127 - midiPan) * 520);
- volumesetting.leftvol = 32767;
- }
- patchTemp->panpot = (Bit8u)(midiPan * 14 / 127);
- //synth->printDebug("%s (%s): Set pan to %d", name, currentInstr, panpot);
-}
-
-void RhythmPart::playNote(unsigned int key, int vel) {
- if (key < 24 || key > 108)/*> 87 on MT-32)*/ {
- synth->printDebug("%s: Attempted to play invalid key %d", name, key);
- return;
- }
- int drumNum = key - 24;
- int drumTimbreNum = rhythmTemp[drumNum].timbre;
- if (drumTimbreNum >= 127) { // 94 on MT-32
- synth->printDebug("%s: Attempted to play unmapped key %d", name, key);
- return;
- }
- int absTimbreNum = drumTimbreNum + 128;
- TimbreParam *timbre = &synth->mt32ram.timbres[absTimbreNum].timbre;
- memcpy(currentInstr, timbre->common.name, 10);
-#if MT32EMU_MONITOR_INSTRUMENTS == 1
- synth->printDebug("%s (%s): starting poly (drum %d, timbre %d) - Vel %d Key %d", name, currentInstr, drumNum, absTimbreNum, vel, key);
-#endif
- if (drumCache[drumNum][0].dirty) {
- cacheTimbre(drumCache[drumNum], timbre);
- }
- playPoly(drumCache[drumNum], key, MIDDLEC, vel);
-}
-
-void Part::playNote(unsigned int key, int vel) {
- int freqNum = key;
- if (freqNum < 12) {
- synth->printDebug("%s (%s): Attempted to play invalid key %d < 12; moving up by octave", name, currentInstr, key);
- freqNum += 12;
- } else if (freqNum > 108) {
- synth->printDebug("%s (%s): Attempted to play invalid key %d > 108; moving down by octave", name, currentInstr, key);
- while (freqNum > 108) {
- freqNum -= 12;
- }
- }
- // POLY1 mode, Single Assign
- // Haven't found any software that uses any of the other poly modes
- // FIXME:KG: Should this also apply to rhythm?
- for (unsigned int i = 0; i < MT32EMU_MAX_POLY; i++) {
- if (polyTable[i].isActive() && (polyTable[i].key == key)) {
- //AbortPoly(&polyTable[i]);
- stopNote(key);
- break;
- }
- }
-#if MT32EMU_MONITOR_INSTRUMENTS == 1
- synth->printDebug("%s (%s): starting poly - Vel %d Key %d", name, currentInstr, vel, key);
-#endif
- if (patchCache[0].dirty) {
- cacheTimbre(patchCache, timbreTemp);
- }
- playPoly(patchCache, key, freqNum, vel);
-}
-
-void Part::playPoly(const PatchCache cache[4], unsigned int key, int freqNum, int vel) {
- unsigned int needPartials = cache[0].partialCount;
- unsigned int freePartials = synth->partialManager->getFreePartialCount();
-
- if (freePartials < needPartials) {
- if (!synth->partialManager->freePartials(needPartials - freePartials, partNum)) {
- synth->printDebug("%s (%s): Insufficient free partials to play key %d (vel=%d); needed=%d, free=%d", name, currentInstr, key, vel, needPartials, synth->partialManager->getFreePartialCount());
- return;
- }
- }
- // Find free poly
- int m;
- for (m = 0; m < MT32EMU_MAX_POLY; m++) {
- if (!polyTable[m].isActive()) {
- break;
- }
- }
- if (m == MT32EMU_MAX_POLY) {
- synth->printDebug("%s (%s): No free poly to play key %d (vel %d)", name, currentInstr, key, vel);
- return;
- }
-
- dpoly *tpoly = &polyTable[m];
-
- tpoly->isPlaying = true;
- tpoly->key = key;
- tpoly->isDecay = false;
- tpoly->freqnum = freqNum;
- tpoly->vel = vel;
- tpoly->pedalhold = false;
-
- bool allnull = true;
- for (int x = 0; x < 4; x++) {
- if (cache[x].playPartial) {
- tpoly->partials[x] = synth->partialManager->allocPartial(partNum);
- allnull = false;
- } else {
- tpoly->partials[x] = NULL;
- }
- }
-
- if (allnull)
- synth->printDebug("%s (%s): No partials to play for this instrument", name, this->currentInstr);
-
- tpoly->sustain = cache[0].sustain;
- tpoly->volumeptr = &volumeMult;
-
- for (int x = 0; x < 4; x++) {
- if (tpoly->partials[x] != NULL) {
- tpoly->partials[x]->startPartial(tpoly, &cache[x], tpoly->partials[cache[x].structurePair]);
- tpoly->partials[x]->setBend(bend);
- }
- }
-}
-
-static void startDecayPoly(dpoly *tpoly) {
- if (tpoly->isDecay) {
- return;
- }
- tpoly->isDecay = true;
-
- for (int t = 0; t < 4; t++) {
- Partial *partial = tpoly->partials[t];
- if (partial == NULL)
- continue;
- partial->startDecayAll();
- }
- tpoly->isPlaying = false;
-}
-
-void Part::allNotesOff() {
- // Note: Unchecked on real MT-32, but the MIDI specification states that all notes off (0x7B)
- // should treat the hold pedal as usual.
- // All *sound* off (0x78) should stop notes immediately regardless of the hold pedal.
- // The latter controller is not implemented on the MT-32 (according to the docs).
- for (int q = 0; q < MT32EMU_MAX_POLY; q++) {
- dpoly *tpoly = &polyTable[q];
- if (tpoly->isPlaying) {
- if (holdpedal)
- tpoly->pedalhold = true;
- else if (tpoly->sustain)
- startDecayPoly(tpoly);
- }
- }
-}
-
-void Part::allSoundOff() {
- for (int q = 0; q < MT32EMU_MAX_POLY; q++) {
- dpoly *tpoly = &polyTable[q];
- if (tpoly->isPlaying) {
- startDecayPoly(tpoly);
- }
- }
-}
-
-void Part::stopPedalHold() {
- for (int q = 0; q < MT32EMU_MAX_POLY; q++) {
- dpoly *tpoly;
- tpoly = &polyTable[q];
- if (tpoly->isActive() && tpoly->pedalhold)
- stopNote(tpoly->key);
- }
-}
-
-void Part::stopNote(unsigned int key) {
- // Non-sustaining instruments ignore stop commands.
- // They die away eventually anyway
-
-#if MT32EMU_MONITOR_INSTRUMENTS == 1
- synth->printDebug("%s (%s): stopping key %d", name, currentInstr, key);
-#endif
-
- if (key != 255) {
- for (int q = 0; q < MT32EMU_MAX_POLY; q++) {
- dpoly *tpoly = &polyTable[q];
- if (tpoly->isPlaying && tpoly->key == key) {
- if (holdpedal)
- tpoly->pedalhold = true;
- else if (tpoly->sustain)
- startDecayPoly(tpoly);
- }
- }
- return;
- }
-
- // Find oldest poly... yes, the MT-32 can be reconfigured to kill different poly first
- // This is simplest
- int oldest = -1;
- Bit32u oldage = 0;
-
- for (int q = 0; q < MT32EMU_MAX_POLY; q++) {
- dpoly *tpoly = &polyTable[q];
-
- if (tpoly->isPlaying && !tpoly->isDecay) {
- if (tpoly->getAge() >= oldage) {
- oldage = tpoly->getAge();
- oldest = q;
- }
- }
- }
-
- if (oldest != -1) {
- startDecayPoly(&polyTable[oldest]);
- }
-}
-
-}
diff --git a/sound/softsynth/mt32/part.h b/sound/softsynth/mt32/part.h
deleted file mode 100644
index 54c4999653..0000000000
--- a/sound/softsynth/mt32/part.h
+++ /dev/null
@@ -1,113 +0,0 @@
-/* Copyright (c) 2003-2005 Various contributors
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- * IN THE SOFTWARE.
- */
-
-#ifndef MT32EMU_PART_H
-#define MT32EMU_PART_H
-
-namespace MT32Emu {
-
-class PartialManager;
-class Synth;
-
-class Part {
-private:
- // Pointers to the areas of the MT-32's memory dedicated to this part (for parts 1-8)
- MemParams::PatchTemp *patchTemp;
- TimbreParam *timbreTemp;
-
- // 0=Part 1, .. 7=Part 8, 8=Rhythm
- unsigned int partNum;
-
- bool holdpedal;
-
- StereoVolume volumesetting;
-
- PatchCache patchCache[4];
-
- float bend; // -1.0 .. +1.0
-
- dpoly polyTable[MT32EMU_MAX_POLY];
-
- void abortPoly(dpoly *poly);
-
- static int fixKeyfollow(int srckey);
- static int fixBiaslevel(int srcpnt, int *dir);
-
- void setPatch(const PatchParam *patch);
-
-protected:
- Synth *synth;
- char name[8]; // "Part 1".."Part 8", "Rhythm"
- char currentInstr[11];
- int expression;
- Bit32u volumeMult;
-
- void updateVolume();
- void backupCacheToPartials(PatchCache cache[4]);
- void cacheTimbre(PatchCache cache[4], const TimbreParam *timbre);
- void playPoly(const PatchCache cache[4], unsigned int key, int freqNum, int vel);
- const char *getName() const;
-
-public:
- Part(Synth *synth, unsigned int usePartNum);
- virtual ~Part() {}
- virtual void playNote(unsigned int key, int vel);
- void stopNote(unsigned int key);
- void allNotesOff();
- void allSoundOff();
- int getVolume() const;
- void setVolume(int midiVolume);
- void setExpression(int midiExpression);
- virtual void setPan(unsigned int midiPan);
- virtual void setBend(unsigned int midiBend);
- virtual void setModulation(unsigned int midiModulation);
- virtual void setProgram(unsigned int midiProgram);
- void setHoldPedal(bool pedalval);
- void stopPedalHold();
- virtual void refresh();
- virtual void refreshTimbre(unsigned int absTimbreNum);
- virtual void setTimbre(TimbreParam *timbre);
- virtual unsigned int getAbsTimbreNum() const;
- const char *getCurrentInstr() const;
-};
-
-class RhythmPart: public Part {
- // Pointer to the area of the MT-32's memory dedicated to rhythm
- const MemParams::RhythmTemp *rhythmTemp;
-
- // This caches the timbres/settings in use by the rhythm part
- PatchCache drumCache[85][4];
- StereoVolume drumPan[85];
-public:
- RhythmPart(Synth *synth, unsigned int usePartNum);
- void refresh();
- void refreshTimbre(unsigned int timbreNum);
- void setTimbre(TimbreParam *timbre);
- void playNote(unsigned int key, int vel);
- unsigned int getAbsTimbreNum() const;
- void setPan(unsigned int midiPan);
- void setBend(unsigned int midiBend);
- void setModulation(unsigned int midiModulation);
- void setProgram(unsigned int patchNum);
-};
-
-}
-#endif
diff --git a/sound/softsynth/mt32/partial.cpp b/sound/softsynth/mt32/partial.cpp
deleted file mode 100644
index 5ba9ef6145..0000000000
--- a/sound/softsynth/mt32/partial.cpp
+++ /dev/null
@@ -1,968 +0,0 @@
-/* Copyright (c) 2003-2005 Various contributors
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- * IN THE SOFTWARE.
- */
-
-#include <stdlib.h>
-#include <math.h>
-#include <string.h>
-
-#include "mt32emu.h"
-
-#if defined(MACOSX) || defined(SOLARIS) || defined(__MINGW32__)
-// Older versions of Mac OS X didn't supply a powf function, so using it
-// will cause a binary incompatibility when trying to run a binary built
-// on a newer OS X release on an olderr one. And Solaris 8 doesn't provide
-// powf, floorf, fabsf etc. at all.
-// Cross-compiled MinGW32 toolchains suffer from a cross-compile bug in
-// libstdc++. math/stubs.o should be empty, but it comes with a symbol for
-// powf, resulting in a linker error because of multiple definitions.
-// Hence we re-define them here. The only potential drawback is that it
-// might be a little bit slower this way.
-#define powf(x,y) ((float)pow(x,y))
-#define floorf(x) ((float)floor(x))
-#define fabsf(x) ((float)fabs(x))
-#endif
-
-#define FIXEDPOINT_UDIV(x, y, point) (((x) << (point)) / ((y)))
-#define FIXEDPOINT_SDIV(x, y, point) (((x) * (1 << point)) / ((y)))
-#define FIXEDPOINT_UMULT(x, y, point) (((x) * (y)) >> point)
-#define FIXEDPOINT_SMULT(x, y, point) (((x) * (y)) / (1 << point))
-
-using namespace MT32Emu;
-
-Partial::Partial(Synth *useSynth) {
- this->synth = useSynth;
- ownerPart = -1;
- poly = NULL;
- pair = NULL;
-#if MT32EMU_ACCURATENOTES == 1
- for (int i = 0; i < 3; i++) {
- noteLookupStorage.waveforms[i] = new Bit16s[65536];
- }
- noteLookup = &noteLookupStorage;
-#endif
-}
-
-Partial::~Partial() {
-#if MT32EMU_ACCURATENOTES == 1
- for (int i = 0; i < 3; i++) {
- delete[] noteLookupStorage.waveforms[i];
- }
- delete[] noteLookupStorage.wavTable;
-#endif
-}
-
-int Partial::getOwnerPart() const {
- return ownerPart;
-}
-
-bool Partial::isActive() {
- return ownerPart > -1;
-}
-
-const dpoly *Partial::getDpoly() const {
- return this->poly;
-}
-
-void Partial::activate(int part) {
- // This just marks the partial as being assigned to a part
- ownerPart = part;
-}
-
-void Partial::deactivate() {
- ownerPart = -1;
- if (poly != NULL) {
- for (int i = 0; i < 4; i++) {
- if (poly->partials[i] == this) {
- poly->partials[i] = NULL;
- break;
- }
- }
- if (pair != NULL) {
- pair->pair = NULL;
- }
- }
-}
-
-void Partial::initKeyFollow(int key) {
- // Setup partial keyfollow
- // Note follow relative to middle C
-
- // Calculate keyfollow for pitch
-#if 1
- float rel = key == -1 ? 0.0f : (key - MIDDLEC);
- float newPitch = rel * patchCache->pitchKeyfollow + patchCache->pitch + patchCache->pitchShift;
- //FIXME:KG: Does it truncate the keyfollowed pitch to a semitone (towards MIDDLEC)?
- //int newKey = (int)(rel * patchCache->pitchKeyfollow);
- //float newPitch = newKey + patchCache->pitch + patchCache->pitchShift;
-#else
- float rel = key == -1 ? 0.0f : (key + patchCache->pitchShift - MIDDLEC);
- float newPitch = rel * patchCache->pitchKeyfollow + patchCache->pitch;
-#endif
-#if MT32EMU_ACCURATENOTES == 1
- noteVal = newPitch;
- synth->printDebug("key=%d, pitch=%f, pitchKeyfollow=%f, pitchShift=%f, newPitch=%f", key, (double)patchCache->pitch, (double)patchCache->pitchKeyfollow, (double)patchCache->pitchShift, (double)newPitch);
-#else
- float newPitchInt;
- float newPitchFract = modff(newPitch, &newPitchInt);
- if (newPitchFract > 0.5f) {
- newPitchInt += 1.0f;
- newPitchFract -= 1.0f;
- }
- noteVal = (int)newPitchInt;
- fineShift = (int)(powf(2.0f, newPitchFract / 12.0f) * 4096.0f);
- synth->printDebug("key=%d, pitch=%f, pitchKeyfollow=%f, pitchShift=%f, newPitch=%f, noteVal=%d, fineShift=%d", key, (double)patchCache->pitch, (double)patchCache->pitchKeyfollow, (double)patchCache->pitchShift, (double)newPitch, noteVal, fineShift);
-#endif
- // FIXME:KG: Raise/lower by octaves until in the supported range.
- while (noteVal > HIGHEST_NOTE) // FIXME:KG: see tables.cpp: >108?
- noteVal -= 12;
- while (noteVal < LOWEST_NOTE) // FIXME:KG: see tables.cpp: <12?
- noteVal += 12;
- // Calculate keyfollow for filter
- int keyfollow = ((key - MIDDLEC) * patchCache->filtkeyfollow) / 4096;
- if (keyfollow > 108)
- keyfollow = 108;
- else if (keyfollow < -108)
- keyfollow = -108;
- filtVal = synth->tables.tvfKeyfollowMult[keyfollow + 108];
- realVal = synth->tables.tvfKeyfollowMult[(noteVal - MIDDLEC) + 108];
-}
-
-int Partial::getKey() const {
- if (poly == NULL) {
- return -1;
- } else {
- return poly->key;
- }
-}
-
-void Partial::startPartial(dpoly *usePoly, const PatchCache *useCache, Partial *pairPartial) {
- if (usePoly == NULL || useCache == NULL) {
- synth->printDebug("*** Error: Starting partial for owner %d, usePoly=%s, useCache=%s", ownerPart, usePoly == NULL ? "*** NULL ***" : "OK", useCache == NULL ? "*** NULL ***" : "OK");
- return;
- }
- patchCache = useCache;
- poly = usePoly;
- mixType = patchCache->structureMix;
- structurePosition = patchCache->structurePosition;
-
- play = true;
- initKeyFollow(poly->freqnum); // Initialises noteVal, filtVal and realVal
-#if MT32EMU_ACCURATENOTES == 0
- noteLookup = &synth->tables.noteLookups[noteVal - LOWEST_NOTE];
-#else
- Tables::initNote(synth, &noteLookupStorage, noteVal, (float)synth->myProp.sampleRate, synth->masterTune, synth->pcmWaves, NULL);
-#endif
- keyLookup = &synth->tables.keyLookups[poly->freqnum - 12];
-
- if (patchCache->PCMPartial) {
- pcmNum = patchCache->pcm;
- if (synth->controlROMMap->pcmCount > 128) {
- // CM-32L, etc. support two "banks" of PCMs, selectable by waveform type parameter.
- if (patchCache->waveform > 1) {
- pcmNum += 128;
- }
- }
- pcmWave = &synth->pcmWaves[pcmNum];
- } else {
- pcmWave = NULL;
- }
-
- lfoPos = 0;
- pulsewidth = patchCache->pulsewidth + synth->tables.pwVelfollowAdd[patchCache->pwsens][poly->vel];
- if (pulsewidth > 100) {
- pulsewidth = 100;
- } else if (pulsewidth < 0) {
- pulsewidth = 0;
- }
-
- for (int e = 0; e < 3; e++) {
- envs[e].envpos = 0;
- envs[e].envstat = -1;
- envs[e].envbase = 0;
- envs[e].envdist = 0;
- envs[e].envsize = 0;
- envs[e].sustaining = false;
- envs[e].decaying = false;
- envs[e].prevlevel = 0;
- envs[e].counter = 0;
- envs[e].count = 0;
- }
- ampEnvVal = 0;
- pitchEnvVal = 0;
- pitchSustain = false;
- loopPos = 0;
- partialOff.pcmoffset = partialOff.pcmplace = 0;
- pair = pairPartial;
- useNoisePair = pairPartial == NULL && (mixType == 1 || mixType == 2);
- age = 0;
- alreadyOutputed = false;
- memset(history,0,sizeof(history));
-}
-
-Bit16s *Partial::generateSamples(long length) {
- if (!isActive() || alreadyOutputed) {
- return NULL;
- }
- if (poly == NULL) {
- synth->printDebug("*** ERROR: poly is NULL at Partial::generateSamples()!");
- return NULL;
- }
-
- alreadyOutputed = true;
-
- // Generate samples
-
- Bit16s *partialBuf = &myBuffer[0];
- Bit32u volume = *poly->volumeptr;
- while (length--) {
- Bit32s envval;
- Bit32s sample = 0;
- if (!envs[EnvelopeType_amp].sustaining) {
- if (envs[EnvelopeType_amp].count <= 0) {
- Bit32u ampval = getAmpEnvelope();
- if (!play) {
- deactivate();
- break;
- }
- if (ampval > 100) {
- ampval = 100;
- }
-
- ampval = synth->tables.volumeMult[ampval];
- ampval = FIXEDPOINT_UMULT(ampval, synth->tables.tvaVelfollowMult[poly->vel][(int)patchCache->ampEnv.velosens], 8);
- //if (envs[EnvelopeType_amp].sustaining)
- ampEnvVal = ampval;
- }
- --envs[EnvelopeType_amp].count;
- }
-
- unsigned int lfoShift = 0x1000;
- if (pitchSustain) {
- // Calculate LFO position
- // LFO does not kick in completely until pitch envelope sustains
- if (patchCache->lfodepth > 0) {
- lfoPos++;
- if (lfoPos >= patchCache->lfoperiod)
- lfoPos = 0;
- int lfoatm = FIXEDPOINT_UDIV(lfoPos, patchCache->lfoperiod, 16);
- int lfoatr = synth->tables.sintable[lfoatm];
- lfoShift = synth->tables.lfoShift[patchCache->lfodepth][lfoatr];
- }
- } else {
- // Calculate Pitch envelope
- envval = getPitchEnvelope();
- int pd = patchCache->pitchEnv.depth;
- pitchEnvVal = synth->tables.pitchEnvVal[pd][envval];
- }
-
- int delta;
-
- // Wrap positions or end if necessary
- if (patchCache->PCMPartial) {
- // PCM partial
-
- delta = noteLookup->wavTable[pcmNum];
- int len = pcmWave->len;
- if (partialOff.pcmplace >= len) {
- if (pcmWave->loop) {
- //partialOff.pcmplace = partialOff.pcmoffset = 0;
- partialOff.pcmplace %= len;
- } else {
- play = false;
- deactivate();
- break;
- }
- }
- } else {
- // Synthesis partial
- delta = 0x10000;
- partialOff.pcmplace %= (Bit16u)noteLookup->div2;
- }
-
- // Build delta for position of next sample
- // Fix delta code
- Bit32u tdelta = delta;
-#if MT32EMU_ACCURATENOTES == 0
- tdelta = FIXEDPOINT_UMULT(tdelta, fineShift, 12);
-#endif
- tdelta = FIXEDPOINT_UMULT(tdelta, pitchEnvVal, 12);
- tdelta = FIXEDPOINT_UMULT(tdelta, lfoShift, 12);
- tdelta = FIXEDPOINT_UMULT(tdelta, bendShift, 12);
- delta = (int)tdelta;
-
- // Get waveform - either PCM or synthesized sawtooth or square
- if (ampEnvVal > 0) {
- if (patchCache->PCMPartial) {
- // Render PCM sample
- int ra, rb, dist;
- Bit32u taddr;
- Bit32u pcmAddr = pcmWave->addr;
- if (delta < 0x10000) {
- // Linear sound interpolation
- taddr = pcmAddr + partialOff.pcmplace;
- ra = synth->pcmROMData[taddr];
- taddr++;
- if (taddr == pcmAddr + pcmWave->len) {
- // Past end of PCM
- if (pcmWave->loop) {
- rb = synth->pcmROMData[pcmAddr];
- } else {
- rb = 0;
- }
- } else {
- rb = synth->pcmROMData[taddr];
- }
- dist = rb - ra;
- sample = (ra + ((dist * (Bit32s)(partialOff.pcmoffset >> 8)) >> 8));
- } else {
- // Sound decimation
- // The right way to do it is to use a lowpass filter on the waveform before selecting
- // a point. This is too slow. The following approximates this as fast as possible
- int idelta = delta >> 16;
- taddr = pcmAddr + partialOff.pcmplace;
- ra = synth->pcmROMData[taddr++];
- for (int ix = 0; ix < idelta - 1; ix++) {
- if (taddr == pcmAddr + pcmWave->len) {
- // Past end of PCM
- if (pcmWave->loop) {
- taddr = pcmAddr;
- } else {
- // Behave as if all subsequent samples were 0
- break;
- }
- }
- ra += synth->pcmROMData[taddr++];
- }
- sample = ra / idelta;
- }
- } else {
- // Render synthesised sample
- int toff = partialOff.pcmplace;
- int minorplace = partialOff.pcmoffset >> 14;
- Bit32s filterInput;
- Bit32s filtval = getFiltEnvelope();
-
- //synth->printDebug("Filtval: %d", filtval);
-
- if ((patchCache->waveform & 1) == 0) {
- // Square waveform. Made by combining two pregenerated bandlimited
- // sawtooth waveforms
- Bit32u ofsA = ((toff << 2) + minorplace) % noteLookup->waveformSize[0];
- int width = FIXEDPOINT_UMULT(noteLookup->div2, synth->tables.pwFactor[pulsewidth], 7);
- Bit32u ofsB = (ofsA + width) % noteLookup->waveformSize[0];
- Bit16s pa = noteLookup->waveforms[0][ofsA];
- Bit16s pb = noteLookup->waveforms[0][ofsB];
- filterInput = pa - pb;
- // Non-bandlimited squarewave
- /*
- ofs = FIXEDPOINT_UMULT(noteLookup->div2, synth->tables.pwFactor[patchCache->pulsewidth], 8);
- if (toff < ofs)
- sample = 1 * WGAMP;
- else
- sample = -1 * WGAMP;
- */
- } else {
- // Sawtooth. Made by combining the full cosine and half cosine according
- // to how it looks on the MT-32. What it really does it takes the
- // square wave and multiplies it by a full cosine
- int waveoff = (toff << 2) + minorplace;
- if (toff < noteLookup->sawTable[pulsewidth])
- filterInput = noteLookup->waveforms[1][waveoff % noteLookup->waveformSize[1]];
- else
- filterInput = noteLookup->waveforms[2][waveoff % noteLookup->waveformSize[2]];
- // This is the correct way
- // Seems slow to me (though bandlimited) -- doesn't seem to
- // sound any better though
- /*
- //int pw = (patchCache->pulsewidth * pulsemod[filtval]) >> 8;
-
- Bit32u ofs = toff % (noteLookup->div2 >> 1);
-
- Bit32u ofs3 = toff + FIXEDPOINT_UMULT(noteLookup->div2, synth->tables.pwFactor[patchCache->pulsewidth], 9);
- ofs3 = ofs3 % (noteLookup->div2 >> 1);
-
- pa = noteLookup->waveforms[0][ofs];
- pb = noteLookup->waveforms[0][ofs3];
- sample = ((pa - pb) * noteLookup->waveforms[2][toff]) / 2;
- */
- }
-
- //Very exact filter
- if (filtval > ((FILTERGRAN * 15) / 16))
- filtval = ((FILTERGRAN * 15) / 16);
- sample = (Bit32s)(floorf((synth->iirFilter)((float)filterInput, &history[0], synth->tables.filtCoeff[filtval][(int)patchCache->filtEnv.resonance])) / synth->tables.resonanceFactor[patchCache->filtEnv.resonance]);
- if (sample < -32768) {
- synth->printDebug("Overdriven amplitude for %d: %d:=%d < -32768", patchCache->waveform, filterInput, sample);
- sample = -32768;
- }
- else if (sample > 32767) {
- synth->printDebug("Overdriven amplitude for %d: %d:=%d > 32767", patchCache->waveform, filterInput, sample);
- sample = 32767;
- }
- }
- }
-
- // Add calculated delta to our waveform offset
- Bit32u absOff = ((partialOff.pcmplace << 16) | partialOff.pcmoffset);
- absOff += delta;
- partialOff.pcmplace = (Bit16u)((absOff & 0xFFFF0000) >> 16);
- partialOff.pcmoffset = (Bit16u)(absOff & 0xFFFF);
-
- // Put volume envelope over generated sample
- sample = FIXEDPOINT_SMULT(sample, ampEnvVal, 9);
- sample = FIXEDPOINT_SMULT(sample, volume, 7);
- envs[EnvelopeType_amp].envpos++;
- envs[EnvelopeType_pitch].envpos++;
- envs[EnvelopeType_filt].envpos++;
-
- *partialBuf++ = (Bit16s)sample;
- }
- // We may have deactivated and broken out of the loop before the end of the buffer,
- // if so then fill the remainder with 0s.
- if (++length > 0)
- memset(partialBuf, 0, length * 2);
- return &myBuffer[0];
-}
-
-void Partial::setBend(float factor) {
- if (!patchCache->useBender || factor == 0.0f) {
- bendShift = 4096;
- return;
- }
- // NOTE:KG: We can't do this smoothly with lookup tables, unless we use several MB.
- // FIXME:KG: Bend should be influenced by pitch key-follow too, according to docs.
- float bendSemitones = factor * patchCache->benderRange; // -24 .. 24
- float mult = powf(2.0f, bendSemitones / 12.0f);
- synth->printDebug("setBend(): factor=%f, benderRange=%f, semitones=%f, mult=%f\n", (double)factor, (double)patchCache->benderRange, (double)bendSemitones, (double)mult);
- bendShift = (int)(mult * 4096.0f);
-}
-
-Bit16s *Partial::mixBuffers(Bit16s * buf1, Bit16s *buf2, int len) {
- if (buf1 == NULL)
- return buf2;
- if (buf2 == NULL)
- return buf1;
-
- Bit16s *outBuf = buf1;
-#if MT32EMU_USE_MMX >= 1
- // KG: This seems to be fine
- int donelen = i386_mixBuffers(buf1, buf2, len);
- len -= donelen;
- buf1 += donelen;
- buf2 += donelen;
-#endif
- while (len--) {
- *buf1 = *buf1 + *buf2;
- buf1++, buf2++;
- }
- return outBuf;
-}
-
-Bit16s *Partial::mixBuffersRingMix(Bit16s * buf1, Bit16s *buf2, int len) {
- if (buf1 == NULL)
- return NULL;
- if (buf2 == NULL) {
- Bit16s *outBuf = buf1;
- while (len--) {
- if (*buf1 < -8192)
- *buf1 = -8192;
- else if (*buf1 > 8192)
- *buf1 = 8192;
- buf1++;
- }
- return outBuf;
- }
-
- Bit16s *outBuf = buf1;
-#if MT32EMU_USE_MMX >= 1
- // KG: This seems to be fine
- int donelen = i386_mixBuffersRingMix(buf1, buf2, len);
- len -= donelen;
- buf1 += donelen;
- buf2 += donelen;
-#endif
- while (len--) {
- float a, b;
- a = ((float)*buf1) / 8192.0f;
- b = ((float)*buf2) / 8192.0f;
- a = (a * b) + a;
- if (a > 1.0f)
- a = 1.0f;
- if (a < -1.0f)
- a = -1.0f;
- *buf1 = (Bit16s)(a * 8192.0f);
- buf1++;
- buf2++;
- //buf1[i] = (Bit16s)(((Bit32s)buf1[i] * (Bit32s)buf2[i]) >> 10) + buf1[i];
- }
- return outBuf;
-}
-
-Bit16s *Partial::mixBuffersRing(Bit16s * buf1, Bit16s *buf2, int len) {
- if (buf1 == NULL) {
- return NULL;
- }
- if (buf2 == NULL) {
- return NULL;
- }
-
- Bit16s *outBuf = buf1;
-#if MT32EMU_USE_MMX >= 1
- // FIXME:KG: Not really checked as working
- int donelen = i386_mixBuffersRing(buf1, buf2, len);
- len -= donelen;
- buf1 += donelen;
- buf2 += donelen;
-#endif
- while (len--) {
- float a, b;
- a = ((float)*buf1) / 8192.0f;
- b = ((float)*buf2) / 8192.0f;
- a *= b;
- if (a > 1.0f)
- a = 1.0f;
- if (a < -1.0f)
- a = -1.0f;
- *buf1 = (Bit16s)(a * 8192.0f);
- buf1++;
- buf2++;
- }
- return outBuf;
-}
-
-void Partial::mixBuffersStereo(Bit16s *buf1, Bit16s *buf2, Bit16s *outBuf, int len) {
- if (buf2 == NULL) {
- while (len--) {
- *outBuf++ = *buf1++;
- *outBuf++ = 0;
- }
- } else if (buf1 == NULL) {
- while (len--) {
- *outBuf++ = 0;
- *outBuf++ = *buf2++;
- }
- } else {
- while (len--) {
- *outBuf++ = *buf1++;
- *outBuf++ = *buf2++;
- }
- }
-}
-
-bool Partial::produceOutput(Bit16s *partialBuf, long length) {
- if (!isActive() || alreadyOutputed)
- return false;
- if (poly == NULL) {
- synth->printDebug("*** ERROR: poly is NULL at Partial::produceOutput()!");
- return false;
- }
-
- Bit16s *pairBuf = NULL;
- // Check for dependant partial
- if (pair != NULL) {
- if (!pair->alreadyOutputed) {
- // Note: pair may have become NULL after this
- pairBuf = pair->generateSamples(length);
- }
- } else if (useNoisePair) {
- // Generate noise for pairless ring mix
- pairBuf = synth->tables.noiseBuf;
- }
-
- Bit16s *myBuf = generateSamples(length);
-
- if (myBuf == NULL && pairBuf == NULL)
- return false;
-
- Bit16s *p1buf, *p2buf;
-
- if (structurePosition == 0 || pairBuf == NULL) {
- p1buf = myBuf;
- p2buf = pairBuf;
- } else {
- p2buf = myBuf;
- p1buf = pairBuf;
- }
-
- //synth->printDebug("mixType: %d", mixType);
-
- Bit16s *mixedBuf;
- switch (mixType) {
- case 0:
- // Standard sound mix
- mixedBuf = mixBuffers(p1buf, p2buf, length);
- break;
-
- case 1:
- // Ring modulation with sound mix
- mixedBuf = mixBuffersRingMix(p1buf, p2buf, length);
- break;
-
- case 2:
- // Ring modulation alone
- mixedBuf = mixBuffersRing(p1buf, p2buf, length);
- break;
-
- case 3:
- // Stereo mixing. One partial to one speaker channel, one to another.
- // FIXME:KG: Surely we should be multiplying by the left/right volumes here?
- mixBuffersStereo(p1buf, p2buf, partialBuf, length);
- return true;
-
- default:
- mixedBuf = mixBuffers(p1buf, p2buf, length);
- break;
- }
-
- if (mixedBuf == NULL)
- return false;
-
- Bit16s leftvol, rightvol;
- leftvol = patchCache->pansetptr->leftvol;
- rightvol = patchCache->pansetptr->rightvol;
-
-#if MT32EMU_USE_MMX >= 2
- // FIXME:KG: This appears to introduce crackle
- int donelen = i386_partialProductOutput(length, leftvol, rightvol, partialBuf, mixedBuf);
- length -= donelen;
- mixedBuf += donelen;
- partialBuf += donelen * 2;
-#endif
- while (length--) {
- *partialBuf++ = (Bit16s)(((Bit32s)*mixedBuf * (Bit32s)leftvol) >> 15);
- *partialBuf++ = (Bit16s)(((Bit32s)*mixedBuf * (Bit32s)rightvol) >> 15);
- mixedBuf++;
- }
- return true;
-}
-
-Bit32s Partial::getFiltEnvelope() {
- int reshigh;
-
- int cutoff, depth;
-
- EnvelopeStatus *tStat = &envs[EnvelopeType_filt];
-
- if (tStat->decaying) {
- reshigh = tStat->envbase;
- reshigh = (reshigh + ((tStat->envdist * tStat->envpos) / tStat->envsize));
- if (tStat->envpos >= tStat->envsize)
- reshigh = 0;
- } else {
- if (tStat->envstat==4) {
- reshigh = patchCache->filtsustain;
- if (!poly->sustain) {
- startDecay(EnvelopeType_filt, reshigh);
- }
- } else {
- if ((tStat->envstat==-1) || (tStat->envpos >= tStat->envsize)) {
- if (tStat->envstat==-1)
- tStat->envbase = 0;
- else
- tStat->envbase = patchCache->filtEnv.envlevel[tStat->envstat];
- tStat->envstat++;
- tStat->envpos = 0;
- if (tStat->envstat == 3) {
- tStat->envsize = synth->tables.envTime[(int)patchCache->filtEnv.envtime[tStat->envstat]];
- } else {
- Bit32u envTime = (int)patchCache->filtEnv.envtime[tStat->envstat];
- if (tStat->envstat > 1) {
- int envDiff = abs(patchCache->filtEnv.envlevel[tStat->envstat] - patchCache->filtEnv.envlevel[tStat->envstat - 1]);
- if (envTime > synth->tables.envDeltaMaxTime[envDiff]) {
- envTime = synth->tables.envDeltaMaxTime[envDiff];
- }
- }
-
- tStat->envsize = (synth->tables.envTime[envTime] * keyLookup->envTimeMult[(int)patchCache->filtEnv.envtkf]) >> 8;
- }
-
- tStat->envsize++;
- tStat->envdist = patchCache->filtEnv.envlevel[tStat->envstat] - tStat->envbase;
- }
-
- reshigh = tStat->envbase;
- reshigh = (reshigh + ((tStat->envdist * tStat->envpos) / tStat->envsize));
-
- }
- tStat->prevlevel = reshigh;
- }
-
- cutoff = patchCache->filtEnv.cutoff;
-
- //if (patchCache->waveform==1) reshigh = (reshigh * 3) >> 2;
-
- depth = patchCache->filtEnv.envdepth;
-
- //int sensedep = (depth * 127-patchCache->filtEnv.envsense) >> 7;
- depth = FIXEDPOINT_UMULT(depth, synth->tables.tvfVelfollowMult[poly->vel][(int)patchCache->filtEnv.envsense], 8);
-
- int bias = patchCache->tvfbias;
- int dist;
-
- if (bias != 0) {
- //FIXME:KG: Is this really based on pitch (as now), or key pressed?
- //synth->printDebug("Cutoff before %d", cutoff);
- if (patchCache->tvfdir == 0) {
- if (noteVal < bias) {
- dist = bias - noteVal;
- cutoff = FIXEDPOINT_UMULT(cutoff, synth->tables.tvfBiasMult[patchCache->tvfblevel][dist], 8);
- }
- } else {
- // > Bias
- if (noteVal > bias) {
- dist = noteVal - bias;
- cutoff = FIXEDPOINT_UMULT(cutoff, synth->tables.tvfBiasMult[patchCache->tvfblevel][dist], 8);
- }
-
- }
- //synth->printDebug("Cutoff after %d", cutoff);
- }
-
- depth = (depth * keyLookup->envDepthMult[patchCache->filtEnv.envdkf]) >> 8;
- reshigh = (reshigh * depth) >> 7;
-
- Bit32s tmp;
-
- cutoff *= filtVal;
- cutoff /= realVal; //FIXME:KG: With filter keyfollow 0, this makes no sense. What's correct?
-
- reshigh *= filtVal;
- reshigh /= realVal; //FIXME:KG: As above for cutoff
-
- if (patchCache->waveform == 1) {
- reshigh = (reshigh * 65) / 100;
- }
-
- if (cutoff > 100)
- cutoff = 100;
- else if (cutoff < 0)
- cutoff = 0;
- if (reshigh > 100)
- reshigh = 100;
- else if (reshigh < 0)
- reshigh = 0;
- tmp = noteLookup->nfiltTable[cutoff][reshigh];
- //tmp *= keyfollow;
- //tmp /= realfollow;
-
- //synth->printDebug("Cutoff %d, tmp %d, freq %d", cutoff, tmp, tmp * 256);
- return tmp;
-}
-
-bool Partial::shouldReverb() {
- if (!isActive())
- return false;
- return patchCache->reverb;
-}
-
-Bit32u Partial::getAmpEnvelope() {
- Bit32s tc;
-
- EnvelopeStatus *tStat = &envs[EnvelopeType_amp];
-
- if (!play)
- return 0;
-
- if (tStat->decaying) {
- tc = tStat->envbase;
- tc += (tStat->envdist * tStat->envpos) / tStat->envsize;
- if (tc < 0)
- tc = 0;
- if ((tStat->envpos >= tStat->envsize) || (tc == 0)) {
- play = false;
- // Don't have to worry about prevlevel storage or anything, this partial's about to die
- return 0;
- }
- } else {
- if ((tStat->envstat == -1) || (tStat->envpos >= tStat->envsize)) {
- if (tStat->envstat == -1)
- tStat->envbase = 0;
- else
- tStat->envbase = patchCache->ampEnv.envlevel[tStat->envstat];
- tStat->envstat++;
- tStat->envpos = 0;
- if (tStat->envstat == 4) {
- //synth->printDebug("Envstat %d, size %d", tStat->envstat, tStat->envsize);
- tc = patchCache->ampEnv.envlevel[3];
- if (!poly->sustain)
- startDecay(EnvelopeType_amp, tc);
- else
- tStat->sustaining = true;
- goto PastCalc;
- }
- Bit8u targetLevel = patchCache->ampEnv.envlevel[tStat->envstat];
- tStat->envdist = targetLevel - tStat->envbase;
- Bit32u envTime = patchCache->ampEnv.envtime[tStat->envstat];
- if (targetLevel == 0) {
- tStat->envsize = synth->tables.envDecayTime[envTime];
- } else {
- int envLevelDelta = abs(tStat->envdist);
- if (envTime > synth->tables.envDeltaMaxTime[envLevelDelta]) {
- envTime = synth->tables.envDeltaMaxTime[envLevelDelta];
- }
- tStat->envsize = synth->tables.envTime[envTime];
- }
-
- // Time keyfollow is used by all sections of the envelope (confirmed on CM-32L)
- tStat->envsize = FIXEDPOINT_UMULT(tStat->envsize, keyLookup->envTimeMult[(int)patchCache->ampEnv.envtkf], 8);
-
- switch (tStat->envstat) {
- case 0:
- //Spot for velocity time follow
- //Only used for first attack
- tStat->envsize = FIXEDPOINT_UMULT(tStat->envsize, synth->tables.envTimeVelfollowMult[(int)patchCache->ampEnv.envvkf][poly->vel], 8);
- //synth->printDebug("Envstat %d, size %d", tStat->envstat, tStat->envsize);
- break;
- case 1:
- case 2:
- case 3:
- //synth->printDebug("Envstat %d, size %d", tStat->envstat, tStat->envsize);
- break;
- default:
- synth->printDebug("Invalid TVA envelope number %d hit!", tStat->envstat);
- break;
- }
-
- tStat->envsize++;
-
- if (tStat->envdist != 0) {
- tStat->counter = abs(tStat->envsize / tStat->envdist);
- //synth->printDebug("Pos %d, envsize %d envdist %d", tStat->envstat, tStat->envsize, tStat->envdist);
- } else {
- tStat->counter = 0;
- //synth->printDebug("Pos %d, envsize %d envdist %d", tStat->envstat, tStat->envsize, tStat->envdist);
- }
- }
- tc = tStat->envbase;
- tc = (tc + ((tStat->envdist * tStat->envpos) / tStat->envsize));
- tStat->count = tStat->counter;
-PastCalc:
- tc = (tc * (Bit32s)patchCache->ampEnv.level) / 100;
- }
-
- // Prevlevel storage is bottle neck
- tStat->prevlevel = tc;
-
- //Bias level crap stuff now
-
- for (int i = 0; i < 2; i++) {
- if (patchCache->ampblevel[i]!=0) {
- int bias = patchCache->ampbias[i];
- if (patchCache->ampdir[i]==0) {
- // < Bias
- if (noteVal < bias) {
- int dist = bias - noteVal;
- tc = FIXEDPOINT_UMULT(tc, synth->tables.tvaBiasMult[patchCache->ampblevel[i]][dist], 8);
- }
- } else {
- // > Bias
- if (noteVal > bias) {
- int dist = noteVal - bias;
- tc = FIXEDPOINT_UMULT(tc, synth->tables.tvaBiasMult[patchCache->ampblevel[i]][dist], 8);
- }
- }
- }
- }
- if (tc < 0) {
- synth->printDebug("*** ERROR: tc < 0 (%d) at getAmpEnvelope()", tc);
- tc = 0;
- }
- return (Bit32u)tc;
-}
-
-Bit32s Partial::getPitchEnvelope() {
- EnvelopeStatus *tStat = &envs[EnvelopeType_pitch];
-
- Bit32s tc;
- pitchSustain = false;
- if (tStat->decaying) {
- if (tStat->envpos >= tStat->envsize)
- tc = patchCache->pitchEnv.level[4];
- else {
- tc = tStat->envbase;
- tc = (tc + ((tStat->envdist * tStat->envpos) / tStat->envsize));
- }
- } else {
- if (tStat->envstat==3) {
- tc = patchCache->pitchsustain;
- if (poly->sustain)
- pitchSustain = true;
- else
- startDecay(EnvelopeType_pitch, tc);
- } else {
- if ((tStat->envstat==-1) || (tStat->envpos >= tStat->envsize)) {
- tStat->envstat++;
-
- tStat->envbase = patchCache->pitchEnv.level[tStat->envstat];
-
- Bit32u envTime = patchCache->pitchEnv.time[tStat->envstat];
- int envDiff = abs(patchCache->pitchEnv.level[tStat->envstat] - patchCache->pitchEnv.level[tStat->envstat + 1]);
- if (envTime > synth->tables.envDeltaMaxTime[envDiff]) {
- envTime = synth->tables.envDeltaMaxTime[envDiff];
- }
-
- tStat->envsize = (synth->tables.envTime[envTime] * keyLookup->envTimeMult[(int)patchCache->pitchEnv.timekeyfollow]) >> 8;
-
- tStat->envpos = 0;
- tStat->envsize++;
- tStat->envdist = patchCache->pitchEnv.level[tStat->envstat + 1] - tStat->envbase;
- }
- tc = tStat->envbase;
- tc = (tc + ((tStat->envdist * tStat->envpos) / tStat->envsize));
- }
- tStat->prevlevel = tc;
- }
- return tc;
-}
-
-void Partial::startDecayAll() {
- startDecay(EnvelopeType_amp, envs[EnvelopeType_amp].prevlevel);
- startDecay(EnvelopeType_filt, envs[EnvelopeType_filt].prevlevel);
- startDecay(EnvelopeType_pitch, envs[EnvelopeType_pitch].prevlevel);
- pitchSustain = false;
-}
-
-void Partial::startDecay(EnvelopeType envnum, Bit32s startval) {
- EnvelopeStatus *tStat = &envs[envnum];
-
- tStat->sustaining = false;
- tStat->decaying = true;
- tStat->envpos = 0;
- tStat->envbase = startval;
-
- switch (envnum) {
- case EnvelopeType_amp:
- tStat->envsize = FIXEDPOINT_UMULT(synth->tables.envDecayTime[(int)patchCache->ampEnv.envtime[4]], keyLookup->envTimeMult[(int)patchCache->ampEnv.envtkf], 8);
- tStat->envdist = -startval;
- break;
- case EnvelopeType_filt:
- tStat->envsize = FIXEDPOINT_UMULT(synth->tables.envDecayTime[(int)patchCache->filtEnv.envtime[4]], keyLookup->envTimeMult[(int)patchCache->filtEnv.envtkf], 8);
- tStat->envdist = -startval;
- break;
- case EnvelopeType_pitch:
- tStat->envsize = FIXEDPOINT_UMULT(synth->tables.envDecayTime[(int)patchCache->pitchEnv.time[3]], keyLookup->envTimeMult[(int)patchCache->pitchEnv.timekeyfollow], 8);
- tStat->envdist = patchCache->pitchEnv.level[4] - startval;
- break;
- default:
- break;
- }
- tStat->envsize++;
-}
diff --git a/sound/softsynth/mt32/partial.h b/sound/softsynth/mt32/partial.h
deleted file mode 100644
index 93d8bcd985..0000000000
--- a/sound/softsynth/mt32/partial.h
+++ /dev/null
@@ -1,148 +0,0 @@
-/* Copyright (c) 2003-2005 Various contributors
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- * IN THE SOFTWARE.
- */
-
-#ifndef MT32EMU_PARTIAL_H
-#define MT32EMU_PARTIAL_H
-
-namespace MT32Emu {
-
-class Synth;
-struct NoteLookup;
-
-enum EnvelopeType {
- EnvelopeType_amp = 0,
- EnvelopeType_filt = 1,
- EnvelopeType_pitch = 2
-};
-
-struct EnvelopeStatus {
- Bit32s envpos;
- Bit32s envstat;
- Bit32s envbase;
- Bit32s envdist;
- Bit32s envsize;
-
- bool sustaining;
- bool decaying;
- Bit32s prevlevel;
-
- Bit32s counter;
- Bit32s count;
-};
-
-// Class definition of MT-32 partials. 32 in all.
-class Partial {
-private:
- Synth *synth;
-
- int ownerPart; // -1 if unassigned
- int mixType;
- int structurePosition; // 0 or 1 of a structure pair
- bool useNoisePair;
-
- Bit16s myBuffer[MAX_SAMPLE_OUTPUT];
-
- // Keyfollowed note value
-#if MT32EMU_ACCURATENOTES == 1
- NoteLookup noteLookupStorage;
- float noteVal;
-#else
- int noteVal;
- int fineShift;
-#endif
- const NoteLookup *noteLookup; // LUTs for this noteVal
- const KeyLookup *keyLookup; // LUTs for the clamped (12..108) key
-
- // Keyfollowed filter values
- int realVal;
- int filtVal;
-
- // Only used for PCM partials
- int pcmNum;
- PCMWaveEntry *pcmWave;
-
- int pulsewidth;
-
- Bit32u lfoPos;
- soundaddr partialOff;
-
- Bit32u ampEnvVal;
- Bit32u pitchEnvVal;
-
- float history[32];
-
- bool pitchSustain;
-
- int loopPos;
-
- dpoly *poly;
-
- int bendShift;
-
- Bit16s *mixBuffers(Bit16s *buf1, Bit16s *buf2, int len);
- Bit16s *mixBuffersRingMix(Bit16s *buf1, Bit16s *buf2, int len);
- Bit16s *mixBuffersRing(Bit16s *buf1, Bit16s *buf2, int len);
- void mixBuffersStereo(Bit16s *buf1, Bit16s *buf2, Bit16s *outBuf, int len);
-
- Bit32s getFiltEnvelope();
- Bit32u getAmpEnvelope();
- Bit32s getPitchEnvelope();
-
- void initKeyFollow(int freqNum);
-
-public:
- const PatchCache *patchCache;
- EnvelopeStatus envs[3];
- bool play;
-
- PatchCache cachebackup;
-
- Partial *pair;
- bool alreadyOutputed;
- Bit32u age;
-
- Partial(Synth *synth);
- ~Partial();
-
- int getOwnerPart() const;
- int getKey() const;
- const dpoly *getDpoly() const;
- bool isActive();
- void activate(int part);
- void deactivate(void);
- void startPartial(dpoly *usePoly, const PatchCache *useCache, Partial *pairPartial);
- void startDecay(EnvelopeType envnum, Bit32s startval);
- void startDecayAll();
- void setBend(float factor);
- bool shouldReverb();
-
- // Returns true only if data written to buffer
- // This function (unlike the one below it) returns processed stereo samples
- // made from combining this single partial with its pair, if it has one.
- bool produceOutput(Bit16s * partialBuf, long length);
-
- // This function produces mono sample output using the partial's private internal buffer
- Bit16s *generateSamples(long length);
-};
-
-}
-
-#endif
diff --git a/sound/softsynth/mt32/partialManager.cpp b/sound/softsynth/mt32/partialManager.cpp
deleted file mode 100644
index 3d3b6302db..0000000000
--- a/sound/softsynth/mt32/partialManager.cpp
+++ /dev/null
@@ -1,272 +0,0 @@
-/* Copyright (c) 2003-2005 Various contributors
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- * IN THE SOFTWARE.
- */
-
-#include <string.h>
-
-#include "mt32emu.h"
-
-using namespace MT32Emu;
-
-PartialManager::PartialManager(Synth *useSynth) {
- this->synth = useSynth;
- for (int i = 0; i < MT32EMU_MAX_PARTIALS; i++)
- partialTable[i] = new Partial(synth);
-}
-
-PartialManager::~PartialManager(void) {
- for (int i = 0; i < MT32EMU_MAX_PARTIALS; i++)
- delete partialTable[i];
-}
-
-void PartialManager::getPerPartPartialUsage(int usage[9]) {
- memset(usage, 0, 9 * sizeof (int));
- for (int i = 0; i < MT32EMU_MAX_PARTIALS; i++) {
- if (partialTable[i]->isActive())
- usage[partialTable[i]->getOwnerPart()]++;
- }
-}
-
-void PartialManager::clearAlreadyOutputed() {
- for (int i = 0; i < MT32EMU_MAX_PARTIALS; i++)
- partialTable[i]->alreadyOutputed = false;
-}
-
-void PartialManager::ageAll() {
- for (int i = 0; i < MT32EMU_MAX_PARTIALS; i++)
- partialTable[i]->age++;
-}
-
-bool PartialManager::shouldReverb(int i) {
- return partialTable[i]->shouldReverb();
-}
-
-bool PartialManager::produceOutput(int i, Bit16s *buffer, Bit32u bufferLength) {
- return partialTable[i]->produceOutput(buffer, bufferLength);
-}
-
-void PartialManager::deactivateAll() {
- for (int i = 0; i < MT32EMU_MAX_PARTIALS; i++) {
- partialTable[i]->deactivate();
- }
-}
-
-unsigned int PartialManager::setReserve(Bit8u *rset) {
- unsigned int pr = 0;
- for (int x = 0; x < 9; x++) {
- for (int y = 0; y < rset[x]; y++) {
- partialReserveTable[pr] = x;
- pr++;
- }
- }
- return pr;
-}
-
-Partial *PartialManager::allocPartial(int partNum) {
- Partial *outPartial = NULL;
-
- // Use the first inactive partial reserved for the specified part (if there are any)
- // Otherwise, use the last inactive partial, if any
- for (int i = 0; i < MT32EMU_MAX_PARTIALS; i++) {
- if (!partialTable[i]->isActive()) {
- outPartial = partialTable[i];
- if (partialReserveTable[i] == partNum)
- break;
- }
- }
- if (outPartial != NULL) {
- outPartial->activate(partNum);
- outPartial->age = 0;
- }
- return outPartial;
-}
-
-unsigned int PartialManager::getFreePartialCount(void) {
- int count = 0;
- memset(partialPart, 0, sizeof(partialPart));
- for (int i = 0; i < MT32EMU_MAX_PARTIALS; i++) {
- if (!partialTable[i]->isActive())
- count++;
- else
- partialPart[partialTable[i]->getOwnerPart()]++;
- }
- return count;
-}
-
-/*
-bool PartialManager::freePartials(unsigned int needed, int partNum) {
- int i;
- int myPartPrior = (int)mt32ram.system.reserveSettings[partNum];
- if (myPartPrior<partialPart[partNum]) {
- //This can have more parts, must kill off those with less priority
- int most, mostPart;
- while (needed > 0) {
- int selectPart = -1;
- //Find the worst offender with more partials than allocated and kill them
- most = -1;
- mostPart = -1;
- int diff;
-
- for (i=0;i<9;i++) {
- diff = partialPart[i] - (int)mt32ram.system.reserveSettings[i];
-
- if (diff>0) {
- if (diff>most) {
- most = diff;
- mostPart = i;
- }
- }
- }
- selectPart = mostPart;
- if (selectPart == -1) {
- // All parts are within the allocated limits, you suck
- // Look for first partial not of this part that's decaying perhaps?
- return false;
- }
- bool found;
- int oldest;
- int oldnum;
- while (partialPart[selectPart] > (int)mt32ram.system.reserveSettings[selectPart]) {
- oldest = -1;
- oldnum = -1;
- found = false;
- for (i = 0; i < MT32EMU_MAX_PARTIALS; i++) {
- if (partialTable[i]->isActive) {
- if (partialTable[i]->ownerPart == selectPart) {
- found = true;
- if (partialTable[i]->age > oldest) {
- oldest = partialTable[i]->age;
- oldnum = i;
- }
- }
- }
- }
- if (!found) break;
- partialTable[oldnum]->deactivate();
- --partialPart[selectPart];
- --needed;
- }
-
- }
- return true;
-
- } else {
- //This part has reached its max, must kill off its own
- bool found;
- int oldest;
- int oldnum;
- while (needed > 0) {
- oldest = -1;
- oldnum = -1;
- found = false;
- for (i = 0; i < MT32EMU_MAX_PARTIALS; i++) {
- if (partialTable[i]->isActive) {
- if (partialTable[i]->ownerPart == partNum) {
- found = true;
- if (partialTable[i]->age > oldest) {
- oldest = partialTable[i]->age;
- oldnum = i;
- }
- }
- }
- }
- if (!found) break;
- partialTable[oldnum]->deactivate();
- --needed;
- }
- // Couldn't free enough partials, sorry
- if (needed>0) return false;
- return true;
- }
-
-}
-*/
-bool PartialManager::freePartials(unsigned int needed, int partNum) {
- if (needed == 0) {
- return true;
- }
- // Reclaim partials reserved for this part
- // Kill those that are already decaying first
- /*
- for (int i = 0; i < MT32EMU_MAX_PARTIALS; i++) {
- if (partialReserveTable[i] == partNum) {
- if (partialTable[i]->ownerPart != partNum) {
- if (partialTable[i]->partCache->envs[AMPENV].decaying) {
- partialTable[i]->isActive = false;
- --needed;
- if (needed == 0)
- return true;
- }
- }
- }
- }*/
- // Then kill those with the lowest part priority -- oldest at the moment
- while (needed > 0) {
- Bit32u prior = 0;
- int priornum = -1;
-
- for (int i = 0; i < MT32EMU_MAX_PARTIALS; i++) {
- if (partialReserveTable[i] == partNum && partialTable[i]->isActive() && partialTable[i]->getOwnerPart() != partNum) {
- /*
- if (mt32ram.system.reserveSettings[partialTable[i]->ownerPart] < prior) {
- prior = mt32ram.system.reserveSettings[partialTable[i]->ownerPart];
- priornum = i;
- }*/
- if (partialTable[i]->age >= prior) {
- prior = partialTable[i]->age;
- priornum = i;
- }
- }
- }
- if (priornum != -1) {
- partialTable[priornum]->deactivate();
- --needed;
- } else {
- break;
- }
- }
-
- // Kill off the oldest partials within this part
- while (needed > 0) {
- Bit32u oldest = 0;
- int oldlist = -1;
- for (int i = 0; i < MT32EMU_MAX_PARTIALS; i++) {
- if (partialTable[i]->getOwnerPart() == partNum && partialTable[i]->isActive()) {
- if (partialTable[i]->age >= oldest) {
- oldest = partialTable[i]->age;
- oldlist = i;
- }
- }
- }
- if (oldlist != -1) {
- partialTable[oldlist]->deactivate();
- --needed;
- } else {
- break;
- }
- }
- return needed == 0;
-}
-
-const Partial *PartialManager::getPartial(unsigned int partialNum) const {
- if (partialNum > MT32EMU_MAX_PARTIALS - 1)
- return NULL;
- return partialTable[partialNum];
-}
diff --git a/sound/softsynth/mt32/partialManager.h b/sound/softsynth/mt32/partialManager.h
deleted file mode 100644
index b10f93ff02..0000000000
--- a/sound/softsynth/mt32/partialManager.h
+++ /dev/null
@@ -1,56 +0,0 @@
-/* Copyright (c) 2003-2005 Various contributors
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- * IN THE SOFTWARE.
- */
-
-#ifndef MT32EMU_PARTIALMANAGER_H
-#define MT32EMU_PARTIALMANAGER_H
-
-namespace MT32Emu {
-
-class Synth;
-
-class PartialManager {
-private:
- Synth *synth; // Only used for sending debug output
-
- Partial *partialTable[MT32EMU_MAX_PARTIALS];
- Bit32s partialReserveTable[MT32EMU_MAX_PARTIALS];
- Bit32s partialPart[9]; // The count of partials played per part
-
-public:
-
- PartialManager(Synth *synth);
- ~PartialManager();
- Partial *allocPartial(int partNum);
- unsigned int getFreePartialCount(void);
- bool freePartials(unsigned int needed, int partNum);
- unsigned int setReserve(Bit8u *rset);
- void deactivateAll();
- void ageAll();
- bool produceOutput(int i, Bit16s *buffer, Bit32u bufferLength);
- bool shouldReverb(int i);
- void clearAlreadyOutputed();
- void getPerPartPartialUsage(int usage[9]);
- const Partial *getPartial(unsigned int partialNum) const;
-};
-
-}
-
-#endif
diff --git a/sound/softsynth/mt32/structures.h b/sound/softsynth/mt32/structures.h
deleted file mode 100644
index ef58c1d20f..0000000000
--- a/sound/softsynth/mt32/structures.h
+++ /dev/null
@@ -1,284 +0,0 @@
-/* Copyright (c) 2003-2005 Various contributors
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- * IN THE SOFTWARE.
- */
-
-#ifndef MT32EMU_STRUCTURES_H
-#define MT32EMU_STRUCTURES_H
-
-namespace MT32Emu {
-
-const unsigned int MAX_SAMPLE_OUTPUT = 4096;
-
-// MT32EMU_MEMADDR() converts from sysex-padded, MT32EMU_SYSEXMEMADDR converts to it
-// Roland provides documentation using the sysex-padded addresses, so we tend to use that in code and output
-#define MT32EMU_MEMADDR(x) ((((x) & 0x7f0000) >> 2) | (((x) & 0x7f00) >> 1) | ((x) & 0x7f))
-#define MT32EMU_SYSEXMEMADDR(x) ((((x) & 0x1FC000) << 2) | (((x) & 0x3F80) << 1) | ((x) & 0x7f))
-
-#ifdef _MSC_VER
-#define MT32EMU_ALIGN_PACKED __declspec(align(1))
-typedef unsigned __int64 Bit64u;
-typedef signed __int64 Bit64s;
-#else
-#define MT32EMU_ALIGN_PACKED __attribute__((packed))
-typedef unsigned long long Bit64u;
-typedef signed long long Bit64s;
-#endif
-
-typedef unsigned int Bit32u;
-typedef signed int Bit32s;
-typedef unsigned short int Bit16u;
-typedef signed short int Bit16s;
-typedef unsigned char Bit8u;
-typedef signed char Bit8s;
-
-// The following structures represent the MT-32's memory
-// Since sysex allows this memory to be written to in blocks of bytes,
-// we keep this packed so that we can copy data into the various
-// banks directly
-#if defined(_MSC_VER) || defined (__MINGW32__)
-#pragma pack(push, 1)
-#else
-#pragma pack(1)
-#endif
-
-struct TimbreParam {
- struct commonParam {
- char name[10];
- Bit8u pstruct12; // 1&2 0-12 (1-13)
- Bit8u pstruct34; // #3&4 0-12 (1-13)
- Bit8u pmute; // 0-15 (0000-1111)
- Bit8u nosustain; // 0-1(Normal, No sustain)
- } MT32EMU_ALIGN_PACKED common;
-
- struct partialParam {
- struct wgParam {
- Bit8u coarse; // 0-96 (C1,C#1-C9)
- Bit8u fine; // 0-100 (-50 to +50 (cents?))
- Bit8u keyfollow; // 0-16 (-1,-1/2,0,1,1/8,1/4,3/8,1/2,5/8,3/4,7/8,1,5/4,3/2,2.s1,s2)
- Bit8u bender; // 0,1 (ON/OFF)
- Bit8u waveform; // MT-32: 0-1 (SQU/SAW); LAPC-I: WG WAVEFORM/PCM BANK 0 - 3 (SQU/1, SAW/1, SQU/2, SAW/2)
- Bit8u pcmwave; // 0-127 (1-128)
- Bit8u pulsewid; // 0-100
- Bit8u pwvelo; // 0-14 (-7 - +7)
- } MT32EMU_ALIGN_PACKED wg;
-
- struct envParam {
- Bit8u depth; // 0-10
- Bit8u sensitivity; // 1-100
- Bit8u timekeyfollow; // 0-4
- Bit8u time[4]; // 1-100
- Bit8u level[5]; // 1-100 (-50 - +50)
- } MT32EMU_ALIGN_PACKED env;
-
- struct lfoParam {
- Bit8u rate; // 0-100
- Bit8u depth; // 0-100
- Bit8u modsense; // 0-100
- } MT32EMU_ALIGN_PACKED lfo;
-
- struct tvfParam {
- Bit8u cutoff; // 0-100
- Bit8u resonance; // 0-30
- Bit8u keyfollow; // 0-16 (-1,-1/2,1/4,0,1,1/8,1/4,3/8,1/2,5/8,3/2,7/8,1,5/4,3/2,2,s1,s2)
- Bit8u biaspoint; // 0-127 (<1A-<7C >1A-7C)
- Bit8u biaslevel; // 0-14 (-7 - +7)
- Bit8u envdepth; // 0-100
- Bit8u envsense; // 0-100
- Bit8u envdkf; // DEPTH KEY FOLL0W 0-4
- Bit8u envtkf; // TIME KEY FOLLOW 0-4
- Bit8u envtime[5]; // 1-100
- Bit8u envlevel[4]; // 1-100
- } MT32EMU_ALIGN_PACKED tvf;
-
- struct tvaParam {
- Bit8u level; // 0-100
- Bit8u velosens; // 0-100
- Bit8u biaspoint1; // 0-127 (<1A-<7C >1A-7C)
- Bit8u biaslevel1; // 0-12 (-12 - 0)
- Bit8u biaspoint2; // 0-127 (<1A-<7C >1A-7C)
- Bit8u biaslevel2; // 0-12 (-12 - 0)
- Bit8u envtkf; // TIME KEY FOLLOW 0-4
- Bit8u envvkf; // VELOS KEY FOLL0W 0-4
- Bit8u envtime[5]; // 1-100
- Bit8u envlevel[4]; // 1-100
- } MT32EMU_ALIGN_PACKED tva;
- } MT32EMU_ALIGN_PACKED partial[4];
-} MT32EMU_ALIGN_PACKED;
-
-struct PatchParam {
- Bit8u timbreGroup; // TIMBRE GROUP 0-3 (group A, group B, Memory, Rhythm)
- Bit8u timbreNum; // TIMBRE NUMBER 0-63
- Bit8u keyShift; // KEY SHIFT 0-48 (-24 - +24 semitones)
- Bit8u fineTune; // FINE TUNE 0-100 (-50 - +50 cents)
- Bit8u benderRange; // BENDER RANGE 0-24
- Bit8u assignMode; // ASSIGN MODE 0-3 (POLY1, POLY2, POLY3, POLY4)
- Bit8u reverbSwitch; // REVERB SWITCH 0-1 (OFF,ON)
- Bit8u dummy; // (DUMMY)
-} MT32EMU_ALIGN_PACKED;
-
-struct MemParams {
- // NOTE: The MT-32 documentation only specifies PatchTemp areas for parts 1-8.
- // The LAPC-I documentation specified an additional area for rhythm at the end,
- // where all parameters but fine tune, assign mode and output level are ignored
- struct PatchTemp {
- PatchParam patch;
- Bit8u outlevel; // OUTPUT LEVEL 0-100
- Bit8u panpot; // PANPOT 0-14 (R-L)
- Bit8u dummyv[6];
- } MT32EMU_ALIGN_PACKED;
-
- PatchTemp patchSettings[9];
-
- struct RhythmTemp {
- Bit8u timbre; // TIMBRE 0-94 (M1-M64,R1-30,OFF)
- Bit8u outlevel; // OUTPUT LEVEL 0-100
- Bit8u panpot; // PANPOT 0-14 (R-L)
- Bit8u reverbSwitch; // REVERB SWITCH 0-1 (OFF,ON)
- } MT32EMU_ALIGN_PACKED;
-
- RhythmTemp rhythmSettings[85];
-
- TimbreParam timbreSettings[8];
-
- PatchParam patches[128];
-
- // NOTE: There are only 30 timbres in the "rhythm" bank for MT-32; the additional 34 are for LAPC-I and above
- struct PaddedTimbre {
- TimbreParam timbre;
- Bit8u padding[10];
- } MT32EMU_ALIGN_PACKED;
-
- PaddedTimbre timbres[64 + 64 + 64 + 64]; // Group A, Group B, Memory, Rhythm
-
- struct SystemArea {
- Bit8u masterTune; // MASTER TUNE 0-127 432.1-457.6Hz
- Bit8u reverbMode; // REVERB MODE 0-3 (room, hall, plate, tap delay)
- Bit8u reverbTime; // REVERB TIME 0-7 (1-8)
- Bit8u reverbLevel; // REVERB LEVEL 0-7 (1-8)
- Bit8u reserveSettings[9]; // PARTIAL RESERVE (PART 1) 0-32
- Bit8u chanAssign[9]; // MIDI CHANNEL (PART1) 0-16 (1-16,OFF)
- Bit8u masterVol; // MASTER VOLUME 0-100
- } MT32EMU_ALIGN_PACKED;
-
- SystemArea system;
-};
-
-#if defined(_MSC_VER) || defined (__MINGW32__)
-#pragma pack(pop)
-#else
-#pragma pack()
-#endif
-
-struct PCMWaveEntry {
- Bit32u addr;
- Bit32u len;
- double tune;
- bool loop;
-};
-
-struct soundaddr {
- Bit16u pcmplace;
- Bit16u pcmoffset;
-};
-
-struct StereoVolume {
- Bit16s leftvol;
- Bit16s rightvol;
-};
-
-// This is basically a per-partial, pre-processed combination of timbre and patch/rhythm settings
-struct PatchCache {
- bool playPartial;
- bool PCMPartial;
- int pcm;
- char waveform;
- int pulsewidth;
- int pwsens;
-
- float pitch;
-
- int lfodepth;
- int lforate;
- Bit32u lfoperiod;
- int modsense;
-
- float pitchKeyfollow;
-
- int filtkeyfollow;
-
- int tvfbias;
- int tvfblevel;
- int tvfdir;
-
- int ampbias[2];
- int ampblevel[2];
- int ampdir[2];
-
- int ampdepth;
- int amplevel;
-
- bool useBender;
- float benderRange; // 0.0, 1.0, .., 24.0 (semitones)
-
- TimbreParam::partialParam::envParam pitchEnv;
- TimbreParam::partialParam::tvaParam ampEnv;
- TimbreParam::partialParam::tvfParam filtEnv;
-
- Bit32s pitchsustain;
- Bit32s filtsustain;
-
- Bit32u structureMix;
- int structurePosition;
- int structurePair;
-
- // The following fields are actually common to all partials in the timbre
- bool dirty;
- Bit32u partialCount;
- bool sustain;
- float pitchShift;
- bool reverb;
- const StereoVolume *pansetptr;
-};
-
-class Partial; // Forward reference for class defined in partial.h
-
-struct dpoly {
- bool isPlaying;
-
- unsigned int key;
- int freqnum;
- int vel;
-
- bool isDecay;
-
- const Bit32u *volumeptr;
-
- Partial *partials[4];
-
- bool pedalhold; // This marks keys that have been released on the keyboard, but are being held by the pedal
- bool sustain;
-
- bool isActive() const;
- Bit32u getAge() const;
-};
-
-}
-
-#endif
diff --git a/sound/softsynth/mt32/synth.cpp b/sound/softsynth/mt32/synth.cpp
deleted file mode 100644
index 16460795a5..0000000000
--- a/sound/softsynth/mt32/synth.cpp
+++ /dev/null
@@ -1,1198 +0,0 @@
-/* Copyright (c) 2003-2005 Various contributors
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- * IN THE SOFTWARE.
- */
-
-#include <math.h>
-#include <string.h>
-#include <stdlib.h>
-
-#include "mt32emu.h"
-
-#include "common/str.h"
-
-#if defined(MACOSX) || defined(SOLARIS) || defined(__MINGW32__)
-// Older versions of Mac OS X didn't supply a powf function, so using it
-// will cause a binary incompatibility when trying to run a binary built
-// on a newer OS X release on an olderr one. And Solaris 8 doesn't provide
-// powf, floorf, fabsf etc. at all.
-// Cross-compiled MinGW32 toolchains suffer from a cross-compile bug in
-// libstdc++. math/stubs.o should be empty, but it comes with a symbol for
-// powf, resulting in a linker error because of multiple definitions.
-// Hence we re-define them here. The only potential drawback is that it
-// might be a little bit slower this way.
-#define powf(x,y) ((float)pow(x,y))
-#define floorf(x) ((float)floor(x))
-#define fabsf(x) ((float)fabs(x))
-#endif
-
-namespace MT32Emu {
-
-const int MAX_SYSEX_SIZE = 512;
-
-const ControlROMMap ControlROMMaps[5] = {
- // ID IDc IDbytes PCMmap PCMc tmbrA tmbrAO, tmbrB tmbrBO, tmbrR trC rhythm rhyC rsrv panpot prog
- {0x4014, 22, "\000 ver1.04 14 July 87 ", 0x3000, 128, 0x8000, 0x0000, 0xC000, 0x4000, 0x3200, 30, 0x73A6, 85, 0x57C7, 0x57D0, 0x57E2}, // MT-32 revision 0
- {0x4014, 22, "\000 ver1.06 31 Aug, 87 ", 0x3000, 128, 0x8000, 0x0000, 0xC000, 0x4000, 0x3200, 30, 0x7414, 85, 0x57D9, 0x57E2, 0x57F4}, // MT-32 revision 0
- {0x4010, 22, "\000 ver1.07 10 Oct, 87 ", 0x3000, 128, 0x8000, 0x0000, 0xC000, 0x4000, 0x3200, 30, 0x73fe, 85, 0x57B1, 0x57BA, 0x57CC}, // MT-32 revision 1
- {0x4010, 22, "\000verX.XX 30 Sep, 88 ", 0x3000, 128, 0x8000, 0x0000, 0xC000, 0x4000, 0x3200, 30, 0x741C, 85, 0x57E5, 0x57EE, 0x5800}, // MT-32 Blue Ridge mod
- {0x2205, 22, "\000CM32/LAPC1.02 891205", 0x8100, 256, 0x8000, 0x8000, 0x8080, 0x8000, 0x8500, 64, 0x8580, 85, 0x4F93, 0x4F9C, 0x4FAE} // CM-32L
- // (Note that all but CM-32L ROM actually have 86 entries for rhythmTemp)
-};
-
-float iir_filter_normal(float input, float *hist1_ptr, float *coef_ptr) {
- float *hist2_ptr;
- float output,new_hist;
-
- hist2_ptr = hist1_ptr + 1; // next history
-
- // 1st number of coefficients array is overall input scale factor, or filter gain
- output = input * (*coef_ptr++);
-
- output = output - *hist1_ptr * (*coef_ptr++);
- new_hist = output - *hist2_ptr * (*coef_ptr++); // poles
-
- output = new_hist + *hist1_ptr * (*coef_ptr++);
- output = output + *hist2_ptr * (*coef_ptr++); // zeros
-
- *hist2_ptr++ = *hist1_ptr;
- *hist1_ptr++ = new_hist;
- hist1_ptr++;
- hist2_ptr++;
-
- // i = 1
- output = output - *hist1_ptr * (*coef_ptr++);
- new_hist = output - *hist2_ptr * (*coef_ptr++); // poles
-
- output = new_hist + *hist1_ptr * (*coef_ptr++);
- output = output + *hist2_ptr * (*coef_ptr++); // zeros
-
- *hist2_ptr++ = *hist1_ptr;
- *hist1_ptr++ = new_hist;
-
- return(output);
-}
-
-Bit8u Synth::calcSysexChecksum(const Bit8u *data, Bit32u len, Bit8u checksum) {
- for (unsigned int i = 0; i < len; i++) {
- checksum = checksum + data[i];
- }
- checksum = checksum & 0x7f;
- if (checksum)
- checksum = 0x80 - checksum;
- return checksum;
-}
-
-Synth::Synth() {
- isOpen = false;
- reverbModel = NULL;
- partialManager = NULL;
- memset(parts, 0, sizeof(parts));
-}
-
-Synth::~Synth() {
- close(); // Make sure we're closed and everything is freed
-}
-
-int Synth::report(ReportType type, const void *data) {
- if (myProp.report != NULL) {
- return myProp.report(myProp.userData, type, data);
- }
- return 0;
-}
-
-void Synth::printDebug(const char *fmt, ...) {
- va_list ap;
- va_start(ap, fmt);
- if (myProp.printDebug != NULL) {
- myProp.printDebug(myProp.userData, fmt, ap);
- } else {
- vprintf(fmt, ap);
- printf("\n");
- }
- va_end(ap);
-}
-
-void Synth::initReverb(Bit8u newRevMode, Bit8u newRevTime, Bit8u newRevLevel) {
- // FIXME:KG: I don't think it's necessary to recreate the reverbModel... Just set the parameters
- delete reverbModel;
- reverbModel = new revmodel();
-
- switch (newRevMode) {
- case 0:
- reverbModel->setroomsize(.1f);
- reverbModel->setdamp(.75f);
- break;
- case 1:
- reverbModel->setroomsize(.5f);
- reverbModel->setdamp(.5f);
- break;
- case 2:
- reverbModel->setroomsize(.5f);
- reverbModel->setdamp(.1f);
- break;
- case 3:
- reverbModel->setroomsize(1.0f);
- reverbModel->setdamp(.75f);
- break;
- default:
- reverbModel->setroomsize(.1f);
- reverbModel->setdamp(.5f);
- break;
- }
- reverbModel->setdry(1);
- reverbModel->setwet((float)newRevLevel / 8.0f);
- reverbModel->setwidth((float)newRevTime / 8.0f);
-}
-
-File *Synth::openFile(const char *filename, File::OpenMode mode) {
- // It should never happen that openFile is NULL in our use case.
- // Just to cover the case where something is horrible wrong we
- // use an assert here.
- assert(myProp.openFile != NULL);
- return myProp.openFile(myProp.userData, filename, mode);
-}
-
-void Synth::closeFile(File *file) {
- if (myProp.closeFile != NULL) {
- myProp.closeFile(myProp.userData, file);
- } else {
- file->close();
- delete file;
- }
-}
-
-bool Synth::loadPreset(File *file) {
- bool inSys = false;
- Bit8u sysexBuf[MAX_SYSEX_SIZE];
- Bit16u syslen = 0;
- bool rc = true;
- for (;;) {
- Bit8u c;
- if (!file->readBit8u(&c)) {
- if (!file->isEOF()) {
- rc = false;
- }
- break;
- }
- sysexBuf[syslen] = c;
- if (inSys) {
- syslen++;
- if (c == 0xF7) {
- playSysex(&sysexBuf[0], syslen);
- inSys = false;
- syslen = 0;
- } else if (syslen == MAX_SYSEX_SIZE) {
- printDebug("MAX_SYSEX_SIZE (%d) exceeded while processing preset, ignoring message", MAX_SYSEX_SIZE);
- inSys = false;
- syslen = 0;
- }
- } else if (c == 0xF0) {
- syslen++;
- inSys = true;
- }
- }
- return rc;
-}
-
-bool Synth::loadControlROM(const char *filename) {
- File *file = openFile(filename, File::OpenMode_read); // ROM File
- if (file == NULL) {
- return false;
- }
- bool rc = (file->read(controlROMData, CONTROL_ROM_SIZE) == CONTROL_ROM_SIZE);
-
- closeFile(file);
- if (!rc)
- return rc;
-
- // Control ROM successfully loaded, now check whether it's a known type
- controlROMMap = NULL;
- for (unsigned int i = 0; i < sizeof (ControlROMMaps) / sizeof (ControlROMMaps[0]); i++) {
- if (memcmp(&controlROMData[ControlROMMaps[i].idPos], ControlROMMaps[i].idBytes, ControlROMMaps[i].idLen) == 0) {
- controlROMMap = &ControlROMMaps[i];
- return true;
- }
- }
- return false;
-}
-
-bool Synth::loadPCMROM(const char *filename) {
- File *file = openFile(filename, File::OpenMode_read); // ROM File
- if (file == NULL) {
- return false;
- }
- bool rc = true;
- int i;
- for (i = 0; i < pcmROMSize; i++) {
- Bit8u s;
- if (!file->readBit8u(&s)) {
- if (!file->isEOF()) {
- rc = false;
- }
- break;
- }
- Bit8u c;
- if (!file->readBit8u(&c)) {
- if (!file->isEOF()) {
- rc = false;
- } else {
- printDebug("PCM ROM file has an odd number of bytes! Ignoring last");
- }
- break;
- }
-
- short e;
- int bit;
- int u;
- int order[16] = {0, 9, 1 ,2, 3, 4, 5, 6, 7, 10, 11, 12, 13, 14, 15, 8};
-
- e = 0;
- for (u = 0; u < 15; u++) {
- if (order[u] < 8)
- bit = (s >> (7 - order[u])) & 0x1;
- else
- bit = (c >> (7 - (order[u] - 8))) & 0x1;
- e = e | (short)(bit << (15 - u));
- }
-
- /*
- //Bit16s e = ( ((s & 0x7f) << 4) | ((c & 0x40) << 6) | ((s & 0x80) << 6) | ((c & 0x3f))) << 2;
- if (e<0)
- e = -32767 - e;
- int ut = abs(e);
- int dif = 0x7fff - ut;
- x = exp(((float)((float)0x8000-(float)dif) / (float)0x1000));
- e = (int)((float)e * (x/3200));
- */
-
- // File is companded (dB?), convert to linear PCM
- // MINDB = -96
- // MAXDB = -15
- float testval;
- testval = (float)((~e) & 0x7fff);
- testval = -(testval / 400.00f);
- //testval = -(testval / 341.32291666666666666666666666667);
- float vol = powf(8, testval / 20) * 32767.0f;
-
- if (e > 0)
- vol = -vol;
-
- pcmROMData[i] = (Bit16s)vol;
- }
- if (i != pcmROMSize) {
- printDebug("PCM ROM file is too short (expected %d, got %d)", pcmROMSize, i);
- rc = false;
- }
- closeFile(file);
- return rc;
-}
-
-bool Synth::initPCMList(Bit16u mapAddress, Bit16u count) {
- ControlROMPCMStruct *tps = (ControlROMPCMStruct *)&controlROMData[mapAddress];
- for (int i = 0; i < count; i++) {
- int rAddr = tps[i].pos * 0x800;
- int rLenExp = (tps[i].len & 0x70) >> 4;
- int rLen = 0x800 << rLenExp;
- bool rLoop = (tps[i].len & 0x80) != 0;
- //Bit8u rFlag = tps[i].len & 0x0F;
- Bit16u rTuneOffset = (tps[i].pitchMSB << 8) | tps[i].pitchLSB;
- // The number below is confirmed to a reasonable degree of accuracy on CM-32L
- double STANDARDFREQ = 442.0;
- float rTune = (float)(STANDARDFREQ * pow(2.0, (0x5000 - rTuneOffset) / 4056.0 - 9.0 / 12.0));
- //printDebug("%f,%d,%d", (double)pTune, tps[i].pitchCoarse, tps[i].pitchFine);
- if (rAddr + rLen > pcmROMSize) {
- printDebug("Control ROM error: Wave map entry %d points to invalid PCM address 0x%04X, length 0x%04X", i, rAddr, rLen);
- return false;
- }
- pcmWaves[i].addr = rAddr;
- pcmWaves[i].len = rLen;
- pcmWaves[i].loop = rLoop;
- pcmWaves[i].tune = rTune;
- }
- return false;
-}
-
-bool Synth::initRhythmTimbre(int timbreNum, const Bit8u *mem, unsigned int memLen) {
- if (memLen < sizeof(TimbreParam::commonParam)) {
- return false;
- }
- TimbreParam *timbre = &mt32ram.timbres[timbreNum].timbre;
- memcpy(&timbre->common, mem, 14);
- unsigned int memPos = 14;
- char drumname[11];
- memset(drumname, 0, 11);
- memcpy(drumname, timbre->common.name, 10);
- for (int t = 0; t < 4; t++) {
- if (((timbre->common.pmute >> t) & 0x1) == 0x1) {
- if (memPos + 58 >= memLen) {
- return false;
- }
- memcpy(&timbre->partial[t], mem + memPos, 58);
- memPos += 58;
- }
- }
- return true;
-}
-
-bool Synth::initRhythmTimbres(Bit16u mapAddress, Bit16u count) {
- const Bit8u *drumMap = &controlROMData[mapAddress];
- int timbreNum = 192;
- for (Bit16u i = 0; i < count * 2; i += 2) {
- Bit16u address = (drumMap[i + 1] << 8) | drumMap[i];
- /*
- // This check is nonsensical when the control ROM is the full 64KB addressable by 16-bit absolute pointers (which it is)
- if (address >= CONTROL_ROM_SIZE) {
- printDebug("Control ROM error: Timbre map entry 0x%04x points to invalid timbre address 0x%04x", i, address);
- return false;
- }
- */
- if (!initRhythmTimbre(timbreNum++, &controlROMData[address], CONTROL_ROM_SIZE - address)) {
- printDebug("Control ROM error: Timbre map entry 0x%04x points to invalid timbre 0x%04x", i, address);
- return false;
- }
- }
- return true;
-}
-
-bool Synth::initTimbres(Bit16u mapAddress, Bit16u offset, int startTimbre) {
- for (Bit16u i = mapAddress; i < mapAddress + 0x80; i += 2) {
- Bit16u address = (controlROMData[i + 1] << 8) | controlROMData[i];
- if (address + sizeof(TimbreParam) > CONTROL_ROM_SIZE) {
- printDebug("Control ROM error: Timbre map entry 0x%04x points to invalid timbre address 0x%04x", i, address);
- return false;
- }
- address = address + offset;
- TimbreParam *timbre = &mt32ram.timbres[startTimbre++].timbre;
- memcpy(timbre, &controlROMData[address], sizeof(TimbreParam));
- }
- return true;
-}
-
-bool Synth::open(SynthProperties &useProp) {
- if (isOpen)
- return false;
-
- myProp = useProp;
- if (useProp.baseDir != NULL) {
- myProp.baseDir = new char[strlen(useProp.baseDir) + 1];
- strcpy(myProp.baseDir, useProp.baseDir);
- }
-
- // This is to help detect bugs
- memset(&mt32ram, '?', sizeof(mt32ram));
-
- printDebug("Loading Control ROM");
- if (!loadControlROM("CM32L_CONTROL.ROM")) {
- if (!loadControlROM("MT32_CONTROL.ROM")) {
- printDebug("Init Error - Missing or invalid MT32_CONTROL.ROM");
- report(ReportType_errorControlROM, NULL);
- return false;
- }
- }
-
- // 512KB PCM ROM for MT-32, etc.
- // 1MB PCM ROM for CM-32L, LAPC-I, CM-64, CM-500
- // Note that the size below is given in samples (16-bit), not bytes
- pcmROMSize = controlROMMap->pcmCount == 256 ? 512 * 1024 : 256 * 1024;
- pcmROMData = new Bit16s[pcmROMSize];
-
- printDebug("Loading PCM ROM");
- if (!loadPCMROM("CM32L_PCM.ROM")) {
- if (!loadPCMROM("MT32_PCM.ROM")) {
- printDebug("Init Error - Missing MT32_PCM.ROM");
- report(ReportType_errorPCMROM, NULL);
- return false;
- }
- }
-
- printDebug("Initialising Timbre Bank A");
- if (!initTimbres(controlROMMap->timbreAMap, controlROMMap->timbreAOffset, 0)) {
- return false;
- }
-
- printDebug("Initialising Timbre Bank B");
- if (!initTimbres(controlROMMap->timbreBMap, controlROMMap->timbreBOffset, 64)) {
- return false;
- }
-
- printDebug("Initialising Timbre Bank R");
- if (!initRhythmTimbres(controlROMMap->timbreRMap, controlROMMap->timbreRCount)) {
- return false;
- }
-
- printDebug("Initialising Timbre Bank M");
- // CM-64 seems to initialise all bytes in this bank to 0.
- memset(&mt32ram.timbres[128], 0, sizeof (mt32ram.timbres[128]) * 64);
-
- partialManager = new PartialManager(this);
-
- pcmWaves = new PCMWaveEntry[controlROMMap->pcmCount];
-
- printDebug("Initialising PCM List");
- initPCMList(controlROMMap->pcmTable, controlROMMap->pcmCount);
-
- printDebug("Initialising Rhythm Temp");
- memcpy(mt32ram.rhythmSettings, &controlROMData[controlROMMap->rhythmSettings], controlROMMap->rhythmSettingsCount * 4);
-
- printDebug("Initialising Patches");
- for (Bit8u i = 0; i < 128; i++) {
- PatchParam *patch = &mt32ram.patches[i];
- patch->timbreGroup = i / 64;
- patch->timbreNum = i % 64;
- patch->keyShift = 24;
- patch->fineTune = 50;
- patch->benderRange = 12;
- patch->assignMode = 0;
- patch->reverbSwitch = 1;
- patch->dummy = 0;
- }
-
- printDebug("Initialising System");
- // The MT-32 manual claims that "Standard pitch" is 442Hz.
- mt32ram.system.masterTune = 0x40; // Confirmed on CM-64 as 0x4A, but SCUMM games use 0x40 and we don't want to initialise twice
- mt32ram.system.reverbMode = 0; // Confirmed
- mt32ram.system.reverbTime = 5; // Confirmed
- mt32ram.system.reverbLevel = 3; // Confirmed
- memcpy(mt32ram.system.reserveSettings, &controlROMData[controlROMMap->reserveSettings], 9); // Confirmed
- for (Bit8u i = 0; i < 9; i++) {
- // This is the default: {1, 2, 3, 4, 5, 6, 7, 8, 9}
- // An alternative configuration can be selected by holding "Master Volume"
- // and pressing "PART button 1" on the real MT-32's frontpanel.
- // The channel assignment is then {0, 1, 2, 3, 4, 5, 6, 7, 9}
- mt32ram.system.chanAssign[i] = i + 1;
- }
- mt32ram.system.masterVol = 100; // Confirmed
- if (!refreshSystem())
- return false;
-
- for (int i = 0; i < 8; i++) {
- mt32ram.patchSettings[i].outlevel = 80;
- mt32ram.patchSettings[i].panpot = controlROMData[controlROMMap->panSettings + i];
- memset(mt32ram.patchSettings[i].dummyv, 0, sizeof(mt32ram.patchSettings[i].dummyv));
- parts[i] = new Part(this, i);
- parts[i]->setProgram(controlROMData[controlROMMap->programSettings + i]);
- }
- parts[8] = new RhythmPart(this, 8);
-
- // For resetting mt32 mid-execution
- mt32default = mt32ram;
-
- iirFilter = &iir_filter_normal;
-
-#ifdef MT32EMU_HAVE_X86
- bool availableSSE = DetectSIMD();
- bool available3DNow = Detect3DNow();
-
- if (availableSSE)
- report(ReportType_availableSSE, NULL);
- if (available3DNow)
- report(ReportType_available3DNow, NULL);
-
- if (available3DNow) {
- printDebug("Detected and using SIMD (AMD 3DNow) extensions");
- iirFilter = &iir_filter_3dnow;
- report(ReportType_using3DNow, NULL);
- } else if (availableSSE) {
- printDebug("Detected and using SIMD (Intel SSE) extensions");
- iirFilter = &iir_filter_sse;
- report(ReportType_usingSSE, NULL);
- }
-#endif
-
- isOpen = true;
- isEnabled = false;
-
- printDebug("*** Initialisation complete ***");
- return true;
-}
-
-void Synth::close(void) {
- if (!isOpen)
- return;
-
- tables.freeNotes();
- if (partialManager != NULL) {
- delete partialManager;
- partialManager = NULL;
- }
-
- if (reverbModel != NULL) {
- delete reverbModel;
- reverbModel = NULL;
- }
-
- for (int i = 0; i < 9; i++) {
- if (parts[i] != NULL) {
- delete parts[i];
- parts[i] = NULL;
- }
- }
- if (myProp.baseDir != NULL) {
- delete myProp.baseDir;
- myProp.baseDir = NULL;
- }
-
- delete[] pcmWaves;
- delete[] pcmROMData;
- isOpen = false;
-}
-
-void Synth::playMsg(Bit32u msg) {
- // FIXME: Implement active sensing
- unsigned char code = (unsigned char)((msg & 0x0000F0) >> 4);
- unsigned char chan = (unsigned char) (msg & 0x00000F);
- unsigned char note = (unsigned char)((msg & 0x00FF00) >> 8);
- unsigned char velocity = (unsigned char)((msg & 0xFF0000) >> 16);
- isEnabled = true;
-
- //printDebug("Playing chan %d, code 0x%01x note: 0x%02x", chan, code, note);
-
- signed char part = chantable[chan];
- if (part < 0 || part > 8) {
- printDebug("Play msg on unreg chan %d (%d): code=0x%01x, vel=%d", chan, part, code, velocity);
- return;
- }
- playMsgOnPart(part, code, note, velocity);
-}
-
-void Synth::playMsgOnPart(unsigned char part, unsigned char code, unsigned char note, unsigned char velocity) {
- Bit32u bend;
-
- //printDebug("Synth::playMsg(0x%02x)",msg);
- switch (code) {
- case 0x8:
- //printDebug("Note OFF - Part %d", part);
- // The MT-32 ignores velocity for note off
- parts[part]->stopNote(note);
- break;
- case 0x9:
- //printDebug("Note ON - Part %d, Note %d Vel %d", part, note, velocity);
- if (velocity == 0) {
- // MIDI defines note-on with velocity 0 as being the same as note-off with velocity 40
- parts[part]->stopNote(note);
- } else {
- parts[part]->playNote(note, velocity);
- }
- break;
- case 0xB: // Control change
- switch (note) {
- case 0x01: // Modulation
- //printDebug("Modulation: %d", velocity);
- parts[part]->setModulation(velocity);
- break;
- case 0x07: // Set volume
- //printDebug("Volume set: %d", velocity);
- parts[part]->setVolume(velocity);
- break;
- case 0x0A: // Pan
- //printDebug("Pan set: %d", velocity);
- parts[part]->setPan(velocity);
- break;
- case 0x0B:
- //printDebug("Expression set: %d", velocity);
- parts[part]->setExpression(velocity);
- break;
- case 0x40: // Hold (sustain) pedal
- //printDebug("Hold pedal set: %d", velocity);
- parts[part]->setHoldPedal(velocity>=64);
- break;
-
- case 0x79: // Reset all controllers
- //printDebug("Reset all controllers");
- //FIXME: Check for accuracy against real thing
- parts[part]->setVolume(100);
- parts[part]->setExpression(127);
- parts[part]->setPan(64);
- parts[part]->setBend(0x2000);
- parts[part]->setHoldPedal(false);
- break;
-
- case 0x7B: // All notes off
- //printDebug("All notes off");
- parts[part]->allNotesOff();
- break;
-
- default:
- printDebug("Unknown MIDI Control code: 0x%02x - vel 0x%02x", note, velocity);
- break;
- }
-
- break;
- case 0xC: // Program change
- //printDebug("Program change %01x", note);
- parts[part]->setProgram(note);
- break;
- case 0xE: // Pitch bender
- bend = (velocity << 7) | (note);
- //printDebug("Pitch bender %02x", bend);
- parts[part]->setBend(bend);
- break;
- default:
- printDebug("Unknown Midi code: 0x%01x - %02x - %02x", code, note, velocity);
- break;
- }
-
- //midiOutShortMsg(m_out, msg);
-}
-
-void Synth::playSysex(const Bit8u *sysex, Bit32u len) {
- if (len < 2) {
- printDebug("playSysex: Message is too short for sysex (%d bytes)", len);
- }
- if (sysex[0] != 0xF0) {
- printDebug("playSysex: Message lacks start-of-sysex (0xF0)");
- return;
- }
- // Due to some programs (e.g. Java) sending buffers with junk at the end, we have to go through and find the end marker rather than relying on len.
- Bit32u endPos;
- for (endPos = 1; endPos < len; endPos++)
- {
- if (sysex[endPos] == 0xF7)
- break;
- }
- if (endPos == len) {
- printDebug("playSysex: Message lacks end-of-sysex (0xf7)");
- return;
- }
- playSysexWithoutFraming(sysex + 1, endPos - 1);
-}
-
-void Synth::playSysexWithoutFraming(const Bit8u *sysex, Bit32u len) {
- if (len < 4) {
- printDebug("playSysexWithoutFraming: Message is too short (%d bytes)!", len);
- return;
- }
- if (sysex[0] != SYSEX_MANUFACTURER_ROLAND) {
- printDebug("playSysexWithoutFraming: Header not intended for this device manufacturer: %02x %02x %02x %02x", (int)sysex[0], (int)sysex[1], (int)sysex[2], (int)sysex[3]);
- return;
- }
- if (sysex[2] == SYSEX_MDL_D50) {
- printDebug("playSysexWithoutFraming: Header is intended for model D-50 (not yet supported): %02x %02x %02x %02x", (int)sysex[0], (int)sysex[1], (int)sysex[2], (int)sysex[3]);
- return;
- }
- else if (sysex[2] != SYSEX_MDL_MT32) {
- printDebug("playSysexWithoutFraming: Header not intended for model MT-32: %02x %02x %02x %02x", (int)sysex[0], (int)sysex[1], (int)sysex[2], (int)sysex[3]);
- return;
- }
- playSysexWithoutHeader(sysex[1], sysex[3], sysex + 4, len - 4);
-}
-
-void Synth::playSysexWithoutHeader(unsigned char device, unsigned char command, const Bit8u *sysex, Bit32u len) {
- if (device > 0x10) {
- // We have device ID 0x10 (default, but changeable, on real MT-32), < 0x10 is for channels
- printDebug("playSysexWithoutHeader: Message is not intended for this device ID (provided: %02x, expected: 0x10 or channel)", (int)device);
- return;
- }
- if (len < 4) {
- printDebug("playSysexWithoutHeader: Message is too short (%d bytes)!", len);
- return;
- }
- unsigned char checksum = calcSysexChecksum(sysex, len - 1, 0);
- if (checksum != sysex[len - 1]) {
- printDebug("playSysexWithoutHeader: Message checksum is incorrect (provided: %02x, expected: %02x)!", sysex[len - 1], checksum);
- return;
- }
- len -= 1; // Exclude checksum
- switch (command) {
- case SYSEX_CMD_DT1:
- writeSysex(device, sysex, len);
- break;
- case SYSEX_CMD_RQ1:
- readSysex(device, sysex, len);
- break;
- default:
- printDebug("playSysexWithoutFraming: Unsupported command %02x", command);
- return;
- }
-}
-
-void Synth::readSysex(unsigned char /*device*/, const Bit8u * /*sysex*/, Bit32u /*len*/) {
-}
-
-const MemoryRegion memoryRegions[8] = {
- {MR_PatchTemp, MT32EMU_MEMADDR(0x030000), sizeof(MemParams::PatchTemp), 9},
- {MR_RhythmTemp, MT32EMU_MEMADDR(0x030110), sizeof(MemParams::RhythmTemp), 85},
- {MR_TimbreTemp, MT32EMU_MEMADDR(0x040000), sizeof(TimbreParam), 8},
- {MR_Patches, MT32EMU_MEMADDR(0x050000), sizeof(PatchParam), 128},
- {MR_Timbres, MT32EMU_MEMADDR(0x080000), sizeof(MemParams::PaddedTimbre), 64 + 64 + 64 + 64},
- {MR_System, MT32EMU_MEMADDR(0x100000), sizeof(MemParams::SystemArea), 1},
- {MR_Display, MT32EMU_MEMADDR(0x200000), MAX_SYSEX_SIZE - 1, 1},
- {MR_Reset, MT32EMU_MEMADDR(0x7F0000), 0x3FFF, 1}
-};
-
-const int NUM_REGIONS = sizeof(memoryRegions) / sizeof(MemoryRegion);
-
-void Synth::writeSysex(unsigned char device, const Bit8u *sysex, Bit32u len) {
- Bit32u addr = (sysex[0] << 16) | (sysex[1] << 8) | (sysex[2]);
- addr = MT32EMU_MEMADDR(addr);
- sysex += 3;
- len -= 3;
- //printDebug("Sysex addr: 0x%06x", MT32EMU_SYSEXMEMADDR(addr));
- // NOTE: Please keep both lower and upper bounds in each check, for ease of reading
-
- // Process channel-specific sysex by converting it to device-global
- if (device < 0x10) {
- printDebug("WRITE-CHANNEL: Channel %d temp area 0x%06x", device, MT32EMU_SYSEXMEMADDR(addr));
- if (/*addr >= MT32EMU_MEMADDR(0x000000) && */addr < MT32EMU_MEMADDR(0x010000)) {
- int offset;
- if (chantable[device] == -1) {
- printDebug(" (Channel not mapped to a partial... 0 offset)");
- offset = 0;
- } else if (chantable[device] == 8) {
- printDebug(" (Channel mapped to rhythm... 0 offset)");
- offset = 0;
- } else {
- offset = chantable[device] * sizeof(MemParams::PatchTemp);
- printDebug(" (Setting extra offset to %d)", offset);
- }
- addr += MT32EMU_MEMADDR(0x030000) + offset;
- } else if (/*addr >= 0x010000 && */ addr < MT32EMU_MEMADDR(0x020000)) {
- addr += MT32EMU_MEMADDR(0x030110) - MT32EMU_MEMADDR(0x010000);
- } else if (/*addr >= 0x020000 && */ addr < MT32EMU_MEMADDR(0x030000)) {
- int offset;
- if (chantable[device] == -1) {
- printDebug(" (Channel not mapped to a partial... 0 offset)");
- offset = 0;
- } else if (chantable[device] == 8) {
- printDebug(" (Channel mapped to rhythm... 0 offset)");
- offset = 0;
- } else {
- offset = chantable[device] * sizeof(TimbreParam);
- printDebug(" (Setting extra offset to %d)", offset);
- }
- addr += MT32EMU_MEMADDR(0x040000) - MT32EMU_MEMADDR(0x020000) + offset;
- } else {
- printDebug("PlaySysexWithoutHeader: Invalid channel %d address 0x%06x", device, MT32EMU_SYSEXMEMADDR(addr));
- return;
- }
- }
-
- // Process device-global sysex (possibly converted from channel-specific sysex above)
- for (;;) {
- // Find the appropriate memory region
- int regionNum;
- const MemoryRegion *region = NULL; // Initialised to please compiler
- for (regionNum = 0; regionNum < NUM_REGIONS; regionNum++) {
- region = &memoryRegions[regionNum];
- if (region->contains(addr)) {
- writeMemoryRegion(region, addr, region->getClampedLen(addr, len), sysex);
- break;
- }
- }
- if (regionNum == NUM_REGIONS) {
- printDebug("Sysex write to unrecognised address %06x, len %d", MT32EMU_SYSEXMEMADDR(addr), len);
- break;
- }
- Bit32u next = region->next(addr, len);
- if (next == 0) {
- break;
- }
- addr += next;
- sysex += next;
- len -= next;
- }
-}
-
-void Synth::readMemory(Bit32u addr, Bit32u len, Bit8u *data) {
- int regionNum;
- const MemoryRegion *region = NULL;
- for (regionNum = 0; regionNum < NUM_REGIONS; regionNum++) {
- region = &memoryRegions[regionNum];
- if (region->contains(addr)) {
- readMemoryRegion(region, addr, len, data);
- break;
- }
- }
-}
-
-void Synth::readMemoryRegion(const MemoryRegion *region, Bit32u addr, Bit32u len, Bit8u *data) {
- unsigned int first = region->firstTouched(addr);
- //unsigned int last = region->lastTouched(addr, len);
- unsigned int off = region->firstTouchedOffset(addr);
- len = region->getClampedLen(addr, len);
-
- unsigned int m;
-
- switch (region->type) {
- case MR_PatchTemp:
- for (m = 0; m < len; m++)
- data[m] = ((Bit8u *)&mt32ram.patchSettings[first])[off + m];
- break;
- case MR_RhythmTemp:
- for (m = 0; m < len; m++)
- data[m] = ((Bit8u *)&mt32ram.rhythmSettings[first])[off + m];
- break;
- case MR_TimbreTemp:
- for (m = 0; m < len; m++)
- data[m] = ((Bit8u *)&mt32ram.timbreSettings[first])[off + m];
- break;
- case MR_Patches:
- for (m = 0; m < len; m++)
- data[m] = ((Bit8u *)&mt32ram.patches[first])[off + m];
- break;
- case MR_Timbres:
- for (m = 0; m < len; m++)
- data[m] = ((Bit8u *)&mt32ram.timbres[first])[off + m];
- break;
- case MR_System:
- for (m = 0; m < len; m++)
- data[m] = ((Bit8u *)&mt32ram.system)[m + off];
- break;
- default:
- for (m = 0; m < len; m += 2) {
- data[m] = 0xff;
- if (m + 1 < len) {
- data[m+1] = (Bit8u)region->type;
- }
- }
- // TODO: Don't care about the others ATM
- break;
- }
-
-}
-
-void Synth::writeMemoryRegion(const MemoryRegion *region, Bit32u addr, Bit32u len, const Bit8u *data) {
- unsigned int first = region->firstTouched(addr);
- unsigned int last = region->lastTouched(addr, len);
- unsigned int off = region->firstTouchedOffset(addr);
- switch (region->type) {
- case MR_PatchTemp:
- for (unsigned int m = 0; m < len; m++) {
- ((Bit8u *)&mt32ram.patchSettings[first])[off + m] = data[m];
- }
- //printDebug("Patch temp: Patch %d, offset %x, len %d", off/16, off % 16, len);
-
- for (unsigned int i = first; i <= last; i++) {
- int absTimbreNum = mt32ram.patchSettings[i].patch.timbreGroup * 64 + mt32ram.patchSettings[i].patch.timbreNum;
- char timbreName[11];
- memcpy(timbreName, mt32ram.timbres[absTimbreNum].timbre.common.name, 10);
- timbreName[10] = 0;
- printDebug("WRITE-PARTPATCH (%d-%d@%d..%d): %d; timbre=%d (%s), outlevel=%d", first, last, off, off + len, i, absTimbreNum, timbreName, mt32ram.patchSettings[i].outlevel);
- if (parts[i] != NULL) {
- if (i != 8) {
- // Note: Confirmed on CM-64 that we definitely *should* update the timbre here,
- // but only in the case that the sysex actually writes to those values
- if (i == first && off > 2) {
- printDebug(" (Not updating timbre, since those values weren't touched)");
- } else {
- parts[i]->setTimbre(&mt32ram.timbres[parts[i]->getAbsTimbreNum()].timbre);
- }
- }
- parts[i]->refresh();
- }
- }
- break;
- case MR_RhythmTemp:
- for (unsigned int m = 0; m < len; m++)
- ((Bit8u *)&mt32ram.rhythmSettings[first])[off + m] = data[m];
- for (unsigned int i = first; i <= last; i++) {
- int timbreNum = mt32ram.rhythmSettings[i].timbre;
- char timbreName[11];
- if (timbreNum < 94) {
- memcpy(timbreName, mt32ram.timbres[128 + timbreNum].timbre.common.name, 10);
- timbreName[10] = 0;
- } else {
- strcpy(timbreName, "[None]");
- }
- printDebug("WRITE-RHYTHM (%d-%d@%d..%d): %d; level=%02x, panpot=%02x, reverb=%02x, timbre=%d (%s)", first, last, off, off + len, i, mt32ram.rhythmSettings[i].outlevel, mt32ram.rhythmSettings[i].panpot, mt32ram.rhythmSettings[i].reverbSwitch, mt32ram.rhythmSettings[i].timbre, timbreName);
- }
- if (parts[8] != NULL) {
- parts[8]->refresh();
- }
- break;
- case MR_TimbreTemp:
- for (unsigned int m = 0; m < len; m++)
- ((Bit8u *)&mt32ram.timbreSettings[first])[off + m] = data[m];
- for (unsigned int i = first; i <= last; i++) {
- char instrumentName[11];
- memcpy(instrumentName, mt32ram.timbreSettings[i].common.name, 10);
- instrumentName[10] = 0;
- printDebug("WRITE-PARTTIMBRE (%d-%d@%d..%d): timbre=%d (%s)", first, last, off, off + len, i, instrumentName);
- if (parts[i] != NULL) {
- parts[i]->refresh();
- }
- }
- break;
- case MR_Patches:
- for (unsigned int m = 0; m < len; m++)
- ((Bit8u *)&mt32ram.patches[first])[off + m] = data[m];
- for (unsigned int i = first; i <= last; i++) {
- PatchParam *patch = &mt32ram.patches[i];
- int patchAbsTimbreNum = patch->timbreGroup * 64 + patch->timbreNum;
- char instrumentName[11];
- memcpy(instrumentName, mt32ram.timbres[patchAbsTimbreNum].timbre.common.name, 10);
- instrumentName[10] = 0;
- Bit8u *n = (Bit8u *)patch;
- printDebug("WRITE-PATCH (%d-%d@%d..%d): %d; timbre=%d (%s) %02X%02X%02X%02X%02X%02X%02X%02X", first, last, off, off + len, i, patchAbsTimbreNum, instrumentName, n[0], n[1], n[2], n[3], n[4], n[5], n[6], n[7]);
- // FIXME:KG: The below is definitely dodgy. We just guess that this is the patch that the part was using
- // based on a timbre match (but many patches could have the same timbre!)
- // If this refresh is really correct, we should store the patch number in use by each part.
- /*
- for (int part = 0; part < 8; part++) {
- if (parts[part] != NULL) {
- int partPatchAbsTimbreNum = mt32ram.patchSettings[part].patch.timbreGroup * 64 + mt32ram.patchSettings[part].patch.timbreNum;
- if (parts[part]->getAbsTimbreNum() == patchAbsTimbreNum) {
- parts[part]->setPatch(patch);
- parts[part]->RefreshPatch();
- }
- }
- }
- */
- }
- break;
- case MR_Timbres:
- // Timbres
- first += 128;
- last += 128;
- for (unsigned int m = 0; m < len; m++)
- ((Bit8u *)&mt32ram.timbres[first])[off + m] = data[m];
- for (unsigned int i = first; i <= last; i++) {
- char instrumentName[11];
- memcpy(instrumentName, mt32ram.timbres[i].timbre.common.name, 10);
- instrumentName[10] = 0;
- printDebug("WRITE-TIMBRE (%d-%d@%d..%d): %d; name=\"%s\"", first, last, off, off + len, i, instrumentName);
- // FIXME:KG: Not sure if the stuff below should be done (for rhythm and/or parts)...
- // Does the real MT-32 automatically do this?
- for (unsigned int part = 0; part < 9; part++) {
- if (parts[part] != NULL) {
- parts[part]->refreshTimbre(i);
- }
- }
- }
- break;
- case MR_System:
- for (unsigned int m = 0; m < len; m++)
- ((Bit8u *)&mt32ram.system)[m + off] = data[m];
-
- report(ReportType_devReconfig, NULL);
-
- printDebug("WRITE-SYSTEM:");
- refreshSystem();
- break;
- case MR_Display:
- char buf[MAX_SYSEX_SIZE];
- memcpy(&buf, &data[0], len);
- buf[len] = 0;
- printDebug("WRITE-LCD: %s", buf);
- report(ReportType_lcdMessage, buf);
- break;
- case MR_Reset:
- printDebug("RESET");
- report(ReportType_devReset, NULL);
- partialManager->deactivateAll();
- mt32ram = mt32default;
- for (int i = 0; i < 9; i++) {
- parts[i]->refresh();
- }
- isEnabled = false;
- break;
- }
-}
-
-bool Synth::refreshSystem() {
- memset(chantable, -1, sizeof(chantable));
-
- for (unsigned int i = 0; i < 9; i++) {
- //LOG(LOG_MISC|LOG_ERROR,"Part %d set to MIDI channel %d",i,mt32ram.system.chanAssign[i]);
- if (mt32ram.system.chanAssign[i] == 16 && parts[i] != NULL) {
- parts[i]->allSoundOff();
- } else {
- chantable[(int)mt32ram.system.chanAssign[i]] = (char)i;
- }
- }
- //FIXME:KG: This is just an educated guess.
- // The LAPC-I documentation claims a range of 427.5Hz-452.6Hz (similar to what we have here)
- // The MT-32 documentation claims a range of 432.1Hz-457.6Hz
- masterTune = 440.0f * powf(2.0f, (mt32ram.system.masterTune - 64.0f) / (128.0f * 12.0f));
- printDebug(" Master Tune: %f", (double)masterTune);
- printDebug(" Reverb: mode=%d, time=%d, level=%d", mt32ram.system.reverbMode, mt32ram.system.reverbTime, mt32ram.system.reverbLevel);
- report(ReportType_newReverbMode, &mt32ram.system.reverbMode);
- report(ReportType_newReverbTime, &mt32ram.system.reverbTime);
- report(ReportType_newReverbLevel, &mt32ram.system.reverbLevel);
-
- if (myProp.useDefaultReverb) {
- initReverb(mt32ram.system.reverbMode, mt32ram.system.reverbTime, mt32ram.system.reverbLevel);
- } else {
- initReverb(myProp.reverbType, myProp.reverbTime, mt32ram.system.reverbLevel);
- }
-
- Bit8u *rset = mt32ram.system.reserveSettings;
- printDebug(" Partial reserve: 1=%02d 2=%02d 3=%02d 4=%02d 5=%02d 6=%02d 7=%02d 8=%02d Rhythm=%02d", rset[0], rset[1], rset[2], rset[3], rset[4], rset[5], rset[6], rset[7], rset[8]);
- int pr = partialManager->setReserve(rset);
- if (pr != 32)
- printDebug(" (Partial Reserve Table with less than 32 partials reserved!)");
- rset = mt32ram.system.chanAssign;
- printDebug(" Part assign: 1=%02d 2=%02d 3=%02d 4=%02d 5=%02d 6=%02d 7=%02d 8=%02d Rhythm=%02d", rset[0], rset[1], rset[2], rset[3], rset[4], rset[5], rset[6], rset[7], rset[8]);
- printDebug(" Master volume: %d", mt32ram.system.masterVol);
- masterVolume = (Bit16u)(mt32ram.system.masterVol * 32767 / 100);
- if (!tables.init(this, pcmWaves, (float)myProp.sampleRate, masterTune)) {
- report(ReportType_errorSampleRate, NULL);
- return false;
- }
- return true;
-}
-
-bool Synth::dumpTimbre(File *file, const TimbreParam *timbre, Bit32u address) {
- // Sysex header
- if (!file->writeBit8u(0xF0))
- return false;
- if (!file->writeBit8u(0x41))
- return false;
- if (!file->writeBit8u(0x10))
- return false;
- if (!file->writeBit8u(0x16))
- return false;
- if (!file->writeBit8u(0x12))
- return false;
-
- char lsb = (char)(address & 0x7f);
- char isb = (char)((address >> 7) & 0x7f);
- char msb = (char)(((address >> 14) & 0x7f) | 0x08);
-
- //Address
- if (!file->writeBit8u(msb))
- return false;
- if (!file->writeBit8u(isb))
- return false;
- if (!file->writeBit8u(lsb))
- return false;
-
- //Data
- if (file->write(timbre, 246) != 246)
- return false;
-
- //Checksum
- unsigned char checksum = calcSysexChecksum((const Bit8u *)timbre, 246, msb + isb + lsb);
- if (!file->writeBit8u(checksum))
- return false;
-
- //End of sysex
- if (!file->writeBit8u(0xF7))
- return false;
- return true;
-}
-
-int Synth::dumpTimbres(const char *filename, int start, int len) {
- File *file = openFile(filename, File::OpenMode_write);
- if (file == NULL)
- return -1;
-
- for (int timbreNum = start; timbreNum < start + len; timbreNum++) {
- int useaddr = (timbreNum - start) * 256;
- TimbreParam *timbre = &mt32ram.timbres[timbreNum].timbre;
- if (!dumpTimbre(file, timbre, useaddr))
- break;
- }
- closeFile(file);
- return 0;
-}
-
-void ProduceOutput1(Bit16s *useBuf, Bit16s *stream, Bit32u len, Bit16s volume) {
-#if MT32EMU_USE_MMX > 2
- //FIXME:KG: This appears to introduce crackle
- int donelen = i386_produceOutput1(useBuf, stream, len, volume);
- len -= donelen;
- stream += donelen * 2;
- useBuf += donelen * 2;
-#endif
- int end = len * 2;
- while (end--) {
- *stream = *stream + (Bit16s)(((Bit32s)*useBuf++ * (Bit32s)volume)>>15);
- stream++;
- }
-}
-
-void Synth::render(Bit16s *stream, Bit32u len) {
- memset(stream, 0, len * sizeof (Bit16s) * 2);
- if (!isEnabled)
- return;
- while (len > 0) {
- Bit32u thisLen = len > MAX_SAMPLE_OUTPUT ? MAX_SAMPLE_OUTPUT : len;
- doRender(stream, thisLen);
- len -= thisLen;
- stream += 2 * thisLen;
- }
-}
-
-void Synth::doRender(Bit16s *stream, Bit32u len) {
- partialManager->ageAll();
-
- if (myProp.useReverb) {
- for (unsigned int i = 0; i < MT32EMU_MAX_PARTIALS; i++) {
- if (partialManager->shouldReverb(i)) {
- if (partialManager->produceOutput(i, &tmpBuffer[0], len)) {
- ProduceOutput1(&tmpBuffer[0], stream, len, masterVolume);
- }
- }
- }
- Bit32u m = 0;
- for (unsigned int i = 0; i < len; i++) {
- sndbufl[i] = (float)stream[m] / 32767.0f;
- m++;
- sndbufr[i] = (float)stream[m] / 32767.0f;
- m++;
- }
- reverbModel->processreplace(sndbufl, sndbufr, outbufl, outbufr, len, 1);
- m=0;
- for (unsigned int i = 0; i < len; i++) {
- stream[m] = (Bit16s)(outbufl[i] * 32767.0f);
- m++;
- stream[m] = (Bit16s)(outbufr[i] * 32767.0f);
- m++;
- }
- for (unsigned int i = 0; i < MT32EMU_MAX_PARTIALS; i++) {
- if (!partialManager->shouldReverb(i)) {
- if (partialManager->produceOutput(i, &tmpBuffer[0], len)) {
- ProduceOutput1(&tmpBuffer[0], stream, len, masterVolume);
- }
- }
- }
- } else {
- for (unsigned int i = 0; i < MT32EMU_MAX_PARTIALS; i++) {
- if (partialManager->produceOutput(i, &tmpBuffer[0], len))
- ProduceOutput1(&tmpBuffer[0], stream, len, masterVolume);
- }
- }
-
- partialManager->clearAlreadyOutputed();
-
-#if MT32EMU_MONITOR_PARTIALS == 1
- samplepos += len;
- if (samplepos > myProp.SampleRate * 5) {
- samplepos = 0;
- int partialUsage[9];
- partialManager->GetPerPartPartialUsage(partialUsage);
- printDebug("1:%02d 2:%02d 3:%02d 4:%02d 5:%02d 6:%02d 7:%02d 8:%02d", partialUsage[0], partialUsage[1], partialUsage[2], partialUsage[3], partialUsage[4], partialUsage[5], partialUsage[6], partialUsage[7]);
- printDebug("Rhythm: %02d TOTAL: %02d", partialUsage[8], MT32EMU_MAX_PARTIALS - partialManager->GetFreePartialCount());
- }
-#endif
-}
-
-const Partial *Synth::getPartial(unsigned int partialNum) const {
- return partialManager->getPartial(partialNum);
-}
-
-const Part *Synth::getPart(unsigned int partNum) const {
- if (partNum > 8)
- return NULL;
- return parts[partNum];
-}
-
-}
diff --git a/sound/softsynth/mt32/synth.h b/sound/softsynth/mt32/synth.h
deleted file mode 100644
index 3fc303d322..0000000000
--- a/sound/softsynth/mt32/synth.h
+++ /dev/null
@@ -1,300 +0,0 @@
-/* Copyright (c) 2003-2005 Various contributors
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- * IN THE SOFTWARE.
- */
-
-#ifndef MT32EMU_SYNTH_H
-#define MT32EMU_SYNTH_H
-
-#include "common/scummsys.h"
-
-class revmodel;
-
-namespace MT32Emu {
-
-class File;
-class TableInitialiser;
-class Partial;
-class PartialManager;
-class Part;
-
-enum ReportType {
- // Errors
- ReportType_errorControlROM = 1,
- ReportType_errorPCMROM,
- ReportType_errorSampleRate,
-
- // Progress
- ReportType_progressInit,
-
- // HW spec
- ReportType_availableSSE,
- ReportType_available3DNow,
- ReportType_usingSSE,
- ReportType_using3DNow,
-
- // General info
- ReportType_lcdMessage,
- ReportType_devReset,
- ReportType_devReconfig,
- ReportType_newReverbMode,
- ReportType_newReverbTime,
- ReportType_newReverbLevel
-};
-
-struct SynthProperties {
- // Sample rate to use in mixing
- int sampleRate;
-
- // Flag to activate reverb. True = use reverb, False = no reverb
- bool useReverb;
- // True to use software set reverb settings, False to set reverb settings in
- // following parameters
- bool useDefaultReverb;
- // When not using the default settings, this specifies one of the 4 reverb types
- // 1 = Room 2 = Hall 3 = Plate 4 = Tap
- unsigned char reverbType;
- // This specifies the delay time, from 0-7 (not sure of the actual MT-32's measurement)
- unsigned char reverbTime;
- // This specifies the reverb level, from 0-7 (not sure of the actual MT-32's measurement)
- unsigned char reverbLevel;
- // The name of the directory in which the ROM and data files are stored (with trailing slash/backslash)
- // Not used if "openFile" is set. May be NULL in any case.
- char *baseDir;
- // This is used as the first argument to all callbacks
- void *userData;
- // Callback for reporting various errors and information. May be NULL
- int (*report)(void *userData, ReportType type, const void *reportData);
- // Callback for debug messages, in vprintf() format
- void (*printDebug)(void *userData, const char *fmt, va_list list);
- // Callback for providing an implementation of File, opened and ready for use
- // May be NULL, in which case a default implementation will be used.
- File *(*openFile)(void *userData, const char *filename, File::OpenMode mode);
- // Callback for closing a File. May be NULL, in which case the File will automatically be close()d/deleted.
- void (*closeFile)(void *userData, File *file);
-};
-
-// This is the specification of the Callback routine used when calling the RecalcWaveforms
-// function
-typedef void (*recalcStatusCallback)(int percDone);
-
-// This external function recreates the base waveform file (waveforms.raw) using a specifed
-// sampling rate. The callback routine provides interactivity to let the user know what
-// percentage is complete in regenerating the waveforms. When a NULL pointer is used as the
-// callback routine, no status is reported.
-bool RecalcWaveforms(char * baseDir, int sampRate, recalcStatusCallback callBack);
-
-typedef float (*iir_filter_type)(float input,float *hist1_ptr, float *coef_ptr);
-
-const Bit8u SYSEX_MANUFACTURER_ROLAND = 0x41;
-
-const Bit8u SYSEX_MDL_MT32 = 0x16;
-const Bit8u SYSEX_MDL_D50 = 0x14;
-
-const Bit8u SYSEX_CMD_RQ1 = 0x11; // Request data #1
-const Bit8u SYSEX_CMD_DT1 = 0x12; // Data set 1
-const Bit8u SYSEX_CMD_WSD = 0x40; // Want to send data
-const Bit8u SYSEX_CMD_RQD = 0x41; // Request data
-const Bit8u SYSEX_CMD_DAT = 0x42; // Data set
-const Bit8u SYSEX_CMD_ACK = 0x43; // Acknowledge
-const Bit8u SYSEX_CMD_EOD = 0x45; // End of data
-const Bit8u SYSEX_CMD_ERR = 0x4E; // Communications error
-const Bit8u SYSEX_CMD_RJC = 0x4F; // Rejection
-
-const unsigned int CONTROL_ROM_SIZE = 64 * 1024;
-
-struct ControlROMPCMStruct
-{
- Bit8u pos;
- Bit8u len;
- Bit8u pitchLSB;
- Bit8u pitchMSB;
-};
-
-struct ControlROMMap {
- Bit16u idPos;
- Bit16u idLen;
- const char *idBytes;
- Bit16u pcmTable;
- Bit16u pcmCount;
- Bit16u timbreAMap;
- Bit16u timbreAOffset;
- Bit16u timbreBMap;
- Bit16u timbreBOffset;
- Bit16u timbreRMap;
- Bit16u timbreRCount;
- Bit16u rhythmSettings;
- Bit16u rhythmSettingsCount;
- Bit16u reserveSettings;
- Bit16u panSettings;
- Bit16u programSettings;
-};
-
-enum MemoryRegionType {
- MR_PatchTemp, MR_RhythmTemp, MR_TimbreTemp, MR_Patches, MR_Timbres, MR_System, MR_Display, MR_Reset
-};
-
-class MemoryRegion {
-public:
- MemoryRegionType type;
- Bit32u startAddr, entrySize, entries;
-
- int lastTouched(Bit32u addr, Bit32u len) const {
- return (offset(addr) + len - 1) / entrySize;
- }
- int firstTouchedOffset(Bit32u addr) const {
- return offset(addr) % entrySize;
- }
- int firstTouched(Bit32u addr) const {
- return offset(addr) / entrySize;
- }
- Bit32u regionEnd() const {
- return startAddr + entrySize * entries;
- }
- bool contains(Bit32u addr) const {
- return addr >= startAddr && addr < regionEnd();
- }
- int offset(Bit32u addr) const {
- return addr - startAddr;
- }
- Bit32u getClampedLen(Bit32u addr, Bit32u len) const {
- if (addr + len > regionEnd())
- return regionEnd() - addr;
- return len;
- }
- Bit32u next(Bit32u addr, Bit32u len) const {
- if (addr + len > regionEnd()) {
- return regionEnd() - addr;
- }
- return 0;
- }
-};
-
-
-class Synth {
-friend class Part;
-friend class RhythmPart;
-friend class Partial;
-friend class Tables;
-private:
- bool isEnabled;
-
- iir_filter_type iirFilter;
-
- PCMWaveEntry *pcmWaves; // Array
-
- const ControlROMMap *controlROMMap;
- Bit8u controlROMData[CONTROL_ROM_SIZE];
- Bit16s *pcmROMData;
- int pcmROMSize; // This is in 16-bit samples, therefore half the number of bytes in the ROM
-
- Bit8s chantable[32];
-
- #if MT32EMU_MONITOR_PARTIALS == 1
- static Bit32s samplepos = 0;
- #endif
-
- Tables tables;
-
- MemParams mt32ram, mt32default;
-
- revmodel *reverbModel;
-
- float masterTune;
- Bit16u masterVolume;
-
- bool isOpen;
-
- PartialManager *partialManager;
- Part *parts[9];
-
- Bit16s tmpBuffer[MAX_SAMPLE_OUTPUT * 2];
- float sndbufl[MAX_SAMPLE_OUTPUT];
- float sndbufr[MAX_SAMPLE_OUTPUT];
- float outbufl[MAX_SAMPLE_OUTPUT];
- float outbufr[MAX_SAMPLE_OUTPUT];
-
- SynthProperties myProp;
-
- bool loadPreset(File *file);
- void initReverb(Bit8u newRevMode, Bit8u newRevTime, Bit8u newRevLevel);
- void doRender(Bit16s * stream, Bit32u len);
-
- void playAddressedSysex(unsigned char channel, const Bit8u *sysex, Bit32u len);
- void readSysex(unsigned char channel, const Bit8u *sysex, Bit32u len);
- void writeMemoryRegion(const MemoryRegion *region, Bit32u addr, Bit32u len, const Bit8u *data);
- void readMemoryRegion(const MemoryRegion *region, Bit32u addr, Bit32u len, Bit8u *data);
-
- bool loadControlROM(const char *filename);
- bool loadPCMROM(const char *filename);
- bool dumpTimbre(File *file, const TimbreParam *timbre, Bit32u addr);
- int dumpTimbres(const char *filename, int start, int len);
-
- bool initPCMList(Bit16u mapAddress, Bit16u count);
- bool initRhythmTimbres(Bit16u mapAddress, Bit16u count);
- bool initTimbres(Bit16u mapAddress, Bit16u offset, int startTimbre);
- bool initRhythmTimbre(int drumNum, const Bit8u *mem, unsigned int memLen);
- bool refreshSystem();
-
-protected:
- int report(ReportType type, const void *reportData);
- File *openFile(const char *filename, File::OpenMode mode);
- void closeFile(File *file);
- void printDebug(const char *fmt, ...) GCC_PRINTF(2, 3);
-
-public:
- static Bit8u calcSysexChecksum(const Bit8u *data, Bit32u len, Bit8u checksum);
-
- Synth();
- ~Synth();
-
- // Used to initialise the MT-32. Must be called before any other function.
- // Returns true if initialization was sucessful, otherwise returns false.
- bool open(SynthProperties &useProp);
-
- // Closes the MT-32 and deallocates any memory used by the synthesizer
- void close(void);
-
- // Sends a 4-byte MIDI message to the MT-32 for immediate playback
- void playMsg(Bit32u msg);
- void playMsgOnPart(unsigned char part, unsigned char code, unsigned char note, unsigned char velocity);
-
- // Sends a string of Sysex commands to the MT-32 for immediate interpretation
- // The length is in bytes
- void playSysex(const Bit8u *sysex, Bit32u len);
- void playSysexWithoutFraming(const Bit8u *sysex, Bit32u len);
- void playSysexWithoutHeader(unsigned char device, unsigned char command, const Bit8u *sysex, Bit32u len);
- void writeSysex(unsigned char channel, const Bit8u *sysex, Bit32u len);
-
- // This callback routine is used to have the MT-32 generate samples to the specified
- // output stream. The length is in whole samples, not bytes. (I.E. in 16-bit stereo,
- // one sample is 4 bytes)
- void render(Bit16s * stream, Bit32u len);
-
- const Partial *getPartial(unsigned int partialNum) const;
-
- void readMemory(Bit32u addr, Bit32u len, Bit8u *data);
-
- // partNum should be 0..7 for Part 1..8, or 8 for Rhythm
- const Part *getPart(unsigned int partNum) const;
-};
-
-}
-
-#endif
diff --git a/sound/softsynth/mt32/tables.cpp b/sound/softsynth/mt32/tables.cpp
deleted file mode 100644
index eba4d2a520..0000000000
--- a/sound/softsynth/mt32/tables.cpp
+++ /dev/null
@@ -1,757 +0,0 @@
-/* Copyright (c) 2003-2005 Various contributors
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- * IN THE SOFTWARE.
- */
-
-#include <stdlib.h>
-#include <string.h>
-#include <math.h>
-
-#include "mt32emu.h"
-
-#if defined(MACOSX) || defined(SOLARIS) || defined(__MINGW32__)
-// Older versions of Mac OS X didn't supply a powf function, so using it
-// will cause a binary incompatibility when trying to run a binary built
-// on a newer OS X release on an olderr one. And Solaris 8 doesn't provide
-// powf, floorf, fabsf etc. at all.
-// Cross-compiled MinGW32 toolchains suffer from a cross-compile bug in
-// libstdc++. math/stubs.o should be empty, but it comes with a symbol for
-// powf, resulting in a linker error because of multiple definitions.
-// Hence we re-define them here. The only potential drawback is that it
-// might be a little bit slower this way.
-#define powf(x,y) ((float)pow(x,y))
-#define floorf(x) ((float)floor(x))
-#define fabsf(x) ((float)fabs(x))
-#endif
-
-#define FIXEDPOINT_MAKE(x, point) ((Bit32u)((1 << point) * x))
-
-namespace MT32Emu {
-
-//Amplitude time velocity follow exponential coefficients
-static const double tvcatconst[5] = {0.0, 0.002791309, 0.005942882, 0.012652792, 0.026938637};
-static const double tvcatmult[5] = {1.0, 1.072662811, 1.169129367, 1.288579123, 1.229630539};
-
-// These are division constants for the TVF depth key follow
-static const Bit32u depexp[5] = {3000, 950, 485, 255, 138};
-
-//Envelope time keyfollow exponential coefficients
-static const double tkcatconst[5] = {0.0, 0.005853144, 0.011148054, 0.019086143, 0.043333215};
-static const double tkcatmult[5] = {1.0, 1.058245688, 1.048488989, 1.016049301, 1.097538067};
-
-// Begin filter stuff
-
-// Pre-warp the coefficients of a numerator or denominator.
-// Note that a0 is assumed to be 1, so there is no wrapping
-// of it.
-static void prewarp(double *a1, double *a2, double fc, double fs) {
- double wp;
-
- wp = 2.0 * fs * tan(DOUBLE_PI * fc / fs);
-
- *a2 = *a2 / (wp * wp);
- *a1 = *a1 / wp;
-}
-
-// Transform the numerator and denominator coefficients
-// of s-domain biquad section into corresponding
-// z-domain coefficients.
-//
-// Store the 4 IIR coefficients in array pointed by coef
-// in following order:
-// beta1, beta2 (denominator)
-// alpha1, alpha2 (numerator)
-//
-// Arguments:
-// a0-a2 - s-domain numerator coefficients
-// b0-b2 - s-domain denominator coefficients
-// k - filter gain factor. initially set to 1
-// and modified by each biquad section in such
-// a way, as to make it the coefficient by
-// which to multiply the overall filter gain
-// in order to achieve a desired overall filter gain,
-// specified in initial value of k.
-// fs - sampling rate (Hz)
-// coef - array of z-domain coefficients to be filled in.
-//
-// Return:
-// On return, set coef z-domain coefficients
-static void bilinear(double a0, double a1, double a2, double b0, double b1, double b2, double *k, double fs, float *coef) {
- double ad, bd;
-
- // alpha (Numerator in s-domain)
- ad = 4. * a2 * fs * fs + 2. * a1 * fs + a0;
- // beta (Denominator in s-domain)
- bd = 4. * b2 * fs * fs + 2. * b1* fs + b0;
-
- // update gain constant for this section
- *k *= ad/bd;
-
- // Denominator
- *coef++ = (float)((2. * b0 - 8. * b2 * fs * fs) / bd); // beta1
- *coef++ = (float)((4. * b2 * fs * fs - 2. * b1 * fs + b0) / bd); // beta2
-
- // Nominator
- *coef++ = (float)((2. * a0 - 8. * a2 * fs * fs) / ad); // alpha1
- *coef = (float)((4. * a2 * fs * fs - 2. * a1 * fs + a0) / ad); // alpha2
-}
-
-// a0-a2: numerator coefficients
-// b0-b2: denominator coefficients
-// fc: Filter cutoff frequency
-// fs: sampling rate
-// k: overall gain factor
-// coef: pointer to 4 iir coefficients
-static void szxform(double *a0, double *a1, double *a2, double *b0, double *b1, double *b2, double fc, double fs, double *k, float *coef) {
- // Calculate a1 and a2 and overwrite the original values
- prewarp(a1, a2, fc, fs);
- prewarp(b1, b2, fc, fs);
- bilinear(*a0, *a1, *a2, *b0, *b1, *b2, k, fs, coef);
-}
-
-static void initFilter(float fs, float fc, float *icoeff, float Q) {
- float *coef;
- double a0, a1, a2, b0, b1, b2;
-
- double k = 1.5; // Set overall filter gain factor
- coef = icoeff + 1; // Skip k, or gain
-
- // Section 1
- a0 = 1.0;
- a1 = 0;
- a2 = 0;
- b0 = 1.0;
- b1 = 0.765367 / Q; // Divide by resonance or Q
- b2 = 1.0;
- szxform(&a0, &a1, &a2, &b0, &b1, &b2, fc, fs, &k, coef);
- coef += 4; // Point to next filter section
-
- // Section 2
- a0 = 1.0;
- a1 = 0;
- a2 = 0;
- b0 = 1.0;
- b1 = 1.847759 / Q;
- b2 = 1.0;
- szxform(&a0, &a1, &a2, &b0, &b1, &b2, fc, fs, &k, coef);
-
- icoeff[0] = (float)k;
-}
-
-void Tables::initFiltCoeff(float samplerate) {
- for (int j = 0; j < FILTERGRAN; j++) {
- for (int res = 0; res < 31; res++) {
- float tres = resonanceFactor[res];
- initFilter((float)samplerate, (((float)(j+1.0)/FILTERGRAN)) * ((float)samplerate/2), filtCoeff[j][res], tres);
- }
- }
-}
-
-void Tables::initEnvelopes(float samplerate) {
- for (int lf = 0; lf <= 100; lf++) {
- float elf = (float)lf;
-
- // General envelope
- // This formula fits observation of the CM-32L by +/- 0.03s or so for the second time value in the filter,
- // when all other times were 0 and all levels were 100. Note that variations occur depending on the level
- // delta of the section, which we're not fully emulating.
- float seconds = powf(2.0f, (elf / 8.0f) + 7.0f) / 32768.0f;
- int samples = (int)(seconds * samplerate);
- envTime[lf] = samples;
-
- // Cap on envelope times depending on the level delta
- if (elf == 0) {
- envDeltaMaxTime[lf] = 63;
- } else {
- float cap = 11.0f * (float)log(elf) + 64;
- if (cap > 100.0f) {
- cap = 100.0f;
- }
- envDeltaMaxTime[lf] = (int)cap;
- }
-
-
- // This (approximately) represents the time durations when the target level is 0.
- // Not sure why this is a special case, but it's seen to be from the real thing.
- seconds = powf(2, (elf / 8.0f) + 6) / 32768.0f;
- envDecayTime[lf] = (int)(seconds * samplerate);
-
- // I am certain of this: Verified by hand LFO log
- lfoPeriod[lf] = (Bit32u)(((float)samplerate) / (powf(1.088883372f, (float)lf) * 0.021236044f));
- }
-}
-
-void Tables::initMT32ConstantTables(Synth *synth) {
- int lf;
- synth->printDebug("Initialising Pitch Tables");
- for (lf = -108; lf <= 108; lf++) {
- tvfKeyfollowMult[lf + 108] = (int)(256 * powf(2.0f, (float)(lf / 24.0f)));
- //synth->printDebug("KT %d = %d", f, keytable[f+108]);
- }
-
- for (int res = 0; res < 31; res++) {
- resonanceFactor[res] = powf((float)res / 30.0f, 5.0f) + 1.0f;
- }
-
- int period = 65536;
-
- for (int ang = 0; ang < period; ang++) {
- int halfang = (period / 2);
- int angval = ang % halfang;
- float tval = (((float)angval / (float)halfang) - 0.5f) * 2;
- if (ang >= halfang)
- tval = -tval;
- sintable[ang] = (Bit16s)(tval * 50.0f) + 50;
- }
-
- int velt, dep;
- float tempdep;
- for (velt = 0; velt < 128; velt++) {
- for (dep = 0; dep < 5; dep++) {
- if (dep > 0) {
- float ff = (float)(exp(3.5f * tvcatconst[dep] * (59.0f - (float)velt)) * tvcatmult[dep]);
- tempdep = 256.0f * ff;
- envTimeVelfollowMult[dep][velt] = (int)tempdep;
- //if ((velt % 16) == 0) {
- // synth->printDebug("Key %d, depth %d, factor %d", velt, dep, (int)tempdep);
- //}
- } else
- envTimeVelfollowMult[dep][velt] = 256;
- }
-
- for (dep = -7; dep < 8; dep++) {
- float fldep = (float)abs(dep) / 7.0f;
- fldep = powf(fldep,2.5f);
- if (dep < 0)
- fldep = fldep * -1.0f;
- pwVelfollowAdd[dep+7][velt] = Bit32s((fldep * (float)velt * 100) / 128.0);
- }
- }
-
- for (dep = 0; dep <= 100; dep++) {
- for (velt = 0; velt < 128; velt++) {
- float fdep = (float)dep * 0.000347013f; // Another MT-32 constant
- float fv = ((float)velt - 64.0f)/7.26f;
- float flogdep = powf(10, fdep * fv);
- float fbase;
-
- if (velt > 64)
- synth->tables.tvfVelfollowMult[velt][dep] = (int)(flogdep * 256.0);
- else {
- //lff = 1 - (pow(((128.0 - (float)lf) / 64.0),.25) * ((float)velt / 96));
- fbase = 1 - (powf(((float)dep / 100.0f),.25f) * ((float)(64-velt) / 96.0f));
- synth->tables.tvfVelfollowMult[velt][dep] = (int)(fbase * 256.0);
- }
- //synth->printDebug("Filvel dep %d velt %d = %x", dep, velt, filveltable[velt][dep]);
- }
- }
-
- for (lf = 0; lf < 128; lf++) {
- float veloFract = lf / 127.0f;
- for (int velsens = 0; velsens <= 100; velsens++) {
- float sensFract = (velsens - 50) / 50.0f;
- if (velsens < 50) {
- tvaVelfollowMult[lf][velsens] = FIXEDPOINT_MAKE(1.0f / powf(2.0f, veloFract * -sensFract * 127.0f / 20.0f), 8);
- } else {
- tvaVelfollowMult[lf][velsens] = FIXEDPOINT_MAKE(1.0f / powf(2.0f, (1.0f - veloFract) * sensFract * 127.0f / 20.0f), 8);
- }
- }
- }
-
- for (lf = 0; lf <= 100; lf++) {
- // Converts the 0-100 range used by the MT-32 to volume multiplier
- volumeMult[lf] = FIXEDPOINT_MAKE(powf((float)lf / 100.0f, FLOAT_LN), 7);
- }
-
- for (lf = 0; lf <= 100; lf++) {
- float mv = lf / 100.0f;
- float pt = mv - 0.5f;
- if (pt < 0)
- pt = 0;
-
- // Original (CC version)
- //pwFactor[lf] = (int)(pt * 210.04f) + 128;
-
- // Approximation from sample comparison
- pwFactor[lf] = (int)(pt * 179.0f) + 128;
- }
-
- for (unsigned int i = 0; i < MAX_SAMPLE_OUTPUT; i++) {
- int myRand;
- myRand = rand();
- //myRand = ((myRand - 16383) * 7168) >> 16;
- // This one is slower but works with all values of RAND_MAX
- myRand = (int)((myRand - RAND_MAX / 2) / (float)RAND_MAX * (7168 / 2));
- //FIXME:KG: Original ultimately set the lowest two bits to 0, for no obvious reason
- noiseBuf[i] = (Bit16s)myRand;
- }
-
- float tdist;
- float padjtable[51];
- for (lf = 0; lf <= 50; lf++) {
- if (lf == 0)
- padjtable[lf] = 7;
- else if (lf == 1)
- padjtable[lf] = 6;
- else if (lf == 2)
- padjtable[lf] = 5;
- else if (lf == 3)
- padjtable[lf] = 4;
- else if (lf == 4)
- padjtable[lf] = 4 - (0.333333f);
- else if (lf == 5)
- padjtable[lf] = 4 - (0.333333f * 2);
- else if (lf == 6)
- padjtable[lf] = 3;
- else if ((lf > 6) && (lf <= 12)) {
- tdist = (lf-6.0f) / 6.0f;
- padjtable[lf] = 3.0f - tdist;
- } else if ((lf > 12) && (lf <= 25)) {
- tdist = (lf - 12.0f) / 13.0f;
- padjtable[lf] = 2.0f - tdist;
- } else {
- tdist = (lf - 25.0f) / 25.0f;
- padjtable[lf] = 1.0f - tdist;
- }
- //synth->printDebug("lf %d = padj %f", lf, (double)padjtable[lf]);
- }
-
- float lfp, depf, finalval, tlf;
- int depat, pval, depti;
- for (lf = 0; lf <= 10; lf++) {
- // I believe the depth is cubed or something
-
- for (depat = 0; depat <= 100; depat++) {
- if (lf > 0) {
- depti = abs(depat - 50);
- tlf = (float)lf - padjtable[depti];
- if (tlf < 0)
- tlf = 0;
- lfp = (float)exp(0.713619942f * tlf) / 407.4945111f;
-
- if (depat < 50)
- finalval = 4096.0f * powf(2, -lfp);
- else
- finalval = 4096.0f * powf(2, lfp);
- pval = (int)finalval;
-
- pitchEnvVal[lf][depat] = pval;
- //synth->printDebug("lf %d depat %d pval %d tlf %f lfp %f", lf,depat,pval, (double)tlf, (double)lfp);
- } else {
- pitchEnvVal[lf][depat] = 4096;
- //synth->printDebug("lf %d depat %d pval 4096", lf, depat);
- }
- }
- }
- for (lf = 0; lf <= 100; lf++) {
- // It's linear - verified on MT-32 - one of the few things linear
- lfp = ((float)lf * 0.1904f) / 310.55f;
-
- for (depat = 0; depat <= 100; depat++) {
- depf = ((float)depat - 50.0f) / 50.0f;
- //finalval = pow(2, lfp * depf * .5);
- finalval = 4096.0f + (4096.0f * lfp * depf);
-
- pval = (int)finalval;
-
- lfoShift[lf][depat] = pval;
-
- //synth->printDebug("lf %d depat %d pval %x", lf,depat,pval);
- }
- }
-
- for (lf = 0; lf <= 12; lf++) {
- for (int distval = 0; distval < 128; distval++) {
- float amplog, dval;
- if (lf == 0) {
- amplog = 0;
- dval = 1;
- tvaBiasMult[lf][distval] = 256;
- } else {
- /*
- amplog = powf(1.431817011f, (float)lf) / FLOAT_PI;
- dval = ((128.0f - (float)distval) / 128.0f);
- amplog = exp(amplog);
- dval = powf(amplog, dval) / amplog;
- tvaBiasMult[lf][distval] = (int)(dval * 256.0);
- */
- // Lets assume for a second it's linear
-
- // Distance of full volume reduction
- amplog = (float)(12.0f / (float)lf) * 24.0f;
- if (distval > amplog) {
- tvaBiasMult[lf][distval] = 0;
- } else {
- dval = (amplog - (float)distval) / amplog;
- tvaBiasMult[lf][distval] = (int)(dval * 256.0f);
- }
- }
- //synth->printDebug("Ampbias lf %d distval %d = %f (%x) %f", lf, distval, (double)dval, tvaBiasMult[lf][distval],(double)amplog);
- }
- }
-
- for (lf = 0; lf <= 14; lf++) {
- for (int distval = 0; distval < 128; distval++) {
- float filval = fabsf((float)((lf - 7) * 12) / 7.0f);
- float amplog, dval;
- if (lf == 7) {
- amplog = 0;
- dval = 1;
- tvfBiasMult[lf][distval] = 256;
- } else {
- //amplog = pow(1.431817011, filval) / FLOAT_PI;
- amplog = powf(1.531817011f, filval) / FLOAT_PI;
- dval = (128.0f - (float)distval) / 128.0f;
- amplog = (float)exp(amplog);
- dval = powf(amplog,dval)/amplog;
- if (lf < 8) {
- tvfBiasMult[lf][distval] = (int)(dval * 256.0f);
- } else {
- dval = powf(dval, 0.3333333f);
- if (dval < 0.01f)
- dval = 0.01f;
- dval = 1 / dval;
- tvfBiasMult[lf][distval] = (int)(dval * 256.0f);
- }
- }
- //synth->printDebug("Fbias lf %d distval %d = %f (%x) %f", lf, distval, (double)dval, tvfBiasMult[lf][distval],(double)amplog);
- }
- }
-}
-
-// Per-note table initialisation follows
-
-static void initSaw(NoteLookup *noteLookup, Bit32s div2) {
- int tmpdiv = div2 << 16;
- for (int rsaw = 0; rsaw <= 100; rsaw++) {
- float fsaw;
- if (rsaw < 50)
- fsaw = 50.0f;
- else
- fsaw = (float)rsaw;
-
- //(66 - (((A8 - 50) / 50) ^ 0.63) * 50) / 132
- float sawfact = (66.0f - (powf((fsaw - 50.0f) / 50.0f, 0.63f) * 50.0f)) / 132.0f;
- noteLookup->sawTable[rsaw] = (int)(sawfact * (float)tmpdiv) >> 16;
- //synth->printDebug("F %d divtable %d saw %d sawtable %d", f, div, rsaw, sawtable[f][rsaw]);
- }
-}
-
-static void initDep(KeyLookup *keyLookup, float f) {
- for (int dep = 0; dep < 5; dep++) {
- if (dep == 0) {
- keyLookup->envDepthMult[dep] = 256;
- keyLookup->envTimeMult[dep] = 256;
- } else {
- float depfac = 3000.0f;
- float ff, tempdep;
- depfac = (float)depexp[dep];
-
- ff = (f - (float)MIDDLEC) / depfac;
- tempdep = powf(2, ff) * 256.0f;
- keyLookup->envDepthMult[dep] = (int)tempdep;
-
- ff = (float)(exp(tkcatconst[dep] * ((float)MIDDLEC - f)) * tkcatmult[dep]);
- keyLookup->envTimeMult[dep] = (int)(ff * 256.0f);
- }
- }
- //synth->printDebug("F %f d1 %x d2 %x d3 %x d4 %x d5 %x", (double)f, noteLookup->fildepTable[0], noteLookup->fildepTable[1], noteLookup->fildepTable[2], noteLookup->fildepTable[3], noteLookup->fildepTable[4]);
-}
-
-Bit16s Tables::clampWF(Synth *synth, const char *n, float ampVal, double input) {
- Bit32s x = (Bit32s)(input * ampVal);
- if (x < -ampVal - 1) {
- synth->printDebug("%s==%d<-WGAMP-1!", n, x);
- x = (Bit32s)(-ampVal - 1);
- } else if (x > ampVal) {
- synth->printDebug("%s==%d>WGAMP!", n, x);
- x = (Bit32s)ampVal;
- }
- return (Bit16s)x;
-}
-
-File *Tables::initWave(Synth *synth, NoteLookup *noteLookup, float ampVal, float div2, File *file) {
- int iDiv2 = (int)div2;
- noteLookup->waveformSize[0] = iDiv2 << 1;
- noteLookup->waveformSize[1] = iDiv2 << 1;
- noteLookup->waveformSize[2] = iDiv2 << 2;
- for (int i = 0; i < 3; i++) {
- if (noteLookup->waveforms[i] == NULL) {
- noteLookup->waveforms[i] = new Bit16s[noteLookup->waveformSize[i]];
- }
- }
- if (file != NULL) {
- for (int i = 0; i < 3 && file != NULL; i++) {
- size_t len = noteLookup->waveformSize[i];
- for (unsigned int j = 0; j < len; j++) {
- if (!file->readBit16u((Bit16u *)&noteLookup->waveforms[i][j])) {
- synth->printDebug("Error reading wave file cache!");
- file->close();
- file = NULL;
- break;
- }
- }
- }
- }
- if (file == NULL) {
- double sd = DOUBLE_PI / div2;
-
- for (int fa = 0; fa < (iDiv2 << 1); fa++) {
- // sa ranges from 0 to 2PI
- double sa = fa * sd;
-
- // Calculate a sample for the bandlimited sawtooth wave
- double saw = 0.0;
- int sincs = iDiv2 >> 1;
- double sinus = 1.0;
- for (int sincNum = 1; sincNum <= sincs; sincNum++) {
- saw += sin(sinus * sa) / sinus;
- sinus++;
- }
-
- // This works pretty well
- // Multiplied by 0.84 so that the spikes caused by bandlimiting don't overdrive the amplitude
- noteLookup->waveforms[0][fa] = clampWF(synth, "saw", ampVal, -saw / (0.5 * DOUBLE_PI) * 0.84);
- noteLookup->waveforms[1][fa] = clampWF(synth, "cos", ampVal, -cos(sa / 2.0));
- noteLookup->waveforms[2][fa * 2] = clampWF(synth, "cosoff_0", ampVal, -cos(sa - DOUBLE_PI));
- noteLookup->waveforms[2][fa * 2 + 1] = clampWF(synth, "cosoff_1", ampVal, -cos((sa + (sd / 2)) - DOUBLE_PI));
- }
- }
- return file;
-}
-
-static void initFiltTable(NoteLookup *noteLookup, float freq, float rate) {
- for (int tr = 0; tr <= 200; tr++) {
- float ftr = (float)tr;
-
- // Verified exact on MT-32
- if (tr > 100)
- ftr = 100.0f + (powf((ftr - 100.0f) / 100.0f, 3.0f) * 100.0f);
-
- // I think this is the one
- float brsq = powf(10.0f, (tr / 50.0f) - 1.0f);
- noteLookup->filtTable[0][tr] = (int)((freq * brsq) / (rate / 2) * FILTERGRAN);
- if (noteLookup->filtTable[0][tr]>=((FILTERGRAN*15)/16))
- noteLookup->filtTable[0][tr] = ((FILTERGRAN*15)/16);
-
- float brsa = powf(10.0f, ((tr / 55.0f) - 1.0f)) / 2.0f;
- noteLookup->filtTable[1][tr] = (int)((freq * brsa) / (rate / 2) * FILTERGRAN);
- if (noteLookup->filtTable[1][tr]>=((FILTERGRAN*15)/16))
- noteLookup->filtTable[1][tr] = ((FILTERGRAN*15)/16);
- }
-}
-
-static void initNFiltTable(NoteLookup *noteLookup, float freq, float rate) {
- for (int cf = 0; cf <= 100; cf++) {
- float cfmult = (float)cf;
-
- for (int tf = 0;tf <= 100; tf++) {
- float tfadd = (float)tf;
-
- //float freqsum = exp((cfmult + tfadd) / 30.0f) / 4.0f;
- //float freqsum = 0.15f * exp(0.45f * ((cfmult + tfadd) / 10.0f));
-
- float freqsum = powf(2.0f, ((cfmult + tfadd) - 40.0f) / 16.0f);
-
- noteLookup->nfiltTable[cf][tf] = (int)((freq * freqsum) / (rate / 2) * FILTERGRAN);
- if (noteLookup->nfiltTable[cf][tf] >= ((FILTERGRAN * 15) / 16))
- noteLookup->nfiltTable[cf][tf] = ((FILTERGRAN * 15) / 16);
- }
- }
-}
-
-File *Tables::initNote(Synth *synth, NoteLookup *noteLookup, float note, float rate, float masterTune, PCMWaveEntry *pcmWaves, File *file) {
- float freq = (float)(masterTune * pow(2.0, ((double)note - MIDDLEA) / 12.0));
- float div2 = rate * 2.0f / freq;
- noteLookup->div2 = (int)div2;
-
- if (noteLookup->div2 == 0)
- noteLookup->div2 = 1;
-
- initSaw(noteLookup, noteLookup->div2);
-
- //synth->printDebug("Note %f; freq=%f, div=%f", (double)note, (double)freq, (double) rate / freq);
- file = initWave(synth, noteLookup, WGAMP, div2, file);
-
- // Create the pitch tables
- if (noteLookup->wavTable == NULL)
- noteLookup->wavTable = new Bit32u[synth->controlROMMap->pcmCount];
- double rateMult = 32000.0 / rate;
- double tuner = freq * 65536.0f;
- for (int pc = 0; pc < synth->controlROMMap->pcmCount; pc++) {
- noteLookup->wavTable[pc] = (int)(tuner / pcmWaves[pc].tune * rateMult);
- }
-
- initFiltTable(noteLookup, freq, rate);
- initNFiltTable(noteLookup, freq, rate);
- return file;
-}
-
-bool Tables::initNotes(Synth *synth, PCMWaveEntry *pcmWaves, float rate, float masterTune) {
- const char *NoteNames[12] = {
- "C ", "C#", "D ", "D#", "E ", "F ", "F#", "G ", "G#", "A ", "A#", "B "
- };
- char filename[64];
- int intRate = (int)rate;
- char version[4] = {0, 0, 0, 5};
- sprintf(filename, "waveformcache-%d-%.2f.raw", intRate, (double)masterTune);
-
- File *file = NULL;
- char header[20];
- memcpy(header, "MT32WAVE", 8);
- int pos = 8;
- // Version...
- for (int i = 0; i < 4; i++)
- header[pos++] = version[i];
- header[pos++] = (char)((intRate >> 24) & 0xFF);
- header[pos++] = (char)((intRate >> 16) & 0xFF);
- header[pos++] = (char)((intRate >> 8) & 0xFF);
- header[pos++] = (char)(intRate & 0xFF);
- int intTuning = (int)masterTune;
- header[pos++] = (char)((intTuning >> 8) & 0xFF);
- header[pos++] = (char)(intTuning & 0xFF);
- header[pos++] = 0;
- header[pos] = (char)((masterTune - intTuning) * 10);
-#if MT32EMU_WAVECACHEMODE < 2
- bool reading = false;
- file = synth->openFile(filename, File::OpenMode_read);
- if (file != NULL) {
- char fileHeader[20];
- if (file->read(fileHeader, 20) == 20) {
- if (memcmp(fileHeader, header, 20) == 0) {
- Bit16u endianCheck;
- if (file->readBit16u(&endianCheck)) {
- if (endianCheck == 1) {
- reading = true;
- } else {
- synth->printDebug("Endian check in %s does not match expected", filename);
- }
- } else {
- synth->printDebug("Unable to read endian check in %s", filename);
- }
- } else {
- synth->printDebug("Header of %s does not match expected", filename);
- }
- } else {
- synth->printDebug("Error reading 16 bytes of %s", filename);
- }
- if (!reading) {
- file->close();
- file = NULL;
- }
- } else {
- synth->printDebug("Unable to open %s for reading", filename);
- }
-#endif
-
- float progress = 0.0f;
- bool abort = false;
- synth->report(ReportType_progressInit, &progress);
- for (int f = LOWEST_NOTE; f <= HIGHEST_NOTE; f++) {
- synth->printDebug("Initialising note %s%d", NoteNames[f % 12], (f / 12) - 2);
- NoteLookup *noteLookup = &noteLookups[f - LOWEST_NOTE];
- file = initNote(synth, noteLookup, (float)f, rate, masterTune, pcmWaves, file);
- progress = (f - LOWEST_NOTE + 1) / (float)NUM_NOTES;
- abort = synth->report(ReportType_progressInit, &progress) != 0;
- if (abort)
- break;
- }
-
-#if MT32EMU_WAVECACHEMODE == 0 || MT32EMU_WAVECACHEMODE == 2
- if (file == NULL) {
- file = synth->openFile(filename, File::OpenMode_write);
- if (file != NULL) {
- if (file->write(header, 20) == 20 && file->writeBit16u(1)) {
- for (int f = 0; f < NUM_NOTES; f++) {
- for (int i = 0; i < 3 && file != NULL; i++) {
- int len = noteLookups[f].waveformSize[i];
- for (int j = 0; j < len; j++) {
- if (!file->writeBit16u(noteLookups[f].waveforms[i][j])) {
- synth->printDebug("Error writing waveform cache file");
- file->close();
- file = NULL;
- break;
- }
- }
- }
- }
- } else {
- synth->printDebug("Error writing 16-byte header to %s - won't continue saving", filename);
- }
- } else {
- synth->printDebug("Unable to open %s for writing - won't be created", filename);
- }
- }
-#endif
-
- if (file != NULL)
- synth->closeFile(file);
- return !abort;
-}
-
-void Tables::freeNotes() {
- for (int t = 0; t < 3; t++) {
- for (int m = 0; m < NUM_NOTES; m++) {
- if (noteLookups[m].waveforms[t] != NULL) {
- delete[] noteLookups[m].waveforms[t];
- noteLookups[m].waveforms[t] = NULL;
- noteLookups[m].waveformSize[t] = 0;
- }
- if (noteLookups[m].wavTable != NULL) {
- delete[] noteLookups[m].wavTable;
- noteLookups[m].wavTable = NULL;
- }
- }
- }
- initialisedMasterTune = 0.0f;
-}
-
-Tables::Tables() {
- initialisedSampleRate = 0.0f;
- initialisedMasterTune = 0.0f;
- memset(&noteLookups, 0, sizeof(noteLookups));
-}
-
-bool Tables::init(Synth *synth, PCMWaveEntry *pcmWaves, float sampleRate, float masterTune) {
- if (sampleRate <= 0.0f) {
- synth->printDebug("Bad sampleRate (%f <= 0.0f)", (double)sampleRate);
- return false;
- }
- if (initialisedSampleRate == 0.0f) {
- initMT32ConstantTables(synth);
- }
- if (initialisedSampleRate != sampleRate) {
- initFiltCoeff(sampleRate);
- initEnvelopes(sampleRate);
- for (int key = 12; key <= 108; key++) {
- initDep(&keyLookups[key - 12], (float)key);
- }
- }
- if (initialisedSampleRate != sampleRate || initialisedMasterTune != masterTune) {
- freeNotes();
- if (!initNotes(synth, pcmWaves, sampleRate, masterTune)) {
- return false;
- }
- initialisedSampleRate = sampleRate;
- initialisedMasterTune = masterTune;
- }
- return true;
-}
-
-}
diff --git a/sound/softsynth/mt32/tables.h b/sound/softsynth/mt32/tables.h
deleted file mode 100644
index d9af5114b2..0000000000
--- a/sound/softsynth/mt32/tables.h
+++ /dev/null
@@ -1,116 +0,0 @@
-/* Copyright (c) 2003-2005 Various contributors
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- * IN THE SOFTWARE.
- */
-
-#ifndef MT32EMU_TABLES_H
-#define MT32EMU_TABLES_H
-
-namespace MT32Emu {
-
-// Mathematical constants
-const double DOUBLE_PI = 3.1415926535897932384626433832795;
-const double DOUBLE_LN = 2.3025850929940456840179914546844;
-const float FLOAT_PI = 3.1415926535897932384626433832795f;
-const float FLOAT_LN = 2.3025850929940456840179914546844f;
-
-// Filter settings
-const int FILTERGRAN = 512;
-
-// Amplitude of waveform generator
-// FIXME: This value is the amplitude possible whilst avoiding
-// overdriven values immediately after filtering when playing
-// back SQ3MT.MID. Needs to be checked.
-const int WGAMP = 12382;
-
-const int MIDDLEC = 60;
-const int MIDDLEA = 69; // By this I mean "A above middle C"
-
-// FIXME:KG: may only need to do 12 to 108
-// 12..108 is the range allowed by note on commands, but the key can be modified by pitch keyfollow
-// and adjustment for timbre pitch, so the results can be outside that range.
-// Should we move it (by octave) into the 12..108 range, or keep it in 0..127 range,
-// or something else altogether?
-const int LOWEST_NOTE = 12;
-const int HIGHEST_NOTE = 127;
-const int NUM_NOTES = HIGHEST_NOTE - LOWEST_NOTE + 1; // Number of slots for note LUT
-
-class Synth;
-
-struct NoteLookup {
- Bit32u div2;
- Bit32u *wavTable;
- Bit32s sawTable[101];
- int filtTable[2][201];
- int nfiltTable[101][101];
- Bit16s *waveforms[3];
- Bit32u waveformSize[3];
-};
-
-struct KeyLookup {
- Bit32s envTimeMult[5]; // For envelope time adjustment for key pressed
- Bit32s envDepthMult[5];
-};
-
-class Tables {
- float initialisedSampleRate;
- float initialisedMasterTune;
- void initMT32ConstantTables(Synth *synth);
- static Bit16s clampWF(Synth *synth, const char *n, float ampVal, double input);
- static File *initWave(Synth *synth, NoteLookup *noteLookup, float ampsize, float div2, File *file);
- bool initNotes(Synth *synth, PCMWaveEntry *pcmWaves, float rate, float tuning);
- void initEnvelopes(float sampleRate);
- void initFiltCoeff(float samplerate);
-public:
- // Constant LUTs
- Bit32s tvfKeyfollowMult[217];
- Bit32s tvfVelfollowMult[128][101];
- Bit32s tvfBiasMult[15][128];
- Bit32u tvaVelfollowMult[128][101];
- Bit32s tvaBiasMult[13][128];
- Bit16s noiseBuf[MAX_SAMPLE_OUTPUT];
- Bit16s sintable[65536];
- Bit32s pitchEnvVal[16][101];
- Bit32s envTimeVelfollowMult[5][128];
- Bit32s pwVelfollowAdd[15][128];
- float resonanceFactor[31];
- Bit32u lfoShift[101][101];
- Bit32s pwFactor[101];
- Bit32s volumeMult[101];
-
- // LUTs varying with sample rate
- Bit32u envTime[101];
- Bit32u envDeltaMaxTime[101];
- Bit32u envDecayTime[101];
- Bit32u lfoPeriod[101];
- float filtCoeff[FILTERGRAN][31][8];
-
- // Various LUTs for each note and key
- NoteLookup noteLookups[NUM_NOTES];
- KeyLookup keyLookups[97];
-
- Tables();
- bool init(Synth *synth, PCMWaveEntry *pcmWaves, float sampleRate, float masterTune);
- File *initNote(Synth *synth, NoteLookup *noteLookup, float note, float rate, float tuning, PCMWaveEntry *pcmWaves, File *file);
- void freeNotes();
-};
-
-}
-
-#endif
diff --git a/sound/softsynth/opl/dbopl.cpp b/sound/softsynth/opl/dbopl.cpp
deleted file mode 100644
index 47e263b6b9..0000000000
--- a/sound/softsynth/opl/dbopl.cpp
+++ /dev/null
@@ -1,1536 +0,0 @@
-/*
- * Copyright (C) 2002-2010 The DOSBox Team
- *
- * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-/*
- DOSBox implementation of a combined Yamaha YMF262 and Yamaha YM3812 emulator.
- Enabling the opl3 bit will switch the emulator to stereo opl3 output instead of regular mono opl2
- Except for the table generation it's all integer math
- Can choose different types of generators, using muls and bigger tables, try different ones for slower platforms
- The generation was based on the MAME implementation but tried to have it use less memory and be faster in general
- MAME uses much bigger envelope tables and this will be the biggest cause of it sounding different at times
-
- //TODO Don't delay first operator 1 sample in opl3 mode
- //TODO Maybe not use class method pointers but a regular function pointers with operator as first parameter
- //TODO Fix panning for the Percussion channels, would any opl3 player use it and actually really change it though?
- //TODO Check if having the same accuracy in all frequency multipliers sounds better or not
-
- //DUNNO Keyon in 4op, switch to 2op without keyoff.
-*/
-
-// Last synch with DOSBox SVN trunk r3556
-
-#include "dbopl.h"
-
-#ifndef DISABLE_DOSBOX_OPL
-
-namespace OPL {
-namespace DOSBox {
-
-#ifndef PI
-#define PI 3.14159265358979323846
-#endif
-
-namespace DBOPL {
-
-#define OPLRATE ((double)(14318180.0 / 288.0))
-#define TREMOLO_TABLE 52
-
-//Try to use most precision for frequencies
-//Else try to keep different waves in synch
-//#define WAVE_PRECISION 1
-#ifndef WAVE_PRECISION
-//Wave bits available in the top of the 32bit range
-//Original adlib uses 10.10, we use 10.22
-#define WAVE_BITS 10
-#else
-//Need some extra bits at the top to have room for octaves and frequency multiplier
-//We support to 8 times lower rate
-//128 * 15 * 8 = 15350, 2^13.9, so need 14 bits
-#define WAVE_BITS 14
-#endif
-#define WAVE_SH ( 32 - WAVE_BITS )
-#define WAVE_MASK ( ( 1 << WAVE_SH ) - 1 )
-
-//Use the same accuracy as the waves
-#define LFO_SH ( WAVE_SH - 10 )
-//LFO is controlled by our tremolo 256 sample limit
-#define LFO_MAX ( 256 << ( LFO_SH ) )
-
-
-//Maximum amount of attenuation bits
-//Envelope goes to 511, 9 bits
-#if (DBOPL_WAVE == WAVE_TABLEMUL )
-//Uses the value directly
-#define ENV_BITS ( 9 )
-#else
-//Add 3 bits here for more accuracy and would have to be shifted up either way
-#define ENV_BITS ( 9 )
-#endif
-//Limits of the envelope with those bits and when the envelope goes silent
-#define ENV_MIN 0
-#define ENV_EXTRA ( ENV_BITS - 9 )
-#define ENV_MAX ( 511 << ENV_EXTRA )
-#define ENV_LIMIT ( ( 12 * 256) >> ( 3 - ENV_EXTRA ) )
-#define ENV_SILENT( _X_ ) ( (_X_) >= ENV_LIMIT )
-
-//Attack/decay/release rate counter shift
-#define RATE_SH 24
-#define RATE_MASK ( ( 1 << RATE_SH ) - 1 )
-//Has to fit within 16bit lookuptable
-#define MUL_SH 16
-
-//Check some ranges
-#if ENV_EXTRA > 3
-#error Too many envelope bits
-#endif
-
-
-//How much to substract from the base value for the final attenuation
-static const Bit8u KslCreateTable[16] = {
- //0 will always be be lower than 7 * 8
- 64, 32, 24, 19,
- 16, 12, 11, 10,
- 8, 6, 5, 4,
- 3, 2, 1, 0,
-};
-
-#define M(_X_) ((Bit8u)( (_X_) * 2))
-static const Bit8u FreqCreateTable[16] = {
- M(0.5), M(1 ), M(2 ), M(3 ), M(4 ), M(5 ), M(6 ), M(7 ),
- M(8 ), M(9 ), M(10), M(10), M(12), M(12), M(15), M(15)
-};
-#undef M
-
-//We're not including the highest attack rate, that gets a special value
-static const Bit8u AttackSamplesTable[13] = {
- 69, 55, 46, 40,
- 35, 29, 23, 20,
- 19, 15, 11, 10,
- 9
-};
-//On a real opl these values take 8 samples to reach and are based upon larger tables
-static const Bit8u EnvelopeIncreaseTable[13] = {
- 4, 5, 6, 7,
- 8, 10, 12, 14,
- 16, 20, 24, 28,
- 32,
-};
-
-#if ( DBOPL_WAVE == WAVE_HANDLER ) || ( DBOPL_WAVE == WAVE_TABLELOG )
-static Bit16u ExpTable[ 256 ];
-#endif
-
-#if ( DBOPL_WAVE == WAVE_HANDLER )
-//PI table used by WAVEHANDLER
-static Bit16u SinTable[ 512 ];
-#endif
-
-#if ( DBOPL_WAVE > WAVE_HANDLER )
-//Layout of the waveform table in 512 entry intervals
-//With overlapping waves we reduce the table to half it's size
-
-// | |//\\|____|WAV7|//__|/\ |____|/\/\|
-// |\\//| | |WAV7| | \/| | |
-// |06 |0126|17 |7 |3 |4 |4 5 |5 |
-
-//6 is just 0 shifted and masked
-
-static Bit16s WaveTable[ 8 * 512 ];
-//Distance into WaveTable the wave starts
-static const Bit16u WaveBaseTable[8] = {
- 0x000, 0x200, 0x200, 0x800,
- 0xa00, 0xc00, 0x100, 0x400,
-
-};
-//Mask the counter with this
-static const Bit16u WaveMaskTable[8] = {
- 1023, 1023, 511, 511,
- 1023, 1023, 512, 1023,
-};
-
-//Where to start the counter on at keyon
-static const Bit16u WaveStartTable[8] = {
- 512, 0, 0, 0,
- 0, 512, 512, 256,
-};
-#endif
-
-#if ( DBOPL_WAVE == WAVE_TABLEMUL )
-static Bit16u MulTable[ 384 ];
-#endif
-
-static Bit8u KslTable[ 8 * 16 ];
-static Bit8u TremoloTable[ TREMOLO_TABLE ];
-//Start of a channel behind the chip struct start
-static Bit16u ChanOffsetTable[32];
-//Start of an operator behind the chip struct start
-static Bit16u OpOffsetTable[64];
-
-//The lower bits are the shift of the operator vibrato value
-//The highest bit is right shifted to generate -1 or 0 for negation
-//So taking the highest input value of 7 this gives 3, 7, 3, 0, -3, -7, -3, 0
-static const Bit8s VibratoTable[ 8 ] = {
- 1 - 0x00, 0 - 0x00, 1 - 0x00, 30 - 0x00,
- 1 - 0x80, 0 - 0x80, 1 - 0x80, 30 - 0x80
-};
-
-//Shift strength for the ksl value determined by ksl strength
-static const Bit8u KslShiftTable[4] = {
- 31,1,2,0
-};
-
-//Generate a table index and table shift value using input value from a selected rate
-static void EnvelopeSelect( Bit8u val, Bit8u& index, Bit8u& shift ) {
- if ( val < 13 * 4 ) { //Rate 0 - 12
- shift = 12 - ( val >> 2 );
- index = val & 3;
- } else if ( val < 15 * 4 ) { //rate 13 - 14
- shift = 0;
- index = val - 12 * 4;
- } else { //rate 15 and up
- shift = 0;
- index = 12;
- }
-}
-
-#if ( DBOPL_WAVE == WAVE_HANDLER )
-/*
- Generate the different waveforms out of the sine/exponetial table using handlers
-*/
-static inline Bits MakeVolume( Bitu wave, Bitu volume ) {
- Bitu total = wave + volume;
- Bitu index = total & 0xff;
- Bitu sig = ExpTable[ index ];
- Bitu exp = total >> 8;
-#if 0
- //Check if we overflow the 31 shift limit
- if ( exp >= 32 ) {
- LOG_MSG( "WTF %d %d", total, exp );
- }
-#endif
- return (sig >> exp);
-}
-
-static Bits DB_FASTCALL WaveForm0( Bitu i, Bitu volume ) {
- Bits neg = 0 - (( i >> 9) & 1);//Create ~0 or 0
- Bitu wave = SinTable[i & 511];
- return (MakeVolume( wave, volume ) ^ neg) - neg;
-}
-static Bits DB_FASTCALL WaveForm1( Bitu i, Bitu volume ) {
- Bit32u wave = SinTable[i & 511];
- wave |= ( ( (i ^ 512 ) & 512) - 1) >> ( 32 - 12 );
- return MakeVolume( wave, volume );
-}
-static Bits DB_FASTCALL WaveForm2( Bitu i, Bitu volume ) {
- Bitu wave = SinTable[i & 511];
- return MakeVolume( wave, volume );
-}
-static Bits DB_FASTCALL WaveForm3( Bitu i, Bitu volume ) {
- Bitu wave = SinTable[i & 255];
- wave |= ( ( (i ^ 256 ) & 256) - 1) >> ( 32 - 12 );
- return MakeVolume( wave, volume );
-}
-static Bits DB_FASTCALL WaveForm4( Bitu i, Bitu volume ) {
- //Twice as fast
- i <<= 1;
- Bits neg = 0 - (( i >> 9) & 1);//Create ~0 or 0
- Bitu wave = SinTable[i & 511];
- wave |= ( ( (i ^ 512 ) & 512) - 1) >> ( 32 - 12 );
- return (MakeVolume( wave, volume ) ^ neg) - neg;
-}
-static Bits DB_FASTCALL WaveForm5( Bitu i, Bitu volume ) {
- //Twice as fast
- i <<= 1;
- Bitu wave = SinTable[i & 511];
- wave |= ( ( (i ^ 512 ) & 512) - 1) >> ( 32 - 12 );
- return MakeVolume( wave, volume );
-}
-static Bits DB_FASTCALL WaveForm6( Bitu i, Bitu volume ) {
- Bits neg = 0 - (( i >> 9) & 1);//Create ~0 or 0
- return (MakeVolume( 0, volume ) ^ neg) - neg;
-}
-static Bits DB_FASTCALL WaveForm7( Bitu i, Bitu volume ) {
- //Negative is reversed here
- Bits neg = (( i >> 9) & 1) - 1;
- Bitu wave = (i << 3);
- //When negative the volume also runs backwards
- wave = ((wave ^ neg) - neg) & 4095;
- return (MakeVolume( wave, volume ) ^ neg) - neg;
-}
-
-static const WaveHandler WaveHandlerTable[8] = {
- WaveForm0, WaveForm1, WaveForm2, WaveForm3,
- WaveForm4, WaveForm5, WaveForm6, WaveForm7
-};
-
-#endif
-
-/*
- Operator
-*/
-
-//We zero out when rate == 0
-inline void Operator::UpdateAttack( const Chip* chip ) {
- Bit8u rate = reg60 >> 4;
- if ( rate ) {
- Bit8u val = (rate << 2) + ksr;
- attackAdd = chip->attackRates[ val ];
- rateZero &= ~(1 << ATTACK);
- } else {
- attackAdd = 0;
- rateZero |= (1 << ATTACK);
- }
-}
-inline void Operator::UpdateDecay( const Chip* chip ) {
- Bit8u rate = reg60 & 0xf;
- if ( rate ) {
- Bit8u val = (rate << 2) + ksr;
- decayAdd = chip->linearRates[ val ];
- rateZero &= ~(1 << DECAY);
- } else {
- decayAdd = 0;
- rateZero |= (1 << DECAY);
- }
-}
-inline void Operator::UpdateRelease( const Chip* chip ) {
- Bit8u rate = reg80 & 0xf;
- if ( rate ) {
- Bit8u val = (rate << 2) + ksr;
- releaseAdd = chip->linearRates[ val ];
- rateZero &= ~(1 << RELEASE);
- if ( !(reg20 & MASK_SUSTAIN ) ) {
- rateZero &= ~( 1 << SUSTAIN );
- }
- } else {
- rateZero |= (1 << RELEASE);
- releaseAdd = 0;
- if ( !(reg20 & MASK_SUSTAIN ) ) {
- rateZero |= ( 1 << SUSTAIN );
- }
- }
-}
-
-inline void Operator::UpdateAttenuation( ) {
- Bit8u kslBase = (Bit8u)((chanData >> SHIFT_KSLBASE) & 0xff);
- Bit32u tl = reg40 & 0x3f;
- Bit8u kslShift = KslShiftTable[ reg40 >> 6 ];
- //Make sure the attenuation goes to the right bits
- totalLevel = tl << ( ENV_BITS - 7 ); //Total level goes 2 bits below max
- totalLevel += ( kslBase << ENV_EXTRA ) >> kslShift;
-}
-
-void Operator::UpdateFrequency( ) {
- Bit32u freq = chanData & (( 1 << 10 ) - 1);
- Bit32u block = (chanData >> 10) & 0xff;
-#ifdef WAVE_PRECISION
- block = 7 - block;
- waveAdd = ( freq * freqMul ) >> block;
-#else
- waveAdd = ( freq << block ) * freqMul;
-#endif
- if ( reg20 & MASK_VIBRATO ) {
- vibStrength = (Bit8u)(freq >> 7);
-
-#ifdef WAVE_PRECISION
- vibrato = ( vibStrength * freqMul ) >> block;
-#else
- vibrato = ( vibStrength << block ) * freqMul;
-#endif
- } else {
- vibStrength = 0;
- vibrato = 0;
- }
-}
-
-void Operator::UpdateRates( const Chip* chip ) {
- //Mame seems to reverse this where enabling ksr actually lowers
- //the rate, but pdf manuals says otherwise?
- Bit8u newKsr = (Bit8u)((chanData >> SHIFT_KEYCODE) & 0xff);
- if ( !( reg20 & MASK_KSR ) ) {
- newKsr >>= 2;
- }
- if ( ksr == newKsr )
- return;
- ksr = newKsr;
- UpdateAttack( chip );
- UpdateDecay( chip );
- UpdateRelease( chip );
-}
-
-INLINE Bit32s Operator::RateForward( Bit32u add ) {
- rateIndex += add;
- Bit32s ret = rateIndex >> RATE_SH;
- rateIndex = rateIndex & RATE_MASK;
- return ret;
-}
-
-template< Operator::State yes>
-Bits Operator::TemplateVolume( ) {
- Bit32s vol = volume;
- Bit32s change;
- switch ( yes ) {
- case OFF:
- return ENV_MAX;
- case ATTACK:
- change = RateForward( attackAdd );
- if ( !change )
- return vol;
- vol += ( (~vol) * change ) >> 3;
- if ( vol < ENV_MIN ) {
- volume = ENV_MIN;
- rateIndex = 0;
- SetState( DECAY );
- return ENV_MIN;
- }
- break;
- case DECAY:
- vol += RateForward( decayAdd );
- if ( GCC_UNLIKELY(vol >= sustainLevel) ) {
- //Check if we didn't overshoot max attenuation, then just go off
- if ( GCC_UNLIKELY(vol >= ENV_MAX) ) {
- volume = ENV_MAX;
- SetState( OFF );
- return ENV_MAX;
- }
- //Continue as sustain
- rateIndex = 0;
- SetState( SUSTAIN );
- }
- break;
- case SUSTAIN:
- if ( reg20 & MASK_SUSTAIN ) {
- return vol;
- }
- //In sustain phase, but not sustaining, do regular release
- case RELEASE:
- vol += RateForward( releaseAdd );
- if ( GCC_UNLIKELY(vol >= ENV_MAX) ) {
- volume = ENV_MAX;
- SetState( OFF );
- return ENV_MAX;
- }
- break;
- }
- volume = vol;
- return vol;
-}
-
-static const VolumeHandler VolumeHandlerTable[5] = {
- &Operator::TemplateVolume< Operator::OFF >,
- &Operator::TemplateVolume< Operator::RELEASE >,
- &Operator::TemplateVolume< Operator::SUSTAIN >,
- &Operator::TemplateVolume< Operator::DECAY >,
- &Operator::TemplateVolume< Operator::ATTACK >
-};
-
-INLINE Bitu Operator::ForwardVolume() {
- return currentLevel + (this->*volHandler)();
-}
-
-
-INLINE Bitu Operator::ForwardWave() {
- waveIndex += waveCurrent;
- return waveIndex >> WAVE_SH;
-}
-
-void Operator::Write20( const Chip* chip, Bit8u val ) {
- Bit8u change = (reg20 ^ val );
- if ( !change )
- return;
- reg20 = val;
- //Shift the tremolo bit over the entire register, saved a branch, YES!
- tremoloMask = (Bit8s)(val) >> 7;
- tremoloMask &= ~(( 1 << ENV_EXTRA ) -1);
- //Update specific features based on changes
- if ( change & MASK_KSR ) {
- UpdateRates( chip );
- }
- //With sustain enable the volume doesn't change
- if ( reg20 & MASK_SUSTAIN || ( !releaseAdd ) ) {
- rateZero |= ( 1 << SUSTAIN );
- } else {
- rateZero &= ~( 1 << SUSTAIN );
- }
- //Frequency multiplier or vibrato changed
- if ( change & (0xf | MASK_VIBRATO) ) {
- freqMul = chip->freqMul[ val & 0xf ];
- UpdateFrequency();
- }
-}
-
-void Operator::Write40( const Chip* /*chip*/, Bit8u val ) {
- if (!(reg40 ^ val ))
- return;
- reg40 = val;
- UpdateAttenuation( );
-}
-
-void Operator::Write60( const Chip* chip, Bit8u val ) {
- Bit8u change = reg60 ^ val;
- reg60 = val;
- if ( change & 0x0f ) {
- UpdateDecay( chip );
- }
- if ( change & 0xf0 ) {
- UpdateAttack( chip );
- }
-}
-
-void Operator::Write80( const Chip* chip, Bit8u val ) {
- Bit8u change = (reg80 ^ val );
- if ( !change )
- return;
- reg80 = val;
- Bit8u sustain = val >> 4;
- //Turn 0xf into 0x1f
- sustain |= ( sustain + 1) & 0x10;
- sustainLevel = sustain << ( ENV_BITS - 5 );
- if ( change & 0x0f ) {
- UpdateRelease( chip );
- }
-}
-
-void Operator::WriteE0( const Chip* chip, Bit8u val ) {
- if ( !(regE0 ^ val) )
- return;
- //in opl3 mode you can always selet 7 waveforms regardless of waveformselect
- Bit8u waveForm = val & ( ( 0x3 & chip->waveFormMask ) | (0x7 & chip->opl3Active ) );
- regE0 = val;
-#if ( DBOPL_WAVE == WAVE_HANDLER )
- waveHandler = WaveHandlerTable[ waveForm ];
-#else
- waveBase = WaveTable + WaveBaseTable[ waveForm ];
- waveStart = WaveStartTable[ waveForm ] << WAVE_SH;
- waveMask = WaveMaskTable[ waveForm ];
-#endif
-}
-
-INLINE void Operator::SetState( Bit8u s ) {
- state = s;
- volHandler = VolumeHandlerTable[ s ];
-}
-
-INLINE bool Operator::Silent() const {
- if ( !ENV_SILENT( totalLevel + volume ) )
- return false;
- if ( !(rateZero & ( 1 << state ) ) )
- return false;
- return true;
-}
-
-INLINE void Operator::Prepare( const Chip* chip ) {
- currentLevel = totalLevel + (chip->tremoloValue & tremoloMask);
- waveCurrent = waveAdd;
- if ( vibStrength >> chip->vibratoShift ) {
- Bit32s add = vibrato >> chip->vibratoShift;
- //Sign extend over the shift value
- Bit32s neg = chip->vibratoSign;
- //Negate the add with -1 or 0
- add = ( add ^ neg ) - neg;
- waveCurrent += add;
- }
-}
-
-void Operator::KeyOn( Bit8u mask ) {
- if ( !keyOn ) {
- //Restart the frequency generator
-#if ( DBOPL_WAVE > WAVE_HANDLER )
- waveIndex = waveStart;
-#else
- waveIndex = 0;
-#endif
- rateIndex = 0;
- SetState( ATTACK );
- }
- keyOn |= mask;
-}
-
-void Operator::KeyOff( Bit8u mask ) {
- keyOn &= ~mask;
- if ( !keyOn ) {
- if ( state != OFF ) {
- SetState( RELEASE );
- }
- }
-}
-
-INLINE Bits Operator::GetWave( Bitu index, Bitu vol ) {
-#if ( DBOPL_WAVE == WAVE_HANDLER )
- return waveHandler( index, vol << ( 3 - ENV_EXTRA ) );
-#elif ( DBOPL_WAVE == WAVE_TABLEMUL )
- return (waveBase[ index & waveMask ] * MulTable[ vol >> ENV_EXTRA ]) >> MUL_SH;
-#elif ( DBOPL_WAVE == WAVE_TABLELOG )
- Bit32s wave = waveBase[ index & waveMask ];
- Bit32u total = ( wave & 0x7fff ) + ( vol << ( 3 - ENV_EXTRA ) );
- Bit32s sig = ExpTable[ total & 0xff ];
- Bit32u exp = total >> 8;
- Bit32s neg = wave >> 16;
- return ((sig ^ neg) - neg) >> exp;
-#else
-#error "No valid wave routine"
-#endif
-}
-
-INLINE Bits Operator::GetSample( Bits modulation ) {
- Bitu vol = ForwardVolume();
- if ( ENV_SILENT( vol ) ) {
- //Simply forward the wave
- waveIndex += waveCurrent;
- return 0;
- } else {
- Bitu index = ForwardWave();
- index += modulation;
- return GetWave( index, vol );
- }
-}
-
-Operator::Operator() {
- chanData = 0;
- freqMul = 0;
- waveIndex = 0;
- waveAdd = 0;
- waveCurrent = 0;
- keyOn = 0;
- ksr = 0;
- reg20 = 0;
- reg40 = 0;
- reg60 = 0;
- reg80 = 0;
- regE0 = 0;
- SetState( OFF );
- rateZero = (1 << OFF);
- sustainLevel = ENV_MAX;
- currentLevel = ENV_MAX;
- totalLevel = ENV_MAX;
- volume = ENV_MAX;
- releaseAdd = 0;
-}
-
-/*
- Channel
-*/
-
-Channel::Channel() {
- old[0] = old[1] = 0;
- chanData = 0;
- regB0 = 0;
- regC0 = 0;
- maskLeft = -1;
- maskRight = -1;
- feedback = 31;
- fourMask = 0;
- synthHandler = &Channel::BlockTemplate< sm2FM >;
-}
-
-void Channel::SetChanData( const Chip* chip, Bit32u data ) {
- Bit32u change = chanData ^ data;
- chanData = data;
- Op( 0 )->chanData = data;
- Op( 1 )->chanData = data;
- //Since a frequency update triggered this, always update frequency
- Op( 0 )->UpdateFrequency();
- Op( 1 )->UpdateFrequency();
- if ( change & ( 0xff << SHIFT_KSLBASE ) ) {
- Op( 0 )->UpdateAttenuation();
- Op( 1 )->UpdateAttenuation();
- }
- if ( change & ( 0xff << SHIFT_KEYCODE ) ) {
- Op( 0 )->UpdateRates( chip );
- Op( 1 )->UpdateRates( chip );
- }
-}
-
-void Channel::UpdateFrequency( const Chip* chip, Bit8u fourOp ) {
- //Extrace the frequency bits
- Bit32u data = chanData & 0xffff;
- Bit32u kslBase = KslTable[ data >> 6 ];
- Bit32u keyCode = ( data & 0x1c00) >> 9;
- if ( chip->reg08 & 0x40 ) {
- keyCode |= ( data & 0x100)>>8; /* notesel == 1 */
- } else {
- keyCode |= ( data & 0x200)>>9; /* notesel == 0 */
- }
- //Add the keycode and ksl into the highest bits of chanData
- data |= (keyCode << SHIFT_KEYCODE) | ( kslBase << SHIFT_KSLBASE );
- ( this + 0 )->SetChanData( chip, data );
- if ( fourOp & 0x3f ) {
- ( this + 1 )->SetChanData( chip, data );
- }
-}
-
-void Channel::WriteA0( const Chip* chip, Bit8u val ) {
- Bit8u fourOp = chip->reg104 & chip->opl3Active & fourMask;
- //Don't handle writes to silent fourop channels
- if ( fourOp > 0x80 )
- return;
- Bit32u change = (chanData ^ val ) & 0xff;
- if ( change ) {
- chanData ^= change;
- UpdateFrequency( chip, fourOp );
- }
-}
-
-void Channel::WriteB0( const Chip* chip, Bit8u val ) {
- Bit8u fourOp = chip->reg104 & chip->opl3Active & fourMask;
- //Don't handle writes to silent fourop channels
- if ( fourOp > 0x80 )
- return;
- Bitu change = (chanData ^ ( val << 8 ) ) & 0x1f00;
- if ( change ) {
- chanData ^= change;
- UpdateFrequency( chip, fourOp );
- }
- //Check for a change in the keyon/off state
- if ( !(( val ^ regB0) & 0x20))
- return;
- regB0 = val;
- if ( val & 0x20 ) {
- Op(0)->KeyOn( 0x1 );
- Op(1)->KeyOn( 0x1 );
- if ( fourOp & 0x3f ) {
- ( this + 1 )->Op(0)->KeyOn( 1 );
- ( this + 1 )->Op(1)->KeyOn( 1 );
- }
- } else {
- Op(0)->KeyOff( 0x1 );
- Op(1)->KeyOff( 0x1 );
- if ( fourOp & 0x3f ) {
- ( this + 1 )->Op(0)->KeyOff( 1 );
- ( this + 1 )->Op(1)->KeyOff( 1 );
- }
- }
-}
-
-void Channel::WriteC0( const Chip* chip, Bit8u val ) {
- Bit8u change = val ^ regC0;
- if ( !change )
- return;
- regC0 = val;
- feedback = ( val >> 1 ) & 7;
- if ( feedback ) {
- //We shift the input to the right 10 bit wave index value
- feedback = 9 - feedback;
- } else {
- feedback = 31;
- }
- //Select the new synth mode
- if ( chip->opl3Active ) {
- //4-op mode enabled for this channel
- if ( (chip->reg104 & fourMask) & 0x3f ) {
- Channel* chan0, *chan1;
- //Check if it's the 2nd channel in a 4-op
- if ( !(fourMask & 0x80 ) ) {
- chan0 = this;
- chan1 = this + 1;
- } else {
- chan0 = this - 1;
- chan1 = this;
- }
-
- Bit8u synth = ( (chan0->regC0 & 1) << 0 )| (( chan1->regC0 & 1) << 1 );
- switch ( synth ) {
- case 0:
- chan0->synthHandler = &Channel::BlockTemplate< sm3FMFM >;
- break;
- case 1:
- chan0->synthHandler = &Channel::BlockTemplate< sm3AMFM >;
- break;
- case 2:
- chan0->synthHandler = &Channel::BlockTemplate< sm3FMAM >;
- break;
- case 3:
- chan0->synthHandler = &Channel::BlockTemplate< sm3AMAM >;
- break;
- }
- //Disable updating percussion channels
- } else if ((fourMask & 0x40) && ( chip->regBD & 0x20) ) {
-
- //Regular dual op, am or fm
- } else if ( val & 1 ) {
- synthHandler = &Channel::BlockTemplate< sm3AM >;
- } else {
- synthHandler = &Channel::BlockTemplate< sm3FM >;
- }
- maskLeft = ( val & 0x10 ) ? -1 : 0;
- maskRight = ( val & 0x20 ) ? -1 : 0;
- //opl2 active
- } else {
- //Disable updating percussion channels
- if ( (fourMask & 0x40) && ( chip->regBD & 0x20 ) ) {
-
- //Regular dual op, am or fm
- } else if ( val & 1 ) {
- synthHandler = &Channel::BlockTemplate< sm2AM >;
- } else {
- synthHandler = &Channel::BlockTemplate< sm2FM >;
- }
- }
-}
-
-void Channel::ResetC0( const Chip* chip ) {
- Bit8u val = regC0;
- regC0 ^= 0xff;
- WriteC0( chip, val );
-}
-
-template< bool opl3Mode>
-INLINE void Channel::GeneratePercussion( Chip* chip, Bit32s* output ) {
- Channel* chan = this;
-
- //BassDrum
- Bit32s mod = (Bit32u)((old[0] + old[1])) >> feedback;
- old[0] = old[1];
- old[1] = Op(0)->GetSample( mod );
-
- //When bassdrum is in AM mode first operator is ignoed
- if ( chan->regC0 & 1 ) {
- mod = 0;
- } else {
- mod = old[0];
- }
- Bit32s sample = Op(1)->GetSample( mod );
-
-
- //Precalculate stuff used by other outputs
- Bit32u noiseBit = chip->ForwardNoise() & 0x1;
- Bit32u c2 = Op(2)->ForwardWave();
- Bit32u c5 = Op(5)->ForwardWave();
- Bit32u phaseBit = (((c2 & 0x88) ^ ((c2<<5) & 0x80)) | ((c5 ^ (c5<<2)) & 0x20)) ? 0x02 : 0x00;
-
- //Hi-Hat
- Bit32u hhVol = Op(2)->ForwardVolume();
- if ( !ENV_SILENT( hhVol ) ) {
- Bit32u hhIndex = (phaseBit<<8) | (0x34 << ( phaseBit ^ (noiseBit << 1 )));
- sample += Op(2)->GetWave( hhIndex, hhVol );
- }
- //Snare Drum
- Bit32u sdVol = Op(3)->ForwardVolume();
- if ( !ENV_SILENT( sdVol ) ) {
- Bit32u sdIndex = ( 0x100 + (c2 & 0x100) ) ^ ( noiseBit << 8 );
- sample += Op(3)->GetWave( sdIndex, sdVol );
- }
- //Tom-tom
- sample += Op(4)->GetSample( 0 );
-
- //Top-Cymbal
- Bit32u tcVol = Op(5)->ForwardVolume();
- if ( !ENV_SILENT( tcVol ) ) {
- Bit32u tcIndex = (1 + phaseBit) << 8;
- sample += Op(5)->GetWave( tcIndex, tcVol );
- }
- sample <<= 1;
- if ( opl3Mode ) {
- output[0] += sample;
- output[1] += sample;
- } else {
- output[0] += sample;
- }
-}
-
-template<SynthMode mode>
-Channel* Channel::BlockTemplate( Chip* chip, Bit32u samples, Bit32s* output ) {
- switch( mode ) {
- case sm2AM:
- case sm3AM:
- if ( Op(0)->Silent() && Op(1)->Silent() ) {
- old[0] = old[1] = 0;
- return (this + 1);
- }
- break;
- case sm2FM:
- case sm3FM:
- if ( Op(1)->Silent() ) {
- old[0] = old[1] = 0;
- return (this + 1);
- }
- break;
- case sm3FMFM:
- if ( Op(3)->Silent() ) {
- old[0] = old[1] = 0;
- return (this + 2);
- }
- break;
- case sm3AMFM:
- if ( Op(0)->Silent() && Op(3)->Silent() ) {
- old[0] = old[1] = 0;
- return (this + 2);
- }
- break;
- case sm3FMAM:
- if ( Op(1)->Silent() && Op(3)->Silent() ) {
- old[0] = old[1] = 0;
- return (this + 2);
- }
- break;
- case sm3AMAM:
- if ( Op(0)->Silent() && Op(2)->Silent() && Op(3)->Silent() ) {
- old[0] = old[1] = 0;
- return (this + 2);
- }
- break;
- case sm2Percussion:
- // This case was not handled in the DOSBox code either
- // thus we leave this blank.
- // TODO: Consider checking this.
- break;
- case sm3Percussion:
- // This case was not handled in the DOSBox code either
- // thus we leave this blank.
- // TODO: Consider checking this.
- break;
- case sm4Start:
- // This case was not handled in the DOSBox code either
- // thus we leave this blank.
- // TODO: Consider checking this.
- break;
- case sm6Start:
- // This case was not handled in the DOSBox code either
- // thus we leave this blank.
- // TODO: Consider checking this.
- break;
- }
- //Init the operators with the the current vibrato and tremolo values
- Op( 0 )->Prepare( chip );
- Op( 1 )->Prepare( chip );
- if ( mode > sm4Start ) {
- Op( 2 )->Prepare( chip );
- Op( 3 )->Prepare( chip );
- }
- if ( mode > sm6Start ) {
- Op( 4 )->Prepare( chip );
- Op( 5 )->Prepare( chip );
- }
- for ( Bitu i = 0; i < samples; i++ ) {
- //Early out for percussion handlers
- if ( mode == sm2Percussion ) {
- GeneratePercussion<false>( chip, output + i );
- continue; //Prevent some unitialized value bitching
- } else if ( mode == sm3Percussion ) {
- GeneratePercussion<true>( chip, output + i * 2 );
- continue; //Prevent some unitialized value bitching
- }
-
- //Do unsigned shift so we can shift out all bits but still stay in 10 bit range otherwise
- Bit32s mod = (Bit32u)((old[0] + old[1])) >> feedback;
- old[0] = old[1];
- old[1] = Op(0)->GetSample( mod );
- Bit32s sample;
- Bit32s out0 = old[0];
- if ( mode == sm2AM || mode == sm3AM ) {
- sample = out0 + Op(1)->GetSample( 0 );
- } else if ( mode == sm2FM || mode == sm3FM ) {
- sample = Op(1)->GetSample( out0 );
- } else if ( mode == sm3FMFM ) {
- Bits next = Op(1)->GetSample( out0 );
- next = Op(2)->GetSample( next );
- sample = Op(3)->GetSample( next );
- } else if ( mode == sm3AMFM ) {
- sample = out0;
- Bits next = Op(1)->GetSample( 0 );
- next = Op(2)->GetSample( next );
- sample += Op(3)->GetSample( next );
- } else if ( mode == sm3FMAM ) {
- sample = Op(1)->GetSample( out0 );
- Bits next = Op(2)->GetSample( 0 );
- sample += Op(3)->GetSample( next );
- } else if ( mode == sm3AMAM ) {
- sample = out0;
- Bits next = Op(1)->GetSample( 0 );
- sample += Op(2)->GetSample( next );
- sample += Op(3)->GetSample( 0 );
- }
- switch( mode ) {
- case sm2AM:
- case sm2FM:
- output[ i ] += sample;
- break;
- case sm3AM:
- case sm3FM:
- case sm3FMFM:
- case sm3AMFM:
- case sm3FMAM:
- case sm3AMAM:
- output[ i * 2 + 0 ] += sample & maskLeft;
- output[ i * 2 + 1 ] += sample & maskRight;
- break;
- case sm2Percussion:
- // This case was not handled in the DOSBox code either
- // thus we leave this blank.
- // TODO: Consider checking this.
- break;
- case sm3Percussion:
- // This case was not handled in the DOSBox code either
- // thus we leave this blank.
- // TODO: Consider checking this.
- break;
- case sm4Start:
- // This case was not handled in the DOSBox code either
- // thus we leave this blank.
- // TODO: Consider checking this.
- break;
- case sm6Start:
- // This case was not handled in the DOSBox code either
- // thus we leave this blank.
- // TODO: Consider checking this.
- break;
- }
- }
- switch( mode ) {
- case sm2AM:
- case sm2FM:
- case sm3AM:
- case sm3FM:
- return ( this + 1 );
- case sm3FMFM:
- case sm3AMFM:
- case sm3FMAM:
- case sm3AMAM:
- return( this + 2 );
- case sm2Percussion:
- case sm3Percussion:
- return( this + 3 );
- case sm4Start:
- // This case was not handled in the DOSBox code either
- // thus we leave this blank.
- // TODO: Consider checking this.
- break;
- case sm6Start:
- // This case was not handled in the DOSBox code either
- // thus we leave this blank.
- // TODO: Consider checking this.
- break;
- }
- return 0;
-}
-
-/*
- Chip
-*/
-
-Chip::Chip() {
- reg08 = 0;
- reg04 = 0;
- regBD = 0;
- reg104 = 0;
- opl3Active = 0;
-}
-
-INLINE Bit32u Chip::ForwardNoise() {
- noiseCounter += noiseAdd;
- Bitu count = noiseCounter >> LFO_SH;
- noiseCounter &= WAVE_MASK;
- for ( ; count > 0; --count ) {
- //Noise calculation from mame
- noiseValue ^= ( 0x800302 ) & ( 0 - (noiseValue & 1 ) );
- noiseValue >>= 1;
- }
- return noiseValue;
-}
-
-INLINE Bit32u Chip::ForwardLFO( Bit32u samples ) {
- //Current vibrato value, runs 4x slower than tremolo
- vibratoSign = ( VibratoTable[ vibratoIndex >> 2] ) >> 7;
- vibratoShift = ( VibratoTable[ vibratoIndex >> 2] & 7) + vibratoStrength;
- tremoloValue = TremoloTable[ tremoloIndex ] >> tremoloStrength;
-
- //Check hom many samples there can be done before the value changes
- Bit32u todo = LFO_MAX - lfoCounter;
- Bit32u count = (todo + lfoAdd - 1) / lfoAdd;
- if ( count > samples ) {
- count = samples;
- lfoCounter += count * lfoAdd;
- } else {
- lfoCounter += count * lfoAdd;
- lfoCounter &= (LFO_MAX - 1);
- //Maximum of 7 vibrato value * 4
- vibratoIndex = ( vibratoIndex + 1 ) & 31;
- //Clip tremolo to the the table size
- if ( tremoloIndex + 1 < TREMOLO_TABLE )
- ++tremoloIndex;
- else
- tremoloIndex = 0;
- }
- return count;
-}
-
-
-void Chip::WriteBD( Bit8u val ) {
- Bit8u change = regBD ^ val;
- if ( !change )
- return;
- regBD = val;
- //TODO could do this with shift and xor?
- vibratoStrength = (val & 0x40) ? 0x00 : 0x01;
- tremoloStrength = (val & 0x80) ? 0x00 : 0x02;
- if ( val & 0x20 ) {
- //Drum was just enabled, make sure channel 6 has the right synth
- if ( change & 0x20 ) {
- if ( opl3Active ) {
- chan[6].synthHandler = &Channel::BlockTemplate< sm3Percussion >;
- } else {
- chan[6].synthHandler = &Channel::BlockTemplate< sm2Percussion >;
- }
- }
- //Bass Drum
- if ( val & 0x10 ) {
- chan[6].op[0].KeyOn( 0x2 );
- chan[6].op[1].KeyOn( 0x2 );
- } else {
- chan[6].op[0].KeyOff( 0x2 );
- chan[6].op[1].KeyOff( 0x2 );
- }
- //Hi-Hat
- if ( val & 0x1 ) {
- chan[7].op[0].KeyOn( 0x2 );
- } else {
- chan[7].op[0].KeyOff( 0x2 );
- }
- //Snare
- if ( val & 0x8 ) {
- chan[7].op[1].KeyOn( 0x2 );
- } else {
- chan[7].op[1].KeyOff( 0x2 );
- }
- //Tom-Tom
- if ( val & 0x4 ) {
- chan[8].op[0].KeyOn( 0x2 );
- } else {
- chan[8].op[0].KeyOff( 0x2 );
- }
- //Top Cymbal
- if ( val & 0x2 ) {
- chan[8].op[1].KeyOn( 0x2 );
- } else {
- chan[8].op[1].KeyOff( 0x2 );
- }
- //Toggle keyoffs when we turn off the percussion
- } else if ( change & 0x20 ) {
- //Trigger a reset to setup the original synth handler
- chan[6].ResetC0( this );
- chan[6].op[0].KeyOff( 0x2 );
- chan[6].op[1].KeyOff( 0x2 );
- chan[7].op[0].KeyOff( 0x2 );
- chan[7].op[1].KeyOff( 0x2 );
- chan[8].op[0].KeyOff( 0x2 );
- chan[8].op[1].KeyOff( 0x2 );
- }
-}
-
-
-#define REGOP( _FUNC_ ) \
- index = ( ( reg >> 3) & 0x20 ) | ( reg & 0x1f ); \
- if ( OpOffsetTable[ index ] ) { \
- Operator* regOp = (Operator*)( ((char *)this ) + OpOffsetTable[ index ] ); \
- regOp->_FUNC_( this, val ); \
- }
-
-#define REGCHAN( _FUNC_ ) \
- index = ( ( reg >> 4) & 0x10 ) | ( reg & 0xf ); \
- if ( ChanOffsetTable[ index ] ) { \
- Channel* regChan = (Channel*)( ((char *)this ) + ChanOffsetTable[ index ] ); \
- regChan->_FUNC_( this, val ); \
- }
-
-void Chip::WriteReg( Bit32u reg, Bit8u val ) {
- Bitu index;
- switch ( (reg & 0xf0) >> 4 ) {
- case 0x00 >> 4:
- if ( reg == 0x01 ) {
- waveFormMask = ( val & 0x20 ) ? 0x7 : 0x0;
- } else if ( reg == 0x104 ) {
- //Only detect changes in lowest 6 bits
- if ( !((reg104 ^ val) & 0x3f) )
- return;
- //Always keep the highest bit enabled, for checking > 0x80
- reg104 = 0x80 | ( val & 0x3f );
- } else if ( reg == 0x105 ) {
- //MAME says the real opl3 doesn't reset anything on opl3 disable/enable till the next write in another register
- if ( !((opl3Active ^ val) & 1 ) )
- return;
- opl3Active = ( val & 1 ) ? 0xff : 0;
- //Update the 0xc0 register for all channels to signal the switch to mono/stereo handlers
- for ( int i = 0; i < 18;i++ ) {
- chan[i].ResetC0( this );
- }
- } else if ( reg == 0x08 ) {
- reg08 = val;
- }
- case 0x10 >> 4:
- break;
- case 0x20 >> 4:
- case 0x30 >> 4:
- REGOP( Write20 );
- break;
- case 0x40 >> 4:
- case 0x50 >> 4:
- REGOP( Write40 );
- break;
- case 0x60 >> 4:
- case 0x70 >> 4:
- REGOP( Write60 );
- break;
- case 0x80 >> 4:
- case 0x90 >> 4:
- REGOP( Write80 );
- break;
- case 0xa0 >> 4:
- REGCHAN( WriteA0 );
- break;
- case 0xb0 >> 4:
- if ( reg == 0xbd ) {
- WriteBD( val );
- } else {
- REGCHAN( WriteB0 );
- }
- break;
- case 0xc0 >> 4:
- REGCHAN( WriteC0 );
- case 0xd0 >> 4:
- break;
- case 0xe0 >> 4:
- case 0xf0 >> 4:
- REGOP( WriteE0 );
- break;
- }
-}
-
-
-Bit32u Chip::WriteAddr( Bit32u port, Bit8u val ) {
- switch ( port & 3 ) {
- case 0:
- return val;
- case 2:
- if ( opl3Active || (val == 0x05) )
- return 0x100 | val;
- else
- return val;
- }
- return 0;
-}
-
-void Chip::GenerateBlock2( Bitu total, Bit32s* output ) {
- while ( total > 0 ) {
- Bit32u samples = ForwardLFO( total );
- memset(output, 0, sizeof(Bit32s) * samples);
- int count = 0;
- for( Channel* ch = chan; ch < chan + 9; ) {
- count++;
- ch = (ch->*(ch->synthHandler))( this, samples, output );
- }
- total -= samples;
- output += samples;
- }
-}
-
-void Chip::GenerateBlock3( Bitu total, Bit32s* output ) {
- while ( total > 0 ) {
- Bit32u samples = ForwardLFO( total );
- memset(output, 0, sizeof(Bit32s) * 2 * samples);
- int count = 0;
- for( Channel* ch = chan; ch < chan + 18; ) {
- count++;
- ch = (ch->*(ch->synthHandler))( this, samples, output );
- }
- total -= samples;
- output += samples * 2;
- }
-}
-
-void Chip::Setup( Bit32u rate ) {
- double scale = OPLRATE / (double)rate;
-
- //Noise counter is run at the same precision as general waves
- noiseAdd = (Bit32u)( 0.5 + scale * ( 1 << LFO_SH ) );
- noiseCounter = 0;
- noiseValue = 1; //Make sure it triggers the noise xor the first time
- //The low frequency oscillation counter
- //Every time his overflows vibrato and tremoloindex are increased
- lfoAdd = (Bit32u)( 0.5 + scale * ( 1 << LFO_SH ) );
- lfoCounter = 0;
- vibratoIndex = 0;
- tremoloIndex = 0;
-
- //With higher octave this gets shifted up
- //-1 since the freqCreateTable = *2
-#ifdef WAVE_PRECISION
- double freqScale = ( 1 << 7 ) * scale * ( 1 << ( WAVE_SH - 1 - 10));
- for ( int i = 0; i < 16; i++ ) {
- freqMul[i] = (Bit32u)( 0.5 + freqScale * FreqCreateTable[ i ] );
- }
-#else
- Bit32u freqScale = (Bit32u)( 0.5 + scale * ( 1 << ( WAVE_SH - 1 - 10)));
- for ( int i = 0; i < 16; i++ ) {
- freqMul[i] = freqScale * FreqCreateTable[ i ];
- }
-#endif
-
- //-3 since the real envelope takes 8 steps to reach the single value we supply
- for ( Bit8u i = 0; i < 76; i++ ) {
- Bit8u index, shift;
- EnvelopeSelect( i, index, shift );
- linearRates[i] = (Bit32u)( scale * (EnvelopeIncreaseTable[ index ] << ( RATE_SH + ENV_EXTRA - shift - 3 )));
- }
- //Generate the best matching attack rate
- for ( Bit8u i = 0; i < 62; i++ ) {
- Bit8u index, shift;
- EnvelopeSelect( i, index, shift );
- //Original amount of samples the attack would take
- Bit32s original = (Bit32u)( (AttackSamplesTable[ index ] << shift) / scale);
-
- Bit32s guessAdd = (Bit32u)( scale * (EnvelopeIncreaseTable[ index ] << ( RATE_SH - shift - 3 )));
- Bit32s bestAdd = guessAdd;
- Bit32u bestDiff = 1 << 30;
- for( Bit32u passes = 0; passes < 16; passes ++ ) {
- Bit32s volume = ENV_MAX;
- Bit32s samples = 0;
- Bit32u count = 0;
- while ( volume > 0 && samples < original * 2 ) {
- count += guessAdd;
- Bit32s change = count >> RATE_SH;
- count &= RATE_MASK;
- if ( GCC_UNLIKELY(change) ) { // less than 1 %
- volume += ( ~volume * change ) >> 3;
- }
- samples++;
-
- }
- Bit32s diff = original - samples;
- Bit32u lDiff = labs( diff );
- //Init last on first pass
- if ( lDiff < bestDiff ) {
- bestDiff = lDiff;
- bestAdd = guessAdd;
- if ( !bestDiff )
- break;
- }
- //Below our target
- if ( diff < 0 ) {
- //Better than the last time
- Bit32s mul = ((original - diff) << 12) / original;
- guessAdd = ((guessAdd * mul) >> 12);
- guessAdd++;
- } else if ( diff > 0 ) {
- Bit32s mul = ((original - diff) << 12) / original;
- guessAdd = (guessAdd * mul) >> 12;
- guessAdd--;
- }
- }
- attackRates[i] = bestAdd;
- }
- for ( Bit8u i = 62; i < 76; i++ ) {
- //This should provide instant volume maximizing
- attackRates[i] = 8 << RATE_SH;
- }
- //Setup the channels with the correct four op flags
- //Channels are accessed through a table so they appear linear here
- chan[ 0].fourMask = 0x00 | ( 1 << 0 );
- chan[ 1].fourMask = 0x80 | ( 1 << 0 );
- chan[ 2].fourMask = 0x00 | ( 1 << 1 );
- chan[ 3].fourMask = 0x80 | ( 1 << 1 );
- chan[ 4].fourMask = 0x00 | ( 1 << 2 );
- chan[ 5].fourMask = 0x80 | ( 1 << 2 );
-
- chan[ 9].fourMask = 0x00 | ( 1 << 3 );
- chan[10].fourMask = 0x80 | ( 1 << 3 );
- chan[11].fourMask = 0x00 | ( 1 << 4 );
- chan[12].fourMask = 0x80 | ( 1 << 4 );
- chan[13].fourMask = 0x00 | ( 1 << 5 );
- chan[14].fourMask = 0x80 | ( 1 << 5 );
-
- //mark the percussion channels
- chan[ 6].fourMask = 0x40;
- chan[ 7].fourMask = 0x40;
- chan[ 8].fourMask = 0x40;
-
- //Clear Everything in opl3 mode
- WriteReg( 0x105, 0x1 );
- for ( int i = 0; i < 512; i++ ) {
- if ( i == 0x105 )
- continue;
- WriteReg( i, 0xff );
- WriteReg( i, 0x0 );
- }
- WriteReg( 0x105, 0x0 );
- //Clear everything in opl2 mode
- for ( int i = 0; i < 255; i++ ) {
- WriteReg( i, 0xff );
- WriteReg( i, 0x0 );
- }
-}
-
-static bool doneTables = false;
-void InitTables( void ) {
- if ( doneTables )
- return;
- doneTables = true;
-#if ( DBOPL_WAVE == WAVE_HANDLER ) || ( DBOPL_WAVE == WAVE_TABLELOG )
- //Exponential volume table, same as the real adlib
- for ( int i = 0; i < 256; i++ ) {
- //Save them in reverse
- ExpTable[i] = (int)( 0.5 + ( pow(2.0, ( 255 - i) * ( 1.0 /256 ) )-1) * 1024 );
- ExpTable[i] += 1024; //or remove the -1 oh well :)
- //Preshift to the left once so the final volume can shift to the right
- ExpTable[i] *= 2;
- }
-#endif
-#if ( DBOPL_WAVE == WAVE_HANDLER )
- //Add 0.5 for the trunc rounding of the integer cast
- //Do a PI sinetable instead of the original 0.5 PI
- for ( int i = 0; i < 512; i++ ) {
- SinTable[i] = (Bit16s)( 0.5 - log10( sin( (i + 0.5) * (PI / 512.0) ) ) / log10(2.0)*256 );
- }
-#endif
-#if ( DBOPL_WAVE == WAVE_TABLEMUL )
- //Multiplication based tables
- for ( int i = 0; i < 384; i++ ) {
- int s = i * 8;
- //TODO maybe keep some of the precision errors of the original table?
- double val = ( 0.5 + ( pow(2.0, -1.0 + ( 255 - s) * ( 1.0 /256 ) )) * ( 1 << MUL_SH ));
- MulTable[i] = (Bit16u)(val);
- }
-
- //Sine Wave Base
- for ( int i = 0; i < 512; i++ ) {
- WaveTable[ 0x0200 + i ] = (Bit16s)(sin( (i + 0.5) * (PI / 512.0) ) * 4084);
- WaveTable[ 0x0000 + i ] = -WaveTable[ 0x200 + i ];
- }
- //Exponential wave
- for ( int i = 0; i < 256; i++ ) {
- WaveTable[ 0x700 + i ] = (Bit16s)( 0.5 + ( pow(2.0, -1.0 + ( 255 - i * 8) * ( 1.0 /256 ) ) ) * 4085 );
- WaveTable[ 0x6ff - i ] = -WaveTable[ 0x700 + i ];
- }
-#endif
-#if ( DBOPL_WAVE == WAVE_TABLELOG )
- //Sine Wave Base
- for ( int i = 0; i < 512; i++ ) {
- WaveTable[ 0x0200 + i ] = (Bit16s)( 0.5 - log10( sin( (i + 0.5) * (PI / 512.0) ) ) / log10(2.0)*256 );
- WaveTable[ 0x0000 + i ] = ((Bit16s)0x8000) | WaveTable[ 0x200 + i];
- }
- //Exponential wave
- for ( int i = 0; i < 256; i++ ) {
- WaveTable[ 0x700 + i ] = i * 8;
- WaveTable[ 0x6ff - i ] = ((Bit16s)0x8000) | i * 8;
- }
-#endif
-
- // | |//\\|____|WAV7|//__|/\ |____|/\/\|
- // |\\//| | |WAV7| | \/| | |
- // |06 |0126|27 |7 |3 |4 |4 5 |5 |
-
-#if (( DBOPL_WAVE == WAVE_TABLELOG ) || ( DBOPL_WAVE == WAVE_TABLEMUL ))
- for ( int i = 0; i < 256; i++ ) {
- //Fill silence gaps
- WaveTable[ 0x400 + i ] = WaveTable[0];
- WaveTable[ 0x500 + i ] = WaveTable[0];
- WaveTable[ 0x900 + i ] = WaveTable[0];
- WaveTable[ 0xc00 + i ] = WaveTable[0];
- WaveTable[ 0xd00 + i ] = WaveTable[0];
- //Replicate sines in other pieces
- WaveTable[ 0x800 + i ] = WaveTable[ 0x200 + i ];
- //double speed sines
- WaveTable[ 0xa00 + i ] = WaveTable[ 0x200 + i * 2 ];
- WaveTable[ 0xb00 + i ] = WaveTable[ 0x000 + i * 2 ];
- WaveTable[ 0xe00 + i ] = WaveTable[ 0x200 + i * 2 ];
- WaveTable[ 0xf00 + i ] = WaveTable[ 0x200 + i * 2 ];
- }
-#endif
-
- //Create the ksl table
- for ( int oct = 0; oct < 8; oct++ ) {
- int base = oct * 8;
- for ( int i = 0; i < 16; i++ ) {
- int val = base - KslCreateTable[i];
- if ( val < 0 )
- val = 0;
- //*4 for the final range to match attenuation range
- KslTable[ oct * 16 + i ] = val * 4;
- }
- }
- //Create the Tremolo table, just increase and decrease a triangle wave
- for ( Bit8u i = 0; i < TREMOLO_TABLE / 2; i++ ) {
- Bit8u val = i << ENV_EXTRA;
- TremoloTable[i] = val;
- TremoloTable[TREMOLO_TABLE - 1 - i] = val;
- }
- //Create a table with offsets of the channels from the start of the chip
- DBOPL::Chip* chip = 0;
- for ( Bitu i = 0; i < 32; i++ ) {
- Bitu index = i & 0xf;
- if ( index >= 9 ) {
- ChanOffsetTable[i] = 0;
- continue;
- }
- //Make sure the four op channels follow eachother
- if ( index < 6 ) {
- index = (index % 3) * 2 + ( index / 3 );
- }
- //Add back the bits for highest ones
- if ( i >= 16 )
- index += 9;
- Bitu blah = reinterpret_cast<size_t>( &(chip->chan[ index ]) );
- ChanOffsetTable[i] = blah;
- }
- //Same for operators
- for ( Bitu i = 0; i < 64; i++ ) {
- if ( i % 8 >= 6 || ( (i / 8) % 4 == 3 ) ) {
- OpOffsetTable[i] = 0;
- continue;
- }
- Bitu chNum = (i / 8) * 3 + (i % 8) % 3;
- //Make sure we use 16 and up for the 2nd range to match the chanoffset gap
- if ( chNum >= 12 )
- chNum += 16 - 12;
- Bitu opNum = ( i % 8 ) / 3;
- DBOPL::Channel* chan = 0;
- Bitu blah = reinterpret_cast<size_t>( &(chan->op[opNum]) );
- OpOffsetTable[i] = ChanOffsetTable[ chNum ] + blah;
- }
-#if 0
- //Stupid checks if table's are correct
- for ( Bitu i = 0; i < 18; i++ ) {
- Bit32u find = (Bit16u)( &(chip->chan[ i ]) );
- for ( Bitu c = 0; c < 32; c++ ) {
- if ( ChanOffsetTable[c] == find ) {
- find = 0;
- break;
- }
- }
- if ( find ) {
- find = find;
- }
- }
- for ( Bitu i = 0; i < 36; i++ ) {
- Bit32u find = (Bit16u)( &(chip->chan[ i / 2 ].op[i % 2]) );
- for ( Bitu c = 0; c < 64; c++ ) {
- if ( OpOffsetTable[c] == find ) {
- find = 0;
- break;
- }
- }
- if ( find ) {
- find = find;
- }
- }
-#endif
-}
-
-} //Namespace DBOPL
-} // End of namespace DOSBox
-} // End of namespace OPL
-
-#endif // !DISABLE_DOSBOX_OPL
diff --git a/sound/softsynth/opl/dbopl.h b/sound/softsynth/opl/dbopl.h
deleted file mode 100644
index 87d1045fab..0000000000
--- a/sound/softsynth/opl/dbopl.h
+++ /dev/null
@@ -1,283 +0,0 @@
-/*
- * Copyright (C) 2002-2010 The DOSBox Team
- *
- * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-// Last synch with DOSBox SVN trunk r3556
-
-#ifndef SOUND_SOFTSYNTH_OPL_DBOPL_H
-#define SOUND_SOFTSYNTH_OPL_DBOPL_H
-
-#include "common/scummsys.h"
-
-#ifndef DISABLE_DOSBOX_OPL
-
-namespace OPL {
-namespace DOSBox {
-
-//Use 8 handlers based on a small logatirmic wavetabe and an exponential table for volume
-#define WAVE_HANDLER 10
-//Use a logarithmic wavetable with an exponential table for volume
-#define WAVE_TABLELOG 11
-//Use a linear wavetable with a multiply table for volume
-#define WAVE_TABLEMUL 12
-
-//Select the type of wave generator routine
-#define DBOPL_WAVE WAVE_TABLEMUL
-
-namespace DBOPL {
-
-// Type aliases for the DBOPL code
-typedef int Bits;
-typedef uint Bitu;
-
-typedef int8 Bit8s;
-typedef uint8 Bit8u;
-
-typedef int16 Bit16s;
-typedef uint16 Bit16u;
-
-typedef int32 Bit32s;
-typedef uint32 Bit32u;
-
-#define DB_FASTCALL
-#define GCC_UNLIKELY(x) (x)
-#define INLINE inline
-// -------------------------------
-
-struct Chip;
-struct Operator;
-struct Channel;
-
-#if (DBOPL_WAVE == WAVE_HANDLER)
-typedef Bits ( DB_FASTCALL *WaveHandler) ( Bitu i, Bitu volume );
-#endif
-
-typedef Bits ( DBOPL::Operator::*VolumeHandler) ( );
-typedef Channel* ( DBOPL::Channel::*SynthHandler) ( Chip* chip, Bit32u samples, Bit32s* output );
-
-//Different synth modes that can generate blocks of data
-typedef enum {
- sm2AM,
- sm2FM,
- sm3AM,
- sm3FM,
- sm4Start,
- sm3FMFM,
- sm3AMFM,
- sm3FMAM,
- sm3AMAM,
- sm6Start,
- sm2Percussion,
- sm3Percussion
-} SynthMode;
-
-//Shifts for the values contained in chandata variable
-enum {
- SHIFT_KSLBASE = 16,
- SHIFT_KEYCODE = 24
-};
-
-struct Operator {
-public:
- //Masks for operator 20 values
- enum {
- MASK_KSR = 0x10,
- MASK_SUSTAIN = 0x20,
- MASK_VIBRATO = 0x40,
- MASK_TREMOLO = 0x80
- };
-
- typedef enum {
- OFF,
- RELEASE,
- SUSTAIN,
- DECAY,
- ATTACK
- } State;
-
- VolumeHandler volHandler;
-
-#if (DBOPL_WAVE == WAVE_HANDLER)
- WaveHandler waveHandler; //Routine that generate a wave
-#else
- Bit16s* waveBase;
- Bit32u waveMask;
- Bit32u waveStart;
-#endif
- Bit32u waveIndex; //WAVE_BITS shifted counter of the frequency index
- Bit32u waveAdd; //The base frequency without vibrato
- Bit32u waveCurrent; //waveAdd + vibratao
-
- Bit32u chanData; //Frequency/octave and derived data coming from whatever channel controls this
- Bit32u freqMul; //Scale channel frequency with this, TODO maybe remove?
- Bit32u vibrato; //Scaled up vibrato strength
- Bit32s sustainLevel; //When stopping at sustain level stop here
- Bit32s totalLevel; //totalLevel is added to every generated volume
- Bit32u currentLevel; //totalLevel + tremolo
- Bit32s volume; //The currently active volume
-
- Bit32u attackAdd; //Timers for the different states of the envelope
- Bit32u decayAdd;
- Bit32u releaseAdd;
- Bit32u rateIndex; //Current position of the evenlope
-
- Bit8u rateZero; //Bits for the different states of the envelope having no changes
- Bit8u keyOn; //Bitmask of different values that can generate keyon
- //Registers, also used to check for changes
- Bit8u reg20, reg40, reg60, reg80, regE0;
- //Active part of the envelope we're in
- Bit8u state;
- //0xff when tremolo is enabled
- Bit8u tremoloMask;
- //Strength of the vibrato
- Bit8u vibStrength;
- //Keep track of the calculated KSR so we can check for changes
- Bit8u ksr;
-private:
- void SetState( Bit8u s );
- void UpdateAttack( const Chip* chip );
- void UpdateRelease( const Chip* chip );
- void UpdateDecay( const Chip* chip );
-public:
- void UpdateAttenuation();
- void UpdateRates( const Chip* chip );
- void UpdateFrequency( );
-
- void Write20( const Chip* chip, Bit8u val );
- void Write40( const Chip* chip, Bit8u val );
- void Write60( const Chip* chip, Bit8u val );
- void Write80( const Chip* chip, Bit8u val );
- void WriteE0( const Chip* chip, Bit8u val );
-
- bool Silent() const;
- void Prepare( const Chip* chip );
-
- void KeyOn( Bit8u mask);
- void KeyOff( Bit8u mask);
-
- template< State state>
- Bits TemplateVolume( );
-
- Bit32s RateForward( Bit32u add );
- Bitu ForwardWave();
- Bitu ForwardVolume();
-
- Bits GetSample( Bits modulation );
- Bits GetWave( Bitu index, Bitu vol );
-public:
- Operator();
-};
-
-struct Channel {
- Operator op[2];
- inline Operator* Op( Bitu index ) {
- return &( ( this + (index >> 1) )->op[ index & 1 ]);
- }
- SynthHandler synthHandler;
- Bit32u chanData; //Frequency/octave and derived values
- Bit32s old[2]; //Old data for feedback
-
- Bit8u feedback; //Feedback shift
- Bit8u regB0; //Register values to check for changes
- Bit8u regC0;
- //This should correspond with reg104, bit 6 indicates a Percussion channel, bit 7 indicates a silent channel
- Bit8u fourMask;
- Bit8s maskLeft; //Sign extended values for both channel's panning
- Bit8s maskRight;
-
- //Forward the channel data to the operators of the channel
- void SetChanData( const Chip* chip, Bit32u data );
- //Change in the chandata, check for new values and if we have to forward to operators
- void UpdateFrequency( const Chip* chip, Bit8u fourOp );
- void WriteA0( const Chip* chip, Bit8u val );
- void WriteB0( const Chip* chip, Bit8u val );
- void WriteC0( const Chip* chip, Bit8u val );
- void ResetC0( const Chip* chip );
-
- //call this for the first channel
- template< bool opl3Mode >
- void GeneratePercussion( Chip* chip, Bit32s* output );
-
- //Generate blocks of data in specific modes
- template<SynthMode mode>
- Channel* BlockTemplate( Chip* chip, Bit32u samples, Bit32s* output );
- Channel();
-};
-
-struct Chip {
- //This is used as the base counter for vibrato and tremolo
- Bit32u lfoCounter;
- Bit32u lfoAdd;
-
-
- Bit32u noiseCounter;
- Bit32u noiseAdd;
- Bit32u noiseValue;
-
- //Frequency scales for the different multiplications
- Bit32u freqMul[16];
- //Rates for decay and release for rate of this chip
- Bit32u linearRates[76];
- //Best match attack rates for the rate of this chip
- Bit32u attackRates[76];
-
- //18 channels with 2 operators each
- Channel chan[18];
-
- Bit8u reg104;
- Bit8u reg08;
- Bit8u reg04;
- Bit8u regBD;
- Bit8u vibratoIndex;
- Bit8u tremoloIndex;
- Bit8s vibratoSign;
- Bit8u vibratoShift;
- Bit8u tremoloValue;
- Bit8u vibratoStrength;
- Bit8u tremoloStrength;
- //Mask for allowed wave forms
- Bit8u waveFormMask;
- //0 or -1 when enabled
- Bit8s opl3Active;
-
- //Return the maximum amount of samples before and LFO change
- Bit32u ForwardLFO( Bit32u samples );
- Bit32u ForwardNoise();
-
- void WriteBD( Bit8u val );
- void WriteReg(Bit32u reg, Bit8u val );
-
- Bit32u WriteAddr( Bit32u port, Bit8u val );
-
- void GenerateBlock2( Bitu samples, Bit32s* output );
- void GenerateBlock3( Bitu samples, Bit32s* output );
-
- void Generate( Bit32u samples );
- void Setup( Bit32u r );
-
- Chip();
-};
-
-void InitTables();
-
-} //Namespace
-} // End of namespace DOSBox
-} // End of namespace OPL
-
-#endif // !DISABLE_DOSBOX_OPL
-
-#endif
diff --git a/sound/softsynth/opl/dosbox.cpp b/sound/softsynth/opl/dosbox.cpp
deleted file mode 100644
index 29993ce3d8..0000000000
--- a/sound/softsynth/opl/dosbox.cpp
+++ /dev/null
@@ -1,335 +0,0 @@
-/* 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$
- */
-
-/*
- * Based on AdLib emulation code of DOSBox
- * Copyright (C) 2002-2009 The DOSBox Team
- * Licensed under GPLv2+
- * http://www.dosbox.com
- */
-
-#ifndef DISABLE_DOSBOX_OPL
-
-#include "dosbox.h"
-#include "dbopl.h"
-
-#include "common/system.h"
-#include "common/scummsys.h"
-
-#include <math.h>
-#include <string.h>
-
-namespace OPL {
-namespace DOSBox {
-
-Timer::Timer() {
- masked = false;
- overflow = false;
- enabled = false;
- counter = 0;
- delay = 0;
-}
-
-void Timer::update(double time) {
- if (!enabled || !delay)
- return;
- double deltaStart = time - startTime;
- // Only set the overflow flag when not masked
- if (deltaStart >= 0 && !masked)
- overflow = 1;
-}
-
-void Timer::reset(double time) {
- overflow = false;
- if (!delay || !enabled)
- return;
- double delta = (time - startTime);
- double rem = fmod(delta, delay);
- double next = delay - rem;
- startTime = time + next;
-}
-
-void Timer::stop() {
- enabled = false;
-}
-
-void Timer::start(double time, int scale) {
- //Don't enable again
- if (enabled)
- return;
- enabled = true;
- delay = 0.001 * (256 - counter) * scale;
- startTime = time + delay;
-}
-
-bool Chip::write(uint32 reg, uint8 val) {
- switch (reg) {
- case 0x02:
- timer[0].counter = val;
- return true;
- case 0x03:
- timer[1].counter = val;
- return true;
- case 0x04:
- double time = g_system->getMillis() / 1000.0;
-
- if (val & 0x80) {
- timer[0].reset(time);
- timer[1].reset(time);
- } else {
- timer[0].update(time);
- timer[1].update(time);
-
- if (val & 0x1)
- timer[0].start(time, 80);
- else
- timer[0].stop();
-
- timer[0].masked = (val & 0x40) > 0;
-
- if (timer[0].masked)
- timer[0].overflow = false;
-
- if (val & 0x2)
- timer[1].start(time, 320);
- else
- timer[1].stop();
-
- timer[1].masked = (val & 0x20) > 0;
-
- if (timer[1].masked)
- timer[1].overflow = false;
- }
- return true;
- }
- return false;
-}
-
-uint8 Chip::read() {
- double time = g_system->getMillis() / 1000.0;
-
- timer[0].update(time);
- timer[1].update(time);
-
- uint8 ret = 0;
- // Overflow won't be set if a channel is masked
- if (timer[0].overflow) {
- ret |= 0x40;
- ret |= 0x80;
- }
- if (timer[1].overflow) {
- ret |= 0x20;
- ret |= 0x80;
- }
- return ret;
-}
-
-OPL::OPL(Config::OplType type) : _type(type), _rate(0), _emulator(0) {
-}
-
-OPL::~OPL() {
- free();
-}
-
-void OPL::free() {
- delete _emulator;
- _emulator = 0;
-}
-
-bool OPL::init(int rate) {
- free();
-
- memset(&_reg, 0, sizeof(_reg));
- memset(_chip, 0, sizeof(_chip));
-
- _emulator = new DBOPL::Chip();
- if (!_emulator)
- return false;
-
- DBOPL::InitTables();
- _emulator->Setup(rate);
-
- if (_type == Config::kDualOpl2) {
- // Setup opl3 mode in the hander
- _emulator->WriteReg(0x105, 1);
- }
-
- _rate = rate;
- return true;
-}
-
-void OPL::reset() {
- init(_rate);
-}
-
-void OPL::write(int port, int val) {
- if (port&1) {
- switch (_type) {
- case Config::kOpl2:
- case Config::kOpl3:
- if (!_chip[0].write(_reg.normal, val))
- _emulator->WriteReg(_reg.normal, val);
- break;
- case Config::kDualOpl2:
- // Not a 0x??8 port, then write to a specific port
- if (!(port & 0x8)) {
- byte index = (port & 2) >> 1;
- dualWrite(index, _reg.dual[index], val);
- } else {
- //Write to both ports
- dualWrite(0, _reg.dual[0], val);
- dualWrite(1, _reg.dual[1], val);
- }
- break;
- }
- } else {
- // Ask the handler to write the address
- // Make sure to clip them in the right range
- switch (_type) {
- case Config::kOpl2:
- _reg.normal = _emulator->WriteAddr(port, val) & 0xff;
- break;
- case Config::kOpl3:
- _reg.normal = _emulator->WriteAddr(port, val) & 0x1ff;
- break;
- case Config::kDualOpl2:
- // Not a 0x?88 port, when write to a specific side
- if (!(port & 0x8)) {
- byte index = (port & 2) >> 1;
- _reg.dual[index] = val & 0xff;
- } else {
- _reg.dual[0] = val & 0xff;
- _reg.dual[1] = val & 0xff;
- }
- break;
- }
- }
-}
-
-byte OPL::read(int port) {
- switch (_type) {
- case Config::kOpl2:
- if (!(port & 1))
- //Make sure the low bits are 6 on opl2
- return _chip[0].read() | 0x6;
- break;
- case Config::kOpl3:
- if (!(port & 1))
- return _chip[0].read();
- break;
- case Config::kDualOpl2:
- // Only return for the lower ports
- if (port & 1)
- return 0xff;
- // Make sure the low bits are 6 on opl2
- return _chip[(port >> 1) & 1].read() | 0x6;
- }
- return 0;
-}
-
-void OPL::writeReg(int r, int v) {
- byte tempReg = 0;
- switch (_type) {
- case Config::kOpl2:
- case Config::kDualOpl2:
- case Config::kOpl3:
- // We can't use _handler->writeReg here directly, since it would miss timer changes.
-
- // Backup old setup register
- tempReg = _reg.normal;
-
- // We need to set the register we want to write to via port 0x388
- write(0x388, r);
- // Do the real writing to the register
- write(0x389, v);
- // Restore the old register
- write(0x388, tempReg);
- break;
- };
-}
-
-void OPL::dualWrite(uint8 index, uint8 reg, uint8 val) {
- // Make sure you don't use opl3 features
- // Don't allow write to disable opl3
- if (reg == 5)
- return;
-
- // Only allow 4 waveforms
- if (reg >= 0xE0 && reg <= 0xE8)
- val &= 3;
-
- // Write to the timer?
- if (_chip[index].write(reg, val))
- return;
-
- // Enabling panning
- if (reg >= 0xC0 && reg <= 0xC8) {
- val &= 15;
- val |= index ? 0xA0 : 0x50;
- }
-
- uint32 fullReg = reg + (index ? 0x100 : 0);
- _emulator->WriteReg(fullReg, val);
-}
-
-void OPL::readBuffer(int16 *buffer, int length) {
- // For stereo OPL cards, we divide the sample count by 2,
- // to match stereo AudioStream behavior.
- if (_type != Config::kOpl2)
- length >>= 1;
-
- const uint bufferLength = 512;
- int32 tempBuffer[bufferLength * 2];
-
- if (_emulator->opl3Active) {
- while (length > 0) {
- const uint readSamples = MIN<uint>(length, bufferLength);
-
- _emulator->GenerateBlock3(readSamples, tempBuffer);
-
- for (uint i = 0; i < (readSamples << 1); ++i)
- buffer[i] = tempBuffer[i];
-
- buffer += (readSamples << 1);
- length -= readSamples;
- }
- } else {
- while (length > 0) {
- const uint readSamples = MIN<uint>(length, bufferLength << 1);
-
- _emulator->GenerateBlock2(readSamples, tempBuffer);
-
- for (uint i = 0; i < readSamples; ++i)
- buffer[i] = tempBuffer[i];
-
- buffer += readSamples;
- length -= readSamples;
- }
- }
-}
-
-} // End of namespace DOSBox
-} // End of namespace OPL
-
-#endif // !DISABLE_DOSBOX_ADLIB
diff --git a/sound/softsynth/opl/dosbox.h b/sound/softsynth/opl/dosbox.h
deleted file mode 100644
index 958310611d..0000000000
--- a/sound/softsynth/opl/dosbox.h
+++ /dev/null
@@ -1,110 +0,0 @@
-/* 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$
- */
-
-/*
- * Based on OPL emulation code of DOSBox
- * Copyright (C) 2002-2009 The DOSBox Team
- * Licensed under GPLv2+
- * http://www.dosbox.com
- */
-
-#ifndef SOUND_SOFTSYNTH_OPL_DOSBOX_H
-#define SOUND_SOFTSYNTH_OPL_DOSBOX_H
-
-#ifndef DISABLE_DOSBOX_OPL
-
-#include "sound/fmopl.h"
-
-namespace OPL {
-namespace DOSBox {
-
-struct Timer {
- double startTime;
- double delay;
- bool enabled, overflow, masked;
- uint8 counter;
-
- Timer();
-
- //Call update before making any further changes
- void update(double time);
-
- //On a reset make sure the start is in sync with the next cycle
- void reset(double time);
-
- void stop();
-
- void start(double time, int scale);
-};
-
-struct Chip {
- //Last selected register
- Timer timer[2];
- //Check for it being a write to the timer
- bool write(uint32 addr, uint8 val);
- //Read the current timer state, will use current double
- uint8 read();
-};
-
-namespace DBOPL {
-struct Chip;
-} // end of namespace DBOPL
-
-class OPL : public ::OPL::OPL {
-private:
- Config::OplType _type;
- uint _rate;
-
- DBOPL::Chip *_emulator;
- Chip _chip[2];
- union {
- uint16 normal;
- uint8 dual[2];
- } _reg;
-
- void free();
- void dualWrite(uint8 index, uint8 reg, uint8 val);
-public:
- OPL(Config::OplType type);
- ~OPL();
-
- bool init(int rate);
- void reset();
-
- void write(int a, int v);
- byte read(int a);
-
- void writeReg(int r, int v);
-
- void readBuffer(int16 *buffer, int length);
- bool isStereo() const { return _type != Config::kOpl2; }
-};
-
-} // End of namespace DOSBox
-} // End of namespace OPL
-
-#endif // !DISABLE_DOSBOX_OPL
-
-#endif
-
diff --git a/sound/softsynth/opl/mame.cpp b/sound/softsynth/opl/mame.cpp
deleted file mode 100644
index c875080e8f..0000000000
--- a/sound/softsynth/opl/mame.cpp
+++ /dev/null
@@ -1,1234 +0,0 @@
-/* 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$
- *
- * LGPL licensed version of MAMEs fmopl (V0.37a modified) by
- * Tatsuyuki Satoh. Included from LGPL'ed AdPlug.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <stdarg.h>
-#include <math.h>
-
-#include "mame.h"
-
-#if defined (_WIN32_WCE) || defined (__SYMBIAN32__) || defined(__GP32__) || defined(GP2X) || defined (__MAEMO__) || defined(__DS__) || defined (__MINT__) || defined(__N64__)
-#include "common/config-manager.h"
-#endif
-
-#if defined(__DS__)
-#include "dsmain.h"
-#endif
-
-namespace OPL {
-namespace MAME {
-
-OPL::~OPL() {
- MAME::OPLDestroy(_opl);
- _opl = 0;
-}
-
-bool OPL::init(int rate) {
- if (_opl)
- MAME::OPLDestroy(_opl);
-
- _opl = MAME::makeAdLibOPL(rate);
- return (_opl != 0);
-}
-
-void OPL::reset() {
- MAME::OPLResetChip(_opl);
-}
-
-void OPL::write(int a, int v) {
- MAME::OPLWrite(_opl, a, v);
-}
-
-byte OPL::read(int a) {
- return MAME::OPLRead(_opl, a);
-}
-
-void OPL::writeReg(int r, int v) {
- MAME::OPLWriteReg(_opl, r, v);
-}
-
-void OPL::readBuffer(int16 *buffer, int length) {
- MAME::YM3812UpdateOne(_opl, buffer, length);
-}
-
-/* -------------------- preliminary define section --------------------- */
-/* attack/decay rate time rate */
-#define OPL_ARRATE 141280 /* RATE 4 = 2826.24ms @ 3.6MHz */
-#define OPL_DRRATE 1956000 /* RATE 4 = 39280.64ms @ 3.6MHz */
-
-#define FREQ_BITS 24 /* frequency turn */
-
-/* counter bits = 20 , octerve 7 */
-#define FREQ_RATE (1<<(FREQ_BITS-20))
-#define TL_BITS (FREQ_BITS+2)
-
-/* final output shift , limit minimum and maximum */
-#define OPL_OUTSB (TL_BITS+3-16) /* OPL output final shift 16bit */
-#define OPL_MAXOUT (0x7fff<<OPL_OUTSB)
-#define OPL_MINOUT (-0x8000<<OPL_OUTSB)
-
-/* -------------------- quality selection --------------------- */
-
-/* sinwave entries */
-/* used static memory = SIN_ENT * 4 (byte) */
-#ifdef __DS__
-#define SIN_ENT_SHIFT 8
-#else
-#define SIN_ENT_SHIFT 11
-#endif
-#define SIN_ENT (1<<SIN_ENT_SHIFT)
-
-/* output level entries (envelope,sinwave) */
-/* envelope counter lower bits */
-int ENV_BITS;
-/* envelope output entries */
-int EG_ENT;
-
-/* used dynamic memory = EG_ENT*4*4(byte)or EG_ENT*6*4(byte) */
-/* used static memory = EG_ENT*4 (byte) */
-int EG_OFF; /* OFF */
-int EG_DED;
-int EG_DST; /* DECAY START */
-int EG_AED;
-#define EG_AST 0 /* ATTACK START */
-
-#define EG_STEP (96.0/EG_ENT) /* OPL is 0.1875 dB step */
-
-/* LFO table entries */
-#define VIB_ENT 512
-#define VIB_SHIFT (32-9)
-#define AMS_ENT 512
-#define AMS_SHIFT (32-9)
-
-#define VIB_RATE_SHIFT 8
-#define VIB_RATE (1<<VIB_RATE_SHIFT)
-
-/* -------------------- local defines , macros --------------------- */
-
-/* register number to channel number , slot offset */
-#define SLOT1 0
-#define SLOT2 1
-
-/* envelope phase */
-#define ENV_MOD_RR 0x00
-#define ENV_MOD_DR 0x01
-#define ENV_MOD_AR 0x02
-
-/* -------------------- tables --------------------- */
-static const int slot_array[32] = {
- 0, 2, 4, 1, 3, 5,-1,-1,
- 6, 8,10, 7, 9,11,-1,-1,
- 12,14,16,13,15,17,-1,-1,
- -1,-1,-1,-1,-1,-1,-1,-1
-};
-
-static uint KSL_TABLE[8 * 16];
-
-static const double KSL_TABLE_SEED[8 * 16] = {
- /* OCT 0 */
- 0.000, 0.000, 0.000, 0.000,
- 0.000, 0.000, 0.000, 0.000,
- 0.000, 0.000, 0.000, 0.000,
- 0.000, 0.000, 0.000, 0.000,
- /* OCT 1 */
- 0.000, 0.000, 0.000, 0.000,
- 0.000, 0.000, 0.000, 0.000,
- 0.000, 0.750, 1.125, 1.500,
- 1.875, 2.250, 2.625, 3.000,
- /* OCT 2 */
- 0.000, 0.000, 0.000, 0.000,
- 0.000, 1.125, 1.875, 2.625,
- 3.000, 3.750, 4.125, 4.500,
- 4.875, 5.250, 5.625, 6.000,
- /* OCT 3 */
- 0.000, 0.000, 0.000, 1.875,
- 3.000, 4.125, 4.875, 5.625,
- 6.000, 6.750, 7.125, 7.500,
- 7.875, 8.250, 8.625, 9.000,
- /* OCT 4 */
- 0.000, 0.000, 3.000, 4.875,
- 6.000, 7.125, 7.875, 8.625,
- 9.000, 9.750, 10.125, 10.500,
- 10.875, 11.250, 11.625, 12.000,
- /* OCT 5 */
- 0.000, 3.000, 6.000, 7.875,
- 9.000, 10.125, 10.875, 11.625,
- 12.000, 12.750, 13.125, 13.500,
- 13.875, 14.250, 14.625, 15.000,
- /* OCT 6 */
- 0.000, 6.000, 9.000, 10.875,
- 12.000, 13.125, 13.875, 14.625,
- 15.000, 15.750, 16.125, 16.500,
- 16.875, 17.250, 17.625, 18.000,
- /* OCT 7 */
- 0.000, 9.000, 12.000, 13.875,
- 15.000, 16.125, 16.875, 17.625,
- 18.000, 18.750, 19.125, 19.500,
- 19.875, 20.250, 20.625, 21.000
-};
-
-/* sustain level table (3db per step) */
-/* 0 - 15: 0, 3, 6, 9,12,15,18,21,24,27,30,33,36,39,42,93 (dB)*/
-
-static int SL_TABLE[16];
-
-static const uint SL_TABLE_SEED[16] = {
- 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 31
-};
-
-#define TL_MAX (EG_ENT * 2) /* limit(tl + ksr + envelope) + sinwave */
-/* TotalLevel : 48 24 12 6 3 1.5 0.75 (dB) */
-/* TL_TABLE[ 0 to TL_MAX ] : plus section */
-/* TL_TABLE[ TL_MAX to TL_MAX+TL_MAX-1 ] : minus section */
-static int *TL_TABLE;
-
-/* pointers to TL_TABLE with sinwave output offset */
-static int **SIN_TABLE;
-
-/* LFO table */
-static int *AMS_TABLE;
-static int *VIB_TABLE;
-
-/* envelope output curve table */
-/* attack + decay + OFF */
-//static int ENV_CURVE[2*EG_ENT+1];
-//static int ENV_CURVE[2 * 4096 + 1]; // to keep it static ...
-static int *ENV_CURVE;
-
-
-/* multiple table */
-#define ML(a) (int)(a * 2)
-static const uint MUL_TABLE[16]= {
-/* 1/2, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15 */
- ML(0.50), ML(1.00), ML(2.00), ML(3.00), ML(4.00), ML(5.00), ML(6.00), ML(7.00),
- ML(8.00), ML(9.00), ML(10.00), ML(10.00),ML(12.00),ML(12.00),ML(15.00),ML(15.00)
-};
-#undef ML
-
-/* dummy attack / decay rate ( when rate == 0 ) */
-static int RATE_0[16]=
-{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
-
-/* -------------------- static state --------------------- */
-
-/* lock level of common table */
-static int num_lock = 0;
-
-/* work table */
-static void *cur_chip = NULL; /* current chip point */
-/* currenct chip state */
-/* static OPLSAMPLE *bufL,*bufR; */
-static OPL_CH *S_CH;
-static OPL_CH *E_CH;
-OPL_SLOT *SLOT7_1, *SLOT7_2, *SLOT8_1, *SLOT8_2;
-
-static int outd[1];
-static int ams;
-static int vib;
-int *ams_table;
-int *vib_table;
-static int amsIncr;
-static int vibIncr;
-static int feedback2; /* connect for SLOT 2 */
-
-/* --------------------- rebuild tables ------------------- */
-
-#define SC_KSL(mydb) ((uint) (mydb / (EG_STEP / 2)))
-#define SC_SL(db) (int)(db * ((3 / EG_STEP) * (1 << ENV_BITS))) + EG_DST
-
-void OPLBuildTables(int ENV_BITS_PARAM, int EG_ENT_PARAM) {
- int i;
-
- ENV_BITS = ENV_BITS_PARAM;
- EG_ENT = EG_ENT_PARAM;
- EG_OFF = ((2 * EG_ENT)<<ENV_BITS); /* OFF */
- EG_DED = EG_OFF;
- EG_DST = (EG_ENT << ENV_BITS); /* DECAY START */
- EG_AED = EG_DST;
- //EG_STEP = (96.0/EG_ENT);
-
- for (i = 0; i < ARRAYSIZE(KSL_TABLE_SEED); i++)
- KSL_TABLE[i] = SC_KSL(KSL_TABLE_SEED[i]);
-
- for (i = 0; i < ARRAYSIZE(SL_TABLE_SEED); i++)
- SL_TABLE[i] = SC_SL(SL_TABLE_SEED[i]);
-}
-
-#undef SC_KSL
-#undef SC_SL
-
-/* --------------------- subroutines --------------------- */
-
-/* status set and IRQ handling */
-inline void OPL_STATUS_SET(FM_OPL *OPL, int flag) {
- /* set status flag */
- OPL->status |= flag;
- if (!(OPL->status & 0x80)) {
- if (OPL->status & OPL->statusmask) { /* IRQ on */
- OPL->status |= 0x80;
- /* callback user interrupt handler (IRQ is OFF to ON) */
- if (OPL->IRQHandler)
- (OPL->IRQHandler)(OPL->IRQParam,1);
- }
- }
-}
-
-/* status reset and IRQ handling */
-inline void OPL_STATUS_RESET(FM_OPL *OPL, int flag) {
- /* reset status flag */
- OPL->status &= ~flag;
- if ((OPL->status & 0x80)) {
- if (!(OPL->status & OPL->statusmask)) {
- OPL->status &= 0x7f;
- /* callback user interrupt handler (IRQ is ON to OFF) */
- if (OPL->IRQHandler) (OPL->IRQHandler)(OPL->IRQParam,0);
- }
- }
-}
-
-/* IRQ mask set */
-inline void OPL_STATUSMASK_SET(FM_OPL *OPL, int flag) {
- OPL->statusmask = flag;
- /* IRQ handling check */
- OPL_STATUS_SET(OPL,0);
- OPL_STATUS_RESET(OPL,0);
-}
-
-/* ----- key on ----- */
-inline void OPL_KEYON(OPL_SLOT *SLOT) {
- /* sin wave restart */
- SLOT->Cnt = 0;
- /* set attack */
- SLOT->evm = ENV_MOD_AR;
- SLOT->evs = SLOT->evsa;
- SLOT->evc = EG_AST;
- SLOT->eve = EG_AED;
-}
-
-/* ----- key off ----- */
-inline void OPL_KEYOFF(OPL_SLOT *SLOT) {
- if (SLOT->evm > ENV_MOD_RR) {
- /* set envelope counter from envleope output */
-
- // WORKAROUND: The Kyra engine does something very strange when
- // starting a new song. For each channel:
- //
- // * The release rate is set to "fastest".
- // * Any note is keyed off.
- // * A very low-frequency note is keyed on.
- //
- // Usually, what happens next is that the real notes is keyed
- // on immediately, in which case there's no problem.
- //
- // However, if the note is again keyed off (because the channel
- // begins on a rest rather than a note), the envelope counter
- // was moved from the very lowest point on the attack curve to
- // the very highest point on the release curve.
- //
- // Again, this might not be a problem, if the release rate is
- // still set to "fastest". But in many cases, it had already
- // been increased. And, possibly because of inaccuracies in the
- // envelope generator, that would cause the note to "fade out"
- // for quite a long time.
- //
- // What we really need is a way to find the correct starting
- // point for the envelope counter, and that may be what the
- // commented-out line below is meant to do. For now, simply
- // handle the pathological case.
-
- if (SLOT->evm == ENV_MOD_AR && SLOT->evc == EG_AST)
- SLOT->evc = EG_DED;
- else if (!(SLOT->evc & EG_DST))
- //SLOT->evc = (ENV_CURVE[SLOT->evc>>ENV_BITS]<<ENV_BITS) + EG_DST;
- SLOT->evc = EG_DST;
- SLOT->eve = EG_DED;
- SLOT->evs = SLOT->evsr;
- SLOT->evm = ENV_MOD_RR;
- }
-}
-
-/* ---------- calcrate Envelope Generator & Phase Generator ---------- */
-
-/* return : envelope output */
-inline uint OPL_CALC_SLOT(OPL_SLOT *SLOT) {
- /* calcrate envelope generator */
- if ((SLOT->evc += SLOT->evs) >= SLOT->eve) {
- switch (SLOT->evm) {
- case ENV_MOD_AR: /* ATTACK -> DECAY1 */
- /* next DR */
- SLOT->evm = ENV_MOD_DR;
- SLOT->evc = EG_DST;
- SLOT->eve = SLOT->SL;
- SLOT->evs = SLOT->evsd;
- break;
- case ENV_MOD_DR: /* DECAY -> SL or RR */
- SLOT->evc = SLOT->SL;
- SLOT->eve = EG_DED;
- if (SLOT->eg_typ) {
- SLOT->evs = 0;
- } else {
- SLOT->evm = ENV_MOD_RR;
- SLOT->evs = SLOT->evsr;
- }
- break;
- case ENV_MOD_RR: /* RR -> OFF */
- SLOT->evc = EG_OFF;
- SLOT->eve = EG_OFF + 1;
- SLOT->evs = 0;
- break;
- }
- }
- /* calcrate envelope */
- return SLOT->TLL + ENV_CURVE[SLOT->evc>>ENV_BITS] + (SLOT->ams ? ams : 0);
-}
-
-/* set algorythm connection */
-static void set_algorythm(OPL_CH *CH) {
- int *carrier = &outd[0];
- CH->connect1 = CH->CON ? carrier : &feedback2;
- CH->connect2 = carrier;
-}
-
-/* ---------- frequency counter for operater update ---------- */
-inline void CALC_FCSLOT(OPL_CH *CH, OPL_SLOT *SLOT) {
- int ksr;
-
- /* frequency step counter */
- SLOT->Incr = CH->fc * SLOT->mul;
- ksr = CH->kcode >> SLOT->KSR;
-
- if (SLOT->ksr != ksr) {
- SLOT->ksr = ksr;
- /* attack , decay rate recalcration */
- SLOT->evsa = SLOT->AR[ksr];
- SLOT->evsd = SLOT->DR[ksr];
- SLOT->evsr = SLOT->RR[ksr];
- }
- SLOT->TLL = SLOT->TL + (CH->ksl_base>>SLOT->ksl);
-}
-
-/* set multi,am,vib,EG-TYP,KSR,mul */
-inline void set_mul(FM_OPL *OPL, int slot, int v) {
- OPL_CH *CH = &OPL->P_CH[slot>>1];
- OPL_SLOT *SLOT = &CH->SLOT[slot & 1];
-
- SLOT->mul = MUL_TABLE[v & 0x0f];
- SLOT->KSR = (v & 0x10) ? 0 : 2;
- SLOT->eg_typ = (v & 0x20) >> 5;
- SLOT->vib = (v & 0x40);
- SLOT->ams = (v & 0x80);
- CALC_FCSLOT(CH, SLOT);
-}
-
-/* set ksl & tl */
-inline void set_ksl_tl(FM_OPL *OPL, int slot, int v) {
- OPL_CH *CH = &OPL->P_CH[slot>>1];
- OPL_SLOT *SLOT = &CH->SLOT[slot & 1];
- int ksl = v >> 6; /* 0 / 1.5 / 3 / 6 db/OCT */
-
- SLOT->ksl = ksl ? 3-ksl : 31;
- SLOT->TL = (int)((v & 0x3f) * (0.75 / EG_STEP)); /* 0.75db step */
-
- if (!(OPL->mode & 0x80)) { /* not CSM latch total level */
- SLOT->TLL = SLOT->TL + (CH->ksl_base >> SLOT->ksl);
- }
-}
-
-/* set attack rate & decay rate */
-inline void set_ar_dr(FM_OPL *OPL, int slot, int v) {
- OPL_CH *CH = &OPL->P_CH[slot>>1];
- OPL_SLOT *SLOT = &CH->SLOT[slot & 1];
- int ar = v >> 4;
- int dr = v & 0x0f;
-
- SLOT->AR = ar ? &OPL->AR_TABLE[ar << 2] : RATE_0;
- SLOT->evsa = SLOT->AR[SLOT->ksr];
- if (SLOT->evm == ENV_MOD_AR)
- SLOT->evs = SLOT->evsa;
-
- SLOT->DR = dr ? &OPL->DR_TABLE[dr<<2] : RATE_0;
- SLOT->evsd = SLOT->DR[SLOT->ksr];
- if (SLOT->evm == ENV_MOD_DR)
- SLOT->evs = SLOT->evsd;
-}
-
-/* set sustain level & release rate */
-inline void set_sl_rr(FM_OPL *OPL, int slot, int v) {
- OPL_CH *CH = &OPL->P_CH[slot>>1];
- OPL_SLOT *SLOT = &CH->SLOT[slot & 1];
- int sl = v >> 4;
- int rr = v & 0x0f;
-
- SLOT->SL = SL_TABLE[sl];
- if (SLOT->evm == ENV_MOD_DR)
- SLOT->eve = SLOT->SL;
- SLOT->RR = &OPL->DR_TABLE[rr<<2];
- SLOT->evsr = SLOT->RR[SLOT->ksr];
- if (SLOT->evm == ENV_MOD_RR)
- SLOT->evs = SLOT->evsr;
-}
-
-/* operator output calcrator */
-
-#define OP_OUT(slot,env,con) slot->wavetable[((slot->Cnt + con)>>(24-SIN_ENT_SHIFT)) & (SIN_ENT-1)][env]
-/* ---------- calcrate one of channel ---------- */
-inline void OPL_CALC_CH(OPL_CH *CH) {
- uint env_out;
- OPL_SLOT *SLOT;
-
- feedback2 = 0;
- /* SLOT 1 */
- SLOT = &CH->SLOT[SLOT1];
- env_out=OPL_CALC_SLOT(SLOT);
- if (env_out < (uint)(EG_ENT - 1)) {
- /* PG */
- if (SLOT->vib)
- SLOT->Cnt += (SLOT->Incr * vib) >> VIB_RATE_SHIFT;
- else
- SLOT->Cnt += SLOT->Incr;
- /* connection */
- if (CH->FB) {
- int feedback1 = (CH->op1_out[0] + CH->op1_out[1]) >> CH->FB;
- CH->op1_out[1] = CH->op1_out[0];
- *CH->connect1 += CH->op1_out[0] = OP_OUT(SLOT, env_out, feedback1);
- } else {
- *CH->connect1 += OP_OUT(SLOT, env_out, 0);
- }
- } else {
- CH->op1_out[1] = CH->op1_out[0];
- CH->op1_out[0] = 0;
- }
- /* SLOT 2 */
- SLOT = &CH->SLOT[SLOT2];
- env_out=OPL_CALC_SLOT(SLOT);
- if (env_out < (uint)(EG_ENT - 1)) {
- /* PG */
- if (SLOT->vib)
- SLOT->Cnt += (SLOT->Incr * vib) >> VIB_RATE_SHIFT;
- else
- SLOT->Cnt += SLOT->Incr;
- /* connection */
- outd[0] += OP_OUT(SLOT, env_out, feedback2);
- }
-}
-
-/* ---------- calcrate rythm block ---------- */
-#define WHITE_NOISE_db 6.0
-inline void OPL_CALC_RH(FM_OPL *OPL, OPL_CH *CH) {
- uint env_tam, env_sd, env_top, env_hh;
- // This code used to do int(OPL->rnd.getRandomBit() * (WHITE_NOISE_db / EG_STEP)),
- // but EG_STEP = 96.0/EG_ENT, and WHITE_NOISE_db=6.0. So, that's equivalent to
- // int(OPL->rnd.getRandomBit() * EG_ENT/16). We know that EG_ENT is 4096, or 1024,
- // or 128, so we can safely avoid any FP ops.
- int whitenoise = OPL->rnd.getRandomBit() * (EG_ENT>>4);
-
- int tone8;
-
- OPL_SLOT *SLOT;
- int env_out;
-
- /* BD : same as FM serial mode and output level is large */
- feedback2 = 0;
- /* SLOT 1 */
- SLOT = &CH[6].SLOT[SLOT1];
- env_out = OPL_CALC_SLOT(SLOT);
- if (env_out < EG_ENT-1) {
- /* PG */
- if (SLOT->vib)
- SLOT->Cnt += (SLOT->Incr * vib) >> VIB_RATE_SHIFT;
- else
- SLOT->Cnt += SLOT->Incr;
- /* connection */
- if (CH[6].FB) {
- int feedback1 = (CH[6].op1_out[0] + CH[6].op1_out[1]) >> CH[6].FB;
- CH[6].op1_out[1] = CH[6].op1_out[0];
- feedback2 = CH[6].op1_out[0] = OP_OUT(SLOT, env_out, feedback1);
- }
- else {
- feedback2 = OP_OUT(SLOT, env_out, 0);
- }
- } else {
- feedback2 = 0;
- CH[6].op1_out[1] = CH[6].op1_out[0];
- CH[6].op1_out[0] = 0;
- }
- /* SLOT 2 */
- SLOT = &CH[6].SLOT[SLOT2];
- env_out = OPL_CALC_SLOT(SLOT);
- if (env_out < EG_ENT-1) {
- /* PG */
- if (SLOT->vib)
- SLOT->Cnt += (SLOT->Incr * vib) >> VIB_RATE_SHIFT;
- else
- SLOT->Cnt += SLOT->Incr;
- /* connection */
- outd[0] += OP_OUT(SLOT, env_out, feedback2) * 2;
- }
-
- // SD (17) = mul14[fnum7] + white noise
- // TAM (15) = mul15[fnum8]
- // TOP (18) = fnum6(mul18[fnum8]+whitenoise)
- // HH (14) = fnum7(mul18[fnum8]+whitenoise) + white noise
- env_sd = OPL_CALC_SLOT(SLOT7_2) + whitenoise;
- env_tam =OPL_CALC_SLOT(SLOT8_1);
- env_top = OPL_CALC_SLOT(SLOT8_2);
- env_hh = OPL_CALC_SLOT(SLOT7_1) + whitenoise;
-
- /* PG */
- if (SLOT7_1->vib)
- SLOT7_1->Cnt += (SLOT7_1->Incr * vib) >> (VIB_RATE_SHIFT-1);
- else
- SLOT7_1->Cnt += 2 * SLOT7_1->Incr;
- if (SLOT7_2->vib)
- SLOT7_2->Cnt += (CH[7].fc * vib) >> (VIB_RATE_SHIFT-3);
- else
- SLOT7_2->Cnt += (CH[7].fc * 8);
- if (SLOT8_1->vib)
- SLOT8_1->Cnt += (SLOT8_1->Incr * vib) >> VIB_RATE_SHIFT;
- else
- SLOT8_1->Cnt += SLOT8_1->Incr;
- if (SLOT8_2->vib)
- SLOT8_2->Cnt += ((CH[8].fc * 3) * vib) >> (VIB_RATE_SHIFT-4);
- else
- SLOT8_2->Cnt += (CH[8].fc * 48);
-
- tone8 = OP_OUT(SLOT8_2,whitenoise,0 );
-
- /* SD */
- if (env_sd < (uint)(EG_ENT - 1))
- outd[0] += OP_OUT(SLOT7_1, env_sd, 0) * 8;
- /* TAM */
- if (env_tam < (uint)(EG_ENT - 1))
- outd[0] += OP_OUT(SLOT8_1, env_tam, 0) * 2;
- /* TOP-CY */
- if (env_top < (uint)(EG_ENT - 1))
- outd[0] += OP_OUT(SLOT7_2, env_top, tone8) * 2;
- /* HH */
- if (env_hh < (uint)(EG_ENT-1))
- outd[0] += OP_OUT(SLOT7_2, env_hh, tone8) * 2;
-}
-
-/* ----------- initialize time tabls ----------- */
-static void init_timetables(FM_OPL *OPL, int ARRATE, int DRRATE) {
- int i;
- double rate;
-
- /* make attack rate & decay rate tables */
- for (i = 0; i < 4; i++)
- OPL->AR_TABLE[i] = OPL->DR_TABLE[i] = 0;
- for (i = 4; i <= 60; i++) {
- rate = OPL->freqbase; /* frequency rate */
- if (i < 60)
- rate *= 1.0 + (i & 3) * 0.25; /* b0-1 : x1 , x1.25 , x1.5 , x1.75 */
- rate *= 1 << ((i >> 2) - 1); /* b2-5 : shift bit */
- rate *= (double)(EG_ENT << ENV_BITS);
- OPL->AR_TABLE[i] = (int)(rate / ARRATE);
- OPL->DR_TABLE[i] = (int)(rate / DRRATE);
- }
- for (i = 60; i < 76; i++) {
- OPL->AR_TABLE[i] = EG_AED-1;
- OPL->DR_TABLE[i] = OPL->DR_TABLE[60];
- }
-}
-
-/* ---------- generic table initialize ---------- */
-static int OPLOpenTable(void) {
- int s,t;
- double rate;
- int i,j;
- double pom;
-
-#ifdef __DS__
- DS::fastRamReset();
-
- TL_TABLE = (int *) DS::fastRamAlloc(TL_MAX * 2 * sizeof(int *));
- SIN_TABLE = (int **) DS::fastRamAlloc(SIN_ENT * 4 * sizeof(int *));
-#else
-
- /* allocate dynamic tables */
- if ((TL_TABLE = (int *)malloc(TL_MAX * 2 * sizeof(int))) == NULL)
- return 0;
-
- if ((SIN_TABLE = (int **)malloc(SIN_ENT * 4 * sizeof(int *))) == NULL) {
- free(TL_TABLE);
- return 0;
- }
-#endif
-
- if ((AMS_TABLE = (int *)malloc(AMS_ENT * 2 * sizeof(int))) == NULL) {
- free(TL_TABLE);
- free(SIN_TABLE);
- return 0;
- }
-
- if ((VIB_TABLE = (int *)malloc(VIB_ENT * 2 * sizeof(int))) == NULL) {
- free(TL_TABLE);
- free(SIN_TABLE);
- free(AMS_TABLE);
- return 0;
- }
- /* make total level table */
- 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];
- }
- /* fill volume off area */
- for (t = EG_ENT - 1; t < TL_MAX; t++) {
- TL_TABLE[t] = TL_TABLE[TL_MAX + t] = 0;
- }
-
- /* make sinwave table (total level offet) */
- /* degree 0 = degree 180 = off */
- SIN_TABLE[0] = SIN_TABLE[SIN_ENT /2 ] = &TL_TABLE[EG_ENT - 1];
- for (s = 1;s <= SIN_ENT / 4; s++) {
- pom = sin(2 * PI * s / SIN_ENT); /* sin */
- pom = 20 * log10(1 / pom); /* decibel */
- j = int(pom / EG_STEP); /* TL_TABLE steps */
-
- /* degree 0 - 90 , degree 180 - 90 : plus section */
- SIN_TABLE[ s] = SIN_TABLE[SIN_ENT / 2 - s] = &TL_TABLE[j];
- /* degree 180 - 270 , degree 360 - 270 : minus section */
- SIN_TABLE[SIN_ENT / 2 + s] = SIN_TABLE[SIN_ENT - s] = &TL_TABLE[TL_MAX + j];
- }
- for (s = 0;s < SIN_ENT; s++) {
- SIN_TABLE[SIN_ENT * 1 + s] = s < (SIN_ENT / 2) ? SIN_TABLE[s] : &TL_TABLE[EG_ENT];
- SIN_TABLE[SIN_ENT * 2 + s] = SIN_TABLE[s % (SIN_ENT / 2)];
- SIN_TABLE[SIN_ENT * 3 + s] = (s / (SIN_ENT / 4)) & 1 ? &TL_TABLE[EG_ENT] : SIN_TABLE[SIN_ENT * 2 + s];
- }
-
-
- ENV_CURVE = (int *)malloc(sizeof(int) * (2*EG_ENT+1));
-
- /* envelope counter -> envelope output table */
- for (i=0; i < EG_ENT; i++) {
- /* ATTACK curve */
- pom = pow(((double)(EG_ENT - 1 - i) / EG_ENT), 8) * EG_ENT;
- /* if (pom >= EG_ENT) pom = EG_ENT-1; */
- ENV_CURVE[i] = (int)pom;
- /* DECAY ,RELEASE curve */
- ENV_CURVE[(EG_DST >> ENV_BITS) + i]= i;
- }
- /* off */
- ENV_CURVE[EG_OFF >> ENV_BITS]= EG_ENT - 1;
- /* make LFO ams table */
- for (i=0; i < AMS_ENT; i++) {
- pom = (1.0 + sin(2 * PI * i / AMS_ENT)) / 2; /* sin */
- AMS_TABLE[i] = (int)((1.0 / EG_STEP) * pom); /* 1dB */
- AMS_TABLE[AMS_ENT + i] = (int)((4.8 / EG_STEP) * pom); /* 4.8dB */
- }
- /* make LFO vibrate table */
- for (i=0; i < VIB_ENT; i++) {
- /* 100cent = 1seminote = 6% ?? */
- pom = (double)VIB_RATE * 0.06 * sin(2 * PI * i / VIB_ENT); /* +-100sect step */
- VIB_TABLE[i] = (int)(VIB_RATE + (pom * 0.07)); /* +- 7cent */
- VIB_TABLE[VIB_ENT + i] = (int)(VIB_RATE + (pom * 0.14)); /* +-14cent */
- }
- return 1;
-}
-
-static void OPLCloseTable(void) {
- free(TL_TABLE);
- free(SIN_TABLE);
- free(AMS_TABLE);
- free(VIB_TABLE);
- free(ENV_CURVE);
-}
-
-/* CSM Key Controll */
-inline void CSMKeyControll(OPL_CH *CH) {
- OPL_SLOT *slot1 = &CH->SLOT[SLOT1];
- OPL_SLOT *slot2 = &CH->SLOT[SLOT2];
- /* all key off */
- OPL_KEYOFF(slot1);
- OPL_KEYOFF(slot2);
- /* total level latch */
- slot1->TLL = slot1->TL + (CH->ksl_base>>slot1->ksl);
- slot1->TLL = slot1->TL + (CH->ksl_base>>slot1->ksl);
- /* key on */
- CH->op1_out[0] = CH->op1_out[1] = 0;
- OPL_KEYON(slot1);
- OPL_KEYON(slot2);
-}
-
-/* ---------- opl initialize ---------- */
-static void OPL_initalize(FM_OPL *OPL) {
- int fn;
-
- /* frequency base */
- OPL->freqbase = (OPL->rate) ? ((double)OPL->clock / OPL->rate) / 72 : 0;
- /* Timer base time */
- OPL->TimerBase = 1.0/((double)OPL->clock / 72.0 );
- /* make time tables */
- init_timetables(OPL, OPL_ARRATE, OPL_DRRATE);
- /* make fnumber -> increment counter table */
- for (fn=0; fn < 1024; fn++) {
- OPL->FN_TABLE[fn] = (uint)(OPL->freqbase * fn * FREQ_RATE * (1<<7) / 2);
- }
- /* LFO freq.table */
- OPL->amsIncr = (int)(OPL->rate ? (double)AMS_ENT * (1 << AMS_SHIFT) / OPL->rate * 3.7 * ((double)OPL->clock/3600000) : 0);
- OPL->vibIncr = (int)(OPL->rate ? (double)VIB_ENT * (1 << VIB_SHIFT) / OPL->rate * 6.4 * ((double)OPL->clock/3600000) : 0);
-}
-
-/* ---------- write a OPL registers ---------- */
-void OPLWriteReg(FM_OPL *OPL, int r, int v) {
- OPL_CH *CH;
- int slot;
- uint block_fnum;
-
- switch (r & 0xe0) {
- case 0x00: /* 00-1f:controll */
- switch (r & 0x1f) {
- case 0x01:
- /* wave selector enable */
- if (OPL->type&OPL_TYPE_WAVESEL) {
- OPL->wavesel = v & 0x20;
- if (!OPL->wavesel) {
- /* preset compatible mode */
- int c;
- for (c = 0; c < OPL->max_ch; c++) {
- OPL->P_CH[c].SLOT[SLOT1].wavetable = &SIN_TABLE[0];
- OPL->P_CH[c].SLOT[SLOT2].wavetable = &SIN_TABLE[0];
- }
- }
- }
- return;
- case 0x02: /* Timer 1 */
- OPL->T[0] = (256-v) * 4;
- break;
- case 0x03: /* Timer 2 */
- OPL->T[1] = (256-v) * 16;
- return;
- case 0x04: /* IRQ clear / mask and Timer enable */
- if (v & 0x80) { /* IRQ flag clear */
- OPL_STATUS_RESET(OPL, 0x7f);
- } else { /* set IRQ mask ,timer enable*/
- uint8 st1 = v & 1;
- uint8 st2 = (v >> 1) & 1;
- /* IRQRST,T1MSK,t2MSK,EOSMSK,BRMSK,x,ST2,ST1 */
- OPL_STATUS_RESET(OPL, v & 0x78);
- OPL_STATUSMASK_SET(OPL,((~v) & 0x78) | 0x01);
- /* timer 2 */
- if (OPL->st[1] != st2) {
- double interval = st2 ? (double)OPL->T[1] * OPL->TimerBase : 0.0;
- OPL->st[1] = st2;
- if (OPL->TimerHandler) (OPL->TimerHandler)(OPL->TimerParam + 1, interval);
- }
- /* timer 1 */
- if (OPL->st[0] != st1) {
- double interval = st1 ? (double)OPL->T[0] * OPL->TimerBase : 0.0;
- OPL->st[0] = st1;
- if (OPL->TimerHandler) (OPL->TimerHandler)(OPL->TimerParam + 0, interval);
- }
- }
- return;
- }
- break;
- case 0x20: /* am,vib,ksr,eg type,mul */
- slot = slot_array[r&0x1f];
- if (slot == -1)
- return;
- set_mul(OPL,slot,v);
- return;
- case 0x40:
- slot = slot_array[r&0x1f];
- if (slot == -1)
- return;
- set_ksl_tl(OPL,slot,v);
- return;
- case 0x60:
- slot = slot_array[r&0x1f];
- if (slot == -1)
- return;
- set_ar_dr(OPL,slot,v);
- return;
- case 0x80:
- slot = slot_array[r&0x1f];
- if (slot == -1)
- return;
- set_sl_rr(OPL,slot,v);
- return;
- case 0xa0:
- switch (r) {
- case 0xbd:
- /* amsep,vibdep,r,bd,sd,tom,tc,hh */
- {
- uint8 rkey = OPL->rythm ^ v;
- OPL->ams_table = &AMS_TABLE[v & 0x80 ? AMS_ENT : 0];
- OPL->vib_table = &VIB_TABLE[v & 0x40 ? VIB_ENT : 0];
- OPL->rythm = v & 0x3f;
- if (OPL->rythm & 0x20) {
- /* BD key on/off */
- if (rkey & 0x10) {
- if (v & 0x10) {
- OPL->P_CH[6].op1_out[0] = OPL->P_CH[6].op1_out[1] = 0;
- OPL_KEYON(&OPL->P_CH[6].SLOT[SLOT1]);
- OPL_KEYON(&OPL->P_CH[6].SLOT[SLOT2]);
- } else {
- OPL_KEYOFF(&OPL->P_CH[6].SLOT[SLOT1]);
- OPL_KEYOFF(&OPL->P_CH[6].SLOT[SLOT2]);
- }
- }
- /* SD key on/off */
- if (rkey & 0x08) {
- if (v & 0x08)
- OPL_KEYON(&OPL->P_CH[7].SLOT[SLOT2]);
- else
- OPL_KEYOFF(&OPL->P_CH[7].SLOT[SLOT2]);
- }/* TAM key on/off */
- if (rkey & 0x04) {
- if (v & 0x04)
- OPL_KEYON(&OPL->P_CH[8].SLOT[SLOT1]);
- else
- OPL_KEYOFF(&OPL->P_CH[8].SLOT[SLOT1]);
- }
- /* TOP-CY key on/off */
- if (rkey & 0x02) {
- if (v & 0x02)
- OPL_KEYON(&OPL->P_CH[8].SLOT[SLOT2]);
- else
- OPL_KEYOFF(&OPL->P_CH[8].SLOT[SLOT2]);
- }
- /* HH key on/off */
- if (rkey & 0x01) {
- if (v & 0x01)
- OPL_KEYON(&OPL->P_CH[7].SLOT[SLOT1]);
- else
- OPL_KEYOFF(&OPL->P_CH[7].SLOT[SLOT1]);
- }
- }
- }
- return;
-
- default:
- break;
- }
- /* keyon,block,fnum */
- if ((r & 0x0f) > 8)
- return;
- CH = &OPL->P_CH[r & 0x0f];
- if (!(r&0x10)) { /* a0-a8 */
- block_fnum = (CH->block_fnum & 0x1f00) | v;
- } else { /* b0-b8 */
- int keyon = (v >> 5) & 1;
- block_fnum = ((v & 0x1f) << 8) | (CH->block_fnum & 0xff);
- if (CH->keyon != keyon) {
- if ((CH->keyon=keyon)) {
- CH->op1_out[0] = CH->op1_out[1] = 0;
- OPL_KEYON(&CH->SLOT[SLOT1]);
- OPL_KEYON(&CH->SLOT[SLOT2]);
- } else {
- OPL_KEYOFF(&CH->SLOT[SLOT1]);
- OPL_KEYOFF(&CH->SLOT[SLOT2]);
- }
- }
- }
- /* update */
- if (CH->block_fnum != block_fnum) {
- int blockRv = 7 - (block_fnum >> 10);
- int fnum = block_fnum & 0x3ff;
- CH->block_fnum = block_fnum;
- CH->ksl_base = KSL_TABLE[block_fnum >> 6];
- CH->fc = OPL->FN_TABLE[fnum] >> blockRv;
- CH->kcode = CH->block_fnum >> 9;
- if ((OPL->mode & 0x40) && CH->block_fnum & 0x100)
- CH->kcode |=1;
- CALC_FCSLOT(CH,&CH->SLOT[SLOT1]);
- CALC_FCSLOT(CH,&CH->SLOT[SLOT2]);
- }
- return;
- case 0xc0:
- /* FB,C */
- if ((r & 0x0f) > 8)
- return;
- CH = &OPL->P_CH[r&0x0f];
- {
- int feedback = (v >> 1) & 7;
- CH->FB = feedback ? (8 + 1) - feedback : 0;
- CH->CON = v & 1;
- set_algorythm(CH);
- }
- return;
- case 0xe0: /* wave type */
- slot = slot_array[r & 0x1f];
- if (slot == -1)
- return;
- CH = &OPL->P_CH[slot>>1];
- if (OPL->wavesel) {
- CH->SLOT[slot&1].wavetable = &SIN_TABLE[(v & 0x03) * SIN_ENT];
- }
- return;
- }
-}
-
-/* lock/unlock for common table */
-static int OPL_LockTable(void) {
- num_lock++;
- if (num_lock>1)
- return 0;
- /* first time */
- cur_chip = NULL;
- /* allocate total level table (128kb space) */
- if (!OPLOpenTable()) {
- num_lock--;
- return -1;
- }
- return 0;
-}
-
-static void OPL_UnLockTable(void) {
- if (num_lock)
- num_lock--;
- if (num_lock)
- return;
- /* last time */
- cur_chip = NULL;
- OPLCloseTable();
-}
-
-/*******************************************************************************/
-/* YM3812 local section */
-/*******************************************************************************/
-
-/* ---------- update one of chip ----------- */
-void YM3812UpdateOne(FM_OPL *OPL, int16 *buffer, int length) {
- int i;
- int data;
- int16 *buf = buffer;
- uint amsCnt = OPL->amsCnt;
- uint vibCnt = OPL->vibCnt;
- uint8 rythm = OPL->rythm & 0x20;
- OPL_CH *CH, *R_CH;
-
-
- if ((void *)OPL != cur_chip) {
- cur_chip = (void *)OPL;
- /* channel pointers */
- S_CH = OPL->P_CH;
- E_CH = &S_CH[9];
- /* rythm slot */
- SLOT7_1 = &S_CH[7].SLOT[SLOT1];
- SLOT7_2 = &S_CH[7].SLOT[SLOT2];
- SLOT8_1 = &S_CH[8].SLOT[SLOT1];
- SLOT8_2 = &S_CH[8].SLOT[SLOT2];
- /* LFO state */
- amsIncr = OPL->amsIncr;
- vibIncr = OPL->vibIncr;
- ams_table = OPL->ams_table;
- vib_table = OPL->vib_table;
- }
- R_CH = rythm ? &S_CH[6] : E_CH;
- for (i = 0; i < length; i++) {
- /* channel A channel B channel C */
- /* LFO */
- ams = ams_table[(amsCnt += amsIncr) >> AMS_SHIFT];
- vib = vib_table[(vibCnt += vibIncr) >> VIB_SHIFT];
- outd[0] = 0;
- /* FM part */
- for (CH = S_CH; CH < R_CH; CH++)
- OPL_CALC_CH(CH);
- /* Rythn part */
- if (rythm)
- OPL_CALC_RH(OPL, S_CH);
- /* limit check */
- data = CLIP(outd[0], OPL_MINOUT, OPL_MAXOUT);
- /* store to sound buffer */
- buf[i] = data >> OPL_OUTSB;
- }
-
- OPL->amsCnt = amsCnt;
- OPL->vibCnt = vibCnt;
-}
-
-/* ---------- reset a chip ---------- */
-void OPLResetChip(FM_OPL *OPL) {
- int c,s;
- int i;
-
- /* reset chip */
- OPL->mode = 0; /* normal mode */
- OPL_STATUS_RESET(OPL, 0x7f);
- /* reset with register write */
- OPLWriteReg(OPL, 0x01,0); /* wabesel disable */
- OPLWriteReg(OPL, 0x02,0); /* Timer1 */
- OPLWriteReg(OPL, 0x03,0); /* Timer2 */
- OPLWriteReg(OPL, 0x04,0); /* IRQ mask clear */
- for (i = 0xff; i >= 0x20; i--)
- OPLWriteReg(OPL,i,0);
- /* reset OPerator parameter */
- 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++) {
- /* wave table */
- CH->SLOT[s].wavetable = &SIN_TABLE[0];
- /* CH->SLOT[s].evm = ENV_MOD_RR; */
- CH->SLOT[s].evc = EG_OFF;
- CH->SLOT[s].eve = EG_OFF + 1;
- CH->SLOT[s].evs = 0;
- }
- }
-}
-
-/* ---------- Create a virtual YM3812 ---------- */
-/* 'rate' is sampling rate and 'bufsiz' is the size of the */
-FM_OPL *OPLCreate(int type, int clock, int rate) {
- char *ptr;
- FM_OPL *OPL;
- int state_size;
- int max_ch = 9; /* normaly 9 channels */
-
- if (OPL_LockTable() == -1)
- return NULL;
- /* allocate OPL state space */
- state_size = sizeof(FM_OPL);
- state_size += sizeof(OPL_CH) * max_ch;
-
- /* allocate memory block */
- ptr = (char *)calloc(state_size, 1);
- if (ptr == NULL)
- return NULL;
-
- /* clear */
- memset(ptr, 0, state_size);
- OPL = (FM_OPL *)ptr; ptr += sizeof(FM_OPL);
- OPL->P_CH = (OPL_CH *)ptr; ptr += sizeof(OPL_CH) * max_ch;
-
- /* set channel state pointer */
- OPL->type = type;
- OPL->clock = clock;
- OPL->rate = rate;
- OPL->max_ch = max_ch;
-
- /* init grobal tables */
- OPL_initalize(OPL);
-
- /* reset chip */
- OPLResetChip(OPL);
- return OPL;
-}
-
-/* ---------- Destroy one of vietual YM3812 ---------- */
-void OPLDestroy(FM_OPL *OPL) {
- OPL_UnLockTable();
- free(OPL);
-}
-
-/* ---------- Option handlers ---------- */
-void OPLSetTimerHandler(FM_OPL *OPL, OPL_TIMERHANDLER TimerHandler,int channelOffset) {
- OPL->TimerHandler = TimerHandler;
- OPL->TimerParam = channelOffset;
-}
-
-void OPLSetIRQHandler(FM_OPL *OPL, OPL_IRQHANDLER IRQHandler, int param) {
- OPL->IRQHandler = IRQHandler;
- OPL->IRQParam = param;
-}
-
-void OPLSetUpdateHandler(FM_OPL *OPL, OPL_UPDATEHANDLER UpdateHandler,int param) {
- OPL->UpdateHandler = UpdateHandler;
- OPL->UpdateParam = param;
-}
-
-/* ---------- YM3812 I/O interface ---------- */
-int OPLWrite(FM_OPL *OPL,int a,int v) {
- if (!(a & 1)) { /* address port */
- OPL->address = v & 0xff;
- } else { /* data port */
- if (OPL->UpdateHandler)
- OPL->UpdateHandler(OPL->UpdateParam,0);
- OPLWriteReg(OPL, OPL->address,v);
- }
- return OPL->status >> 7;
-}
-
-unsigned char OPLRead(FM_OPL *OPL,int a) {
- if (!(a & 1)) { /* status port */
- return OPL->status & (OPL->statusmask | 0x80);
- }
- /* data port */
- switch (OPL->address) {
- case 0x05: /* KeyBoard IN */
- warning("OPL:read unmapped KEYBOARD port");
- return 0;
- case 0x19: /* I/O DATA */
- warning("OPL:read unmapped I/O port");
- return 0;
- case 0x1a: /* PCM-DATA */
- return 0;
- default:
- break;
- }
- return 0;
-}
-
-int OPLTimerOver(FM_OPL *OPL, int c) {
- if (c) { /* Timer B */
- OPL_STATUS_SET(OPL, 0x20);
- } else { /* Timer A */
- OPL_STATUS_SET(OPL, 0x40);
- /* CSM mode key,TL controll */
- if (OPL->mode & 0x80) { /* CSM mode total level latch and auto key on */
- int ch;
- if (OPL->UpdateHandler)
- OPL->UpdateHandler(OPL->UpdateParam,0);
- for (ch = 0; ch < 9; ch++)
- CSMKeyControll(&OPL->P_CH[ch]);
- }
- }
- /* reload timer */
- if (OPL->TimerHandler)
- (OPL->TimerHandler)(OPL->TimerParam + c, (double)OPL->T[c] * OPL->TimerBase);
- return OPL->status >> 7;
-}
-
-FM_OPL *makeAdLibOPL(int rate) {
- // We need to emulate one YM3812 chip
- int env_bits = FMOPL_ENV_BITS_HQ;
- int eg_ent = FMOPL_EG_ENT_HQ;
-#if defined (_WIN32_WCE) || defined(__SYMBIAN32__) || defined(__GP32__) || defined (GP2X) || defined(__MAEMO__) || defined(__DS__) || defined (__MINT__) || defined(__N64__)
- if (ConfMan.hasKey("FM_high_quality") && ConfMan.getBool("FM_high_quality")) {
- env_bits = FMOPL_ENV_BITS_HQ;
- eg_ent = FMOPL_EG_ENT_HQ;
- } else if (ConfMan.hasKey("FM_medium_quality") && ConfMan.getBool("FM_medium_quality")) {
- env_bits = FMOPL_ENV_BITS_MQ;
- eg_ent = FMOPL_EG_ENT_MQ;
- } else {
- env_bits = FMOPL_ENV_BITS_LQ;
- eg_ent = FMOPL_EG_ENT_LQ;
- }
-#endif
-
- OPLBuildTables(env_bits, eg_ent);
- return OPLCreate(OPL_TYPE_YM3812, 3579545, rate);
-}
-
-} // End of namespace MAME
-} // End of namespace OPL
-
diff --git a/sound/softsynth/opl/mame.h b/sound/softsynth/opl/mame.h
deleted file mode 100644
index ec812d0c4e..0000000000
--- a/sound/softsynth/opl/mame.h
+++ /dev/null
@@ -1,202 +0,0 @@
-/* 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$
- *
- * LGPL licensed version of MAMEs fmopl (V0.37a modified) by
- * Tatsuyuki Satoh. Included from LGPL'ed AdPlug.
- */
-
-
-#ifndef SOUND_SOFTSYNTH_OPL_MAME_H
-#define SOUND_SOFTSYNTH_OPL_MAME_H
-
-#include "common/scummsys.h"
-#include "common/util.h"
-#include "common/random.h"
-
-#include "sound/fmopl.h"
-
-namespace OPL {
-namespace MAME {
-
-enum {
- FMOPL_ENV_BITS_HQ = 16,
- FMOPL_ENV_BITS_MQ = 8,
- FMOPL_ENV_BITS_LQ = 8,
- FMOPL_EG_ENT_HQ = 4096,
- FMOPL_EG_ENT_MQ = 1024,
- FMOPL_EG_ENT_LQ = 128
-};
-
-
-typedef void (*OPL_TIMERHANDLER)(int channel,double interval_Sec);
-typedef void (*OPL_IRQHANDLER)(int param,int irq);
-typedef void (*OPL_UPDATEHANDLER)(int param,int min_interval_us);
-
-#define OPL_TYPE_WAVESEL 0x01 /* waveform select */
-
-/* Saving is necessary for member of the 'R' mark for suspend/resume */
-/* ---------- OPL one of slot ---------- */
-typedef struct fm_opl_slot {
- int TL; /* total level :TL << 8 */
- int TLL; /* adjusted now TL */
- uint8 KSR; /* key scale rate :(shift down bit) */
- int *AR; /* attack rate :&AR_TABLE[AR<<2] */
- int *DR; /* decay rate :&DR_TABLE[DR<<2] */
- int SL; /* sustain level :SL_TABLE[SL] */
- int *RR; /* release rate :&DR_TABLE[RR<<2] */
- uint8 ksl; /* keyscale level :(shift down bits) */
- uint8 ksr; /* key scale rate :kcode>>KSR */
- uint mul; /* multiple :ML_TABLE[ML] */
- uint Cnt; /* frequency count */
- uint Incr; /* frequency step */
-
- /* envelope generator state */
- uint8 eg_typ;/* envelope type flag */
- uint8 evm; /* envelope phase */
- int evc; /* envelope counter */
- int eve; /* envelope counter end point */
- int evs; /* envelope counter step */
- int evsa; /* envelope step for AR :AR[ksr] */
- int evsd; /* envelope step for DR :DR[ksr] */
- int evsr; /* envelope step for RR :RR[ksr] */
-
- /* LFO */
- uint8 ams; /* ams flag */
- uint8 vib; /* vibrate flag */
- /* wave selector */
- int **wavetable;
-} OPL_SLOT;
-
-/* ---------- OPL one of channel ---------- */
-typedef struct fm_opl_channel {
- OPL_SLOT SLOT[2];
- uint8 CON; /* connection type */
- uint8 FB; /* feed back :(shift down bit)*/
- int *connect1; /* slot1 output pointer */
- int *connect2; /* slot2 output pointer */
- int op1_out[2]; /* slot1 output for selfeedback */
-
- /* phase generator state */
- uint block_fnum; /* block+fnum */
- uint8 kcode; /* key code : KeyScaleCode */
- uint fc; /* Freq. Increment base */
- uint ksl_base; /* KeyScaleLevel Base step */
- uint8 keyon; /* key on/off flag */
-} OPL_CH;
-
-/* OPL state */
-typedef struct fm_opl_f {
- uint8 type; /* chip type */
- int clock; /* master clock (Hz) */
- int rate; /* sampling rate (Hz) */
- double freqbase; /* frequency base */
- double TimerBase; /* Timer base time (==sampling time) */
- uint8 address; /* address register */
- uint8 status; /* status flag */
- uint8 statusmask; /* status mask */
- uint mode; /* Reg.08 : CSM , notesel,etc. */
-
- /* Timer */
- int T[2]; /* timer counter */
- uint8 st[2]; /* timer enable */
-
- /* FM channel slots */
- OPL_CH *P_CH; /* pointer of CH */
- int max_ch; /* maximum channel */
-
- /* Rythm sention */
- uint8 rythm; /* Rythm mode , key flag */
-
- /* time tables */
- int AR_TABLE[76]; /* atttack rate tables */
- int DR_TABLE[76]; /* decay rate tables */
- uint FN_TABLE[1024];/* fnumber -> increment counter */
-
- /* LFO */
- int *ams_table;
- int *vib_table;
- int amsCnt;
- int amsIncr;
- int vibCnt;
- int vibIncr;
-
- /* wave selector enable flag */
- uint8 wavesel;
-
- /* external event callback handler */
- OPL_TIMERHANDLER TimerHandler; /* TIMER handler */
- int TimerParam; /* TIMER parameter */
- OPL_IRQHANDLER IRQHandler; /* IRQ handler */
- int IRQParam; /* IRQ parameter */
- OPL_UPDATEHANDLER UpdateHandler; /* stream update handler */
- int UpdateParam; /* stream update parameter */
-
- Common::RandomSource rnd;
-} FM_OPL;
-
-/* ---------- Generic interface section ---------- */
-#define OPL_TYPE_YM3526 (0)
-#define OPL_TYPE_YM3812 (OPL_TYPE_WAVESEL)
-
-void OPLBuildTables(int ENV_BITS_PARAM, int EG_ENT_PARAM);
-
-FM_OPL *OPLCreate(int type, int clock, int rate);
-void OPLDestroy(FM_OPL *OPL);
-void OPLSetTimerHandler(FM_OPL *OPL, OPL_TIMERHANDLER TimerHandler, int channelOffset);
-void OPLSetIRQHandler(FM_OPL *OPL, OPL_IRQHANDLER IRQHandler, int param);
-void OPLSetUpdateHandler(FM_OPL *OPL, OPL_UPDATEHANDLER UpdateHandler, int param);
-
-void OPLResetChip(FM_OPL *OPL);
-int OPLWrite(FM_OPL *OPL, int a, int v);
-unsigned char OPLRead(FM_OPL *OPL, int a);
-int OPLTimerOver(FM_OPL *OPL, int c);
-void OPLWriteReg(FM_OPL *OPL, int r, int v);
-void YM3812UpdateOne(FM_OPL *OPL, int16 *buffer, int length);
-
-// Factory method
-FM_OPL *makeAdLibOPL(int rate);
-
-// OPL API implementation
-class OPL : public ::OPL::OPL {
-private:
- FM_OPL *_opl;
-public:
- OPL() : _opl(0) {}
- ~OPL();
-
- bool init(int rate);
- void reset();
-
- void write(int a, int v);
- byte read(int a);
-
- void writeReg(int r, int v);
-
- void readBuffer(int16 *buffer, int length);
- bool isStereo() const { return false; }
-};
-
-} // End of namespace MAME
-} // End of namespace OPL
-
-#endif
diff --git a/sound/softsynth/pcspk.cpp b/sound/softsynth/pcspk.cpp
deleted file mode 100644
index bdf9f112e8..0000000000
--- a/sound/softsynth/pcspk.cpp
+++ /dev/null
@@ -1,187 +0,0 @@
-/* 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/pcspk.h"
-#include "sound/null.h"
-
-namespace Audio {
-
-const PCSpeaker::generatorFunc PCSpeaker::generateWave[] =
- {&PCSpeaker::generateSquare, &PCSpeaker::generateSine,
- &PCSpeaker::generateSaw, &PCSpeaker::generateTriangle};
-
-PCSpeaker::PCSpeaker(int rate) {
- _rate = rate;
- _wave = kWaveFormSquare;
- _playForever = false;
- _oscLength = 0;
- _oscSamples = 0;
- _remainingSamples = 0;
- _mixedSamples = 0;
- _volume = 255;
-}
-
-PCSpeaker::~PCSpeaker() {
-}
-
-void PCSpeaker::play(WaveForm wave, int freq, int32 length) {
- Common::StackLock lock(_mutex);
-
- assert((wave >= kWaveFormSquare) && (wave <= kWaveFormTriangle));
-
- _wave = wave;
- _oscLength = _rate / freq;
- _oscSamples = 0;
- if (length == -1) {
- _remainingSamples = 1;
- _playForever = true;
- } else {
- _remainingSamples = (_rate * length) / 1000;
- _playForever = false;
- }
- _mixedSamples = 0;
-}
-
-void PCSpeaker::stop(int32 delay) {
- Common::StackLock lock(_mutex);
-
- _remainingSamples = (_rate * delay) / 1000;
- _playForever = false;
-}
-
-void PCSpeaker::setVolume(byte volume) {
- _volume = volume;
-}
-
-bool PCSpeaker::isPlaying() const {
- return _remainingSamples != 0;
-}
-
-int PCSpeaker::readBuffer(int16 *buffer, const int numSamples) {
- Common::StackLock lock(_mutex);
-
- int i;
-
- for (i = 0; _remainingSamples && (i < numSamples); i++) {
- buffer[i] = generateWave[_wave](_oscSamples, _oscLength) * _volume;
- if (_oscSamples++ >= _oscLength)
- _oscSamples = 0;
- if (!_playForever)
- _remainingSamples--;
- _mixedSamples++;
- }
-
- // Clear the rest of the buffer
- if (i < numSamples)
- memset(buffer + i, 0, (numSamples - i) * sizeof(int16));
-
- return numSamples;
-}
-
-int8 PCSpeaker::generateSquare(uint32 x, uint32 oscLength) {
- return (x < (oscLength / 2)) ? 127 : -128;
-}
-
-int8 PCSpeaker::generateSine(uint32 x, uint32 oscLength) {
- if (oscLength == 0)
- return 0;
-
- // TODO: Maybe using a look-up-table would be better?
- return CLIP<int16>((int16) (128 * sin(2.0 * PI * x / oscLength)), -128, 127);
-}
-
-int8 PCSpeaker::generateSaw(uint32 x, uint32 oscLength) {
- if (oscLength == 0)
- return 0;
-
- return ((x * (65536 / oscLength)) >> 8) - 128;
-}
-
-int8 PCSpeaker::generateTriangle(uint32 x, uint32 oscLength) {
- if (oscLength == 0)
- return 0;
-
- int y = ((x * (65536 / (oscLength / 2))) >> 8) - 128;
-
- return (x <= (oscLength / 2)) ? y : (256 - y);
-}
-
-} // End of namespace Audio
-
-
-// Plugin interface
-// (This can only create a null driver since pc speaker support is not part of the
-// midi driver architecture. But we need the plugin for the options menu in the launcher
-// and for MidiDriver::detectDevice() which is more or less used by all engines.)
-
-class PCSpeakerMusicPlugin : public NullMusicPlugin {
-public:
- const char *getName() const {
- return _s("PC Speaker Emulator");
- }
-
- const char *getId() const {
- return "pcspk";
- }
-
- MusicDevices getDevices() const;
-};
-
-MusicDevices PCSpeakerMusicPlugin::getDevices() const {
- MusicDevices devices;
- devices.push_back(MusicDevice(this, "", MT_PCSPK));
- return devices;
-}
-
-class PCjrMusicPlugin : public NullMusicPlugin {
-public:
- const char *getName() const {
- return _s("IBM PCjr Emulator");
- }
-
- const char *getId() const {
- return "pcjr";
- }
-
- MusicDevices getDevices() const;
-};
-
-MusicDevices PCjrMusicPlugin::getDevices() const {
- MusicDevices devices;
- devices.push_back(MusicDevice(this, "", MT_PCJR));
- return devices;
-}
-
-//#if PLUGIN_ENABLED_DYNAMIC(PCSPK)
- //REGISTER_PLUGIN_DYNAMIC(PCSPK, PLUGIN_TYPE_MUSIC, PCSpeakerMusicPlugin);
-//#else
- REGISTER_PLUGIN_STATIC(PCSPK, PLUGIN_TYPE_MUSIC, PCSpeakerMusicPlugin);
-//#endif
-
-//#if PLUGIN_ENABLED_DYNAMIC(PCJR)
- //REGISTER_PLUGIN_DYNAMIC(PCJR, PLUGIN_TYPE_MUSIC, PCjrMusicPlugin);
-//#else
- REGISTER_PLUGIN_STATIC(PCJR, PLUGIN_TYPE_MUSIC, PCjrMusicPlugin);
-//#endif
diff --git a/sound/softsynth/pcspk.h b/sound/softsynth/pcspk.h
deleted file mode 100644
index 3cd8734a7e..0000000000
--- a/sound/softsynth/pcspk.h
+++ /dev/null
@@ -1,88 +0,0 @@
-/* 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_PCSPK_H
-#define SOUND_SOFTSYNTH_PCSPK_H
-
-#include "sound/audiostream.h"
-#include "sound/mixer.h"
-#include "common/mutex.h"
-
-namespace Audio {
-
-class PCSpeaker : public AudioStream {
-public:
- enum WaveForm {
- kWaveFormSquare = 0,
- kWaveFormSine,
- kWaveFormSaw,
- kWaveFormTriangle
- };
-
- PCSpeaker(int rate = 44100);
- ~PCSpeaker();
-
- /** Play a note for length ms.
- *
- * If length is negative, play until told to stop.
- */
- void play(WaveForm wave, int freq, int32 length);
- /** Stop the currently playing note after delay ms. */
- void stop(int32 delay = 0);
- /** Adjust the volume. */
- void setVolume(byte volume);
-
- bool isPlaying() const;
-
- int readBuffer(int16 *buffer, const int numSamples);
-
- bool isStereo() const { return false; }
- bool endOfData() const { return false; }
- bool endOfStream() const { return false; }
- int getRate() const { return _rate; }
-
-protected:
- Common::Mutex _mutex;
-
- int _rate;
- WaveForm _wave;
- bool _playForever;
- uint32 _oscLength;
- uint32 _oscSamples;
- uint32 _remainingSamples;
- uint32 _mixedSamples;
- byte _volume;
-
- typedef int8 (*generatorFunc)(uint32, uint32);
- static const generatorFunc generateWave[];
-
- static int8 generateSquare(uint32 x, uint32 oscLength);
- static int8 generateSine(uint32 x, uint32 oscLength);
- static int8 generateSaw(uint32 x, uint32 oscLength);
- static int8 generateTriangle(uint32 x, uint32 oscLength);
-};
-
-} // End of namespace Audio
-
-#endif // SOUND_SOFTSYNTH_PCSPEAKER_H
diff --git a/sound/softsynth/sid.cpp b/sound/softsynth/sid.cpp
deleted file mode 100644
index c05ae2e8f5..0000000000
--- a/sound/softsynth/sid.cpp
+++ /dev/null
@@ -1,1456 +0,0 @@
-/* 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$
- *
- */
-
-/*
- * This file is based on reSID, a MOS6581 SID emulator engine.
- * Copyright (C) 2004 Dag Lem <resid@nimrod.no>
- */
-
-#ifndef DISABLE_SID
-
-#include "sid.h"
-#include "sound/null.h"
-#include <math.h>
-
-namespace Resid {
-
-// Fixpoint constants (16.16 bits).
-const int SID::FIXP_SHIFT = 16;
-const int SID::FIXP_MASK = 0xffff;
-
-/*
- * WaveformGenerator
- */
-
-WaveformGenerator::WaveformGenerator() {
- sync_source = this;
-
- reset();
-}
-
-void WaveformGenerator::set_sync_source(WaveformGenerator* source) {
- sync_source = source;
- source->sync_dest = this;
-}
-
-void WaveformGenerator::writeFREQ_LO(reg8 freq_lo) {
- freq = (freq & 0xff00) | (freq_lo & 0x00ff);
-}
-
-void WaveformGenerator::writeFREQ_HI(reg8 freq_hi) {
- freq = ((freq_hi << 8) & 0xff00) | (freq & 0x00ff);
-}
-
-void WaveformGenerator::writePW_LO(reg8 pw_lo) {
- pw = (pw & 0xf00) | (pw_lo & 0x0ff);
-}
-
-void WaveformGenerator::writePW_HI(reg8 pw_hi) {
- pw = ((pw_hi << 8) & 0xf00) | (pw & 0x0ff);
-}
-
-void WaveformGenerator::writeCONTROL_REG(reg8 control) {
- waveform = (control >> 4) & 0x0f;
- ring_mod = control & 0x04;
- sync = control & 0x02;
-
- reg8 test_next = control & 0x08;
-
- // Test bit set.
- if (test_next) {
- accumulator = 0;
- shift_register = 0;
- }
- // Test bit cleared.
- else if (test) {
- shift_register = 0x7ffff8;
- }
-
- test = test_next;
-
- // The gate bit is handled by the EnvelopeGenerator.
-}
-
-reg8 WaveformGenerator::readOSC() {
- return output() >> 4;
-}
-
-void WaveformGenerator::reset() {
- accumulator = 0;
- shift_register = 0x7ffff8;
- freq = 0;
- pw = 0;
-
- test = 0;
- ring_mod = 0;
- sync = 0;
-
- msb_rising = false;
-}
-
-RESID_INLINE void WaveformGenerator::clock(cycle_count delta_t) {
- // No operation if test bit is set.
- if (test) {
- return;
- }
-
- reg24 accumulator_prev = accumulator;
-
- // Calculate new accumulator value;
- reg24 delta_accumulator = delta_t*freq;
- accumulator += delta_accumulator;
- accumulator &= 0xffffff;
-
- // Check whether the MSB is set high. This is used for synchronization.
- msb_rising = !(accumulator_prev & 0x800000) && (accumulator & 0x800000);
-
- // Shift noise register once for each time accumulator bit 19 is set high.
- // Bit 19 is set high each time 2^20 (0x100000) is added to the accumulator.
- reg24 shift_period = 0x100000;
-
- while (delta_accumulator) {
- if (delta_accumulator < shift_period) {
- shift_period = delta_accumulator;
- // Determine whether bit 19 is set on the last period.
- // NB! Requires two's complement integer.
- if (shift_period <= 0x080000) {
- // Check for flip from 0 to 1.
- if (((accumulator - shift_period) & 0x080000) || !(accumulator & 0x080000))
- {
- break;
- }
- }
- else {
- // Check for flip from 0 (to 1 or via 1 to 0) or from 1 via 0 to 1.
- if (((accumulator - shift_period) & 0x080000) && !(accumulator & 0x080000))
- {
- break;
- }
- }
- }
-
- // Shift the noise/random register.
- // NB! The shift is actually delayed 2 cycles, this is not modeled.
- reg24 bit0 = ((shift_register >> 22) ^ (shift_register >> 17)) & 0x1;
- shift_register <<= 1;
- shift_register &= 0x7fffff;
- shift_register |= bit0;
-
- delta_accumulator -= shift_period;
- }
-}
-
-
-/**
- * Synchronize oscillators.
- * This must be done after all the oscillators have been clock()'ed since the
- * oscillators operate in parallel.
- * Note that the oscillators must be clocked exactly on the cycle when the
- * MSB is set high for hard sync to operate correctly. See SID::clock().
- */
-RESID_INLINE void WaveformGenerator::synchronize() {
- // A special case occurs when a sync source is synced itself on the same
- // cycle as when its MSB is set high. In this case the destination will
- // not be synced. This has been verified by sampling OSC3.
- if (msb_rising && sync_dest->sync && !(sync && sync_source->msb_rising)) {
- sync_dest->accumulator = 0;
- }
-}
-
-
-/*
- * Output functions
- */
-
-// No waveform: Zero output.
-RESID_INLINE reg12 WaveformGenerator::output____() {
- return 0x000;
-}
-
-// Triangle:
-RESID_INLINE reg12 WaveformGenerator::output___T() {
- reg24 msb = (ring_mod ? accumulator ^ sync_source->accumulator : accumulator)
- & 0x800000;
- return ((msb ? ~accumulator : accumulator) >> 11) & 0xfff;
-}
-
-// Sawtooth:
-RESID_INLINE reg12 WaveformGenerator::output__S_() {
- return accumulator >> 12;
-}
-
-// Pulse:
-RESID_INLINE reg12 WaveformGenerator::output_P__() {
- return (test || (accumulator >> 12) >= pw) ? 0xfff : 0x000;
-}
-
-// Noise:
-RESID_INLINE reg12 WaveformGenerator::outputN___() {
- return
- ((shift_register & 0x400000) >> 11) |
- ((shift_register & 0x100000) >> 10) |
- ((shift_register & 0x010000) >> 7) |
- ((shift_register & 0x002000) >> 5) |
- ((shift_register & 0x000800) >> 4) |
- ((shift_register & 0x000080) >> 1) |
- ((shift_register & 0x000010) << 1) |
- ((shift_register & 0x000004) << 2);
-}
-
-// Combined waveforms:
-
-RESID_INLINE reg12 WaveformGenerator::output__ST() {
- return wave6581__ST[output__S_()] << 4;
-}
-
-RESID_INLINE reg12 WaveformGenerator::output_P_T() {
- return (wave6581_P_T[output___T() >> 1] << 4) & output_P__();
-}
-
-RESID_INLINE reg12 WaveformGenerator::output_PS_() {
- return (wave6581_PS_[output__S_()] << 4) & output_P__();
-}
-
-RESID_INLINE reg12 WaveformGenerator::output_PST() {
- return (wave6581_PST[output__S_()] << 4) & output_P__();
-}
-
-// Combined waveforms including noise:
-
-RESID_INLINE reg12 WaveformGenerator::outputN__T() {
- return 0;
-}
-
-RESID_INLINE reg12 WaveformGenerator::outputN_S_() {
- return 0;
-}
-
-RESID_INLINE reg12 WaveformGenerator::outputN_ST() {
- return 0;
-}
-
-RESID_INLINE reg12 WaveformGenerator::outputNP__() {
- return 0;
-}
-
-RESID_INLINE reg12 WaveformGenerator::outputNP_T() {
- return 0;
-}
-
-RESID_INLINE reg12 WaveformGenerator::outputNPS_() {
- return 0;
-}
-
-RESID_INLINE reg12 WaveformGenerator::outputNPST() {
- return 0;
-}
-
-/**
- * Select one of 16 possible combinations of waveforms.
- */
-RESID_INLINE reg12 WaveformGenerator::output() {
- // It may seem cleaner to use an array of member functions to return
- // waveform output; however a switch with inline functions is faster.
-
- switch (waveform) {
- default:
- case 0x0:
- return output____();
- case 0x1:
- return output___T();
- case 0x2:
- return output__S_();
- case 0x3:
- return output__ST();
- case 0x4:
- return output_P__();
- case 0x5:
- return output_P_T();
- case 0x6:
- return output_PS_();
- case 0x7:
- return output_PST();
- case 0x8:
- return outputN___();
- case 0x9:
- return outputN__T();
- case 0xa:
- return outputN_S_();
- case 0xb:
- return outputN_ST();
- case 0xc:
- return outputNP__();
- case 0xd:
- return outputNP_T();
- case 0xe:
- return outputNPS_();
- case 0xf:
- return outputNPST();
- }
-}
-
-/*
- * Our objective is to construct a smooth interpolating single-valued function
- * y = f(x).
- * Our approach is to approximate the properties of Catmull-Rom splines for
- * piecewice cubic polynomials.
- */
-
-/**
- * Calculation of coefficients.
- */
-inline void cubic_coefficients(double x1, double y1, double x2, double y2,
- double k1, double k2,
- double& a, double& b, double& c, double& d)
-{
- double dx = x2 - x1, dy = y2 - y1;
-
- a = ((k1 + k2) - 2*dy/dx)/(dx*dx);
- b = ((k2 - k1)/dx - 3*(x1 + x2)*a)/2;
- c = k1 - (3*x1*a + 2*b)*x1;
- d = y1 - ((x1*a + b)*x1 + c)*x1;
-}
-
-/**
- * Evaluation of cubic polynomial by forward differencing.
- */
-template<class PointPlotter>
-inline void interpolate_segment(double x1, double y1, double x2, double y2,
- double k1, double k2,
- PointPlotter plot, double res)
-{
- double a, b, c, d;
- cubic_coefficients(x1, y1, x2, y2, k1, k2, a, b, c, d);
-
- double y = ((a*x1 + b)*x1 + c)*x1 + d;
- double dy = (3*a*(x1 + res) + 2*b)*x1*res + ((a*res + b)*res + c)*res;
- double d2y = (6*a*(x1 + res) + 2*b)*res*res;
- double d3y = 6*a*res*res*res;
-
- // Calculate each point.
- for (double x = x1; x <= x2; x += res) {
- plot(x, y);
- y += dy; dy += d2y; d2y += d3y;
- }
-}
-
-template<class PointIter>
-inline double x(PointIter p) {
- return (*p)[0];
-}
-
-template<class PointIter>
-inline double y(PointIter p) {
- return (*p)[1];
-}
-
-/**
- * Evaluation of complete interpolating function.
- * Note that since each curve segment is controlled by four points, the
- * end points will not be interpolated. If extra control points are not
- * desirable, the end points can simply be repeated to ensure interpolation.
- * Note also that points of non-differentiability and discontinuity can be
- * introduced by repeating points.
- */
-template<class PointIter, class PointPlotter>
-inline void interpolate(PointIter p0, PointIter pn, PointPlotter plot, double res) {
- double k1, k2;
-
- // Set up points for first curve segment.
- PointIter p1 = p0; ++p1;
- PointIter p2 = p1; ++p2;
- PointIter p3 = p2; ++p3;
-
- // Draw each curve segment.
- for (; p2 != pn; ++p0, ++p1, ++p2, ++p3) {
- // p1 and p2 equal; single point.
- if (x(p1) == x(p2)) {
- continue;
- }
- // Both end points repeated; straight line.
- if (x(p0) == x(p1) && x(p2) == x(p3)) {
- k1 = k2 = (y(p2) - y(p1))/(x(p2) - x(p1));
- }
- // p0 and p1 equal; use f''(x1) = 0.
- else if (x(p0) == x(p1)) {
- k2 = (y(p3) - y(p1))/(x(p3) - x(p1));
- k1 = (3*(y(p2) - y(p1))/(x(p2) - x(p1)) - k2)/2;
- }
- // p2 and p3 equal; use f''(x2) = 0.
- else if (x(p2) == x(p3)) {
- k1 = (y(p2) - y(p0))/(x(p2) - x(p0));
- k2 = (3*(y(p2) - y(p1))/(x(p2) - x(p1)) - k1)/2;
- }
- // Normal curve.
- else {
- k1 = (y(p2) - y(p0))/(x(p2) - x(p0));
- k2 = (y(p3) - y(p1))/(x(p3) - x(p1));
- }
-
- interpolate_segment(x(p1), y(p1), x(p2), y(p2), k1, k2, plot, res);
- }
-}
-
-/**
- * Class for plotting integers into an array.
- */
-template<class F>
-class PointPlotter {
-protected:
- F* f;
-
-public:
- PointPlotter(F* arr) : f(arr) {
- }
-
- void operator ()(double x, double y) {
- // Clamp negative values to zero.
- if (y < 0) {
- y = 0;
- }
-
- f[F(x)] = F(y);
- }
-};
-
-fc_point Filter::f0_points_6581[] = {
- // FC f FCHI FCLO
- // ----------------------------
- { 0, 220 }, // 0x00 - repeated end point
- { 0, 220 }, // 0x00
- { 128, 230 }, // 0x10
- { 256, 250 }, // 0x20
- { 384, 300 }, // 0x30
- { 512, 420 }, // 0x40
- { 640, 780 }, // 0x50
- { 768, 1600 }, // 0x60
- { 832, 2300 }, // 0x68
- { 896, 3200 }, // 0x70
- { 960, 4300 }, // 0x78
- { 992, 5000 }, // 0x7c
- { 1008, 5400 }, // 0x7e
- { 1016, 5700 }, // 0x7f
- { 1023, 6000 }, // 0x7f 0x07
- { 1023, 6000 }, // 0x7f 0x07 - discontinuity
- { 1024, 4600 }, // 0x80 -
- { 1024, 4600 }, // 0x80
- { 1032, 4800 }, // 0x81
- { 1056, 5300 }, // 0x84
- { 1088, 6000 }, // 0x88
- { 1120, 6600 }, // 0x8c
- { 1152, 7200 }, // 0x90
- { 1280, 9500 }, // 0xa0
- { 1408, 12000 }, // 0xb0
- { 1536, 14500 }, // 0xc0
- { 1664, 16000 }, // 0xd0
- { 1792, 17100 }, // 0xe0
- { 1920, 17700 }, // 0xf0
- { 2047, 18000 }, // 0xff 0x07
- { 2047, 18000 } // 0xff 0x07 - repeated end point
-};
-
-
-/*
- * Filter
- */
-
-Filter::Filter() {
- fc = 0;
-
- res = 0;
-
- filt = 0;
-
- voice3off = 0;
-
- hp_bp_lp = 0;
-
- vol = 0;
-
- // State of filter.
- Vhp = 0;
- Vbp = 0;
- Vlp = 0;
- Vnf = 0;
-
- enable_filter(true);
-
- // Create mappings from FC to cutoff frequency.
- interpolate(f0_points_6581, f0_points_6581
- + sizeof(f0_points_6581)/sizeof(*f0_points_6581) - 1,
- PointPlotter<sound_sample>(f0_6581), 1.0);
-
- mixer_DC = (-0xfff*0xff/18) >> 7;
-
- f0 = f0_6581;
- f0_points = f0_points_6581;
- f0_count = sizeof(f0_points_6581)/sizeof(*f0_points_6581);
-
- set_w0();
- set_Q();
-}
-
-void Filter::enable_filter(bool enable) {
- enabled = enable;
-}
-
-void Filter::reset(){
- fc = 0;
-
- res = 0;
-
- filt = 0;
-
- voice3off = 0;
-
- hp_bp_lp = 0;
-
- vol = 0;
-
- // State of filter.
- Vhp = 0;
- Vbp = 0;
- Vlp = 0;
- Vnf = 0;
-
- set_w0();
- set_Q();
-}
-
-void Filter::writeFC_LO(reg8 fc_lo) {
- fc = (fc & 0x7f8) | (fc_lo & 0x007);
- set_w0();
-}
-
-void Filter::writeFC_HI(reg8 fc_hi) {
- fc = ((fc_hi << 3) & 0x7f8) | (fc & 0x007);
- set_w0();
-}
-
-void Filter::writeRES_FILT(reg8 res_filt) {
- res = (res_filt >> 4) & 0x0f;
- set_Q();
-
- filt = res_filt & 0x0f;
-}
-
-void Filter::writeMODE_VOL(reg8 mode_vol) {
- voice3off = mode_vol & 0x80;
-
- hp_bp_lp = (mode_vol >> 4) & 0x07;
-
- vol = mode_vol & 0x0f;
-}
-
-// Set filter cutoff frequency.
-void Filter::set_w0() {
- const double pi = 3.1415926535897932385;
-
- // Multiply with 1.048576 to facilitate division by 1 000 000 by right-
- // shifting 20 times (2 ^ 20 = 1048576).
- w0 = static_cast<sound_sample>(2*pi*f0[fc]*1.048576);
-
- // Limit f0 to 16kHz to keep 1 cycle filter stable.
- const sound_sample w0_max_1 = static_cast<sound_sample>(2*pi*16000*1.048576);
- w0_ceil_1 = w0 <= w0_max_1 ? w0 : w0_max_1;
-
- // Limit f0 to 4kHz to keep delta_t cycle filter stable.
- const sound_sample w0_max_dt = static_cast<sound_sample>(2*pi*4000*1.048576);
- w0_ceil_dt = w0 <= w0_max_dt ? w0 : w0_max_dt;
-}
-
-// Set filter resonance.
-void Filter::set_Q() {
- // Q is controlled linearly by res. Q has approximate range [0.707, 1.7].
- // As resonance is increased, the filter must be clocked more often to keep
- // stable.
-
- // The coefficient 1024 is dispensed of later by right-shifting 10 times
- // (2 ^ 10 = 1024).
- _1024_div_Q = static_cast<sound_sample>(1024.0/(0.707 + 1.0*res/0x0f));
-}
-
-RESID_INLINE void Filter::clock(cycle_count delta_t,
- sound_sample voice1,
- sound_sample voice2,
- sound_sample voice3)
-{
- // Scale each voice down from 20 to 13 bits.
- voice1 >>= 7;
- voice2 >>= 7;
-
- // NB! Voice 3 is not silenced by voice3off if it is routed through
- // the filter.
- if (voice3off && !(filt & 0x04)) {
- voice3 = 0;
- }
- else {
- voice3 >>= 7;
- }
-
- // Enable filter on/off.
- // This is not really part of SID, but is useful for testing.
- // On slow CPUs it may be necessary to bypass the filter to lower the CPU
- // load.
- if (!enabled) {
- Vnf = voice1 + voice2 + voice3;
- Vhp = Vbp = Vlp = 0;
- return;
- }
-
- // Route voices into or around filter.
- // The code below is expanded to a switch for faster execution.
- // (filt1 ? Vi : Vnf) += voice1;
- // (filt2 ? Vi : Vnf) += voice2;
- // (filt3 ? Vi : Vnf) += voice3;
-
- sound_sample Vi;
-
- switch (filt) {
- default:
- case 0x0:
- Vi = 0;
- Vnf = voice1 + voice2 + voice3;
- break;
- case 0x1:
- Vi = voice1;
- Vnf = voice2 + voice3;
- break;
- case 0x2:
- Vi = voice2;
- Vnf = voice1 + voice3;
- break;
- case 0x3:
- Vi = voice1 + voice2;
- Vnf = voice3;
- break;
- case 0x4:
- Vi = voice3;
- Vnf = voice1 + voice2;
- break;
- case 0x5:
- Vi = voice1 + voice3;
- Vnf = voice2;
- break;
- case 0x6:
- Vi = voice2 + voice3;
- Vnf = voice1;
- break;
- case 0x7:
- Vi = voice1 + voice2 + voice3;
- Vnf = 0;
- break;
- case 0x8:
- Vi = 0;
- Vnf = voice1 + voice2 + voice3;
- break;
- case 0x9:
- Vi = voice1;
- Vnf = voice2 + voice3;
- break;
- case 0xa:
- Vi = voice2;
- Vnf = voice1 + voice3;
- break;
- case 0xb:
- Vi = voice1 + voice2;
- Vnf = voice3;
- break;
- case 0xc:
- Vi = voice3;
- Vnf = voice1 + voice2;
- break;
- case 0xd:
- Vi = voice1 + voice3;
- Vnf = voice2;
- break;
- case 0xe:
- Vi = voice2 + voice3;
- Vnf = voice1;
- break;
- case 0xf:
- Vi = voice1 + voice2 + voice3;
- Vnf = 0;
- break;
- }
-
- // Maximum delta cycles for the filter to work satisfactorily under current
- // cutoff frequency and resonance constraints is approximately 8.
- cycle_count delta_t_flt = 8;
-
- while (delta_t) {
- if (delta_t < delta_t_flt) {
- delta_t_flt = delta_t;
- }
-
- // delta_t is converted to seconds given a 1MHz clock by dividing
- // with 1 000 000. This is done in two operations to avoid integer
- // multiplication overflow.
-
- // Calculate filter outputs.
- // Vhp = Vbp/Q - Vlp - Vi;
- // dVbp = -w0*Vhp*dt;
- // dVlp = -w0*Vbp*dt;
- sound_sample w0_delta_t = w0_ceil_dt*delta_t_flt >> 6;
-
- sound_sample dVbp = (w0_delta_t*Vhp >> 14);
- sound_sample dVlp = (w0_delta_t*Vbp >> 14);
- Vbp -= dVbp;
- Vlp -= dVlp;
- Vhp = (Vbp*_1024_div_Q >> 10) - Vlp - Vi;
-
- delta_t -= delta_t_flt;
- }
-}
-
-RESID_INLINE sound_sample Filter::output() {
- // This is handy for testing.
- if (!enabled) {
- return (Vnf + mixer_DC)*static_cast<sound_sample>(vol);
- }
-
- // Mix highpass, bandpass, and lowpass outputs. The sum is not
- // weighted, this can be confirmed by sampling sound output for
- // e.g. bandpass, lowpass, and bandpass+lowpass from a SID chip.
-
- // The code below is expanded to a switch for faster execution.
- // if (hp) Vf += Vhp;
- // if (bp) Vf += Vbp;
- // if (lp) Vf += Vlp;
-
- sound_sample Vf;
-
- switch (hp_bp_lp) {
- default:
- case 0x0:
- Vf = 0;
- break;
- case 0x1:
- Vf = Vlp;
- break;
- case 0x2:
- Vf = Vbp;
- break;
- case 0x3:
- Vf = Vlp + Vbp;
- break;
- case 0x4:
- Vf = Vhp;
- break;
- case 0x5:
- Vf = Vlp + Vhp;
- break;
- case 0x6:
- Vf = Vbp + Vhp;
- break;
- case 0x7:
- Vf = Vlp + Vbp + Vhp;
- break;
- }
-
- // Sum non-filtered and filtered output.
- // Multiply the sum with volume.
- return (Vnf + Vf + mixer_DC)*static_cast<sound_sample>(vol);
-}
-
-
-/*
- * EnvelopeGenerator
- */
-
-EnvelopeGenerator::EnvelopeGenerator() {
- reset();
-}
-
-void EnvelopeGenerator::reset() {
- envelope_counter = 0;
-
- attack = 0;
- decay = 0;
- sustain = 0;
- release = 0;
-
- gate = 0;
-
- rate_counter = 0;
- exponential_counter = 0;
- exponential_counter_period = 1;
-
- state = RELEASE;
- rate_period = rate_counter_period[release];
- hold_zero = true;
-}
-
-reg16 EnvelopeGenerator::rate_counter_period[] = {
- 9, // 2ms*1.0MHz/256 = 7.81
- 32, // 8ms*1.0MHz/256 = 31.25
- 63, // 16ms*1.0MHz/256 = 62.50
- 95, // 24ms*1.0MHz/256 = 93.75
- 149, // 38ms*1.0MHz/256 = 148.44
- 220, // 56ms*1.0MHz/256 = 218.75
- 267, // 68ms*1.0MHz/256 = 265.63
- 313, // 80ms*1.0MHz/256 = 312.50
- 392, // 100ms*1.0MHz/256 = 390.63
- 977, // 250ms*1.0MHz/256 = 976.56
- 1954, // 500ms*1.0MHz/256 = 1953.13
- 3126, // 800ms*1.0MHz/256 = 3125.00
- 3907, // 1 s*1.0MHz/256 = 3906.25
- 11720, // 3 s*1.0MHz/256 = 11718.75
- 19532, // 5 s*1.0MHz/256 = 19531.25
- 31251 // 8 s*1.0MHz/256 = 31250.00
-};
-
-
-reg8 EnvelopeGenerator::sustain_level[] = {
- 0x00,
- 0x11,
- 0x22,
- 0x33,
- 0x44,
- 0x55,
- 0x66,
- 0x77,
- 0x88,
- 0x99,
- 0xaa,
- 0xbb,
- 0xcc,
- 0xdd,
- 0xee,
- 0xff,
-};
-
-void EnvelopeGenerator::writeCONTROL_REG(reg8 control) {
- reg8 gate_next = control & 0x01;
-
- // The rate counter is never reset, thus there will be a delay before the
- // envelope counter starts counting up (attack) or down (release).
-
- // Gate bit on: Start attack, decay, sustain.
- if (!gate && gate_next) {
- state = ATTACK;
- rate_period = rate_counter_period[attack];
-
- // Switching to attack state unlocks the zero freeze.
- hold_zero = false;
- }
- // Gate bit off: Start release.
- else if (gate && !gate_next) {
- state = RELEASE;
- rate_period = rate_counter_period[release];
- }
-
- gate = gate_next;
-}
-
-void EnvelopeGenerator::writeATTACK_DECAY(reg8 attack_decay) {
- attack = (attack_decay >> 4) & 0x0f;
- decay = attack_decay & 0x0f;
- if (state == ATTACK) {
- rate_period = rate_counter_period[attack];
- }
- else if (state == DECAY_SUSTAIN) {
- rate_period = rate_counter_period[decay];
- }
-}
-
-void EnvelopeGenerator::writeSUSTAIN_RELEASE(reg8 sustain_release) {
- sustain = (sustain_release >> 4) & 0x0f;
- release = sustain_release & 0x0f;
- if (state == RELEASE) {
- rate_period = rate_counter_period[release];
- }
-}
-
-reg8 EnvelopeGenerator::readENV() {
- return output();
-}
-
-RESID_INLINE void EnvelopeGenerator::clock(cycle_count delta_t) {
- // Check for ADSR delay bug.
- // If the rate counter comparison value is set below the current value of the
- // rate counter, the counter will continue counting up until it wraps around
- // to zero at 2^15 = 0x8000, and then count rate_period - 1 before the
- // envelope can finally be stepped.
- // This has been verified by sampling ENV3.
- //
-
- // NB! This requires two's complement integer.
- int rate_step = rate_period - rate_counter;
- if (rate_step <= 0) {
- rate_step += 0x7fff;
- }
-
- while (delta_t) {
- if (delta_t < rate_step) {
- rate_counter += delta_t;
- if (rate_counter & 0x8000) {
- ++rate_counter &= 0x7fff;
- }
- return;
- }
-
- rate_counter = 0;
- delta_t -= rate_step;
-
- // The first envelope step in the attack state also resets the exponential
- // counter. This has been verified by sampling ENV3.
- //
- if (state == ATTACK || ++exponential_counter == exponential_counter_period)
- {
- exponential_counter = 0;
-
- // Check whether the envelope counter is frozen at zero.
- if (hold_zero) {
- rate_step = rate_period;
- continue;
- }
-
- switch (state) {
- case ATTACK:
- // The envelope counter can flip from 0xff to 0x00 by changing state to
- // release, then to attack. The envelope counter is then frozen at
- // zero; to unlock this situation the state must be changed to release,
- // then to attack. This has been verified by sampling ENV3.
- //
- ++envelope_counter &= 0xff;
- if (envelope_counter == 0xff) {
- state = DECAY_SUSTAIN;
- rate_period = rate_counter_period[decay];
- }
- break;
- case DECAY_SUSTAIN:
- if (envelope_counter != sustain_level[sustain]) {
- --envelope_counter;
- }
- break;
- case RELEASE:
- // The envelope counter can flip from 0x00 to 0xff by changing state to
- // attack, then to release. The envelope counter will then continue
- // counting down in the release state.
- // This has been verified by sampling ENV3.
- // NB! The operation below requires two's complement integer.
- //
- --envelope_counter &= 0xff;
- break;
- }
-
- // Check for change of exponential counter period.
- switch (envelope_counter) {
- case 0xff:
- exponential_counter_period = 1;
- break;
- case 0x5d:
- exponential_counter_period = 2;
- break;
- case 0x36:
- exponential_counter_period = 4;
- break;
- case 0x1a:
- exponential_counter_period = 8;
- break;
- case 0x0e:
- exponential_counter_period = 16;
- break;
- case 0x06:
- exponential_counter_period = 30;
- break;
- case 0x00:
- exponential_counter_period = 1;
-
- // When the envelope counter is changed to zero, it is frozen at zero.
- // This has been verified by sampling ENV3.
- hold_zero = true;
- break;
- }
- }
-
- rate_step = rate_period;
- }
-}
-
-RESID_INLINE reg8 EnvelopeGenerator::output() {
- return envelope_counter;
-}
-
-
-/*
- * ExternalFilter
- */
-
-ExternalFilter::ExternalFilter() {
- reset();
- enable_filter(true);
- set_sampling_parameter(15915.6);
- mixer_DC = ((((0x800 - 0x380) + 0x800)*0xff*3 - 0xfff*0xff/18) >> 7)*0x0f;
-}
-
-void ExternalFilter::enable_filter(bool enable) {
- enabled = enable;
-}
-
-void ExternalFilter::set_sampling_parameter(double pass_freq) {
- static const double pi = 3.1415926535897932385;
-
- w0hp = 105;
- w0lp = (sound_sample) (pass_freq * (2.0 * pi * 1.048576));
- if (w0lp > 104858)
- w0lp = 104858;
-}
-
-void ExternalFilter::reset() {
- // State of filter.
- Vlp = 0;
- Vhp = 0;
- Vo = 0;
-}
-
-RESID_INLINE void ExternalFilter::clock(cycle_count delta_t, sound_sample Vi) {
- // This is handy for testing.
- if (!enabled) {
- // Remove maximum DC level since there is no filter to do it.
- Vlp = Vhp = 0;
- Vo = Vi - mixer_DC;
- return;
- }
-
- // Maximum delta cycles for the external filter to work satisfactorily
- // is approximately 8.
- cycle_count delta_t_flt = 8;
-
- while (delta_t) {
- if (delta_t < delta_t_flt) {
- delta_t_flt = delta_t;
- }
-
- // delta_t is converted to seconds given a 1MHz clock by dividing
- // with 1 000 000.
-
- // Calculate filter outputs.
- // Vo = Vlp - Vhp;
- // Vlp = Vlp + w0lp*(Vi - Vlp)*delta_t;
- // Vhp = Vhp + w0hp*(Vlp - Vhp)*delta_t;
-
- sound_sample dVlp = (w0lp*delta_t_flt >> 8)*(Vi - Vlp) >> 12;
- sound_sample dVhp = w0hp*delta_t_flt*(Vlp - Vhp) >> 20;
- Vo = Vlp - Vhp;
- Vlp += dVlp;
- Vhp += dVhp;
-
- delta_t -= delta_t_flt;
- }
-}
-
-RESID_INLINE sound_sample ExternalFilter::output() {
- return Vo;
-}
-
-
-/*
- * Voice
- */
-
-Voice::Voice() {
- wave_zero = 0x380;
- voice_DC = 0x800*0xff;
-}
-
-void Voice::set_sync_source(Voice* source) {
- wave.set_sync_source(&source->wave);
-}
-
-void Voice::writeCONTROL_REG(reg8 control) {
- wave.writeCONTROL_REG(control);
- envelope.writeCONTROL_REG(control);
-}
-
-void Voice::reset() {
- wave.reset();
- envelope.reset();
-}
-
-
-/*
- * SID
- */
-
-SID::SID() {
- voice[0].set_sync_source(&voice[2]);
- voice[1].set_sync_source(&voice[0]);
- voice[2].set_sync_source(&voice[1]);
-
- set_sampling_parameters(985248, 44100);
-
- bus_value = 0;
- bus_value_ttl = 0;
-}
-
-SID::~SID() {}
-
-void SID::reset() {
- for (int i = 0; i < 3; i++) {
- voice[i].reset();
- }
- filter.reset();
- extfilt.reset();
-
- bus_value = 0;
- bus_value_ttl = 0;
-}
-
-int SID::output() {
- const int range = 1 << 16;
- const int half = range >> 1;
- int sample = extfilt.output()/((4095*255 >> 7)*3*15*2/range);
- if (sample >= half) {
- return half - 1;
- }
- if (sample < -half) {
- return -half;
- }
- return sample;
-}
-
-
-/**
- * Read registers.
- *
- * Reading a write only register returns the last byte written to any SID
- * register. The individual bits in this value start to fade down towards
- * zero after a few cycles. All bits reach zero within approximately
- * $2000 - $4000 cycles.
- * It has been claimed that this fading happens in an orderly fashion, however
- * sampling of write only registers reveals that this is not the case.
- * NB! This is not correctly modeled.
- * The actual use of write only registers has largely been made in the belief
- * that all SID registers are readable. To support this belief the read
- * would have to be done immediately after a write to the same register
- * (remember that an intermediate write to another register would yield that
- * value instead). With this in mind we return the last value written to
- * any SID register for $2000 cycles without modeling the bit fading.
- */
-reg8 SID::read(reg8 offset) {
- switch (offset) {
- case 0x19:
- case 0x1a:
- return 0; //readPOT();
- case 0x1b:
- return voice[2].wave.readOSC();
- case 0x1c:
- return voice[2].envelope.readENV();
- default:
- return bus_value;
- }
-}
-
-void SID::write(reg8 offset, reg8 value) {
- bus_value = value;
- bus_value_ttl = 0x2000;
-
- switch (offset) {
- case 0x00:
- voice[0].wave.writeFREQ_LO(value);
- break;
- case 0x01:
- voice[0].wave.writeFREQ_HI(value);
- break;
- case 0x02:
- voice[0].wave.writePW_LO(value);
- break;
- case 0x03:
- voice[0].wave.writePW_HI(value);
- break;
- case 0x04:
- voice[0].writeCONTROL_REG(value);
- break;
- case 0x05:
- voice[0].envelope.writeATTACK_DECAY(value);
- break;
- case 0x06:
- voice[0].envelope.writeSUSTAIN_RELEASE(value);
- break;
- case 0x07:
- voice[1].wave.writeFREQ_LO(value);
- break;
- case 0x08:
- voice[1].wave.writeFREQ_HI(value);
- break;
- case 0x09:
- voice[1].wave.writePW_LO(value);
- break;
- case 0x0a:
- voice[1].wave.writePW_HI(value);
- break;
- case 0x0b:
- voice[1].writeCONTROL_REG(value);
- break;
- case 0x0c:
- voice[1].envelope.writeATTACK_DECAY(value);
- break;
- case 0x0d:
- voice[1].envelope.writeSUSTAIN_RELEASE(value);
- break;
- case 0x0e:
- voice[2].wave.writeFREQ_LO(value);
- break;
- case 0x0f:
- voice[2].wave.writeFREQ_HI(value);
- break;
- case 0x10:
- voice[2].wave.writePW_LO(value);
- break;
- case 0x11:
- voice[2].wave.writePW_HI(value);
- break;
- case 0x12:
- voice[2].writeCONTROL_REG(value);
- break;
- case 0x13:
- voice[2].envelope.writeATTACK_DECAY(value);
- break;
- case 0x14:
- voice[2].envelope.writeSUSTAIN_RELEASE(value);
- break;
- case 0x15:
- filter.writeFC_LO(value);
- break;
- case 0x16:
- filter.writeFC_HI(value);
- break;
- case 0x17:
- filter.writeRES_FILT(value);
- break;
- case 0x18:
- filter.writeMODE_VOL(value);
- break;
- default:
- break;
- }
-}
-
-void SID::enable_filter(bool enable) {
- filter.enable_filter(enable);
-}
-
-void SID::enable_external_filter(bool enable) {
- extfilt.enable_filter(enable);
-}
-
-
-/**
- * Setting of SID sampling parameters.
- *
- * Use a clock freqency of 985248Hz for PAL C64, 1022730Hz for NTSC C64.
- * The default end of passband frequency is pass_freq = 0.9*sample_freq/2
- * for sample frequencies up to ~ 44.1kHz, and 20kHz for higher sample
- * frequencies.
- *
- * For resampling, the ratio between the clock frequency and the sample
- * frequency is limited as follows:
- * 125*clock_freq/sample_freq < 16384
- * E.g. provided a clock frequency of ~ 1MHz, the sample frequency can not
- * be set lower than ~ 8kHz. A lower sample frequency would make the
- * resampling code overfill its 16k sample ring buffer.
- *
- * The end of passband frequency is also limited:
- * pass_freq <= 0.9*sample_freq/2
- *
- * E.g. for a 44.1kHz sampling rate the end of passband frequency is limited
- * to slightly below 20kHz. This constraint ensures that the FIR table is
- * not overfilled.
- */
-bool SID::set_sampling_parameters(double clock_freq,
- double sample_freq, double pass_freq,
- double filter_scale)
-{
- // The default passband limit is 0.9*sample_freq/2 for sample
- // frequencies below ~ 44.1kHz, and 20kHz for higher sample frequencies.
- if (pass_freq < 0) {
- pass_freq = 20000;
- if (2*pass_freq/sample_freq >= 0.9) {
- pass_freq = 0.9*sample_freq/2;
- }
- }
- // Check whether the FIR table would overfill.
- else if (pass_freq > 0.9*sample_freq/2) {
- return false;
- }
-
- // The filter scaling is only included to avoid clipping, so keep
- // it sane.
- if (filter_scale < 0.9 || filter_scale > 1.0) {
- return false;
- }
-
- // Set the external filter to the pass freq
- extfilt.set_sampling_parameter (pass_freq);
- clock_frequency = clock_freq;
-
- cycles_per_sample =
- cycle_count(clock_freq/sample_freq*(1 << FIXP_SHIFT) + 0.5);
-
- sample_offset = 0;
- sample_prev = 0;
-
- return true;
-}
-
-void SID::clock(cycle_count delta_t) {
- int i;
-
- if (delta_t <= 0) {
- return;
- }
-
- // Age bus value.
- bus_value_ttl -= delta_t;
- if (bus_value_ttl <= 0) {
- bus_value = 0;
- bus_value_ttl = 0;
- }
-
- // Clock amplitude modulators.
- for (i = 0; i < 3; i++) {
- voice[i].envelope.clock(delta_t);
- }
-
- // Clock and synchronize oscillators.
- // Loop until we reach the current cycle.
- cycle_count delta_t_osc = delta_t;
- while (delta_t_osc) {
- cycle_count delta_t_min = delta_t_osc;
-
- // Find minimum number of cycles to an oscillator accumulator MSB toggle.
- // We have to clock on each MSB on / MSB off for hard sync to operate
- // correctly.
- for (i = 0; i < 3; i++) {
- WaveformGenerator& wave = voice[i].wave;
-
- // It is only necessary to clock on the MSB of an oscillator that is
- // a sync source and has freq != 0.
- if (!(wave.sync_dest->sync && wave.freq)) {
- continue;
- }
-
- reg16 freq = wave.freq;
- reg24 accumulator = wave.accumulator;
-
- // Clock on MSB off if MSB is on, clock on MSB on if MSB is off.
- reg24 delta_accumulator =
- (accumulator & 0x800000 ? 0x1000000 : 0x800000) - accumulator;
-
- cycle_count delta_t_next = delta_accumulator/freq;
- if (delta_accumulator%freq) {
- ++delta_t_next;
- }
-
- if (delta_t_next < delta_t_min) {
- delta_t_min = delta_t_next;
- }
- }
-
- // Clock oscillators.
- for (i = 0; i < 3; i++) {
- voice[i].wave.clock(delta_t_min);
- }
-
- // Synchronize oscillators.
- for (i = 0; i < 3; i++) {
- voice[i].wave.synchronize();
- }
-
- delta_t_osc -= delta_t_min;
- }
-
- // Clock filter.
- filter.clock(delta_t,
- voice[0].output(), voice[1].output(), voice[2].output());
-
- // Clock external filter.
- extfilt.clock(delta_t, filter.output());
-}
-
-
-/**
- * SID clocking with audio sampling.
- * Fixpoint arithmetics is used.
- */
-int SID::clock(cycle_count& delta_t, short* buf, int n, int interleave) {
- int s = 0;
-
- for (;;) {
- cycle_count next_sample_offset = sample_offset + cycles_per_sample + (1 << (FIXP_SHIFT - 1));
- cycle_count delta_t_sample = next_sample_offset >> FIXP_SHIFT;
- if (delta_t_sample > delta_t) {
- break;
- }
- if (s >= n) {
- return s;
- }
- clock(delta_t_sample);
- delta_t -= delta_t_sample;
- sample_offset = (next_sample_offset & FIXP_MASK) - (1 << (FIXP_SHIFT - 1));
- buf[s++*interleave] = output();
- }
-
- clock(delta_t);
- sample_offset -= delta_t << FIXP_SHIFT;
- delta_t = 0;
- return s;
-}
-
-}
-
-// Plugin interface
-// (This can only create a null driver since C64 audio support is not part of the
-// midi driver architecture. But we need the plugin for the options menu in the launcher
-// and for MidiDriver::detectDevice() which is more or less used by all engines.)
-
-class C64MusicPlugin : public NullMusicPlugin {
-public:
- const char *getName() const {
- return _s("C64 Audio Emulator");
- }
-
- const char *getId() const {
- return "C64";
- }
-
- MusicDevices getDevices() const;
-};
-
-MusicDevices C64MusicPlugin::getDevices() const {
- MusicDevices devices;
- devices.push_back(MusicDevice(this, "", MT_C64));
- return devices;
-}
-
-//#if PLUGIN_ENABLED_DYNAMIC(C64)
- //REGISTER_PLUGIN_DYNAMIC(C64, PLUGIN_TYPE_MUSIC, C64MusicPlugin);
-//#else
- REGISTER_PLUGIN_STATIC(C64, PLUGIN_TYPE_MUSIC, C64MusicPlugin);
-//#endif
-
-#endif
diff --git a/sound/softsynth/sid.h b/sound/softsynth/sid.h
deleted file mode 100644
index c78f538441..0000000000
--- a/sound/softsynth/sid.h
+++ /dev/null
@@ -1,348 +0,0 @@
-/* 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$
- *
- */
-
-/*
- * This file is based on reSID, a MOS6581 SID emulator engine.
- * Copyright (C) 2004 Dag Lem <resid@nimrod.no>
- */
-
-#ifndef __SID_H__
-#define __SID_H__
-
-// Inlining on/off.
-#define RESID_INLINE inline
-
-namespace Resid {
-
-// We could have used the smallest possible data type for each SID register,
-// however this would give a slower engine because of data type conversions.
-// An int is assumed to be at least 32 bits (necessary in the types reg24,
-// cycle_count, and sound_sample). GNU does not support 16-bit machines
-// (GNU Coding Standards: Portability between CPUs), so this should be
-// a valid assumption.
-
-typedef unsigned int reg4;
-typedef unsigned int reg8;
-typedef unsigned int reg12;
-typedef unsigned int reg16;
-typedef unsigned int reg24;
-
-typedef int cycle_count;
-typedef int sound_sample;
-typedef sound_sample fc_point[2];
-
-
-class WaveformGenerator {
-public:
- WaveformGenerator();
-
- void set_sync_source(WaveformGenerator*);
-
- void clock(cycle_count delta_t);
- void synchronize();
- void reset();
-
- void writeFREQ_LO(reg8);
- void writeFREQ_HI(reg8);
- void writePW_LO(reg8);
- void writePW_HI(reg8);
- void writeCONTROL_REG(reg8);
- reg8 readOSC();
-
- // 12-bit waveform output.
- reg12 output();
-
-protected:
- const WaveformGenerator* sync_source;
- WaveformGenerator* sync_dest;
-
- // Tell whether the accumulator MSB was set high on this cycle.
- bool msb_rising;
-
- reg24 accumulator;
- reg24 shift_register;
-
- // Fout = (Fn*Fclk/16777216)Hz
- reg16 freq;
- // PWout = (PWn/40.95)%
- reg12 pw;
-
- // The control register right-shifted 4 bits; used for output function
- // table lookup.
- reg8 waveform;
-
- // The remaining control register bits.
- reg8 test;
- reg8 ring_mod;
- reg8 sync;
- // The gate bit is handled by the EnvelopeGenerator.
-
- // 16 possible combinations of waveforms.
- reg12 output____();
- reg12 output___T();
- reg12 output__S_();
- reg12 output__ST();
- reg12 output_P__();
- reg12 output_P_T();
- reg12 output_PS_();
- reg12 output_PST();
- reg12 outputN___();
- reg12 outputN__T();
- reg12 outputN_S_();
- reg12 outputN_ST();
- reg12 outputNP__();
- reg12 outputNP_T();
- reg12 outputNPS_();
- reg12 outputNPST();
-
- // Sample data for combinations of waveforms.
- static const reg8 wave6581__ST[];
- static const reg8 wave6581_P_T[];
- static const reg8 wave6581_PS_[];
- static const reg8 wave6581_PST[];
-
- friend class Voice;
- friend class SID;
-};
-
-class Filter {
-public:
- Filter();
-
- void enable_filter(bool enable);
-
- void clock(cycle_count delta_t,
- sound_sample voice1, sound_sample voice2, sound_sample voice3);
- void reset();
-
- // Write registers.
- void writeFC_LO(reg8);
- void writeFC_HI(reg8);
- void writeRES_FILT(reg8);
- void writeMODE_VOL(reg8);
-
- // SID audio output (16 bits).
- sound_sample output();
-
-protected:
- void set_w0();
- void set_Q();
-
- // Filter enabled.
- bool enabled;
-
- // Filter cutoff frequency.
- reg12 fc;
-
- // Filter resonance.
- reg8 res;
-
- // Selects which inputs to route through filter.
- reg8 filt;
-
- // Switch voice 3 off.
- reg8 voice3off;
-
- // Highpass, bandpass, and lowpass filter modes.
- reg8 hp_bp_lp;
-
- // Output master volume.
- reg4 vol;
-
- // Mixer DC offset.
- sound_sample mixer_DC;
-
- // State of filter.
- sound_sample Vhp; // highpass
- sound_sample Vbp; // bandpass
- sound_sample Vlp; // lowpass
- sound_sample Vnf; // not filtered
-
- // Cutoff frequency, resonance.
- sound_sample w0, w0_ceil_1, w0_ceil_dt;
- sound_sample _1024_div_Q;
-
- // Cutoff frequency tables.
- // FC is an 11 bit register.
- sound_sample f0_6581[2048];
- sound_sample* f0;
- static fc_point f0_points_6581[];
- fc_point* f0_points;
- int f0_count;
-
- friend class SID;
-};
-
-class EnvelopeGenerator {
-public:
- EnvelopeGenerator();
-
- enum State { ATTACK, DECAY_SUSTAIN, RELEASE };
-
- void clock(cycle_count delta_t);
- void reset();
-
- void writeCONTROL_REG(reg8);
- void writeATTACK_DECAY(reg8);
- void writeSUSTAIN_RELEASE(reg8);
- reg8 readENV();
-
- // 8-bit envelope output.
- reg8 output();
-
-protected:
- reg16 rate_counter;
- reg16 rate_period;
- reg8 exponential_counter;
- reg8 exponential_counter_period;
- reg8 envelope_counter;
- bool hold_zero;
-
- reg4 attack;
- reg4 decay;
- reg4 sustain;
- reg4 release;
-
- reg8 gate;
-
- State state;
-
- // Lookup table to convert from attack, decay, or release value to rate
- // counter period.
- static reg16 rate_counter_period[];
-
- // The 16 selectable sustain levels.
- static reg8 sustain_level[];
-
- friend class SID;
-};
-
-class ExternalFilter {
-public:
- ExternalFilter();
-
- void enable_filter(bool enable);
- void set_sampling_parameter(double pass_freq);
-
- void clock(cycle_count delta_t, sound_sample Vi);
- void reset();
-
- // Audio output (20 bits).
- sound_sample output();
-
-protected:
- // Filter enabled.
- bool enabled;
-
- // Maximum mixer DC offset.
- sound_sample mixer_DC;
-
- // State of filters.
- sound_sample Vlp; // lowpass
- sound_sample Vhp; // highpass
- sound_sample Vo;
-
- // Cutoff frequencies.
- sound_sample w0lp;
- sound_sample w0hp;
-
- friend class SID;
-};
-
-class Voice {
-public:
- Voice();
-
- void set_sync_source(Voice*);
- void reset();
-
- void writeCONTROL_REG(reg8);
-
- // Amplitude modulated waveform output.
- // Range [-2048*255, 2047*255].
- sound_sample output() {
- // Multiply oscillator output with envelope output.
- return (wave.output() - wave_zero)*envelope.output() + voice_DC;
- }
-
-protected:
- WaveformGenerator wave;
- EnvelopeGenerator envelope;
-
- // Waveform D/A zero level.
- sound_sample wave_zero;
-
- // Multiplying D/A DC offset.
- sound_sample voice_DC;
-
- friend class SID;
-};
-
-
-class SID {
-public:
- SID();
- ~SID();
-
- void enable_filter(bool enable);
- void enable_external_filter(bool enable);
- bool set_sampling_parameters(double clock_freq,
- double sample_freq, double pass_freq = -1,
- double filter_scale = 0.97);
-
- void clock(cycle_count delta_t);
- int clock(cycle_count& delta_t, short* buf, int n, int interleave = 1);
- void reset();
-
- // Read/write registers.
- reg8 read(reg8 offset);
- void write(reg8 offset, reg8 value);
-
- // 16-bit output (AUDIO OUT).
- int output();
-
-protected:
- Voice voice[3];
- Filter filter;
- ExternalFilter extfilt;
-
- reg8 bus_value;
- cycle_count bus_value_ttl;
-
- double clock_frequency;
-
- // Fixpoint constants.
- static const int FIXP_SHIFT;
- static const int FIXP_MASK;
-
- // Sampling variables.
- cycle_count cycles_per_sample;
- cycle_count sample_offset;
- short sample_prev;
-};
-
-}
-
-#endif // not __SID_H__
diff --git a/sound/softsynth/wave6581.cpp b/sound/softsynth/wave6581.cpp
deleted file mode 100644
index d1ddad1623..0000000000
--- a/sound/softsynth/wave6581.cpp
+++ /dev/null
@@ -1,2098 +0,0 @@
-/* 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$
- *
- */
-
-/*
- * This file is based on reSID, a MOS6581 SID emulator engine.
- * Copyright (C) 2004 Dag Lem <resid@nimrod.no>
- */
-
-#ifndef DISABLE_SID
-
-#include "sid.h"
-
-namespace Resid {
-
-const reg8 WaveformGenerator::wave6581__ST[] = {
-/* 0x000: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x008: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x010: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x018: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x020: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x028: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x030: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x038: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x040: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x048: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x050: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x058: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x060: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x068: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x070: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x078: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03,
-/* 0x080: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x088: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x090: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x098: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x0a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x0a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x0b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x0b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
-/* 0x0c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x0c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x0d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x0d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x0e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x0e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x0f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x0f8: */ 0x00, 0x00, 0x00, 0x00, 0x07, 0x07, 0x07, 0x07,
-/* 0x100: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x108: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x110: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x118: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x120: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x128: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x130: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x138: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
-/* 0x140: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x148: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x150: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x158: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x160: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x168: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x170: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x178: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03,
-/* 0x180: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x188: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x190: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x198: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x1a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x1a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x1b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x1b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
-/* 0x1c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x1c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x1d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x1d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x1e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x1e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x1f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x1f8: */ 0x0e, 0x0e, 0x0e, 0x0e, 0x0f, 0x0f, 0x0f, 0x0f,
-/* 0x200: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x208: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x210: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x218: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x220: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x228: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x230: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x238: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x240: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x248: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x250: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x258: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x260: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x268: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x270: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x278: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03,
-/* 0x280: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x288: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x290: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x298: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x2a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x2a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x2b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x2b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
-/* 0x2c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x2c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x2d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x2d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x2e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x2e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x2f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x2f8: */ 0x00, 0x00, 0x00, 0x00, 0x07, 0x07, 0x07, 0x07,
-/* 0x300: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x308: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x310: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x318: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x320: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x328: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x330: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x338: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
-/* 0x340: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x348: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x350: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x358: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x360: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x368: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x370: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x378: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03,
-/* 0x380: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x388: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x390: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x398: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x3a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x3a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x3b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x3b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
-/* 0x3c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x3c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x3d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x3d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x3e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x3e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x3f0: */ 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c,
-/* 0x3f8: */ 0x1e, 0x1e, 0x1e, 0x1e, 0x1f, 0x1f, 0x3f, 0x3f,
-/* 0x400: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x408: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x410: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x418: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x420: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x428: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x430: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x438: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x440: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x448: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x450: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x458: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x460: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x468: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x470: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x478: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03,
-/* 0x480: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x488: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x490: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x498: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x4a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x4a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x4b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x4b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
-/* 0x4c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x4c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x4d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x4d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x4e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x4e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x4f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x4f8: */ 0x00, 0x00, 0x00, 0x00, 0x07, 0x07, 0x07, 0x07,
-/* 0x500: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x508: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x510: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x518: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x520: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x528: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x530: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x538: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
-/* 0x540: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x548: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x550: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x558: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x560: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x568: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x570: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x578: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03,
-/* 0x580: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x588: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x590: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x598: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x5a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x5a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x5b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x5b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
-/* 0x5c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x5c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x5d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x5d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x5e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x5e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x5f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x5f8: */ 0x0e, 0x0e, 0x0e, 0x0e, 0x0f, 0x0f, 0x0f, 0x1f,
-/* 0x600: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x608: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x610: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x618: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x620: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x628: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x630: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x638: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x640: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x648: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x650: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x658: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x660: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x668: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x670: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x678: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03,
-/* 0x680: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x688: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x690: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x698: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x6a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x6a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x6b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x6b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
-/* 0x6c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x6c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x6d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x6d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x6e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x6e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x6f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x6f8: */ 0x00, 0x00, 0x00, 0x00, 0x07, 0x07, 0x07, 0x07,
-/* 0x700: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x708: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x710: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x718: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x720: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x728: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x730: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x738: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
-/* 0x740: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x748: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x750: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x758: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x760: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x768: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x770: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x778: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03,
-/* 0x780: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x788: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x790: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x798: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x7a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x7a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x7b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x7b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
-/* 0x7c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x7c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x7d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x7d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x7e0: */ 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38,
-/* 0x7e8: */ 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38,
-/* 0x7f0: */ 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c,
-/* 0x7f8: */ 0x3e, 0x3e, 0x3f, 0x3f, 0x7f, 0x7f, 0x7f, 0x7f,
-/* 0x800: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x808: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x810: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x818: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x820: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x828: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x830: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x838: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x840: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x848: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x850: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x858: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x860: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x868: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x870: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x878: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03,
-/* 0x880: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x888: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x890: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x898: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x8a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x8a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x8b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x8b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
-/* 0x8c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x8c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x8d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x8d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x8e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x8e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x8f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x8f8: */ 0x00, 0x00, 0x00, 0x00, 0x07, 0x07, 0x07, 0x07,
-/* 0x900: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x908: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x910: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x918: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x920: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x928: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x930: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x938: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
-/* 0x940: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x948: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x950: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x958: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x960: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x968: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x970: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x978: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03,
-/* 0x980: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x988: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x990: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x998: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x9a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x9a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x9b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x9b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
-/* 0x9c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x9c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x9d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x9d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x9e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x9e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x9f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x9f8: */ 0x0e, 0x0e, 0x0e, 0x0e, 0x0f, 0x0f, 0x0f, 0x0f,
-/* 0xa00: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xa08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xa10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xa18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xa20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xa28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xa30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xa38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xa40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xa48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xa50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xa58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xa60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xa68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xa70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xa78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03,
-/* 0xa80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xa88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xa90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xa98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xaa0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xaa8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xab0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xab8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
-/* 0xac0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xac8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xad0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xad8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xae0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xae8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xaf0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xaf8: */ 0x00, 0x00, 0x00, 0x00, 0x07, 0x07, 0x07, 0x07,
-/* 0xb00: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xb08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xb10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xb18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xb20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xb28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xb30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xb38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
-/* 0xb40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xb48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xb50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xb58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xb60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xb68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xb70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xb78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03,
-/* 0xb80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xb88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xb90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xb98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xba0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xba8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xbb0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xbb8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
-/* 0xbc0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xbc8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xbd0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xbd8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xbe0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xbe8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xbf0: */ 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c,
-/* 0xbf8: */ 0x1e, 0x1e, 0x1e, 0x1e, 0x1f, 0x1f, 0x3f, 0x3f,
-/* 0xc00: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xc08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xc10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xc18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xc20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xc28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xc30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xc38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xc40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xc48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xc50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xc58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xc60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xc68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xc70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xc78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03,
-/* 0xc80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xc88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xc90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xc98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xca0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xca8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xcb0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xcb8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
-/* 0xcc0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xcc8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xcd0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xcd8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xce0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xce8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xcf0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xcf8: */ 0x00, 0x00, 0x00, 0x00, 0x07, 0x07, 0x07, 0x07,
-/* 0xd00: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xd08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xd10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xd18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xd20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xd28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xd30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xd38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
-/* 0xd40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xd48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xd50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xd58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xd60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xd68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xd70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xd78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03,
-/* 0xd80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xd88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xd90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xd98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xda0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xda8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xdb0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xdb8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
-/* 0xdc0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xdc8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xdd0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xdd8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xde0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xde8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xdf0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xdf8: */ 0x0e, 0x0e, 0x0e, 0x0e, 0x0f, 0x0f, 0x0f, 0x1f,
-/* 0xe00: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xe08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xe10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xe18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xe20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xe28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xe30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xe38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xe40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xe48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xe50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xe58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xe60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xe68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xe70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xe78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03,
-/* 0xe80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xe88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xe90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xe98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xea0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xea8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xeb0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xeb8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
-/* 0xec0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xec8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xed0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xed8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xee0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xee8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xef0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xef8: */ 0x00, 0x00, 0x00, 0x00, 0x07, 0x07, 0x07, 0x07,
-/* 0xf00: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xf08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xf10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xf18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xf20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xf28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xf30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xf38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
-/* 0xf40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xf48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xf50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xf58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xf60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xf68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xf70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xf78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03,
-/* 0xf80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xf88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xf90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xf98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xfa0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xfa8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xfb0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xfb8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
-/* 0xfc0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xfc8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xfd0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xfd8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xfe0: */ 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38,
-/* 0xfe8: */ 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38,
-/* 0xff0: */ 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c,
-/* 0xff8: */ 0x3e, 0x3e, 0x3f, 0x3f, 0x7f, 0x7f, 0x7f, 0x7f,
-};
-
-const reg8 WaveformGenerator::wave6581_P_T[] = {
-/* 0x000: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x008: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x010: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x018: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x020: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x028: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x030: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x038: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x040: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x048: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x050: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x058: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x060: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x068: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x070: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x078: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x080: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x088: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x090: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x098: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x0a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x0a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x0b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x0b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x0c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x0c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x0d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x0d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x0e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x0e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x0f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x0f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x100: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x108: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x110: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x118: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x120: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x128: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x130: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x138: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x140: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x148: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x150: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x158: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x160: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x168: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x170: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x178: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x180: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x188: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x190: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x198: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x1a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x1a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x1b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x1b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x1c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x1c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x1d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x1d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x1e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x1e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x1f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x1f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x38, 0x3f,
-/* 0x200: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x208: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x210: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x218: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x220: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x228: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x230: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x238: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x240: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x248: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x250: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x258: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x260: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x268: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x270: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x278: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x280: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x288: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x290: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x298: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x2a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x2a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x2b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x2b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x2c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x2c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x2d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x2d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x2e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x2e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x2f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x2f8: */ 0x00, 0x00, 0x00, 0x40, 0x00, 0x40, 0x40, 0x5f,
-/* 0x300: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x308: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x310: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x318: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x320: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x328: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x330: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x338: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x340: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x348: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x350: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x358: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x360: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x368: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40,
-/* 0x370: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40,
-/* 0x378: */ 0x00, 0x00, 0x00, 0x60, 0x00, 0x60, 0x60, 0x6f,
-/* 0x380: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x388: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x390: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x398: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40,
-/* 0x3a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x3a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60,
-/* 0x3b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60,
-/* 0x3b8: */ 0x00, 0x00, 0x00, 0x60, 0x00, 0x60, 0x70, 0x77,
-/* 0x3c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x3c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60,
-/* 0x3d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60,
-/* 0x3d8: */ 0x00, 0x00, 0x00, 0x70, 0x40, 0x70, 0x70, 0x7b,
-/* 0x3e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x70,
-/* 0x3e8: */ 0x00, 0x40, 0x40, 0x70, 0x60, 0x70, 0x78, 0x7d,
-/* 0x3f0: */ 0x00, 0x40, 0x60, 0x78, 0x60, 0x78, 0x78, 0x7e,
-/* 0x3f8: */ 0x70, 0x7c, 0x7c, 0x7f, 0x7e, 0x7f, 0x7f, 0x7f,
-/* 0x400: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x408: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x410: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x418: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x420: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x428: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x430: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x438: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x440: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x448: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x450: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x458: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x460: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x468: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x470: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x478: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
-/* 0x480: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x488: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x490: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x498: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x4a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x4a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x4b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x4b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
-/* 0x4c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x4c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x4d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x4d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
-/* 0x4e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x4e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
-/* 0x4f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
-/* 0x4f8: */ 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x9f,
-/* 0x500: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x508: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x510: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x518: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x520: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x528: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x530: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x538: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
-/* 0x540: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x548: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x550: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x558: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
-/* 0x560: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x568: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
-/* 0x570: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
-/* 0x578: */ 0x00, 0x80, 0x80, 0x80, 0x80, 0xa0, 0xa0, 0xaf,
-/* 0x580: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x588: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x590: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x598: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
-/* 0x5a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x5a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80,
-/* 0x5b0: */ 0x00, 0x00, 0x00, 0x80, 0x00, 0x80, 0x80, 0xa0,
-/* 0x5b8: */ 0x00, 0x80, 0x80, 0xa0, 0x80, 0xa0, 0xb0, 0xb7,
-/* 0x5c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
-/* 0x5c8: */ 0x00, 0x00, 0x00, 0x80, 0x00, 0x80, 0x80, 0xa0,
-/* 0x5d0: */ 0x00, 0x00, 0x00, 0x80, 0x00, 0x80, 0x80, 0xa0,
-/* 0x5d8: */ 0x00, 0x80, 0x80, 0xa0, 0x80, 0xb0, 0xb0, 0xbb,
-/* 0x5e0: */ 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0xb0,
-/* 0x5e8: */ 0x80, 0x80, 0x80, 0xb0, 0x80, 0xb0, 0xb8, 0xbd,
-/* 0x5f0: */ 0x80, 0x80, 0x80, 0xb8, 0xa0, 0xb8, 0xb8, 0xbe,
-/* 0x5f8: */ 0xa0, 0xb8, 0xbc, 0xbf, 0xbe, 0xbf, 0xbf, 0xbf,
-/* 0x600: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x608: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x610: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x618: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x620: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x628: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x630: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x638: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
-/* 0x640: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x648: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x650: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x658: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0xc0,
-/* 0x660: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x668: */ 0x00, 0x00, 0x00, 0x80, 0x00, 0x80, 0x80, 0xc0,
-/* 0x670: */ 0x00, 0x00, 0x00, 0x80, 0x00, 0x80, 0x80, 0xc0,
-/* 0x678: */ 0x00, 0x80, 0x80, 0xc0, 0xc0, 0xc0, 0xc0, 0xcf,
-/* 0x680: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x688: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
-/* 0x690: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
-/* 0x698: */ 0x00, 0x00, 0x00, 0x80, 0x00, 0x80, 0x80, 0xc0,
-/* 0x6a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
-/* 0x6a8: */ 0x00, 0x00, 0x00, 0x80, 0x00, 0x80, 0x80, 0xc0,
-/* 0x6b0: */ 0x00, 0x00, 0x00, 0x80, 0x00, 0x80, 0xc0, 0xc0,
-/* 0x6b8: */ 0x80, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xd0, 0xd7,
-/* 0x6c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
-/* 0x6c8: */ 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0xc0, 0xc0,
-/* 0x6d0: */ 0x00, 0x80, 0x80, 0xc0, 0x80, 0xc0, 0xc0, 0xc0,
-/* 0x6d8: */ 0x80, 0xc0, 0xc0, 0xc0, 0xc0, 0xd0, 0xd0, 0xdb,
-/* 0x6e0: */ 0x00, 0x80, 0x80, 0xc0, 0x80, 0xc0, 0xc0, 0xd0,
-/* 0x6e8: */ 0x80, 0xc0, 0xc0, 0xd0, 0xc0, 0xd0, 0xd8, 0xdd,
-/* 0x6f0: */ 0xc0, 0xc0, 0xc0, 0xd0, 0xc0, 0xd8, 0xd8, 0xde,
-/* 0x6f8: */ 0xc0, 0xd8, 0xdc, 0xdf, 0xdc, 0xdf, 0xdf, 0xdf,
-/* 0x700: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x708: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
-/* 0x710: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
-/* 0x718: */ 0x00, 0x00, 0x00, 0x80, 0x80, 0xc0, 0xc0, 0xe0,
-/* 0x720: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
-/* 0x728: */ 0x00, 0x80, 0x80, 0xc0, 0x80, 0xc0, 0xc0, 0xe0,
-/* 0x730: */ 0x00, 0x80, 0x80, 0xc0, 0x80, 0xc0, 0xc0, 0xe0,
-/* 0x738: */ 0x80, 0xc0, 0xc0, 0xe0, 0xc0, 0xe0, 0xe0, 0xe7,
-/* 0x740: */ 0x00, 0x00, 0x00, 0x80, 0x00, 0x80, 0x80, 0xc0,
-/* 0x748: */ 0x00, 0x80, 0x80, 0xc0, 0x80, 0xc0, 0xc0, 0xe0,
-/* 0x750: */ 0x00, 0x80, 0x80, 0xc0, 0x80, 0xc0, 0xc0, 0xe0,
-/* 0x758: */ 0xc0, 0xc0, 0xc0, 0xe0, 0xe0, 0xe0, 0xe0, 0xeb,
-/* 0x760: */ 0x80, 0x80, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xe0,
-/* 0x768: */ 0xc0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xed,
-/* 0x770: */ 0xc0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe8, 0xe8, 0xee,
-/* 0x778: */ 0xe0, 0xe8, 0xec, 0xef, 0xec, 0xef, 0xef, 0xef,
-/* 0x780: */ 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0xc0,
-/* 0x788: */ 0x80, 0x80, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xf0,
-/* 0x790: */ 0x80, 0xc0, 0xc0, 0xc0, 0xc0, 0xe0, 0xe0, 0xf0,
-/* 0x798: */ 0xc0, 0xe0, 0xe0, 0xf0, 0xe0, 0xf0, 0xf0, 0xf3,
-/* 0x7a0: */ 0x80, 0xc0, 0xc0, 0xe0, 0xc0, 0xe0, 0xe0, 0xf0,
-/* 0x7a8: */ 0xc0, 0xe0, 0xe0, 0xf0, 0xe0, 0xf0, 0xf0, 0xf5,
-/* 0x7b0: */ 0xe0, 0xe0, 0xe0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf6,
-/* 0x7b8: */ 0xf0, 0xf0, 0xf4, 0xf7, 0xf4, 0xf7, 0xf7, 0xf7,
-/* 0x7c0: */ 0xc0, 0xc0, 0xc0, 0xe0, 0xe0, 0xe0, 0xe0, 0xf0,
-/* 0x7c8: */ 0xe0, 0xe0, 0xe0, 0xf8, 0xf0, 0xf8, 0xf8, 0xf9,
-/* 0x7d0: */ 0xe0, 0xf0, 0xf0, 0xf8, 0xf0, 0xf8, 0xf8, 0xfa,
-/* 0x7d8: */ 0xf0, 0xf8, 0xf8, 0xfb, 0xf8, 0xfb, 0xfb, 0xfb,
-/* 0x7e0: */ 0xe0, 0xf0, 0xf0, 0xf8, 0xf0, 0xf8, 0xfc, 0xfc,
-/* 0x7e8: */ 0xf8, 0xfc, 0xfc, 0xfd, 0xfc, 0xfd, 0xfd, 0xfd,
-/* 0x7f0: */ 0xf8, 0xfc, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe,
-/* 0x7f8: */ 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-/* 0x800: */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe,
-/* 0x808: */ 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfc, 0xf8,
-/* 0x810: */ 0xfd, 0xfd, 0xfd, 0xfc, 0xfd, 0xfc, 0xfc, 0xf8,
-/* 0x818: */ 0xfc, 0xfc, 0xfc, 0xf0, 0xf8, 0xf0, 0xf0, 0xe0,
-/* 0x820: */ 0xfb, 0xfb, 0xfb, 0xf8, 0xfb, 0xf8, 0xf8, 0xf0,
-/* 0x828: */ 0xfa, 0xf8, 0xf8, 0xf0, 0xf8, 0xf0, 0xf0, 0xe0,
-/* 0x830: */ 0xf9, 0xf8, 0xf8, 0xf0, 0xf8, 0xf0, 0xe0, 0xe0,
-/* 0x838: */ 0xf0, 0xe0, 0xe0, 0xe0, 0xe0, 0xc0, 0xc0, 0xc0,
-/* 0x840: */ 0xf7, 0xf7, 0xf7, 0xf4, 0xf7, 0xf4, 0xf0, 0xf0,
-/* 0x848: */ 0xf6, 0xf0, 0xf0, 0xf0, 0xf0, 0xe0, 0xe0, 0xe0,
-/* 0x850: */ 0xf5, 0xf0, 0xf0, 0xe0, 0xf0, 0xe0, 0xe0, 0xc0,
-/* 0x858: */ 0xf0, 0xe0, 0xe0, 0xc0, 0xe0, 0xc0, 0xc0, 0x80,
-/* 0x860: */ 0xf3, 0xf0, 0xf0, 0xe0, 0xf0, 0xe0, 0xe0, 0xc0,
-/* 0x868: */ 0xf0, 0xe0, 0xe0, 0xc0, 0xc0, 0xc0, 0xc0, 0x80,
-/* 0x870: */ 0xf0, 0xe0, 0xc0, 0xc0, 0xc0, 0xc0, 0x80, 0x80,
-/* 0x878: */ 0xc0, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00,
-/* 0x880: */ 0xef, 0xef, 0xef, 0xec, 0xef, 0xec, 0xe8, 0xe0,
-/* 0x888: */ 0xee, 0xe8, 0xe8, 0xe0, 0xe0, 0xe0, 0xe0, 0xc0,
-/* 0x890: */ 0xed, 0xe8, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xc0,
-/* 0x898: */ 0xe0, 0xe0, 0xc0, 0xc0, 0xc0, 0xc0, 0x80, 0x80,
-/* 0x8a0: */ 0xeb, 0xe0, 0xe0, 0xe0, 0xe0, 0xc0, 0xc0, 0xc0,
-/* 0x8a8: */ 0xe0, 0xc0, 0xc0, 0x80, 0xc0, 0x80, 0x80, 0x00,
-/* 0x8b0: */ 0xe0, 0xc0, 0xc0, 0x80, 0xc0, 0x80, 0x80, 0x00,
-/* 0x8b8: */ 0xc0, 0x80, 0x80, 0x00, 0x80, 0x00, 0x00, 0x00,
-/* 0x8c0: */ 0xe7, 0xe0, 0xe0, 0xc0, 0xe0, 0xc0, 0xc0, 0x80,
-/* 0x8c8: */ 0xe0, 0xc0, 0xc0, 0x80, 0xc0, 0x80, 0x80, 0x00,
-/* 0x8d0: */ 0xe0, 0xc0, 0xc0, 0x80, 0xc0, 0x80, 0x80, 0x00,
-/* 0x8d8: */ 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x8e0: */ 0xe0, 0xc0, 0xc0, 0x80, 0x80, 0x00, 0x00, 0x00,
-/* 0x8e8: */ 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x8f0: */ 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x8f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x900: */ 0xdf, 0xdf, 0xdf, 0xdc, 0xdf, 0xdc, 0xd8, 0xc0,
-/* 0x908: */ 0xde, 0xd8, 0xd8, 0xc0, 0xd8, 0xc0, 0xc0, 0xc0,
-/* 0x910: */ 0xdd, 0xd8, 0xd0, 0xc0, 0xd0, 0xc0, 0xc0, 0x80,
-/* 0x918: */ 0xd0, 0xc0, 0xc0, 0x80, 0xc0, 0x80, 0x80, 0x00,
-/* 0x920: */ 0xdb, 0xd0, 0xd0, 0xc0, 0xc0, 0xc0, 0xc0, 0x80,
-/* 0x928: */ 0xc0, 0xc0, 0xc0, 0x80, 0xc0, 0x80, 0x80, 0x00,
-/* 0x930: */ 0xc0, 0xc0, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00,
-/* 0x938: */ 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x940: */ 0xd7, 0xd0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0x80,
-/* 0x948: */ 0xc0, 0xc0, 0x80, 0x00, 0x80, 0x00, 0x00, 0x00,
-/* 0x950: */ 0xc0, 0x80, 0x80, 0x00, 0x80, 0x00, 0x00, 0x00,
-/* 0x958: */ 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x960: */ 0xc0, 0x80, 0x80, 0x00, 0x80, 0x00, 0x00, 0x00,
-/* 0x968: */ 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x970: */ 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x978: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x980: */ 0xcf, 0xc0, 0xc0, 0xc0, 0xc0, 0x80, 0x80, 0x00,
-/* 0x988: */ 0xc0, 0x80, 0x80, 0x00, 0x80, 0x00, 0x00, 0x00,
-/* 0x990: */ 0xc0, 0x80, 0x80, 0x00, 0x80, 0x00, 0x00, 0x00,
-/* 0x998: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x9a0: */ 0xc0, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x9a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x9b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x9b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x9c0: */ 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x9c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x9d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x9d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x9e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x9e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x9f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x9f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xa00: */ 0xbf, 0xbf, 0xbf, 0xbe, 0xbf, 0xbc, 0xbc, 0xa0,
-/* 0xa08: */ 0xbe, 0xbc, 0xb8, 0xa0, 0xb8, 0xa0, 0x80, 0x80,
-/* 0xa10: */ 0xbd, 0xb8, 0xb0, 0x80, 0xb0, 0x80, 0x80, 0x80,
-/* 0xa18: */ 0xb0, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00,
-/* 0xa20: */ 0xbb, 0xb0, 0xb0, 0x80, 0xa0, 0x80, 0x80, 0x00,
-/* 0xa28: */ 0xa0, 0x80, 0x80, 0x00, 0x80, 0x00, 0x00, 0x00,
-/* 0xa30: */ 0xa0, 0x80, 0x80, 0x00, 0x80, 0x00, 0x00, 0x00,
-/* 0xa38: */ 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xa40: */ 0xb7, 0xb0, 0xa0, 0x80, 0xa0, 0x80, 0x80, 0x00,
-/* 0xa48: */ 0xa0, 0x80, 0x80, 0x00, 0x80, 0x00, 0x00, 0x00,
-/* 0xa50: */ 0x80, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xa58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xa60: */ 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xa68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xa70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xa78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xa80: */ 0xaf, 0xa0, 0xa0, 0x80, 0x80, 0x80, 0x80, 0x00,
-/* 0xa88: */ 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xa90: */ 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xa98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xaa0: */ 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xaa8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xab0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xab8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xac0: */ 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xac8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xad0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xad8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xae0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xae8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xaf0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xaf8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xb00: */ 0x9f, 0x90, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00,
-/* 0xb08: */ 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xb10: */ 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xb18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xb20: */ 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xb28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xb30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xb38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xb40: */ 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xb48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xb50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xb58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xb60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xb68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xb70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xb78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xb80: */ 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xb88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xb90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xb98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xba0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xba8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xbb0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xbb8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xbc0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xbc8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xbd0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xbd8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xbe0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xbe8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xbf0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xbf8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xc00: */ 0x7f, 0x7f, 0x7f, 0x7e, 0x7f, 0x7c, 0x7c, 0x70,
-/* 0xc08: */ 0x7e, 0x7c, 0x78, 0x60, 0x78, 0x60, 0x60, 0x00,
-/* 0xc10: */ 0x7d, 0x78, 0x78, 0x60, 0x70, 0x40, 0x40, 0x00,
-/* 0xc18: */ 0x70, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xc20: */ 0x7b, 0x78, 0x70, 0x40, 0x70, 0x40, 0x00, 0x00,
-/* 0xc28: */ 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xc30: */ 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xc38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xc40: */ 0x77, 0x70, 0x70, 0x00, 0x60, 0x00, 0x00, 0x00,
-/* 0xc48: */ 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xc50: */ 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xc58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xc60: */ 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xc68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xc70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xc78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xc80: */ 0x6f, 0x60, 0x60, 0x00, 0x60, 0x00, 0x00, 0x00,
-/* 0xc88: */ 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xc90: */ 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xc98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xca0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xca8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xcb0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xcb8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xcc0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xcc8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xcd0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xcd8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xce0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xce8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xcf0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xcf8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xd00: */ 0x5f, 0x58, 0x40, 0x00, 0x40, 0x00, 0x00, 0x00,
-/* 0xd08: */ 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xd10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xd18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xd20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xd28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xd30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xd38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xd40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xd48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xd50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xd58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xd60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xd68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xd70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xd78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xd80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xd88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xd90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xd98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xda0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xda8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xdb0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xdb8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xdc0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xdc8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xdd0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xdd8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xde0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xde8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xdf0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xdf8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xe00: */ 0x3f, 0x3c, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xe08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xe10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xe18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xe20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xe28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xe30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xe38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xe40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xe48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xe50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xe58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xe60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xe68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xe70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xe78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xe80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xe88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xe90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xe98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xea0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xea8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xeb0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xeb8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xec0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xec8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xed0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xed8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xee0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xee8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xef0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xef8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xf00: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xf08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xf10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xf18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xf20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xf28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xf30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xf38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xf40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xf48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xf50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xf58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xf60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xf68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xf70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xf78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xf80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xf88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xf90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xf98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xfa0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xfa8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xfb0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xfb8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xfc0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xfc8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xfd0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xfd8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xfe0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xfe8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xff0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xff8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-};
-
-const reg8 WaveformGenerator::wave6581_PS_[] = {
-/* 0x000: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x008: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x010: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x018: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x020: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x028: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x030: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x038: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x040: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x048: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x050: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x058: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x060: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x068: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x070: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x078: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x080: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x088: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x090: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x098: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x0a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x0a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x0b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x0b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x0c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x0c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x0d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x0d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x0e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x0e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x0f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x0f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07,
-/* 0x100: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x108: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x110: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x118: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x120: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x128: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x130: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x138: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x140: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x148: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x150: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x158: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x160: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x168: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x170: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x178: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
-/* 0x180: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x188: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x190: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x198: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x1a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x1a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x1b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x1b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
-/* 0x1c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x1c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x1d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x1d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x1e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x1e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x1f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x1f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x1f,
-/* 0x200: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x208: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x210: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x218: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x220: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x228: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x230: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x238: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x240: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x248: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x250: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x258: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x260: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x268: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x270: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x278: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
-/* 0x280: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x288: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x290: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x298: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x2a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x2a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x2b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x2b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
-/* 0x2c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x2c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x2d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x2d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x2e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x2e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x2f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x2f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2f,
-/* 0x300: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x308: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x310: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x318: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x320: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x328: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x330: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x338: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x340: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x348: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x350: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x358: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x360: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x368: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x370: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x378: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x37,
-/* 0x380: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x388: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x390: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x398: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x3a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x3a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x3b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x3b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3b,
-/* 0x3c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x3c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x3d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x3d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3d,
-/* 0x3e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x3e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e,
-/* 0x3f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x3f,
-/* 0x3f8: */ 0x00, 0x30, 0x38, 0x3f, 0x3e, 0x3f, 0x3f, 0x3f,
-/* 0x400: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x408: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x410: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x418: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x420: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x428: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x430: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x438: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x440: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x448: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x450: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x458: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x460: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x468: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x470: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x478: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
-/* 0x480: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x488: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x490: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x498: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x4a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x4a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x4b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x4b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x4c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x4c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x4d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x4d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x4e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x4e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x4f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x4f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4f,
-/* 0x500: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x508: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x510: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x518: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x520: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x528: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x530: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x538: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x540: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x548: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x550: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x558: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x560: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x568: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x570: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x578: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x57,
-/* 0x580: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x588: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x590: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x598: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x5a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x5a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x5b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x5b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5b,
-/* 0x5c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x5c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x5d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x5d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5d,
-/* 0x5e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x5e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5e,
-/* 0x5f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x5f,
-/* 0x5f8: */ 0x00, 0x40, 0x40, 0x5f, 0x5c, 0x5f, 0x5f, 0x5f,
-/* 0x600: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x608: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x610: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x618: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x620: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x628: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x630: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x638: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x640: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x648: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x650: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x658: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x660: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x668: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x670: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x678: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x67,
-/* 0x680: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x688: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x690: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x698: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x6a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x6a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x6b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x6b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x6b,
-/* 0x6c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x6c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x6d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x6d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x40, 0x6d,
-/* 0x6e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40,
-/* 0x6e8: */ 0x00, 0x00, 0x00, 0x40, 0x00, 0x40, 0x40, 0x6e,
-/* 0x6f0: */ 0x00, 0x00, 0x00, 0x40, 0x00, 0x60, 0x60, 0x6f,
-/* 0x6f8: */ 0x00, 0x60, 0x60, 0x6f, 0x60, 0x6f, 0x6f, 0x6f,
-/* 0x700: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x708: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x710: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x718: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40,
-/* 0x720: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x728: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40,
-/* 0x730: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40,
-/* 0x738: */ 0x00, 0x00, 0x00, 0x40, 0x00, 0x40, 0x60, 0x73,
-/* 0x740: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x748: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40,
-/* 0x750: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40,
-/* 0x758: */ 0x00, 0x00, 0x00, 0x40, 0x00, 0x60, 0x60, 0x75,
-/* 0x760: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60,
-/* 0x768: */ 0x00, 0x00, 0x00, 0x60, 0x00, 0x60, 0x60, 0x76,
-/* 0x770: */ 0x00, 0x00, 0x00, 0x60, 0x00, 0x60, 0x60, 0x77,
-/* 0x778: */ 0x00, 0x70, 0x70, 0x77, 0x70, 0x77, 0x77, 0x77,
-/* 0x780: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x788: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60,
-/* 0x790: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60,
-/* 0x798: */ 0x00, 0x00, 0x00, 0x60, 0x00, 0x60, 0x60, 0x79,
-/* 0x7a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60,
-/* 0x7a8: */ 0x00, 0x00, 0x00, 0x60, 0x00, 0x70, 0x70, 0x7a,
-/* 0x7b0: */ 0x00, 0x00, 0x00, 0x70, 0x00, 0x70, 0x70, 0x7b,
-/* 0x7b8: */ 0x40, 0x70, 0x70, 0x7b, 0x78, 0x7b, 0x7b, 0x7b,
-/* 0x7c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70,
-/* 0x7c8: */ 0x00, 0x00, 0x00, 0x70, 0x00, 0x70, 0x70, 0x7c,
-/* 0x7d0: */ 0x00, 0x00, 0x00, 0x70, 0x40, 0x70, 0x70, 0x7d,
-/* 0x7d8: */ 0x40, 0x70, 0x78, 0x7d, 0x78, 0x7d, 0x7d, 0x7d,
-/* 0x7e0: */ 0x00, 0x40, 0x40, 0x78, 0x60, 0x78, 0x78, 0x7e,
-/* 0x7e8: */ 0x60, 0x78, 0x78, 0x7e, 0x7c, 0x7e, 0x7e, 0x7e,
-/* 0x7f0: */ 0x70, 0x7c, 0x7c, 0x7f, 0x7e, 0x7f, 0x7f, 0x7f,
-/* 0x7f8: */ 0x7e, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
-/* 0x800: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x808: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x810: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x818: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x820: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x828: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x830: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x838: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x840: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x848: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x850: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x858: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x860: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x868: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x870: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x878: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x880: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x888: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x890: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x898: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x8a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x8a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x8b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x8b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x8c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x8c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x8d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x8d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x8e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x8e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x8f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x8f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07,
-/* 0x900: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x908: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x910: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x918: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x920: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x928: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x930: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x938: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x940: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x948: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x950: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x958: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x960: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x968: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x970: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x978: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
-/* 0x980: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x988: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x990: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x998: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x9a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x9a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x9b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x9b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
-/* 0x9c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x9c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x9d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x9d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x9e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x9e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x9f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x9f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x1f,
-/* 0xa00: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xa08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xa10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xa18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xa20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xa28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xa30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xa38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xa40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xa48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xa50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xa58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xa60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xa68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xa70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xa78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
-/* 0xa80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xa88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xa90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xa98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xaa0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xaa8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xab0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xab8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
-/* 0xac0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xac8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xad0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xad8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xae0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xae8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xaf0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xaf8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2f,
-/* 0xb00: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xb08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xb10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xb18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xb20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xb28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xb30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xb38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xb40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xb48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xb50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xb58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xb60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xb68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xb70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xb78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x37,
-/* 0xb80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xb88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xb90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xb98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xba0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xba8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xbb0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xbb8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3b,
-/* 0xbc0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xbc8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xbd0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xbd8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3d,
-/* 0xbe0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xbe8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e,
-/* 0xbf0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x3f,
-/* 0xbf8: */ 0x00, 0x30, 0x38, 0x3f, 0x3e, 0x3f, 0x3f, 0x3f,
-/* 0xc00: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xc08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xc10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xc18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xc20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xc28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xc30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xc38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xc40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xc48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xc50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xc58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xc60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xc68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xc70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xc78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
-/* 0xc80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xc88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xc90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xc98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xca0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xca8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xcb0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xcb8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xcc0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xcc8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xcd0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xcd8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xce0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xce8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xcf0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xcf8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4f,
-/* 0xd00: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xd08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xd10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xd18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xd20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xd28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xd30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xd38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xd40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xd48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xd50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xd58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xd60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xd68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xd70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xd78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x57,
-/* 0xd80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xd88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xd90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xd98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xda0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xda8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xdb0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xdb8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5b,
-/* 0xdc0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xdc8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xdd0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xdd8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5d,
-/* 0xde0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xde8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5e,
-/* 0xdf0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x5f,
-/* 0xdf8: */ 0x00, 0x40, 0x40, 0x5f, 0x5c, 0x5f, 0x5f, 0x5f,
-/* 0xe00: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xe08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xe10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xe18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xe20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xe28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xe30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xe38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xe40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xe48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xe50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xe58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xe60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xe68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xe70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xe78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x67,
-/* 0xe80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xe88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xe90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xe98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xea0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xea8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xeb0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xeb8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x6b,
-/* 0xec0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xec8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xed0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xed8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x6d,
-/* 0xee0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40,
-/* 0xee8: */ 0x00, 0x00, 0x00, 0x40, 0x00, 0x40, 0x40, 0x6e,
-/* 0xef0: */ 0x00, 0x00, 0x00, 0x40, 0x00, 0x60, 0x60, 0x6f,
-/* 0xef8: */ 0x00, 0x60, 0x60, 0x6f, 0x60, 0x6f, 0x6f, 0x6f,
-/* 0xf00: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xf08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xf10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xf18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40,
-/* 0xf20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xf28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40,
-/* 0xf30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40,
-/* 0xf38: */ 0x00, 0x00, 0x00, 0x40, 0x00, 0x40, 0x60, 0x73,
-/* 0xf40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xf48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40,
-/* 0xf50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40,
-/* 0xf58: */ 0x00, 0x00, 0x00, 0x40, 0x00, 0x60, 0x60, 0x75,
-/* 0xf60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60,
-/* 0xf68: */ 0x00, 0x00, 0x00, 0x60, 0x00, 0x60, 0x60, 0x76,
-/* 0xf70: */ 0x00, 0x00, 0x00, 0x60, 0x00, 0x60, 0x60, 0x77,
-/* 0xf78: */ 0x00, 0x70, 0x70, 0x77, 0x70, 0x77, 0x77, 0x77,
-/* 0xf80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xf88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60,
-/* 0xf90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60,
-/* 0xf98: */ 0x00, 0x00, 0x00, 0x60, 0x00, 0x60, 0x60, 0x79,
-/* 0xfa0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60,
-/* 0xfa8: */ 0x00, 0x00, 0x00, 0x60, 0x00, 0x70, 0x70, 0x7a,
-/* 0xfb0: */ 0x00, 0x00, 0x00, 0x70, 0x00, 0x70, 0x70, 0x7b,
-/* 0xfb8: */ 0x40, 0x70, 0x70, 0x7b, 0x78, 0x7b, 0x7b, 0x7b,
-/* 0xfc0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70,
-/* 0xfc8: */ 0x00, 0x00, 0x00, 0x70, 0x00, 0x70, 0x70, 0x7c,
-/* 0xfd0: */ 0x00, 0x00, 0x00, 0x70, 0x40, 0x70, 0x70, 0x7d,
-/* 0xfd8: */ 0x40, 0x70, 0x78, 0x7d, 0x78, 0x7d, 0x7d, 0x7d,
-/* 0xfe0: */ 0x00, 0x40, 0x40, 0x78, 0x60, 0x78, 0x78, 0x7e,
-/* 0xfe8: */ 0x60, 0x78, 0x78, 0x7e, 0x7c, 0x7e, 0x7e, 0x7e,
-/* 0xff0: */ 0x70, 0x7c, 0x7c, 0x7f, 0x7c, 0x7f, 0x7f, 0x7f,
-/* 0xff8: */ 0x7e, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
-};
-
-const reg8 WaveformGenerator::wave6581_PST[] = {
-/* 0x000: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x008: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x010: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x018: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x020: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x028: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x030: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x038: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x040: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x048: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x050: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x058: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x060: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x068: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x070: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x078: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x080: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x088: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x090: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x098: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x0a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x0a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x0b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x0b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x0c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x0c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x0d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x0d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x0e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x0e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x0f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x0f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x100: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x108: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x110: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x118: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x120: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x128: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x130: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x138: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x140: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x148: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x150: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x158: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x160: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x168: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x170: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x178: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x180: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x188: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x190: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x198: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x1a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x1a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x1b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x1b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x1c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x1c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x1d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x1d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x1e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x1e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x1f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x1f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x200: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x208: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x210: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x218: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x220: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x228: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x230: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x238: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x240: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x248: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x250: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x258: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x260: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x268: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x270: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x278: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x280: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x288: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x290: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x298: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x2a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x2a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x2b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x2b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x2c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x2c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x2d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x2d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x2e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x2e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x2f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x2f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x300: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x308: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x310: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x318: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x320: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x328: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x330: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x338: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x340: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x348: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x350: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x358: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x360: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x368: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x370: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x378: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x380: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x388: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x390: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x398: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x3a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x3a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x3b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x3b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x3c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x3c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x3d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x3d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x3e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x3e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x3f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x3f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f,
-/* 0x400: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x408: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x410: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x418: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x420: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x428: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x430: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x438: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x440: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x448: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x450: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x458: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x460: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x468: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x470: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x478: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x480: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x488: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x490: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x498: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x4a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x4a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x4b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x4b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x4c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x4c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x4d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x4d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x4e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x4e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x4f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x4f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x500: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x508: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x510: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x518: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x520: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x528: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x530: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x538: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x540: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x548: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x550: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x558: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x560: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x568: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x570: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x578: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x580: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x588: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x590: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x598: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x5a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x5a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x5b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x5b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x5c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x5c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x5d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x5d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x5e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x5e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x5f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x5f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x600: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x608: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x610: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x618: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x620: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x628: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x630: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x638: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x640: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x648: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x650: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x658: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x660: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x668: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x670: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x678: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x680: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x688: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x690: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x698: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x6a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x6a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x6b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x6b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x6c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x6c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x6d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x6d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x6e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x6e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x6f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x6f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x700: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x708: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x710: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x718: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x720: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x728: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x730: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x738: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x740: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x748: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x750: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x758: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x760: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x768: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x770: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x778: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x780: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x788: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x790: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x798: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x7a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x7a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x7b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x7b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x7c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x7c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x7d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x7d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x7e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x7e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20,
-/* 0x7f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30,
-/* 0x7f8: */ 0x00, 0x00, 0x00, 0x78, 0x78, 0x7e, 0x7f, 0x7f,
-/* 0x800: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x808: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x810: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x818: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x820: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x828: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x830: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x838: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x840: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x848: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x850: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x858: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x860: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x868: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x870: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x878: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x880: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x888: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x890: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x898: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x8a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x8a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x8b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x8b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x8c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x8c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x8d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x8d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x8e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x8e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x8f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x8f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x900: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x908: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x910: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x918: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x920: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x928: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x930: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x938: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x940: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x948: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x950: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x958: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x960: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x968: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x970: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x978: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x980: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x988: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x990: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x998: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x9a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x9a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x9b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x9b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x9c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x9c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x9d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x9d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x9e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x9e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x9f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0x9f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xa00: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xa08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xa10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xa18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xa20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xa28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xa30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xa38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xa40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xa48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xa50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xa58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xa60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xa68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xa70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xa78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xa80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xa88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xa90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xa98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xaa0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xaa8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xab0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xab8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xac0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xac8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xad0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xad8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xae0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xae8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xaf0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xaf8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xb00: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xb08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xb10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xb18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xb20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xb28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xb30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xb38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xb40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xb48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xb50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xb58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xb60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xb68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xb70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xb78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xb80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xb88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xb90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xb98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xba0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xba8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xbb0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xbb8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xbc0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xbc8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xbd0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xbd8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xbe0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xbe8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xbf0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xbf8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f,
-/* 0xc00: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xc08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xc10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xc18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xc20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xc28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xc30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xc38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xc40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xc48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xc50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xc58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xc60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xc68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xc70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xc78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xc80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xc88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xc90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xc98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xca0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xca8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xcb0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xcb8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xcc0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xcc8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xcd0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xcd8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xce0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xce8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xcf0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xcf8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xd00: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xd08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xd10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xd18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xd20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xd28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xd30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xd38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xd40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xd48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xd50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xd58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xd60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xd68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xd70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xd78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xd80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xd88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xd90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xd98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xda0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xda8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xdb0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xdb8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xdc0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xdc8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xdd0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xdd8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xde0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xde8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xdf0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xdf8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xe00: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xe08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xe10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xe18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xe20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xe28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xe30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xe38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xe40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xe48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xe50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xe58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xe60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xe68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xe70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xe78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xe80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xe88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xe90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xe98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xea0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xea8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xeb0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xeb8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xec0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xec8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xed0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xed8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xee0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xee8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xef0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xef8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xf00: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xf08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xf10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xf18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xf20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xf28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xf30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xf38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xf40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xf48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xf50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xf58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xf60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xf68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xf70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xf78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xf80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xf88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xf90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xf98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xfa0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xfa8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xfb0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xfb8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xfc0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xfc8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xfd0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xfd8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xfe0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 0xfe8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20,
-/* 0xff0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30,
-/* 0xff8: */ 0x00, 0x00, 0x00, 0x78, 0x78, 0x7e, 0x7f, 0x7f,
-};
-
-}
-#endif
diff --git a/sound/softsynth/ym2612.cpp b/sound/softsynth/ym2612.cpp
deleted file mode 100644
index 08331c6244..0000000000
--- a/sound/softsynth/ym2612.cpp
+++ /dev/null
@@ -1,789 +0,0 @@
-/* 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 <math.h>
-
-#include "sound/softsynth/ym2612.h"
-#include "common/util.h"
-#include "sound/musicplugin.h"
-#include "common/translation.h"
-
-////////////////////////////////////////
-//
-// Miscellaneous
-//
-////////////////////////////////////////
-
-static int *sintbl = 0;
-static int *powtbl = 0;
-static int *frequencyTable = 0;
-static int *keycodeTable = 0;
-static int *keyscaleTable = 0;
-static int *attackOut = 0;
-
-
-////////////////////////////////////////
-//
-// Operator2612 implementation
-//
-////////////////////////////////////////
-
-Operator2612::Operator2612 (Voice2612 *owner) :
- _owner (owner),
- _state (_s_ready),
- _currentLevel ((int32)0x7f << 15),
- _phase (0),
- _lastOutput (0),
- _feedbackLevel (0),
- _detune (0),
- _multiple (1),
- _keyScale (0),
- _specifiedTotalLevel (127),
- _specifiedAttackRate (0),
- _specifiedDecayRate (0),
- _specifiedSustainRate (0),
- _specifiedReleaseRate (15) {
- velocity(0);
-}
-
-Operator2612::~Operator2612()
-{ }
-
-void Operator2612::velocity(int velo) {
- _velocity = velo;
- _totalLevel = ((int32)_specifiedTotalLevel << 15) +
- ((int32)(127-_velocity) << 13);
- _sustainLevel = ((int32)_specifiedSustainLevel << 17);
-}
-
-void Operator2612::feedbackLevel(int level) {
- _feedbackLevel = level;
-}
-
-void Operator2612::setInstrument(byte const *instrument) {
- _detune = (instrument[8] >> 4) & 7;
- _multiple = instrument[8] & 15;
- _specifiedTotalLevel = instrument[12] & 127;
- _keyScale = (instrument[16] >> 6) & 3;
- _specifiedAttackRate = instrument[16] & 31;
- _specifiedDecayRate = instrument[20] & 31;
- _specifiedSustainRate = instrument[24] & 31;
- _specifiedSustainLevel = (instrument[28] >> 4) & 15;
- _specifiedReleaseRate = instrument[28] & 15;
- _state = _s_ready;
- velocity(_velocity);
-}
-
-void Operator2612::keyOn() {
- _state = _s_attacking;
- _tickCount = 0;
- _phase = 0;
- _currentLevel = ((int32)0x7f << 15);
-}
-
-void Operator2612::keyOff() {
- if (_state != _s_ready)
- _state = _s_releasing;
-}
-
-void Operator2612::frequency(int freq) {
- double value; // Use for intermediate computations to avoid int64 arithmetic
- int r;
-
- _frequency = freq / _owner->_rate;
-
- r = _specifiedAttackRate;
- if (r != 0) {
- r = r * 2 + (keyscaleTable[freq/262205] >> (3-_keyScale));
- if (r >= 64)
- r = 63;
- }
-
- r = 63 - r;
- if (_specifiedTotalLevel >= 128)
- value = 0;
- else {
- value = powtbl[(r&3) << 7];
- value *= 1 << (r >> 2);
- value *= 41;
- value /= 1 << (15 + 5);
- value *= 127 - _specifiedTotalLevel;
- value /= 127;
- }
- _attackTime = (int32) value; // 1 ?? == (1 << 12)
- if (_attackTime > 0)
- _attackTime = (1 << (12+10)) / (_owner->_rate * _attackTime);
-
- r = _specifiedDecayRate;
- if (r != 0) {
- r = r * 2 + (keyscaleTable[freq/262205] >> (3-_keyScale));
- if (r >= 64)
- r = 63;
- }
- value = (double) powtbl[(r&3) << 7] * (0x10 << (r>>2)) / 31;
- _decayRate = (int32) value / _owner->_rate;
-
- r = _specifiedSustainRate;
- if (r != 0) {
- r = r * 2 + (keyscaleTable[freq/262205] >> (3-_keyScale));
- if (r >= 64)
- r = 63;
- }
- value = (double) powtbl[(r&3) << 7] * (0x10 << (r>>2)) / 31;
- _sustainRate = (int32) value / _owner->_rate;
-
- r = _specifiedReleaseRate;
- if (r != 0) {
- r = r * 2 + 1; // (Translated) I cannot know whether the timing is a good choice or not
- r = r * 2 + (keyscaleTable[freq/262205] >> (3-_keyScale));
- // KS
- if (r >= 64)
- r = 63;
- }
- value = (double) powtbl[(r&3) << 7] * (0x10 << (r>>2)) / 31;
- _releaseRate = (int32) value / _owner->_rate;
-}
-
-void Operator2612::nextTick(const int *phasebuf, int *outbuf, int buflen) {
- if (_state == _s_ready)
- return;
- if (_state == _s_attacking && _attackTime <= 0) {
- _currentLevel = 0;
- _state = _s_decaying;
- }
-
- int32 levelIncrement = 0;
- int32 target = 0;
- State next_state = _s_ready;
- const int32 zero_level = ((int32)0x7f << 15);
- const int phaseIncrement = (_multiple > 0) ? (_frequency * _multiple) : (_frequency / 2);
-
- int32 output = _lastOutput;
- int32 level = _currentLevel + _totalLevel;
-
- while (buflen) {
- switch (_state) {
- case _s_ready:
- return;
- case _s_attacking:
- next_state = _s_attacking;
- break;
- case _s_decaying:
- levelIncrement = _decayRate;
- target = _sustainLevel + _totalLevel;
- next_state = _s_sustaining;
- break;
- case _s_sustaining:
- levelIncrement = _sustainRate;
- target = zero_level + _totalLevel;
- next_state = _s_ready;
- break;
- case _s_releasing:
- levelIncrement = _releaseRate;
- target = zero_level + _totalLevel;
- next_state = _s_ready;
- break;
- }
-
- bool switching = false;
- do {
- if (next_state == _s_attacking) {
- // Attack phase
- ++_tickCount;
- int i = (int) (_tickCount * _attackTime);
- if (i >= 1024) {
- level = _totalLevel;
- _state = _s_decaying;
- switching = true;
- } else {
- level = (attackOut[i] << (31 - 8 - 16)) + _totalLevel;
- }
- } else {
- // Decay, Sustain and Release phases
- level += levelIncrement;
- if (level >= target) {
- level = target;
- _state = next_state;
- switching = true;
- }
- }
-
- if (level < zero_level) {
- int phaseShift = *phasebuf >> 2;
- if (_feedbackLevel)
- phaseShift += (output << (_feedbackLevel - 1)) / 1024;
- output = sintbl[((_phase >> 7) + phaseShift) & 0x7ff];
- output >>= (level >> 18);
- // Here is the original code, which requires 64-bit ints
-// output *= powtbl[511 - ((level>>25)&511)];
-// output >>= 16;
-// output >>= 1;
- // And here's our 32-bit trick for doing it. (Props to Fingolfin!)
- // Result varies from original code by max of 1.
-// int powVal = powtbl[511 - ((level>>9)&511)];
-// int outputHI = output / 256;
-// int powHI = powVal / 256;
-// output = (outputHI * powHI) / 2 + (outputHI * (powVal % 256) + powHI * (output % 256)) / 512;
- // And here's the even faster code.
- // Result varies from original code by max of 8.
- output = ((output >> 4) * (powtbl[511-((level>>9)&511)] >> 3)) / 1024;
-
- _phase += phaseIncrement;
- _phase &= 0x3ffff;
- } else
- output = 0;
-
- *outbuf += output;
- --buflen;
- ++phasebuf;
- ++outbuf;
- } while (buflen && !switching);
- }
- _lastOutput = output;
- _currentLevel = level - _totalLevel;
-}
-
-////////////////////////////////////////
-//
-// Voice2612 implementation
-//
-////////////////////////////////////////
-
-Voice2612::Voice2612() {
- next = 0;
- _control7 = 127;
- _note = 40;
- _frequency = 440;
- _frequencyOffs = 0x2000;
- _algorithm = 7;
-
- _buffer = 0;
- _buflen = 0;
-
- int i;
- for (i = 0; i < ARRAYSIZE(_opr); ++i)
- _opr[i] = new Operator2612 (this);
- velocity(0);
-}
-
-Voice2612::~Voice2612() {
- int i;
- for (i = 0; i < ARRAYSIZE(_opr); ++i)
- delete _opr[i];
- free(_buffer);
-}
-
-void Voice2612::velocity(int velo) {
- _velocity = velo;
-#if 0
- int v = (velo * _control7) >> 7;
-#else
- int v = velo + (_control7 - 127) * 4;
-#endif
- bool iscarrier[8][4] = {
- { false, false, false, true, }, //0
- { false, false, false, true, }, //1
- { false, false, false, true, }, //2
- { false, false, false, true, }, //3
- { false, true, false, true, }, //4
- { false, true, true, true, }, //5
- { false, true, true, true, }, //6
- { true, true, true, true, }, //7
- };
- int opr;
- for (opr = 0; opr < 4; opr++)
- if (iscarrier[_algorithm][opr])
- _opr[opr]->velocity(v);
- else
- _opr[opr]->velocity(127);
-}
-
-void Voice2612::setControlParameter(int control, int value) {
- switch (control) {
- case 7:
- _control7 = value;
- velocity(_velocity);
- break;
- case 123:
- // All notes off
- noteOff(_note);
- };
-}
-
-void Voice2612::setInstrument(byte const *instrument) {
- if (instrument == NULL)
- return;
-
- _algorithm = instrument[32] & 7;
- _opr[0]->feedbackLevel((instrument[32] >> 3) & 7);
- _opr[1]->feedbackLevel(0);
- _opr[2]->feedbackLevel(0);
- _opr[3]->feedbackLevel(0);
- _opr[0]->setInstrument(instrument + 0);
- _opr[1]->setInstrument(instrument + 2);
- _opr[2]->setInstrument(instrument + 1);
- _opr[3]->setInstrument(instrument + 3);
-}
-
-void Voice2612::nextTick(int *outbuf, int buflen) {
- if (_velocity == 0)
- return;
-
- if (_buflen < buflen) {
- free(_buffer);
- _buflen = buflen;
- _buffer = (int *) malloc(sizeof(int) * buflen * 2);
- }
-
- int *buf1 = _buffer;
- int *buf2 = _buffer + buflen;
- memset(_buffer, 0, sizeof(int) * buflen * 2);
-
- switch (_algorithm) {
- case 0:
- _opr[0]->nextTick(buf1, buf2, buflen);
- _opr[1]->nextTick(buf2, buf1, buflen);
- memset (buf2, 0, sizeof (int) * buflen);
- _opr[2]->nextTick(buf1, buf2, buflen);
- _opr[3]->nextTick(buf2, outbuf, buflen);
- break;
- case 1:
- _opr[0]->nextTick(buf1, buf2, buflen);
- _opr[1]->nextTick(buf1, buf2, buflen);
- _opr[2]->nextTick(buf2, buf1, buflen);
- _opr[3]->nextTick(buf1, outbuf, buflen);
- break;
- case 2:
- _opr[1]->nextTick(buf1, buf2, buflen);
- _opr[2]->nextTick(buf2, buf1, buflen);
- memset(buf2, 0, sizeof(int) * buflen);
- _opr[0]->nextTick(buf2, buf1, buflen);
- _opr[3]->nextTick(buf1, outbuf, buflen);
- break;
- case 3:
- _opr[0]->nextTick(buf1, buf2, buflen);
- _opr[1]->nextTick(buf2, buf1, buflen);
- memset(buf2, 0, sizeof(int) * buflen);
- _opr[2]->nextTick(buf2, buf1, buflen);
- _opr[3]->nextTick(buf1, outbuf, buflen);
- break;
- case 4:
- _opr[0]->nextTick(buf1, buf2, buflen);
- _opr[1]->nextTick(buf2, outbuf, buflen);
- _opr[2]->nextTick(buf1, buf1, buflen);
- _opr[3]->nextTick(buf1, outbuf, buflen);
- break;
- case 5:
- _opr[0]->nextTick(buf1, buf2, buflen);
- _opr[1]->nextTick(buf2, outbuf, buflen);
- _opr[2]->nextTick(buf2, outbuf, buflen);
- _opr[3]->nextTick(buf2, outbuf, buflen);
- break;
- case 6:
- _opr[0]->nextTick(buf1, buf2, buflen);
- _opr[1]->nextTick(buf2, outbuf, buflen);
- _opr[2]->nextTick(buf1, outbuf, buflen);
- _opr[3]->nextTick(buf1, outbuf, buflen);
- break;
- case 7:
- _opr[0]->nextTick(buf1, outbuf, buflen);
- _opr[1]->nextTick(buf1, outbuf, buflen);
- _opr[2]->nextTick(buf1, outbuf, buflen);
- _opr[3]->nextTick(buf1, outbuf, buflen);
- break;
- };
-}
-
-void Voice2612::noteOn(int n, int onVelo) {
- _note = n;
- velocity(onVelo);
- recalculateFrequency();
- int i;
- for (i = 0; i < ARRAYSIZE(_opr); i++)
- _opr[i]->keyOn();
-}
-
-bool Voice2612::noteOff(int note) {
- if (_note != note)
- return false;
- int i;
- for (i = 0; i < ARRAYSIZE(_opr); i++)
- _opr[i]->keyOff();
- return true;
-}
-
-void Voice2612::pitchBend(int value) {
- _frequencyOffs = value;
- recalculateFrequency();
-}
-
-void Voice2612::recalculateFrequency() {
- //
- //
- //
- int32 basefreq = frequencyTable[_note];
- int cfreq = frequencyTable[_note - (_note % 12)];
- int oct = _note / 12;
- int fnum = (int) (((double)basefreq * (1 << 13)) / cfreq);
- fnum += _frequencyOffs - 0x2000;
- if (fnum < 0x2000) {
- fnum += 0x2000;
- oct--;
- }
- if (fnum >= 0x4000) {
- fnum -= 0x2000;
- oct++;
- }
-
- //
- _frequency = (int) ((frequencyTable[oct*12] * (double)fnum) / 8);
-
- int i;
- for (i = 0; i < ARRAYSIZE(_opr); i++)
- _opr[i]->frequency(_frequency);
-}
-
-////////////////////////////////////////
-//
-// MidiChannel_YM2612
-//
-////////////////////////////////////////
-
-MidiChannel_YM2612::MidiChannel_YM2612() {
- _voices = 0;
- _next_voice = 0;
-}
-
-MidiChannel_YM2612::~MidiChannel_YM2612() {
- removeAllVoices();
-}
-
-void MidiChannel_YM2612::removeAllVoices() {
- if (!_voices)
- return;
- Voice2612 *last, *voice = _voices;
- for (; voice; voice = last) {
- last = voice->next;
- delete voice;
- }
- _voices = _next_voice = 0;
-}
-
-void MidiChannel_YM2612::noteOn(byte note, byte onVelo) {
- if (!_voices)
- return;
- _next_voice = _next_voice ? _next_voice : _voices;
- _next_voice->noteOn(note, onVelo);
- _next_voice = _next_voice->next;
-}
-
-void MidiChannel_YM2612::noteOff(byte note) {
- if (!_voices)
- return;
- if (_next_voice == _voices)
- _next_voice = 0;
- Voice2612 *voice = _next_voice;
- do {
- if (!voice)
- voice = _voices;
- if (voice->noteOff(note)) {
- _next_voice = voice;
- break;
- }
- voice = voice->next;
- } while (voice != _next_voice);
-}
-
-void MidiChannel_YM2612::controlChange(byte control, byte value) {
- //
- if (control == 121) {
- // Reset controller
- removeAllVoices();
- } else {
- Voice2612 *voice = _voices;
- for (; voice; voice = voice->next)
- voice->setControlParameter(control, value);
- }
-}
-
-void MidiChannel_YM2612::sysEx_customInstrument(uint32 type, const byte *fmInst) {
- if (type != 'EUP ')
- return;
- Voice2612 *voice = new Voice2612;
- voice->next = _voices;
- _voices = voice;
- voice->_rate = _rate;
- voice->setInstrument(fmInst);
-}
-
-void MidiChannel_YM2612::pitchBend(int16 value) {
- //
- Voice2612 *voice = _voices;
- for (; voice; voice = voice->next)
- voice->pitchBend(value);
-}
-
-void MidiChannel_YM2612::nextTick(int *outbuf, int buflen) {
- Voice2612 *voice = _voices;
- for (; voice; voice = voice->next)
- voice->nextTick(outbuf, buflen);
-}
-
-void MidiChannel_YM2612::rate(uint16 r) {
- _rate = r;
- Voice2612 *voice = _voices;
- for (; voice; voice = voice->next)
- voice->_rate = r;
-}
-
-////////////////////////////////////////
-//
-// MidiDriver_YM2612
-//
-////////////////////////////////////////
-
-MidiDriver_YM2612::MidiDriver_YM2612(Audio::Mixer *mixer)
- : MidiDriver_Emulated(mixer) {
- _next_voice = 0;
-
- createLookupTables();
- _volume = 256;
- int i;
- for (i = 0; i < ARRAYSIZE(_channel); i++)
- _channel[i] = new MidiChannel_YM2612;
- rate(getRate());
-}
-
-MidiDriver_YM2612::~MidiDriver_YM2612() {
- int i;
- for (i = 0; i < ARRAYSIZE(_channel); i++)
- delete _channel[i];
- removeLookupTables();
-}
-
-int MidiDriver_YM2612::open() {
- if (_isOpen)
- return MERR_ALREADY_OPEN;
-
- MidiDriver_Emulated::open();
-
- _mixer->playStream(Audio::Mixer::kPlainSoundType, &_mixerSoundHandle, this, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO, true);
- return 0;
-}
-
-void MidiDriver_YM2612::close() {
- if (!_isOpen)
- return;
- _isOpen = false;
-
- _mixer->stopHandle(_mixerSoundHandle);
-}
-
-void MidiDriver_YM2612::send(uint32 b) {
- send(b & 0xF, b & 0xFFFFFFF0);
-}
-
-void MidiDriver_YM2612::send(byte chan, uint32 b) {
- //byte param3 = (byte) ((b >> 24) & 0xFF);
- byte param2 = (byte) ((b >> 16) & 0xFF);
- byte param1 = (byte) ((b >> 8) & 0xFF);
- byte cmd = (byte) (b & 0xF0);
- if (chan > ARRAYSIZE(_channel))
- return;
-
- switch (cmd) {
- case 0x80:// Note Off
- _channel[chan]->noteOff(param1);
- break;
- case 0x90: // Note On
- _channel[chan]->noteOn(param1, param2);
- break;
- case 0xA0: // Aftertouch
- break; // Not supported.
- case 0xB0: // Control Change
- _channel[chan]->controlChange(param1, param2);
- break;
- case 0xC0: // Program Change
- _channel[chan]->programChange(param1);
- break;
- case 0xD0: // Channel Pressure
- break; // Not supported.
- case 0xE0: // Pitch Bend
- _channel[chan]->pitchBend((param1 | (param2 << 7)) - 0x2000);
- break;
- case 0xF0: // SysEx
- // We should never get here! SysEx information has to be
- // sent via high-level semantic methods.
- warning("MidiDriver_YM2612: Receiving SysEx command on a send() call");
- break;
-
- default:
- warning("MidiDriver_YM2612: Unknown send() command 0x%02X", cmd);
- }
-}
-
-void MidiDriver_YM2612::sysEx(const byte *msg, uint16 length) {
- if (msg[0] != 0x7C || msg[1] >= ARRAYSIZE(_channel))
- return;
- _channel[msg[1]]->sysEx_customInstrument('EUP ', &msg[2]);
-}
-
-void MidiDriver_YM2612::generateSamples(int16 *data, int len) {
- memset(data, 0, 2 * sizeof(int16) * len);
- nextTick(data, len);
-}
-
-void MidiDriver_YM2612::nextTick(int16 *buf1, int buflen) {
- int *buf0 = (int *)buf1;
-
- int i;
- for (i = 0; i < ARRAYSIZE(_channel); i++)
- _channel[i]->nextTick(buf0, buflen);
-
- for (i = 0; i < buflen; ++i)
- buf1[i*2+1] = buf1[i*2] = ((buf0[i] * volume()) >> 10) & 0xffff;
-}
-
-void MidiDriver_YM2612::rate(uint16 r)
-{
- int i;
- for (i = 0; i < ARRAYSIZE(_channel); i++)
- _channel[i]->rate(r);
-}
-
-void MidiDriver_YM2612::createLookupTables() {
- {
- int i;
- sintbl = new int [2048];
- for (i = 0; i < 2048; i++)
- sintbl[i] = (int)(0xffff * sin(i/2048.0*2.0*PI));
- }
-
- {
- int i;
- powtbl = new int [1025];
- for (i = 0; i <= 1024; i++)
- powtbl[i] = (int)(0x10000 * pow(2.0, (i-512)/512.0));
- }
-
- {
- int i;
- int block;
-
- static int fnum[] = {
- 0x026a, 0x028f, 0x02b6, 0x02df,
- 0x030b, 0x0339, 0x036a, 0x039e,
- 0x03d5, 0x0410, 0x044e, 0x048f,
- };
-
- // (int)(880.0 * 256.0 * pow(2.0, (note-0x51)/12.0))
- //
- frequencyTable = new int [120];
- for (block = -1; block < 9; block++) {
- for (i = 0; i < 12; i++) {
- double freq = fnum[i] * (166400.0 / 3) * pow(2.0, block-21);
- frequencyTable[(block+1)*12+i] = (int)(256.0 * freq);
- }
- }
-
- keycodeTable = new int [120];
- // detune
- for (block = -1; block < 9; block++) {
- for (i = 0; i < 12; i++) {
- // see p.204
- int f8 = (fnum[i] >> 7) & 1;
- int f9 = (fnum[i] >> 8) & 1;
- int f10 = (fnum[i] >> 9) & 1;
- int f11 = (fnum[i] >> 10) & 1;
- int n4 = f11;
- int n3 = (f11&(f10|f9|f8)) | (~f11&f10&f9&f8);
- int note = n4*2 + n3;
- // see p.207
- keycodeTable[(block+1)*12+i] = block*4 + note;
- }
- }
- }
-
- {
- int freq;
- keyscaleTable = new int [8192];
- keyscaleTable[0] = 0;
- for (freq = 1; freq < 8192; freq++) {
- keyscaleTable[freq] = (int)(log((double)freq) / 9.03 * 32.0) - 1;
- // 8368[Hz] (o9c)
- }
- }
-
- {
- int i;
- attackOut = new int [1024];
- for (i = 0; i < 1024; i++)
- attackOut[i] = (int)(((0x7fff+0x03a5)*30.0) / (30.0+i)) - 0x03a5;
- }
-}
-
-void MidiDriver_YM2612::removeLookupTables() {
- delete[] sintbl;
- delete[] powtbl;
- delete[] frequencyTable;
- delete[] keycodeTable;
- delete[] keyscaleTable;
- delete[] attackOut;
- sintbl = powtbl = frequencyTable = keycodeTable = keyscaleTable = attackOut = 0;
-}
-
-
-// Plugin interface
-
-class TownsEmuMusicPlugin : public MusicPluginObject {
-public:
- const char *getName() const {
- return _s("FM Towns Emulator");
- }
-
- const char *getId() const {
- return "towns";
- }
-
- MusicDevices getDevices() const;
- Common::Error createInstance(MidiDriver **mididriver, MidiDriver::DeviceHandle = 0) const;
-};
-
-MusicDevices TownsEmuMusicPlugin::getDevices() const {
- MusicDevices devices;
- devices.push_back(MusicDevice(this, "", MT_TOWNS));
- return devices;
-}
-
-Common::Error TownsEmuMusicPlugin::createInstance(MidiDriver **mididriver, MidiDriver::DeviceHandle) const {
- *mididriver = new MidiDriver_YM2612(g_system->getMixer());
-
- return Common::kNoError;
-}
-
-//#if PLUGIN_ENABLED_DYNAMIC(TOWNS)
- //REGISTER_PLUGIN_DYNAMIC(TOWNS, PLUGIN_TYPE_MUSIC, TownsEmuMusicPlugin);
-//#else
- REGISTER_PLUGIN_STATIC(TOWNS, PLUGIN_TYPE_MUSIC, TownsEmuMusicPlugin);
-//#endif
diff --git a/sound/softsynth/ym2612.h b/sound/softsynth/ym2612.h
deleted file mode 100644
index 5fb2f32ef0..0000000000
--- a/sound/softsynth/ym2612.h
+++ /dev/null
@@ -1,179 +0,0 @@
-/* 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_Y2612_H
-#define SOUND_SOFTSYNTH_Y2612_H
-
-#include "common/scummsys.h"
-
-#include "sound/softsynth/emumidi.h"
-
-////////////////////////////////////////
-//
-// Class declarations
-//
-////////////////////////////////////////
-
-class Voice2612;
-class Operator2612 {
-protected:
- Voice2612 *_owner;
- enum State { _s_ready, _s_attacking, _s_decaying, _s_sustaining, _s_releasing };
- State _state;
- int32 _currentLevel;
- int _frequency;
- uint32 _phase;
- int _lastOutput;
- int _feedbackLevel;
- int _detune;
- int _multiple;
- int32 _totalLevel;
- int _keyScale;
- int _velocity;
- int _specifiedTotalLevel;
- int _specifiedAttackRate;
- int _specifiedDecayRate;
- int _specifiedSustainLevel;
- int _specifiedSustainRate;
- int _specifiedReleaseRate;
- int _tickCount;
- int _attackTime;
- int32 _decayRate;
- int32 _sustainLevel;
- int32 _sustainRate;
- int32 _releaseRate;
-
-public:
- Operator2612 (Voice2612 *owner);
- ~Operator2612();
- void feedbackLevel(int level);
- void setInstrument(byte const *instrument);
- void velocity(int velo);
- void keyOn();
- void keyOff();
- void frequency(int freq);
- void nextTick(const int *phaseShift, int *outbuf, int buflen);
- bool inUse() { return (_state != _s_ready); }
-};
-
-class Voice2612 {
-public:
- Voice2612 *next;
- uint16 _rate;
-
-protected:
- Operator2612 *_opr[4];
- int _velocity;
- int _control7;
- int _note;
- int _frequencyOffs;
- int _frequency;
- int _algorithm;
-
- int *_buffer;
- int _buflen;
-
-public:
- Voice2612();
- ~Voice2612();
- void setControlParameter(int control, int value);
- void setInstrument(byte const *instrument);
- void velocity(int velo);
- void nextTick(int *outbuf, int buflen);
- void noteOn(int n, int onVelo);
- bool noteOff(int note);
- void pitchBend(int value);
- void recalculateFrequency();
-};
-
-class MidiChannel_YM2612 : public MidiChannel {
-protected:
- uint16 _rate;
- Voice2612 *_voices;
- Voice2612 *_next_voice;
-
-public:
- void removeAllVoices();
- void nextTick(int *outbuf, int buflen);
- void rate(uint16 r);
-
-public:
- MidiChannel_YM2612();
- virtual ~MidiChannel_YM2612();
-
- // MidiChannel interface
- MidiDriver *device() { return 0; }
- byte getNumber() { return 0; }
- void release() { }
- void send(uint32 b) { }
- void noteOff(byte note);
- void noteOn(byte note, byte onVelo);
- void programChange(byte program) { }
- void pitchBend(int16 value);
- void controlChange(byte control, byte value);
- void pitchBendFactor(byte value) { }
- void sysEx_customInstrument(uint32 type, const byte *instr);
-};
-
-class MidiDriver_YM2612 : public MidiDriver_Emulated {
-protected:
- MidiChannel_YM2612 *_channel[16];
-
- int _next_voice;
- int _volume;
-
-protected:
- void nextTick(int16 *buf1, int buflen);
- int volume(int val = -1) { if (val >= 0) _volume = val; return _volume; }
- void rate(uint16 r);
-
- void generateSamples(int16 *buf, int len);
-
-public:
- MidiDriver_YM2612(Audio::Mixer *mixer);
- virtual ~MidiDriver_YM2612();
-
- static void createLookupTables();
- static void removeLookupTables();
-
- int open();
- void close();
- void send(uint32 b);
- void send(byte channel, uint32 b); // Supports higher than channel 15
- uint32 property(int prop, uint32 param) { return 0; }
-
- void setPitchBendRange(byte channel, uint range) { }
- void sysEx(const byte *msg, uint16 length);
-
- MidiChannel *allocateChannel() { return 0; }
- MidiChannel *getPercussionChannel() { return 0; }
-
-
- // AudioStream API
- bool isStereo() const { return true; }
- int getRate() const { return _mixer->getOutputRate(); }
-};
-
-#endif
-
diff --git a/sound/timestamp.cpp b/sound/timestamp.cpp
deleted file mode 100644
index 1e49e1b476..0000000000
--- a/sound/timestamp.cpp
+++ /dev/null
@@ -1,212 +0,0 @@
-/* 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/timestamp.h"
-#include "common/algorithm.h"
-
-namespace Audio {
-
-Timestamp::Timestamp(uint ms, uint fr) {
- assert(fr > 0);
-
- _secs = ms / 1000;
- _framerateFactor = 1000 / Common::gcd<uint>(1000, fr);
- _framerate = fr * _framerateFactor;
-
- // Note that _framerate is always divisible by 1000.
- _numFrames = (ms % 1000) * (_framerate / 1000);
-}
-
-Timestamp::Timestamp(uint s, uint frames, uint fr) {
- assert(fr > 0);
-
- _secs = s;
- _framerateFactor = 1000 / Common::gcd<uint>(1000, fr);
- _framerate = fr * _framerateFactor;
- _numFrames = frames * _framerateFactor;
-
- normalize();
-}
-
-Timestamp Timestamp::convertToFramerate(uint newFramerate) const {
- Timestamp ts(*this);
-
- if (ts.framerate() != newFramerate) {
- ts._framerateFactor = 1000 / Common::gcd<uint>(1000, newFramerate);
- ts._framerate = newFramerate * ts._framerateFactor;
-
- const uint g = Common::gcd(_framerate, ts._framerate);
- const uint p = _framerate / g;
- const uint q = ts._framerate / g;
-
- // Convert the frame offset to the new framerate.
- // We round to the nearest (as opposed to always
- // rounding down), to minimize rounding errors during
- // round trip conversions.
- ts._numFrames = (ts._numFrames * q + p/2) / p;
-
- ts.normalize();
- }
-
- return ts;
-}
-
-void Timestamp::normalize() {
- // Convert negative _numFrames values to positive ones by adjusting _secs
- if (_numFrames < 0) {
- int secsub = 1 + (-_numFrames / _framerate);
-
- _numFrames += _framerate * secsub;
- _secs -= secsub;
- }
-
- // Wrap around if necessary
- _secs += (_numFrames / _framerate);
- _numFrames %= _framerate;
-}
-
-bool Timestamp::operator==(const Timestamp &ts) const {
- return cmp(ts) == 0;
-}
-
-bool Timestamp::operator!=(const Timestamp &ts) const {
- return cmp(ts) != 0;
-}
-
-bool Timestamp::operator<(const Timestamp &ts) const {
- return cmp(ts) < 0;
-}
-
-bool Timestamp::operator<=(const Timestamp &ts) const {
- return cmp(ts) <= 0;
-}
-
-bool Timestamp::operator>(const Timestamp &ts) const {
- return cmp(ts) > 0;
-}
-
-bool Timestamp::operator>=(const Timestamp &ts) const {
- return cmp(ts) >= 0;
-}
-
-int Timestamp::cmp(const Timestamp &ts) const {
- int delta = _secs - ts._secs;
- if (!delta) {
- const uint g = Common::gcd(_framerate, ts._framerate);
- const uint p = _framerate / g;
- const uint q = ts._framerate / g;
-
- delta = (_numFrames * q - ts._numFrames * p);
- }
-
- return delta;
-}
-
-
-Timestamp Timestamp::addFrames(int frames) const {
- Timestamp ts(*this);
-
- // The frames are given in the original framerate, so we have to
- // adjust by _framerateFactor accordingly.
- ts._numFrames += frames * _framerateFactor;
- ts.normalize();
-
- return ts;
-}
-
-Timestamp Timestamp::addMsecs(int ms) const {
- Timestamp ts(*this);
- ts._secs += ms / 1000;
- // Add the remaining frames. Note that _framerate is always divisible by 1000.
- ts._numFrames += (ms % 1000) * (ts._framerate / 1000);
-
- ts.normalize();
-
- return ts;
-}
-
-void Timestamp::addIntern(const Timestamp &ts) {
- assert(_framerate == ts._framerate);
- _secs += ts._secs;
- _numFrames += ts._numFrames;
-
- normalize();
-}
-
-Timestamp Timestamp::operator-() const {
- Timestamp result(*this);
- result._secs = -_secs;
- result._numFrames = -_numFrames;
- result.normalize();
- return result;
-}
-
-Timestamp Timestamp::operator+(const Timestamp &ts) const {
- Timestamp result(*this);
- result.addIntern(ts);
- return result;
-}
-
-Timestamp Timestamp::operator-(const Timestamp &ts) const {
- Timestamp result(*this);
- result.addIntern(-ts);
- return result;
-}
-
-int Timestamp::frameDiff(const Timestamp &ts) const {
-
- int delta = 0;
- if (_secs != ts._secs)
- delta = (_secs - ts._secs) * _framerate;
-
- delta += _numFrames;
-
- if (_framerate == ts._framerate) {
- delta -= ts._numFrames;
- } else {
- // We need to multiply by the quotient of the two framerates.
- // We cancel the GCD in this fraction to reduce the risk of
- // overflows.
- const uint g = Common::gcd(_framerate, ts._framerate);
- const uint p = _framerate / g;
- const uint q = ts._framerate / g;
-
- delta -= ((long)ts._numFrames * p + q/2) / (long)q;
- }
-
- return delta / (int)_framerateFactor;
-}
-
-int Timestamp::msecsDiff(const Timestamp &ts) const {
- return msecs() - ts.msecs();
-}
-
-int Timestamp::msecs() const {
- // Note that _framerate is always divisible by 1000.
- return _secs * 1000 + _numFrames / (_framerate / 1000);
-}
-
-
-} // End of namespace Audio
diff --git a/sound/timestamp.h b/sound/timestamp.h
deleted file mode 100644
index 4130793fc8..0000000000
--- a/sound/timestamp.h
+++ /dev/null
@@ -1,251 +0,0 @@
-/* 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_TIMESTAMP_H
-#define SOUND_TIMESTAMP_H
-
-#include "common/scummsys.h"
-
-namespace Audio {
-
-/**
- * Timestamps allow specifying points in time and measuring time intervals
- * with a sub-millisecond granularity.
- *
- * When dealing with audio and video decoding, it is often necessary to
- * measure time (intervals) in terms of frames, relative to a fixed
- * frame rate (that is, a fixed number of frames per seconds). For
- * example, in a typical video there are 24 frames per second, and in a
- * typical sound there are 44100 frames (i.e. samples for mono sound
- * and pairs of samples for stereo) per second.
- *
- * At the same time, the system clock provided by ScummVM measures time
- * in milliseconds. For syncing purposes and other reasons, it is often
- * necessary to convert between and compare time measures given on the
- * one hand as a frame count, and on the other hand as a number of
- * milliseconds.
- *
- * If handled carelessly, this can introduce rounding errors that
- * quickly accumulate, resulting in user noticeable disturbance, such as
- * audio and video running out of sync. E.g. a typical approach is to
- * measure all time in milliseconds. But with a frame rate of 24 frames
- * per second, one frame is 41.66666... milliseconds long. On the other
- * hand, if measuring in frames, then similar rounding issue occur when
- * converting from milliseconds to frames.
- *
- * One solution is to use floating point arithmetic to compute with
- * fractional frames resp. (milli)seconds. This has other undesirable
- * side effects; foremost, some platforms ScummVM runs on still have
- * only limited (and slow) floating point support.
- *
- * This class provides an alternate solution: It stores time in terms of
- * frames, but with a twist: Client code can specify arbitrary
- * (integral) framerates; but internally, Timestamp modifies the
- * framerate to be a multiple of 1000. This way, both numbers of frames
- * (relative to the original framerate) as well as milliseconds can be
- * represented as integers. This change is completely hidden from the
- * user, however.
- *
- * A Timestamp can be converted to a frame count or milliseconds at
- * virtually no cost. Likewise, it is posible to compute the difference
- * between two Timestamps in milliseconds or number of frames.
- * Timestamps can be easily compared using regular comparison operators,
- * resulting in nicely readable code; this is even possible for
- * timestamps that are specified using different framerates.
- * Client code can modify Timestamps by adding a number of frames
- * to it, or adding a number of milliseconds. Adding negative amounts is
- * also allowed, and a Timestamp can even represent a "negative time"
- * (mainly useful when using the Timestamp to store a time interval).
- */
-class Timestamp {
-public:
- /**
- * Set up a timestamp with a given time and framerate.
- * @param msecs starting time in milliseconds
- * @param framerate number of frames per second (must be > 0)
- */
- Timestamp(uint msecs = 0, uint framerate = 1);
-
- /**
- * Set up a timestamp with a given time, frames and framerate.
- * @param secs starting time in seconds
- * @param frames starting frames
- * @param framerate number of frames per second (must be > 0)
- */
- Timestamp(uint secs, uint frames, uint framerate);
-
- /**
- * Return a timestamp which represents as closely as possible
- * the point in time describes by this timestamp, but with
- * a different framerate.
- */
- Timestamp convertToFramerate(uint newFramerate) const;
-
- /**
- * Check whether to timestamps describe the exact same moment
- * in time. This means that two timestamps can compare
- * as equal even if they use different framerates.
- */
- bool operator==(const Timestamp &ts) const;
- bool operator!=(const Timestamp &ts) const;
- bool operator<(const Timestamp &ts) const;
- bool operator<=(const Timestamp &ts) const;
- bool operator>(const Timestamp &ts) const;
- bool operator>=(const Timestamp &ts) const;
-
- /**
- * Returns a new timestamp, which corresponds to the time encoded
- * by this timestamp with the given number of frames added.
- * @param frames number of frames to add
- */
- Timestamp addFrames(int frames) const;
-
- /**
- * Returns a new timestamp, which corresponds to the time encoded
- * by this timestamp with the given number of milliseconds added.
- * @param msecs number of milliseconds to add
- */
- Timestamp addMsecs(int msecs) const;
-
-
- // unary minus
- Timestamp operator-() const;
-
- /**
- * Compute the sum of two timestamps. This is only
- * allowed if they use the same framerate.
- */
- Timestamp operator+(const Timestamp &ts) const;
-
- /**
- * Compute the difference between two timestamps. This is only
- * allowed if they use the same framerate.
- */
- Timestamp operator-(const Timestamp &ts) const;
-
- /**
- * Computes the number of frames between this timestamp and ts.
- * The frames are with respect to the framerate used by this
- * Timestamp (which may differ from the framerate used by ts).
- */
- int frameDiff(const Timestamp &ts) const;
-
- /** Computes the number off milliseconds between this timestamp and ts. */
- int msecsDiff(const Timestamp &ts) const;
-
- /**
- * Return the time in milliseconds described by this timestamp,
- * rounded down.
- */
- int msecs() const;
-
- /**
- * Return the time in seconds described by this timestamp,
- * rounded down.
- */
- inline int secs() const {
- return _secs;
- }
-
- /**
- * Return the time in frames described by this timestamp.
- */
- inline int totalNumberOfFrames() const {
- return _numFrames / (int)_framerateFactor + _secs * (int)(_framerate / _framerateFactor);
- }
-
- /**
- * A timestamp consists of a number of seconds, plus a number
- * of frames, the latter describing a fraction of a second.
- * This method returns the latter number.
- */
- inline int numberOfFrames() const {
- return _numFrames / (int)_framerateFactor;
- }
-
- /** Return the framerate used by this timestamp. */
- inline uint framerate() const { return _framerate / _framerateFactor; }
-
-protected:
- /**
- * Compare this timestamp to another one and return
- * a value similar to strcmp.
- */
- int cmp(const Timestamp &ts) const;
-
- /**
- * Normalize this timestamp by making _numFrames non-negative
- * and reducing it modulo _framerate.
- */
- void normalize();
-
- /**
- * Add another timestamp to this one and normalize the result.
- */
- void addIntern(const Timestamp &ts);
-
-protected:
- /**
- * The seconds part of this timestamp.
- * The total time in seconds represented by this timestamp can be
- * computed as follows:
- * _secs + (double)_numFrames / _framerate
- */
- int _secs;
-
- /**
- * The number of frames which together with _secs encodes the
- * timestamp. The total number of *internal* frames represented
- * by this timestamp can be computed as follows:
- * _numFrames + _secs * _framerate
- * To obtain the number of frames with respect to the original
- * framerate, this value has to be divided by _framerateFactor.
- *
- * This is always a value greater or equal to zero.
- * The only reason this is an int and not an uint is to
- * allow intermediate negative values.
- */
- int _numFrames;
-
- /**
- * The internal framerate, i.e. the number of frames per second.
- * This is computed as the least common multiple of the framerate
- * specified by the client code, and 1000.
- * This way, we ensure that we can store both frames and
- * milliseconds without any rounding losses.
- */
- uint _framerate;
-
- /**
- * Factor by which the original framerate specified by the client
- * code was multipled to obtain the internal _framerate value.
- */
- uint _framerateFactor;
-};
-
-
-} // End of namespace Audio
-
-#endif