aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--audio/midiparser.cpp2
-rw-r--r--audio/midiplayer.cpp63
-rw-r--r--audio/midiplayer.h75
-rw-r--r--audio/module.mk1
-rw-r--r--audio/softsynth/eas.cpp420
-rw-r--r--backends/events/gph/gph-events.cpp6
-rw-r--r--backends/events/gph/gph-events.h19
-rw-r--r--backends/platform/android/texture.cpp11
-rw-r--r--base/plugins.cpp3
-rw-r--r--engines/agi/sound_midi.cpp37
-rw-r--r--engines/agi/sound_midi.h13
-rw-r--r--engines/draci/music.cpp42
-rw-r--r--engines/draci/music.h9
-rw-r--r--engines/hugo/sound.cpp87
-rw-r--r--engines/hugo/sound.h10
-rw-r--r--engines/m4/midi.cpp55
-rw-r--r--engines/m4/midi.h5
-rw-r--r--engines/made/music.cpp43
-rw-r--r--engines/made/music.h7
-rw-r--r--engines/parallaction/parallaction_br.cpp4
-rw-r--r--engines/parallaction/parallaction_ns.cpp4
-rw-r--r--engines/parallaction/sound.h4
-rw-r--r--engines/parallaction/sound_br.cpp73
-rw-r--r--engines/parallaction/sound_ns.cpp69
-rw-r--r--engines/sci/console.cpp4
-rw-r--r--engines/sci/debug.h12
-rw-r--r--engines/sci/engine/vm.cpp296
-rw-r--r--engines/sci/engine/workarounds.cpp2
-rw-r--r--engines/sci/graphics/frameout.cpp3
-rw-r--r--engines/sci/graphics/screen.cpp2
-rw-r--r--engines/sword25/gfx/image/pngloader.cpp2
-rw-r--r--engines/sword25/gfx/image/renderedimage.cpp18
-rw-r--r--engines/sword25/gfx/image/renderedimage.h24
-rw-r--r--engines/sword25/gfx/image/swimage.cpp8
-rw-r--r--engines/sword25/gfx/image/vectorimage.cpp102
-rw-r--r--engines/tinsel/music.cpp38
-rw-r--r--engines/tinsel/music.h7
-rw-r--r--engines/tinsel/tinsel.cpp2
-rw-r--r--engines/tinsel/tinsel.h3
-rw-r--r--engines/touche/midi.cpp115
-rw-r--r--engines/touche/midi.h32
-rw-r--r--engines/touche/staticres.cpp11
42 files changed, 923 insertions, 820 deletions
diff --git a/audio/midiparser.cpp b/audio/midiparser.cpp
index e01b8a7fc6..a6df6024cd 100644
--- a/audio/midiparser.cpp
+++ b/audio/midiparser.cpp
@@ -350,7 +350,7 @@ void MidiParser::hangAllActiveNotes() {
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());
+ 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");
diff --git a/audio/midiplayer.cpp b/audio/midiplayer.cpp
index 12d03d73f8..1e39b999f9 100644
--- a/audio/midiplayer.cpp
+++ b/audio/midiplayer.cpp
@@ -33,6 +33,7 @@ namespace Audio {
MidiPlayer::MidiPlayer() :
_driver(0),
_parser(0),
+ _midiData(0),
_isLooping(false),
_isPlaying(false),
_masterVolume(0),
@@ -45,19 +46,29 @@ MidiPlayer::MidiPlayer() :
}
MidiPlayer::~MidiPlayer() {
-// TODO
+ // FIXME/TODO: In some engines, stop() was called first;
+ // in others, _driver->setTimerCallback(NULL, NULL) came first.
+ // Hopefully, this make no real difference, but we should
+ // watch out for regressions.
+ stop();
+
+ // Unhook & unload the driver
+ if (_driver) {
+ _driver->setTimerCallback(0, 0);
+ _driver->close();
+ delete _driver;
+ _driver = 0;
+ }
}
void MidiPlayer::setVolume(int volume) {
volume = CLIP(volume, 0, 255);
-
if (_masterVolume == volume)
return;
Common::StackLock lock(_mutex);
_masterVolume = volume;
-
for (int i = 0; i < kNumChannels; ++i) {
if (_channelsTable[i]) {
_channelsTable[i]->volume(_channelsVolume[i] * _masterVolume / 255);
@@ -75,32 +86,33 @@ void MidiPlayer::syncVolume() {
void MidiPlayer::send(uint32 b) {
- byte channel = (byte)(b & 0x0F);
+ byte ch = (byte)(b & 0x0F);
if ((b & 0xFFF0) == 0x07B0) {
// Adjust volume changes by master volume
byte volume = (byte)((b >> 16) & 0x7F);
- _channelsVolume[channel] = volume;
+ _channelsVolume[ch] = volume;
volume = volume * _masterVolume / 255;
b = (b & 0xFF00FFFF) | (volume << 16);
} else if ((b & 0xFFF0) == 0x007BB0) {
// Only respond to All Notes Off if this channel
// has currently been allocated
- if (!_channelsTable[channel])
+ if (!_channelsTable[ch])
return;
}
- sendToChannel(channel, b);
+ sendToChannel(ch, b);
}
-void MidiPlayer::sendToChannel(byte channel, uint32 b) {
- if (!_channelsTable[channel]) {
- _channelsTable[channel] = (channel == 9) ? _driver->getPercussionChannel() : _driver->allocateChannel();
+void MidiPlayer::sendToChannel(byte ch, uint32 b) {
+ if (!_channelsTable[ch]) {
+ _channelsTable[ch] = (ch == 9) ? _driver->getPercussionChannel() : _driver->allocateChannel();
// TODO: Some engines overload this method to insert code at this
// point which calls the channel's volume() method.
// Does this make sense, and should we maybe do it in general?
}
- if (_channelsTable[channel])
- _channelsTable[channel]->send(b);
+ if (_channelsTable[ch]) {
+ _channelsTable[ch]->send(b);
+ }
}
void MidiPlayer::metaEvent(byte type, byte *data, uint16 length) {
@@ -122,8 +134,7 @@ void MidiPlayer::endOfTrack() {
stop();
}
-#if 0
-void MidiPlayer::onTimer(void *data) {
+void MidiPlayer::timerCallback(void *data) {
assert(data);
((MidiPlayer *)data)->onTimer();
}
@@ -131,20 +142,13 @@ void MidiPlayer::onTimer(void *data) {
void MidiPlayer::onTimer() {
Common::StackLock lock(_mutex);
- // FIXME: There are various alternatives for this function:
+ // TODO: Maybe we can replace _isPlaying
+ // by a simple check for "_parser != 0" ?
-#if 0
- if (_parser) {
+ if (_isPlaying && _parser) {
_parser->onTimer();
}
-#elif 0
- if (_isPlaying) {
- assert(_parser);
- _parser->onTimer();
- }
-#endif
}
-#endif
void MidiPlayer::stop() {
@@ -153,8 +157,19 @@ void MidiPlayer::stop() {
_isPlaying = false;
if (_parser) {
_parser->unloadMusic();
+
+ // FIXME/TODO: The MidiParser destructor calls allNotesOff()
+ // but unloadMusic also does. To suppress double notes-off,
+ // we reset the midi driver of _parser before deleting it.
+ // This smells very fishy, in any case.
+ _parser->setMidiDriver(0);
+
+ delete _parser;
_parser = NULL;
}
+
+ free(_midiData);
+ _midiData = 0;
}
void MidiPlayer::pause() {
diff --git a/audio/midiplayer.h b/audio/midiplayer.h
index fd60d0bc07..1bb7942343 100644
--- a/audio/midiplayer.h
+++ b/audio/midiplayer.h
@@ -47,11 +47,10 @@ namespace Audio {
* should perform memory management on the MidiParser object(s) being
* used, and possibly more.
*
- * Also, care should be taken to ensure that mutex locking is done right;
- * currently, it isn't: That is, many engines have (and already had before
- * this class was introduced) various potential deadlocks hiding in their
- * MIDI code, caused by a thread trying to lock a mutex twice -- this may
- * work on some systems, but on others is a sure way towards a deadlock.
+ * Also, pause/resume handling should be unified (we provide an implementation,
+ * but several subclasses use different ones).
+ *
+ * Also, care should be taken to ensure that mutex locking is done right.
*
* @todo Document origin of this class. It is based on code shared by
* several engines (e.g. DRACI says it copied it from MADE, which took
@@ -64,6 +63,7 @@ public:
// TODO: Implement ways to actually play stuff
//virtual void play(TODO);
+
// TODO: Document these
virtual void stop();
virtual void pause();
@@ -71,21 +71,44 @@ public:
bool isPlaying() const { return _isPlaying; }
+ /**
+ * Return the currently active master volume, in the range 0-255.
+ */
int getVolume() const { return _masterVolume; }
- virtual void setVolume(int volume); // FIXME: Overloaded by Tinsel
+
+ /**
+ * Set the master volume to the specified value in the range 0-255.
+ * (values outside this range are automatically clipped).
+ * This may cause suitable MIDI events to be sent to active channels.
+ *
+ * @todo This method currently does not do anything if the new volume
+ * matches the old volume. But some engines always update the
+ * volume (Parallaction, Tinsel, Touche, ...). This is why
+ * this method is currently virtual. We really should figure
+ * which way to do it, and then make this the default, and make
+ * this method non-virtual again.
+ */
+ virtual void setVolume(int volume);
+
+ /**
+ * Update the volume according to the ConfMan's 'music_volume'
+ * setting. also respects the 'mute' setting.
+ */
void syncVolume();
+ // TODO: Document this
bool hasNativeMT32() const { return _nativeMT32; }
- // MidiDriver_BASE interface
+ // MidiDriver_BASE implementation
virtual void send(uint32 b);
virtual void metaEvent(byte type, byte *data, uint16 length);
+protected:
/**
- * This method is invoked by send() after suitably filtering
- * the message b.
+ * This method is invoked by the default send() implementation,
+ * after suitably filtering the message b.
*/
- virtual void sendToChannel(byte channel, uint32 b);
+ virtual void sendToChannel(byte ch, uint32 b);
/**
* This method is invoked by metaEvent when an end-of-track
@@ -96,28 +119,46 @@ public:
*/
virtual void endOfTrack();
-protected:
-
-#if 0
- // TODO: Start to make use of these, once we figured
- // out the right way :)
- static void onTimer(void *data);
+ // TODO: Document this
virtual void onTimer();
-#endif
+
+ static void timerCallback(void *data);
enum {
+ /**
+ * The number of MIDI channels supported.
+ */
kNumChannels = 16
};
Common::Mutex _mutex;
MidiDriver *_driver;
+
+ /**
+ * A MidiParser instances, to be created by methods of a MidiPlayer
+ * subclass.
+ * @note The stop() method (and hence the destructor) invoke the
+ * unloadMusic() method of _parser and then delete it.
+ */
MidiParser *_parser;
+ /**
+ * This is an (optional) pointer to a malloc'ed buffer containing
+ * MIDI data used by _parser. The stop() method (and hence the
+ * destructor) will free this if set.
+ * Subclasses of this class may use _midiData, but don't have to
+ */
+ byte *_midiData;
+
MidiChannel *_channelsTable[kNumChannels];
uint8 _channelsVolume[kNumChannels];
bool _isLooping;
bool _isPlaying;
+
+ /**
+ * The master volume, in the range 0-255.
+ */
int _masterVolume; // FIXME: byte or int ?
bool _nativeMT32;
diff --git a/audio/module.mk b/audio/module.mk
index 661d3ccad4..a9d9bfc869 100644
--- a/audio/module.mk
+++ b/audio/module.mk
@@ -45,6 +45,7 @@ MODULE_OBJS := \
softsynth/ym2612.o \
softsynth/fluidsynth.o \
softsynth/mt32.o \
+ softsynth/eas.o \
softsynth/pcspk.o \
softsynth/sid.o \
softsynth/wave6581.o
diff --git a/audio/softsynth/eas.cpp b/audio/softsynth/eas.cpp
new file mode 100644
index 0000000000..c5c60b253d
--- /dev/null
+++ b/audio/softsynth/eas.cpp
@@ -0,0 +1,420 @@
+/* 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"
+
+#if defined(__ANDROID__)
+
+#include <dlfcn.h>
+
+#include "common/debug.h"
+#include "common/endian.h"
+#include "common/config-manager.h"
+#include "audio/audiostream.h"
+#include "audio/mpu401.h"
+#include "audio/musicplugin.h"
+#include "audio/mixer.h"
+
+// NOTE:
+// EAS's render function *only* accepts one mix buffer size. it's defined at
+// compile time of the library and can be retrieved via EASLibConfig.bufSize
+// (seen: 128 bytes).
+// to avoid local intermediate buffers, this implementation insists on a fixed
+// buffer size of the calling rate converter, which in return must be a
+// multiple of EAS's. that may change if there're hickups because slower
+// devices can't render fast enough
+
+// from rate_arm.cpp
+#define INTERMEDIATE_BUFFER_SIZE 512
+
+// so far all android versions have the very same library version
+#define EAS_LIBRARY "libsonivox.so"
+#define EAS_KNOWNVERSION 0x03060a0e
+
+#define EAS_REVERB 2
+#define EAS_REVERB_BYPASS 0
+#define EAS_REVERB_PRESET 1
+#define EAS_REVERB_CHAMBER 2
+
+class MidiDriver_EAS : public MidiDriver_MPU401, Audio::AudioStream {
+public:
+ MidiDriver_EAS();
+ virtual ~MidiDriver_EAS();
+
+ // MidiDriver
+ virtual int open();
+ virtual bool isOpen() const;
+ virtual void close();
+ virtual void send(uint32 b);
+ virtual void sysEx(const byte *msg, uint16 length);
+ virtual void setTimerCallback(void *timerParam,
+ Common::TimerManager::TimerProc timerProc);
+ virtual uint32 getBaseTempo();
+
+ // AudioStream
+ virtual int readBuffer(int16 *buffer, const int numSamples);
+ virtual bool isStereo() const;
+ virtual int getRate() const;
+ virtual bool endOfData() const;
+
+private:
+ struct EASLibConfig {
+ uint32 version;
+ uint32 debug;
+ int32 voices;
+ int32 channels;
+ int32 rate;
+ int32 bufSize;
+ uint32 filter;
+ uint32 timeStamp;
+ char *GUID;
+ };
+
+ typedef void * EASDataHandle;
+ typedef void * EASHandle;
+
+ typedef EASLibConfig *(*ConfigFunc)();
+ typedef int32 (*InitFunc)(EASDataHandle *);
+ typedef int32 (*ShutdownFunc)(EASDataHandle);
+ typedef int32 (*SetParameterFunc)(EASDataHandle, int32, int32, int32);
+ typedef int32 (*OpenStreamFunc)(EASDataHandle, EASHandle *, EASHandle);
+ typedef int32 (*WriteStreamFunc)(EASDataHandle, EASHandle, byte *, int32);
+ typedef int32 (*CloseStreamFunc)(EASDataHandle, EASHandle);
+ typedef int32 (*RenderFunc)(EASDataHandle, int16 *, int32, int32 *);
+
+ template<typename T>
+ void sym(T &t, const char *symbol) {
+ union {
+ void *v;
+ T t;
+ } u;
+
+ assert(sizeof(u.v) == sizeof(u.t));
+
+ u.v = dlsym(_dlHandle, symbol);
+
+ if (!u.v)
+ warning("couldn't resolve %s from " EAS_LIBRARY, symbol);
+
+ t = u.t;
+ }
+
+ void *_dlHandle;
+
+ ConfigFunc _configFunc;
+ InitFunc _initFunc;
+ ShutdownFunc _shutdownFunc;
+ SetParameterFunc _setParameterFunc;
+ OpenStreamFunc _openStreamFunc;
+ WriteStreamFunc _writeStreamFunc;
+ CloseStreamFunc _closeStreamFunc;
+ RenderFunc _renderFunc;
+
+ const EASLibConfig *_config;
+ EASDataHandle _EASHandle;
+ EASHandle _midiStream;
+
+ Common::TimerManager::TimerProc _timerProc;
+ void *_timerParam;
+ uint32 _baseTempo;
+ uint _rounds;
+ Audio::SoundHandle _soundHandle;
+};
+
+MidiDriver_EAS::MidiDriver_EAS() :
+ MidiDriver_MPU401(),
+ _dlHandle(0),
+ _configFunc(0),
+ _initFunc(0),
+ _shutdownFunc(0),
+ _setParameterFunc(0),
+ _openStreamFunc(0),
+ _writeStreamFunc(0),
+ _closeStreamFunc(0),
+ _renderFunc(0),
+ _config(0),
+ _EASHandle(0),
+ _midiStream(0),
+ _timerProc(0),
+ _timerParam(0),
+ _baseTempo(0),
+ _rounds(0),
+ _soundHandle() {
+}
+
+MidiDriver_EAS::~MidiDriver_EAS() {
+}
+
+int MidiDriver_EAS::open() {
+ if (isOpen())
+ return MERR_ALREADY_OPEN;
+
+ _dlHandle = dlopen(EAS_LIBRARY, RTLD_LAZY);
+ if (!_dlHandle) {
+ warning("error opening " EAS_LIBRARY ": %s", dlerror());
+ return MERR_DEVICE_NOT_AVAILABLE;
+ }
+
+ sym(_configFunc, "EAS_Config");
+ if (!_configFunc) {
+ close();
+ return -1;
+ }
+
+ _config = _configFunc();
+ if (!_config) {
+ close();
+ warning("error retrieving EAS library configuration");
+ return -1;
+ }
+
+ if (_config->version != EAS_KNOWNVERSION) {
+ close();
+ warning("unknown EAS library version: 0x%08x", _config->version);
+ return -1;
+ }
+
+ if (_config->channels > 2) {
+ close();
+ warning("unsupported number of EAS channels: %d", _config->channels);
+ return -1;
+ }
+
+ // see note at top of this file
+ if (INTERMEDIATE_BUFFER_SIZE % (_config->bufSize * _config->channels)) {
+ close();
+ warning("unsupported EAS buffer size: %d", _config->bufSize);
+ return -1;
+ }
+
+ sym(_initFunc, "EAS_Init");
+ sym(_shutdownFunc, "EAS_Shutdown");
+ sym(_setParameterFunc, "EAS_SetParameter");
+ sym(_openStreamFunc, "EAS_OpenMIDIStream");
+ sym(_writeStreamFunc, "EAS_WriteMIDIStream");
+ sym(_closeStreamFunc, "EAS_CloseMIDIStream");
+ sym(_renderFunc, "EAS_Render");
+
+ if (!_initFunc || !_shutdownFunc || !_setParameterFunc ||
+ !_openStreamFunc || !_writeStreamFunc || !_closeStreamFunc ||
+ !_renderFunc) {
+ close();
+ return -1;
+ }
+
+ int32 res = _initFunc(&_EASHandle);
+ if (res) {
+ close();
+ warning("error initializing the EAS library: %d", res);
+ return -1;
+ }
+
+ _setParameterFunc(_EASHandle, EAS_REVERB, EAS_REVERB_PRESET,
+ EAS_REVERB_CHAMBER);
+ if (res)
+ warning("error setting reverb preset: %d", res);
+
+ _setParameterFunc(_EASHandle, EAS_REVERB, EAS_REVERB_BYPASS, 0);
+ if (res)
+ warning("error disabling reverb bypass: %d", res);
+
+ res = _openStreamFunc(_EASHandle, &_midiStream, 0);
+ if (res) {
+ close();
+ warning("error opening EAS MIDI stream: %d", res);
+ return -1;
+ }
+
+ // set the timer frequency to match a single buffer size
+ _baseTempo = (1000000 * _config->bufSize) / _config->rate;
+
+ // number of buffer fills per readBuffer()
+ _rounds = INTERMEDIATE_BUFFER_SIZE / (_config->bufSize * _config->channels);
+
+ debug("EAS initialized (voices:%d channels:%d rate:%d buffer:%d) "
+ "tempo:%u rounds:%u", _config->voices, _config->channels,
+ _config->rate, _config->bufSize, _baseTempo, _rounds);
+
+ g_system->getMixer()->playStream(Audio::Mixer::kMusicSoundType,
+ &_soundHandle, this, -1,
+ Audio::Mixer::kMaxChannelVolume, 0,
+ DisposeAfterUse::NO, true);
+
+ return 0;
+}
+
+bool MidiDriver_EAS::isOpen() const {
+ return _dlHandle != 0;
+}
+
+void MidiDriver_EAS::close() {
+ MidiDriver_MPU401::close();
+
+ if (!isOpen())
+ return;
+
+ g_system->getMixer()->stopHandle(_soundHandle);
+
+ // not pretty, but better than a mutex
+ g_system->delayMillis((_baseTempo * _rounds) / 1000);
+
+ if (_midiStream) {
+ int32 res = _closeStreamFunc(_EASHandle, _midiStream);
+ if (res)
+ warning("error closing EAS MIDI stream: %d", res);
+
+ _midiStream = 0;
+ }
+
+ if (_EASHandle) {
+ int32 res = _shutdownFunc(_EASHandle);
+ if (res)
+ warning("error shutting down the EAS library: %d", res);
+
+ _EASHandle = 0;
+ }
+
+ if (dlclose(_dlHandle))
+ warning("error closing " EAS_LIBRARY ": %s", dlerror());
+
+ _dlHandle = 0;
+}
+
+void MidiDriver_EAS::send(uint32 b) {
+ byte buf[4];
+
+ WRITE_UINT32(buf, b);
+
+ int32 res = _writeStreamFunc(_EASHandle, _midiStream, buf, 4);
+ if (res)
+ warning("error writing to EAS MIDI stream: %d", res);
+}
+
+void MidiDriver_EAS::sysEx(const byte *msg, uint16 length) {
+ byte buf[266];
+
+ assert(length + 2 <= ARRAYSIZE(buf));
+
+ buf[0] = 0xF0;
+ memcpy(buf + 1, msg, length);
+ buf[length + 1] = 0xF7;
+
+ int32 res = _writeStreamFunc(_EASHandle, _midiStream, buf, length + 2);
+ if (res)
+ warning("error writing to EAS MIDI stream: %d", res);
+}
+
+void MidiDriver_EAS::setTimerCallback(void *timerParam,
+ Common::TimerManager::TimerProc timerProc) {
+ _timerParam = timerParam;
+ _timerProc = timerProc;
+}
+
+uint32 MidiDriver_EAS::getBaseTempo() {
+ return _baseTempo;
+}
+
+int MidiDriver_EAS::readBuffer(int16 *buffer, const int numSamples) {
+ // see note at top of this file
+ assert(numSamples == INTERMEDIATE_BUFFER_SIZE);
+
+ int32 res, c;
+
+ for (uint i = 0; i < _rounds; ++i) {
+ // pull in MIDI events for exactly one buffer size
+ if (_timerProc)
+ (*_timerProc)(_timerParam);
+
+ // if there are no MIDI events, this just renders silence
+ res = _renderFunc(_EASHandle, buffer, _config->bufSize, &c);
+ if (res) {
+ warning("error rendering EAS samples: %d", res);
+ return -1;
+ }
+
+ buffer += c * _config->channels;
+ }
+
+ return numSamples;
+}
+
+bool MidiDriver_EAS::isStereo() const {
+ return _config->channels == 2;
+}
+
+int MidiDriver_EAS::getRate() const {
+ return _config->rate;
+}
+
+bool MidiDriver_EAS::endOfData() const {
+ return false;
+}
+
+class EASMusicPlugin : public MusicPluginObject {
+public:
+ EASMusicPlugin();
+ virtual ~EASMusicPlugin();
+
+ const char *getName() const;
+ const char *getId() const;
+ MusicDevices getDevices() const;
+ Common::Error createInstance(MidiDriver **mididriver,
+ MidiDriver::DeviceHandle = 0) const;
+};
+
+EASMusicPlugin::EASMusicPlugin() {
+}
+
+EASMusicPlugin::~EASMusicPlugin() {
+}
+
+const char *EASMusicPlugin::getName() const {
+ return "Embedded Audio Synthesis";
+}
+
+const char *EASMusicPlugin::getId() const {
+ return "eas";
+}
+
+MusicDevices EASMusicPlugin::getDevices() const {
+ MusicDevices devices;
+ devices.push_back(MusicDevice(this, "", MT_GM));
+
+ return devices;
+}
+
+Common::Error EASMusicPlugin::createInstance(MidiDriver **mididriver, MidiDriver::DeviceHandle) const {
+ *mididriver = new MidiDriver_EAS();
+
+ return Common::kNoError;
+}
+
+//#if PLUGIN_ENABLED_DYNAMIC(EAS)
+ //REGISTER_PLUGIN_DYNAMIC(EAS, PLUGIN_TYPE_MUSIC, EASMusicPlugin);
+//#else
+ REGISTER_PLUGIN_STATIC(EAS, PLUGIN_TYPE_MUSIC, EASMusicPlugin);
+//#endif
+
+#endif
+
diff --git a/backends/events/gph/gph-events.cpp b/backends/events/gph/gph-events.cpp
index 8a5bee9b4a..05fd747605 100644
--- a/backends/events/gph/gph-events.cpp
+++ b/backends/events/gph/gph-events.cpp
@@ -122,9 +122,9 @@ enum {
TAPMODE_HOVER = 2
};
-//GPHEventSource::GPHEventSource()
-// : _buttonStateL(false){
-//}
+GPHEventSource::GPHEventSource()
+ : _buttonStateL(false){
+}
//void GPHEventSource::fillMouseEvent(Common::Event &event, int x, int y) {
// if (GPHGraphicsManager::_videoMode.mode == GFX_HALF && !GPHGraphicsManager::_overlayVisible){
diff --git a/backends/events/gph/gph-events.h b/backends/events/gph/gph-events.h
index f929a14113..7672bffed2 100644
--- a/backends/events/gph/gph-events.h
+++ b/backends/events/gph/gph-events.h
@@ -30,8 +30,8 @@
*/
class GPHEventSource : public SdlEventSource {
-//public:
-// GPHEventSource();
+public:
+ GPHEventSource();
protected:
bool _stickBtn[32];
@@ -46,16 +46,11 @@ protected:
*/
void moveStick();
- virtual bool handleKeyDown(SDL_Event &ev, Common::Event &event);
- virtual bool handleJoyButtonDown(SDL_Event &ev, Common::Event &event);
- virtual bool handleJoyButtonUp(SDL_Event &ev, Common::Event &event);
- virtual bool handleMouseButtonDown(SDL_Event &ev, Common::Event &event);
- virtual bool handleMouseButtonUp(SDL_Event &ev, Common::Event &event);
- virtual bool handleJoyAxisMotion(SDL_Event &ev, Common::Event &event);
-
-// void fillMouseEvent(Common::Event &event, int x, int y);
- virtual bool remapKey(SDL_Event &ev, Common::Event &event);
- virtual void SDLModToOSystemKeyFlags(SDLMod mod, Common::Event &event);
+ bool handleJoyButtonDown(SDL_Event &ev, Common::Event &event);
+ bool handleJoyButtonUp(SDL_Event &ev, Common::Event &event);
+ bool handleMouseButtonDown(SDL_Event &ev, Common::Event &event);
+ bool handleMouseButtonUp(SDL_Event &ev, Common::Event &event);
+ bool remapKey(SDL_Event &ev, Common::Event &event);
};
#endif /* BACKEND_EVENTS_GPH_H */
diff --git a/backends/platform/android/texture.cpp b/backends/platform/android/texture.cpp
index 407ba0419d..573f8f83e1 100644
--- a/backends/platform/android/texture.cpp
+++ b/backends/platform/android/texture.cpp
@@ -231,6 +231,8 @@ void GLESTexture::allocBuffer(GLuint w, GLuint h) {
GLESBaseTexture::allocBuffer(w, h);
+ _surface.pitch = w * _pixelFormat.bytesPerPixel;
+
if (_surface.w == oldw && _surface.h == oldh) {
fillBuffer(0);
return;
@@ -243,7 +245,6 @@ void GLESTexture::allocBuffer(GLuint w, GLuint h) {
assert(_pixels);
_surface.pixels = _pixels;
- _surface.pitch = w * _pixelFormat.bytesPerPixel;
fillBuffer(0);
@@ -364,6 +365,8 @@ void GLESPaletteTexture::allocBuffer(GLuint w, GLuint h) {
GLESBaseTexture::allocBuffer(w, h);
+ _surface.pitch = _texture_width;
+
if (_surface.w == oldw && _surface.h == oldh) {
fillBuffer(0);
return;
@@ -375,7 +378,6 @@ void GLESPaletteTexture::allocBuffer(GLuint w, GLuint h) {
assert(_texture);
_surface.pixels = _texture + _paletteSize;
- _surface.pitch = _texture_width;
fillBuffer(0);
@@ -490,6 +492,9 @@ void GLESFakePaletteTexture::allocBuffer(GLuint w, GLuint h) {
GLESBaseTexture::allocBuffer(w, h);
+ _surface.bytesPerPixel = 1;
+ _surface.pitch = w;
+
if (_surface.w == oldw && _surface.h == oldh) {
fillBuffer(0);
return;
@@ -503,8 +508,6 @@ void GLESFakePaletteTexture::allocBuffer(GLuint w, GLuint h) {
// fixup surface, for the outside this is a CLUT8 surface
_surface.pixels = _pixels;
- _surface.bytesPerPixel = 1;
- _surface.pitch = w;
fillBuffer(0);
diff --git a/base/plugins.cpp b/base/plugins.cpp
index 1db9c0d499..7d0557c474 100644
--- a/base/plugins.cpp
+++ b/base/plugins.cpp
@@ -212,6 +212,9 @@ public:
#ifdef USE_MT32EMU
LINK_PLUGIN(MT32)
#endif
+ #if defined(__ANDROID__)
+ LINK_PLUGIN(EAS)
+ #endif
LINK_PLUGIN(ADLIB)
LINK_PLUGIN(PCSPK)
LINK_PLUGIN(PCJR)
diff --git a/engines/agi/sound_midi.cpp b/engines/agi/sound_midi.cpp
index 2c6a189fbd..ff23a70808 100644
--- a/engines/agi/sound_midi.cpp
+++ b/engines/agi/sound_midi.cpp
@@ -90,24 +90,11 @@ SoundGenMIDI::SoundGenMIDI(AgiEngine *vm, Audio::Mixer *pMixer) : SoundGen(vm, p
else
_driver->sendGMReset();
- _driver->setTimerCallback(this, &onTimer);
+ // FIXME: We need to cast "this" here due to the effects of
+ // multiple inheritance. This hack can go away once this
+ // setTimerCallback() has been moved inside Audio::MidiPlayer code.
+ _driver->setTimerCallback(static_cast<Audio::MidiPlayer *>(this), &timerCallback);
}
-
- _smfParser = MidiParser::createParser_SMF();
- _midiMusicData = NULL;
-}
-
-SoundGenMIDI::~SoundGenMIDI() {
- _driver->setTimerCallback(NULL, NULL);
- stop();
- if (_driver) {
- _driver->close();
- delete _driver;
- _driver = 0;
- }
- _smfParser->setMidiDriver(NULL);
- delete _smfParser;
- delete[] _midiMusicData;
}
void SoundGenMIDI::send(uint32 b) {
@@ -136,14 +123,6 @@ void SoundGenMIDI::endOfTrack() {
_vm->_sound->soundIsFinished();
}
-void SoundGenMIDI::onTimer(void *refCon) {
- SoundGenMIDI *music = (SoundGenMIDI *)refCon;
- Common::StackLock lock(music->_mutex);
-
- if (music->_parser)
- music->_parser->onTimer();
-}
-
void SoundGenMIDI::play(int resnum) {
MIDISound *track;
@@ -154,10 +133,10 @@ void SoundGenMIDI::play(int resnum) {
track = (MIDISound *)_vm->_game.sounds[resnum];
// Convert AGI Sound data to MIDI
- int midiMusicSize = convertSND2MIDI(track->_data, &_midiMusicData);
+ int midiMusicSize = convertSND2MIDI(track->_data, &_midiData);
- if (_smfParser->loadMusic(_midiMusicData, midiMusicSize)) {
- MidiParser *parser = _smfParser;
+ MidiParser *parser = MidiParser::createParser_SMF();
+ if (parser->loadMusic(_midiData, midiMusicSize)) {
parser->setTrack(0);
parser->setMidiDriver(this);
parser->setTimerRate(_driver->getBaseTempo());
@@ -168,6 +147,8 @@ void SoundGenMIDI::play(int resnum) {
syncVolume();
_isPlaying = true;
+ } else {
+ delete parser;
}
}
diff --git a/engines/agi/sound_midi.h b/engines/agi/sound_midi.h
index 9551673a4e..5733358fee 100644
--- a/engines/agi/sound_midi.h
+++ b/engines/agi/sound_midi.h
@@ -28,6 +28,8 @@
#ifndef AGI_SOUND_MIDI_H
#define AGI_SOUND_MIDI_H
+#include "agi/sound.h"
+
#include "audio/midiplayer.h"
namespace Agi {
@@ -47,13 +49,12 @@ protected:
class SoundGenMIDI : public SoundGen, public Audio::MidiPlayer {
public:
SoundGenMIDI(AgiEngine *vm, Audio::Mixer *pMixer);
- ~SoundGenMIDI();
void play(int resnum);
+ // We must overload stop() here to implement the pure virtual
+ // stop() method of the SoundGen class.
void stop() { Audio::MidiPlayer::stop(); }
- void setGM(bool isGM) { _isGM = isGM; }
-
// MidiDriver_BASE interface implementation
virtual void send(uint32 b);
@@ -62,14 +63,8 @@ public:
virtual void endOfTrack();
private:
-
- static void onTimer(void *data);
-
- MidiParser *_smfParser;
bool _isGM;
- byte *_midiMusicData;
-
SoundMgr *_manager;
};
diff --git a/engines/draci/music.cpp b/engines/draci/music.cpp
index 77f51544d5..242e58e92c 100644
--- a/engines/draci/music.cpp
+++ b/engines/draci/music.cpp
@@ -47,9 +47,6 @@ MusicPlayer::MusicPlayer(const char *pathMask) : _pathMask(pathMask), _isGM(fals
if (_nativeMT32)
_driver->property(MidiDriver::PROP_CHANNEL_MASK, 0x03FE);
- _smfParser = MidiParser::createParser_SMF();
- _midiMusicData = NULL;
-
int ret = _driver->open();
if (ret == 0) {
if (_nativeMT32)
@@ -61,21 +58,8 @@ MusicPlayer::MusicPlayer(const char *pathMask) : _pathMask(pathMask), _isGM(fals
// interface for such an operation is supported for AdLib. Maybe for
// this card, setting instruments is necessary.
- _driver->setTimerCallback(this, &onTimer);
- }
-}
-
-MusicPlayer::~MusicPlayer() {
- _driver->setTimerCallback(NULL, NULL);
- stop();
- if (_driver) {
- _driver->close();
- delete _driver;
- _driver = 0;
+ _driver->setTimerCallback(this, &timerCallback);
}
- _smfParser->setMidiDriver(NULL);
- delete _smfParser;
- delete[] _midiMusicData;
}
void MusicPlayer::sendToChannel(byte channel, uint32 b) {
@@ -91,15 +75,9 @@ void MusicPlayer::sendToChannel(byte channel, uint32 b) {
_channelsTable[channel]->send(b);
}
-void MusicPlayer::onTimer(void *refCon) {
- MusicPlayer *music = (MusicPlayer *)refCon;
- Common::StackLock lock(music->_mutex);
-
- if (music->_parser)
- music->_parser->onTimer();
-}
-
void MusicPlayer::playSMF(int track, bool loop) {
+ Common::StackLock lock(_mutex);
+
if (_isPlaying && track == _track) {
debugC(2, kDraciSoundDebugLevel, "Already plaing track %d", track);
return;
@@ -109,24 +87,23 @@ void MusicPlayer::playSMF(int track, bool loop) {
_isGM = true;
-
// Load MIDI resource data
Common::File musicFile;
char musicFileName[40];
- sprintf(musicFileName, _pathMask.c_str(), track);
+ snprintf(musicFileName, sizeof(musicFileName), _pathMask.c_str(), track);
musicFile.open(musicFileName);
if (!musicFile.isOpen()) {
debugC(2, kDraciSoundDebugLevel, "Cannot open track %d", track);
return;
}
int midiMusicSize = musicFile.size();
- delete[] _midiMusicData;
- _midiMusicData = new byte[midiMusicSize];
- musicFile.read(_midiMusicData, midiMusicSize);
+ free(_midiData);
+ _midiData = (byte *)malloc(midiMusicSize);
+ musicFile.read(_midiData, midiMusicSize);
musicFile.close();
- if (_smfParser->loadMusic(_midiMusicData, midiMusicSize)) {
- MidiParser *parser = _smfParser;
+ MidiParser *parser = MidiParser::createParser_SMF();
+ if (parser->loadMusic(_midiData, midiMusicSize)) {
parser->setTrack(0);
parser->setMidiDriver(this);
parser->setTimerRate(_driver->getBaseTempo());
@@ -142,6 +119,7 @@ void MusicPlayer::playSMF(int track, bool loop) {
debugC(2, kDraciSoundDebugLevel, "Playing track %d", track);
} else {
debugC(2, kDraciSoundDebugLevel, "Cannot play track %d", track);
+ delete parser;
}
}
diff --git a/engines/draci/music.h b/engines/draci/music.h
index a1d0aaacb6..c0228074e5 100644
--- a/engines/draci/music.h
+++ b/engines/draci/music.h
@@ -37,27 +37,18 @@ namespace Draci {
class MusicPlayer : public Audio::MidiPlayer {
public:
MusicPlayer(const char *pathMask);
- ~MusicPlayer();
void playSMF(int track, bool loop);
void stop();
- void setGM(bool isGM) { _isGM = isGM; }
-
// Overload Audio::MidiPlayer method
virtual void sendToChannel(byte channel, uint32 b);
protected:
-
- static void onTimer(void *data);
-
- MidiParser *_smfParser;
Common::String _pathMask;
bool _isGM;
int _track;
-
- byte *_midiMusicData;
};
} // End of namespace Draci
diff --git a/engines/hugo/sound.cpp b/engines/hugo/sound.cpp
index 04da0c89ee..24359a2c54 100644
--- a/engines/hugo/sound.cpp
+++ b/engines/hugo/sound.cpp
@@ -47,58 +47,46 @@
namespace Hugo {
-MidiPlayer::MidiPlayer(MidiDriver *driver)
- : _midiData(0) {
+MidiPlayer::MidiPlayer() {
+ MidiDriver::DeviceHandle dev = MidiDriver::detectDevice(MDT_MIDI | MDT_ADLIB | MDT_PREFER_GM);
+ _driver = MidiDriver::createMidi(dev);
assert(_driver);
_paused = false;
-}
-MidiPlayer::~MidiPlayer() {
- stop();
- Common::StackLock lock(_mutex);
- _driver->setTimerCallback(0, 0);
- _driver->close();
- delete _driver;
- _driver = 0;
- if (_parser)
- _parser->setMidiDriver(0);
- delete _parser;
+ int ret = _driver->open();
+ if (ret == 0) {
+ _driver->sendGMReset();
+
+ _driver->setTimerCallback(this, &timerCallback);
+ }
}
void MidiPlayer::play(uint8 *stream, uint16 size) {
debugC(3, kDebugMusic, "MidiPlayer::play");
- if (!stream) {
- stop();
- return;
- }
+
+ Common::StackLock lock(_mutex);
stop();
+ if (!stream)
+ return;
+
_midiData = (uint8 *)malloc(size);
if (_midiData) {
memcpy(_midiData, stream, size);
- Common::StackLock lock(_mutex);
syncVolume(); // FIXME: syncVolume calls setVolume which in turn also locks the mutex! ugh
+
+ _parser = MidiParser::createParser_SMF();
_parser->loadMusic(_midiData, size);
_parser->setTrack(0);
+ _parser->setMidiDriver(this);
+ _parser->setTimerRate(_driver->getBaseTempo());
_isLooping = false;
_isPlaying = true;
}
}
-void MidiPlayer::stop() {
- debugC(3, kDebugMusic, "MidiPlayer::stop");
-
- Common::StackLock lock(_mutex);
- if (_isPlaying) {
- _isPlaying = false;
- _parser->unloadMusic();
- free(_midiData);
- _midiData = 0;
- }
-}
-
void MidiPlayer::pause(bool p) {
_paused = p;
@@ -109,34 +97,14 @@ void MidiPlayer::pause(bool p) {
}
}
-void MidiPlayer::updateTimer() {
- if (_paused) {
- return;
- }
-
+void MidiPlayer::onTimer() {
Common::StackLock lock(_mutex);
- if (_isPlaying) {
+
+ if (!_paused && _isPlaying && _parser) {
_parser->onTimer();
}
}
-int MidiPlayer::open() {
- if (!_driver)
- return 255;
- int ret = _driver->open();
- if (ret)
- return ret;
-
- _driver->sendGMReset();
-
- _parser = MidiParser::createParser_SMF();
- _parser->setMidiDriver(this);
- _parser->setTimerRate(_driver->getBaseTempo());
- _driver->setTimerCallback(this, &timerCallback);
-
- return 0;
-}
-
void MidiPlayer::sendToChannel(byte channel, uint32 b) {
if (!_channelsTable[channel]) {
_channelsTable[channel] = (channel == 9) ? _driver->getPercussionChannel() : _driver->allocateChannel();
@@ -151,17 +119,8 @@ void MidiPlayer::sendToChannel(byte channel, uint32 b) {
}
-void MidiPlayer::timerCallback(void *p) {
- MidiPlayer *player = (MidiPlayer *)p;
-
- player->updateTimer();
-}
-
SoundHandler::SoundHandler(HugoEngine *vm) : _vm(vm) {
- MidiDriver::DeviceHandle dev = MidiDriver::detectDevice(MDT_MIDI | MDT_ADLIB | MDT_PREFER_GM);
- MidiDriver *driver = MidiDriver::createMidi(dev);
-
- _midiPlayer = new MidiPlayer(driver);
+ _midiPlayer = new MidiPlayer();
_speakerStream = new Audio::PCSpeaker(_vm->_mixer->getOutputRate());
_vm->_mixer->playStream(Audio::Mixer::kSFXSoundType, &_speakerHandle,
_speakerStream, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO, true);
@@ -263,7 +222,7 @@ void SoundHandler::playSound(int16 sound, const byte priority) {
* Initialize for MCI sound and midi
*/
void SoundHandler::initSound() {
- _midiPlayer->open();
+ //_midiPlayer->open();
}
void SoundHandler::syncVolume() {
diff --git a/engines/hugo/sound.h b/engines/hugo/sound.h
index b8a7bf9678..d5f51704aa 100644
--- a/engines/hugo/sound.h
+++ b/engines/hugo/sound.h
@@ -41,24 +41,18 @@ namespace Hugo {
class MidiPlayer : public Audio::MidiPlayer {
public:
- MidiPlayer(MidiDriver *driver);
- ~MidiPlayer();
+ MidiPlayer();
void pause(bool p);
void play(uint8 *stream, uint16 size);
- void stop();
- void updateTimer();
- int open();
uint32 getBaseTempo();
// Overload Audio::MidiPlayer method
virtual void sendToChannel(byte channel, uint32 b);
+ virtual void onTimer();
private:
- static void timerCallback(void *p);
-
- uint8 *_midiData;
bool _paused;
};
diff --git a/engines/m4/midi.cpp b/engines/m4/midi.cpp
index b982fc8129..d58b92bf01 100644
--- a/engines/m4/midi.cpp
+++ b/engines/m4/midi.cpp
@@ -34,7 +34,7 @@
namespace M4 {
-MidiPlayer::MidiPlayer(MadsM4Engine *vm) : _vm(vm), _midiData(NULL), _isGM(false) {
+MidiPlayer::MidiPlayer(MadsM4Engine *vm) : _vm(vm), _isGM(false) {
MidiDriver::DeviceHandle dev = MidiDriver::detectDevice(MDT_MIDI | MDT_ADLIB | MDT_PREFER_GM);
_nativeMT32 = ((MidiDriver::getMusicType(dev) == MT_MT32) || ConfMan.getBool("native_mt32"));
@@ -44,26 +44,10 @@ MidiPlayer::MidiPlayer(MadsM4Engine *vm) : _vm(vm), _midiData(NULL), _isGM(false
if (_nativeMT32)
_driver->property(MidiDriver::PROP_CHANNEL_MASK, 0x03FE);
- _parser = MidiParser::createParser_SMF();
- _parser->setMidiDriver(this);
- _parser->setTimerRate(_driver->getBaseTempo());
-
int ret = _driver->open();
- if (ret == 0)
- _driver->setTimerCallback(this, &onTimer);
-}
-
-MidiPlayer::~MidiPlayer() {
- _driver->setTimerCallback(NULL, NULL);
- _parser->setMidiDriver(NULL);
- stop();
- if (_driver) {
- _driver->close();
- delete _driver;
+ if (ret == 0) {
+ _driver->setTimerCallback(this, &timerCallback);
}
- _driver = 0;
- delete _parser;
- free(_midiData);
}
void MidiPlayer::send(uint32 b) {
@@ -74,15 +58,9 @@ void MidiPlayer::send(uint32 b) {
Audio::MidiPlayer::send(b);
}
-void MidiPlayer::onTimer(void *refCon) {
- MidiPlayer *midi = (MidiPlayer *)refCon;
- Common::StackLock lock(midi->_mutex);
-
- if (midi->_isPlaying)
- midi->_parser->onTimer();
-}
-
void MidiPlayer::playMusic(const char *name, int32 vol, bool loop, int32 trigger, int32 scene) {
+ Common::StackLock lock(_mutex);
+
stop();
char fullname[144];
@@ -99,11 +77,10 @@ void MidiPlayer::playMusic(const char *name, int32 vol, bool loop, int32 trigger
_vm->res()->purge();
if (_midiData) {
- /*
- FILE *out = fopen("music.mid", "wb");
- fwrite(_midiData, smfSize, 1, out);
- fclose(out);
- */
+ _parser = MidiParser::createParser_SMF();
+ _parser->setMidiDriver(this);
+ _parser->setTimerRate(_driver->getBaseTempo());
+
_parser->loadMusic(_midiData, smfSize);
_parser->property(MidiParser::mpAutoLoop, loop);
}
@@ -113,20 +90,6 @@ void MidiPlayer::playMusic(const char *name, int32 vol, bool loop, int32 trigger
_isPlaying = true;
}
-void MidiPlayer::stop() {
- Common::StackLock lock(_mutex);
-
- _isPlaying = false;
- if (_parser) {
- _parser->unloadMusic();
- }
-
- if (_midiData) {
- free(_midiData);
- _midiData = NULL;
- }
-}
-
// This function will convert HMP music into type 1 SMF, which our SMF parser
// will be able to handle. It is based on Hans de Goede's HMP 2 MIDI file
// converter, which in turn is "based on the conversion algorithms found in
diff --git a/engines/m4/midi.h b/engines/m4/midi.h
index e1f92cd4b6..a544fb72aa 100644
--- a/engines/m4/midi.h
+++ b/engines/m4/midi.h
@@ -35,10 +35,8 @@ namespace M4 {
class MidiPlayer : public Audio::MidiPlayer {
public:
MidiPlayer(MadsM4Engine *vm);
- ~MidiPlayer();
void playMusic(const char *name, int32 vol, bool loop, int32 trigger, int32 scene);
- virtual void stop();
void setGM(bool isGM) { _isGM = isGM; }
@@ -46,10 +44,7 @@ public:
virtual void send(uint32 b);
protected:
- static void onTimer(void *data);
-
MadsM4Engine *_vm;
- byte *_midiData;
bool _isGM;
diff --git a/engines/made/music.cpp b/engines/made/music.cpp
index 054f8126d6..c8b13ba210 100644
--- a/engines/made/music.cpp
+++ b/engines/made/music.cpp
@@ -47,9 +47,6 @@ MusicPlayer::MusicPlayer() : _isGM(false) {
if (_nativeMT32)
_driver->property(MidiDriver::PROP_CHANNEL_MASK, 0x03FE);
- _xmidiParser = MidiParser::createParser_XMIDI();
- _smfParser = MidiParser::createParser_SMF();
-
int ret = _driver->open();
if (ret == 0) {
if (_nativeMT32)
@@ -57,22 +54,8 @@ MusicPlayer::MusicPlayer() : _isGM(false) {
else
_driver->sendGMReset();
- _driver->setTimerCallback(this, &onTimer);
- }
-}
-
-MusicPlayer::~MusicPlayer() {
- _driver->setTimerCallback(NULL, NULL);
- stop();
- if (_driver) {
- _driver->close();
- delete _driver;
- _driver = 0;
+ _driver->setTimerCallback(this, &timerCallback);
}
- _xmidiParser->setMidiDriver(NULL);
- _smfParser->setMidiDriver(NULL);
- delete _xmidiParser;
- delete _smfParser;
}
void MusicPlayer::send(uint32 b) {
@@ -83,15 +66,9 @@ void MusicPlayer::send(uint32 b) {
Audio::MidiPlayer::send(b);
}
-void MusicPlayer::onTimer(void *refCon) {
- MusicPlayer *music = (MusicPlayer *)refCon;
- Common::StackLock lock(music->_mutex);
-
- if (music->_isPlaying)
- music->_parser->onTimer();
-}
-
void MusicPlayer::playXMIDI(GenericResource *midiResource, MusicFlags flags) {
+ Common::StackLock lock(_mutex);
+
if (_isPlaying)
return;
@@ -101,8 +78,8 @@ void MusicPlayer::playXMIDI(GenericResource *midiResource, MusicFlags flags) {
_isGM = true;
- if (_xmidiParser->loadMusic(midiResource->getData(), midiResource->getSize())) {
- MidiParser *parser = _xmidiParser;
+ MidiParser *parser = MidiParser::createParser_XMIDI();
+ if (parser->loadMusic(midiResource->getData(), midiResource->getSize())) {
parser->setTrack(0);
parser->setMidiDriver(this);
parser->setTimerRate(_driver->getBaseTempo());
@@ -115,10 +92,14 @@ void MusicPlayer::playXMIDI(GenericResource *midiResource, MusicFlags flags) {
_isLooping = flags & MUSIC_LOOP;
_isPlaying = true;
+ } else {
+ delete parser;
}
}
void MusicPlayer::playSMF(GenericResource *midiResource, MusicFlags flags) {
+ Common::StackLock lock(_mutex);
+
if (_isPlaying)
return;
@@ -128,8 +109,8 @@ void MusicPlayer::playSMF(GenericResource *midiResource, MusicFlags flags) {
_isGM = true;
- if (_smfParser->loadMusic(midiResource->getData(), midiResource->getSize())) {
- MidiParser *parser = _smfParser;
+ MidiParser *parser = MidiParser::createParser_SMF();
+ if (parser->loadMusic(midiResource->getData(), midiResource->getSize())) {
parser->setTrack(0);
parser->setMidiDriver(this);
parser->setTimerRate(_driver->getBaseTempo());
@@ -141,6 +122,8 @@ void MusicPlayer::playSMF(GenericResource *midiResource, MusicFlags flags) {
_isLooping = flags & MUSIC_LOOP;
_isPlaying = true;
+ } else {
+ delete parser;
}
}
diff --git a/engines/made/music.h b/engines/made/music.h
index 8925440b75..f8f70cdad6 100644
--- a/engines/made/music.h
+++ b/engines/made/music.h
@@ -44,7 +44,6 @@ enum MusicFlags {
class MusicPlayer : public Audio::MidiPlayer {
public:
MusicPlayer();
- ~MusicPlayer();
void playXMIDI(GenericResource *midiResource, MusicFlags flags = MUSIC_NORMAL);
void playSMF(GenericResource *midiResource, MusicFlags flags = MUSIC_NORMAL);
@@ -52,16 +51,10 @@ public:
void pause();
void resume();
- void setGM(bool isGM) { _isGM = isGM; }
-
// MidiDriver_BASE interface implementation
virtual void send(uint32 b);
protected:
-
- static void onTimer(void *data);
-
- MidiParser *_xmidiParser, *_smfParser;
bool _isGM;
};
diff --git a/engines/parallaction/parallaction_br.cpp b/engines/parallaction/parallaction_br.cpp
index 457c421fd7..619a4f7559 100644
--- a/engines/parallaction/parallaction_br.cpp
+++ b/engines/parallaction/parallaction_br.cpp
@@ -61,9 +61,7 @@ Common::Error Parallaction_br::init() {
_disk = new DosDisk_br(this);
}
_disk->setLanguage(2); // NOTE: language is now hardcoded to English. Original used command-line parameters.
- MidiDriver::DeviceHandle dev = MidiDriver::detectDevice(MDT_MIDI | MDT_ADLIB | MDT_PREFER_GM);
- MidiDriver *driver = MidiDriver::createMidi(dev);
- _soundManI = new DosSoundMan_br(this, driver);
+ _soundManI = new DosSoundMan_br(this);
} else {
_disk = new AmigaDisk_br(this);
_disk->setLanguage(2); // NOTE: language is now hardcoded to English. Original used command-line parameters.
diff --git a/engines/parallaction/parallaction_ns.cpp b/engines/parallaction/parallaction_ns.cpp
index c3d917a33d..ffac22e118 100644
--- a/engines/parallaction/parallaction_ns.cpp
+++ b/engines/parallaction/parallaction_ns.cpp
@@ -166,9 +166,7 @@ Common::Error Parallaction_ns::init() {
_disk->init();
if (getPlatform() == Common::kPlatformPC) {
- MidiDriver::DeviceHandle dev = MidiDriver::detectDevice(MDT_MIDI | MDT_ADLIB | MDT_PREFER_GM);
- MidiDriver *driver = MidiDriver::createMidi(dev);
- _soundManI = new DosSoundMan_ns(this, driver);
+ _soundManI = new DosSoundMan_ns(this);
_soundManI->setMusicVolume(ConfMan.getInt("music_volume"));
} else {
_soundManI = new AmigaSoundMan_ns(this);
diff --git a/engines/parallaction/sound.h b/engines/parallaction/sound.h
index 7b3eff37cb..455189d1fc 100644
--- a/engines/parallaction/sound.h
+++ b/engines/parallaction/sound.h
@@ -140,7 +140,7 @@ class DosSoundMan_ns : public SoundMan_ns {
public:
- DosSoundMan_ns(Parallaction_ns *vm, MidiDriver *midiDriver);
+ DosSoundMan_ns(Parallaction_ns *vm);
~DosSoundMan_ns();
void playMusic();
void stopMusic();
@@ -228,7 +228,7 @@ class DosSoundMan_br : public SoundMan_br {
Audio::AudioStream *loadChannelData(const char *filename, Channel *ch, bool looping);
public:
- DosSoundMan_br(Parallaction_br *vm, MidiDriver *midiDriver);
+ DosSoundMan_br(Parallaction_br *vm);
~DosSoundMan_br();
void playMusic();
diff --git a/engines/parallaction/sound_br.cpp b/engines/parallaction/sound_br.cpp
index 1bc085fd34..ee53f9641e 100644
--- a/engines/parallaction/sound_br.cpp
+++ b/engines/parallaction/sound_br.cpp
@@ -204,94 +204,69 @@ MidiParser *createParser_MSC() {
class MidiPlayer_MSC : public Audio::MidiPlayer {
public:
- MidiPlayer_MSC(MidiDriver *driver);
- ~MidiPlayer_MSC();
+ MidiPlayer_MSC();
void play(Common::SeekableReadStream *stream);
- void stop();
- void pause(bool p);
- void updateTimer();
- void setVolume(int volume);
+ virtual void pause(bool p);
+ virtual void setVolume(int volume);
+ virtual void onTimer();
// MidiDriver_BASE interface
virtual void send(uint32 b);
-private:
- static void timerCallback(void *p);
+private:
void setVolumeInternal(int volume);
-
- uint8 *_midiData;
bool _paused;
};
-MidiPlayer_MSC::MidiPlayer_MSC(MidiDriver *driver)
- : _midiData(0), _paused(false) {
- _driver = driver;
+MidiPlayer_MSC::MidiPlayer_MSC()
+ : _paused(false) {
+
+ MidiDriver::DeviceHandle dev = MidiDriver::detectDevice(MDT_MIDI | MDT_ADLIB | MDT_PREFER_GM);
+ _driver = MidiDriver::createMidi(dev);
assert(_driver);
int ret = _driver->open();
if (ret == 0) {
- _parser = createParser_MSC();
- _parser->setMidiDriver(this);
- _parser->setTimerRate(_driver->getBaseTempo());
_driver->setTimerCallback(this, &timerCallback);
}
}
-MidiPlayer_MSC::~MidiPlayer_MSC() {
- stop();
-
+void MidiPlayer_MSC::play(Common::SeekableReadStream *stream) {
Common::StackLock lock(_mutex);
- _driver->setTimerCallback(NULL, NULL);
- _driver->close();
- delete _driver;
- _driver = 0;
- _parser->setMidiDriver(NULL);
- delete _parser;
-}
-void MidiPlayer_MSC::play(Common::SeekableReadStream *stream) {
- if (!stream) {
- stop();
+ stop();
+ if (!stream)
return;
- }
- stop();
int size = stream->size();
_midiData = (uint8 *)malloc(size);
if (_midiData) {
stream->read(_midiData, size);
delete stream;
- Common::StackLock lock(_mutex);
+ _parser = createParser_MSC();
_parser->loadMusic(_midiData, size);
_parser->setTrack(0);
+ _parser->setMidiDriver(this);
+ _parser->setTimerRate(_driver->getBaseTempo());
_isLooping = true;
_isPlaying = true;
}
}
-void MidiPlayer_MSC::stop() {
- Audio::MidiPlayer::stop();
- free(_midiData);
- _midiData = 0;
-}
-
void MidiPlayer_MSC::pause(bool p) {
_paused = p;
setVolumeInternal(_paused ? 0 : _masterVolume);
}
-void MidiPlayer_MSC::updateTimer() {
- if (_paused) {
- return;
- }
-
+void MidiPlayer_MSC::onTimer() {
Common::StackLock lock(_mutex);
- if (_isPlaying) {
+
+ if (!_paused && _isPlaying && _parser) {
_parser->onTimer();
}
}
@@ -327,14 +302,8 @@ void MidiPlayer_MSC::send(uint32 b) {
sendToChannel(ch, b);
}
-void MidiPlayer_MSC::timerCallback(void *p) {
- MidiPlayer_MSC *player = (MidiPlayer_MSC *)p;
-
- player->updateTimer();
-}
-
-DosSoundMan_br::DosSoundMan_br(Parallaction_br *vm, MidiDriver *driver) : SoundMan_br(vm) {
- _midiPlayer = new MidiPlayer_MSC(driver);
+DosSoundMan_br::DosSoundMan_br(Parallaction_br *vm) : SoundMan_br(vm) {
+ _midiPlayer = new MidiPlayer_MSC();
assert(_midiPlayer);
}
diff --git a/engines/parallaction/sound_ns.cpp b/engines/parallaction/sound_ns.cpp
index 8f3f0c39e6..ba81314da6 100644
--- a/engines/parallaction/sound_ns.cpp
+++ b/engines/parallaction/sound_ns.cpp
@@ -42,74 +42,52 @@ namespace Parallaction {
class MidiPlayer : public Audio::MidiPlayer {
public:
- MidiPlayer(MidiDriver *driver);
- ~MidiPlayer();
+ MidiPlayer();
void play(Common::SeekableReadStream *stream);
- void stop();
void pause(bool p);
- void updateTimer();
+ virtual void onTimer();
private:
- static void timerCallback(void *p);
-
- uint8 *_midiData;
bool _paused;
};
-MidiPlayer::MidiPlayer(MidiDriver *driver)
- : _midiData(0), _paused(false) {
- assert(driver);
- _driver = driver;
+MidiPlayer::MidiPlayer()
+ : _paused(false) {
+
+ MidiDriver::DeviceHandle dev = MidiDriver::detectDevice(MDT_MIDI | MDT_ADLIB | MDT_PREFER_GM);
+ _driver = MidiDriver::createMidi(dev);
+ assert(_driver);
int ret = _driver->open();
if (ret == 0) {
- _parser = MidiParser::createParser_SMF();
- _parser->setMidiDriver(this);
- _parser->setTimerRate(_driver->getBaseTempo());
_driver->setTimerCallback(this, &timerCallback);
}
}
-MidiPlayer::~MidiPlayer() {
- stop();
-
+void MidiPlayer::play(Common::SeekableReadStream *stream) {
Common::StackLock lock(_mutex);
- _driver->setTimerCallback(NULL, NULL);
- _driver->close();
- delete _driver;
- _driver = 0;
- _parser->setMidiDriver(NULL);
- delete _parser;
-}
-void MidiPlayer::play(Common::SeekableReadStream *stream) {
- if (!stream) {
- stop();
+ stop();
+ if (!stream)
return;
- }
int size = stream->size();
-
_midiData = (uint8 *)malloc(size);
if (_midiData) {
stream->read(_midiData, size);
delete stream;
- Common::StackLock lock(_mutex);
+ _parser = MidiParser::createParser_SMF();
_parser->loadMusic(_midiData, size);
_parser->setTrack(0);
+ _parser->setMidiDriver(this);
+ _parser->setTimerRate(_driver->getBaseTempo());
_isLooping = true;
_isPlaying = true;
}
}
-void MidiPlayer::stop() {
- Audio::MidiPlayer::stop();
- free(_midiData);
- _midiData = 0;
-}
-
void MidiPlayer::pause(bool p) {
_paused = p;
@@ -120,25 +98,16 @@ void MidiPlayer::pause(bool p) {
}
}
-void MidiPlayer::updateTimer() {
- if (_paused) {
- return;
- }
-
+void MidiPlayer::onTimer() {
Common::StackLock lock(_mutex);
- if (_isPlaying) {
+
+ if (!_paused && _isPlaying && _parser) {
_parser->onTimer();
}
}
-void MidiPlayer::timerCallback(void *p) {
- MidiPlayer *player = (MidiPlayer *)p;
-
- player->updateTimer();
-}
-
-DosSoundMan_ns::DosSoundMan_ns(Parallaction_ns *vm, MidiDriver *midiDriver) : SoundMan_ns(vm), _playing(false) {
- _midiPlayer = new MidiPlayer(midiDriver);
+DosSoundMan_ns::DosSoundMan_ns(Parallaction_ns *vm) : SoundMan_ns(vm), _playing(false) {
+ _midiPlayer = new MidiPlayer();
}
DosSoundMan_ns::~DosSoundMan_ns() {
diff --git a/engines/sci/console.cpp b/engines/sci/console.cpp
index 93d21c32e0..e2e5ee9682 100644
--- a/engines/sci/console.cpp
+++ b/engines/sci/console.cpp
@@ -3154,10 +3154,9 @@ bool Console::cmdBreakpointKernel(int argc, const char **argv) {
}
bool Console::cmdBreakpointFunction(int argc, const char **argv) {
- // TODO/FIXME: Why does this accept 2 parameters (the high and the low part of the address)?"
if (argc != 3) {
DebugPrintf("Sets a breakpoint on the execution of the specified exported function.\n");
- DebugPrintf("Usage: %s <addr1> <addr2>\n", argv[0]);
+ DebugPrintf("Usage: %s <script number> <export number\n", argv[0]);
return true;
}
@@ -3166,6 +3165,7 @@ bool Console::cmdBreakpointFunction(int argc, const char **argv) {
A breakpoint set on an invalid method name will just never trigger. */
Breakpoint bp;
bp.type = BREAK_EXPORT;
+ // script number, export number
bp.address = (atoi(argv[1]) << 16 | atoi(argv[2]));
_debugState._breakpoints.push_back(bp);
diff --git a/engines/sci/debug.h b/engines/sci/debug.h
index d9959f0b7f..8ddbbd0d45 100644
--- a/engines/sci/debug.h
+++ b/engines/sci/debug.h
@@ -34,18 +34,18 @@ namespace Sci {
// These types are used both as identifiers and as elements of bitfields
enum BreakpointType {
/**
- * Break when selector is executed. data contains (char *) selector name
+ * Break when a selector is executed. Data contains (char *) selector name
* (in the format Object::Method)
*/
- BREAK_SELECTOREXEC = 1 << 0, // break when selector gets executed
- BREAK_SELECTORREAD = 1 << 1, // break when selector gets executed
- BREAK_SELECTORWRITE = 1 << 2, // break when selector gets executed
+ BREAK_SELECTOREXEC = 1 << 0, // break when a function selector is executed
+ BREAK_SELECTORREAD = 1 << 1, // break when a variable selector is read
+ BREAK_SELECTORWRITE = 1 << 2, // break when a variable selector is written
/**
- * Break when an exported function is called. data contains
+ * Break when an exported function is called. Data contains
* script_no << 16 | export_no.
*/
- BREAK_EXPORT = 1 << 3
+ BREAK_EXPORT = 1 << 3
};
struct Breakpoint {
diff --git a/engines/sci/engine/vm.cpp b/engines/sci/engine/vm.cpp
index 24f3c96f62..7e75dbf000 100644
--- a/engines/sci/engine/vm.cpp
+++ b/engines/sci/engine/vm.cpp
@@ -270,26 +270,6 @@ static void validate_write_var(reg_t *r, reg_t *stack_base, int type, int max, i
#define PUSH32(a) (*(validate_stack_addr(s, (s->xs->sp)++)) = (a))
#define POP32() (*(validate_stack_addr(s, --(s->xs->sp))))
-bool SciEngine::checkExportBreakpoint(uint16 script, uint16 pubfunct) {
- if (_debugState._activeBreakpointTypes & BREAK_EXPORT) {
- uint32 bpaddress;
-
- bpaddress = (script << 16 | pubfunct);
-
- Common::List<Breakpoint>::const_iterator bp;
- for (bp = _debugState._breakpoints.begin(); bp != _debugState._breakpoints.end(); ++bp) {
- if (bp->type == BREAK_EXPORT && bp->address == bpaddress) {
- _console->DebugPrintf("Break on script %d, export %d\n", script, pubfunct);
- _debugState.debugging = true;
- _debugState.breakpointWasHit = true;
- return true;
- }
- }
- }
-
- return false;
-}
-
ExecStack *execute_method(EngineState *s, uint16 script, uint16 pubfunct, StackPtr sp, reg_t calling_obj, uint16 argc, StackPtr argp) {
int seg = s->_segMan->getScriptSegment(script);
Script *scr = s->_segMan->getScriptIfLoaded(seg);
@@ -322,6 +302,111 @@ ExecStack *execute_method(EngineState *s, uint16 script, uint16 pubfunct, StackP
return add_exec_stack_entry(s->_executionStack, make_reg(seg, temp), sp, calling_obj, argc, argp, -1, pubfunct, -1, calling_obj, s->_executionStack.size()-1, seg);
}
+bool SciEngine::checkSelectorBreakpoint(BreakpointType breakpointType, reg_t send_obj, int selector) {
+ Common::String methodName = _gamestate->_segMan->getObjectName(send_obj);
+ methodName += ("::" + getKernel()->getSelectorName(selector));
+
+ Common::List<Breakpoint>::const_iterator bpIter;
+ for (bpIter = _debugState._breakpoints.begin(); bpIter != _debugState._breakpoints.end(); ++bpIter) {
+ if ((*bpIter).type == breakpointType && (*bpIter).name == methodName) {
+ _console->DebugPrintf("Break on %s (in [%04x:%04x])\n", methodName.c_str(), PRINT_REG(send_obj));
+ _debugState.debugging = true;
+ _debugState.breakpointWasHit = true;
+ return true;
+ }
+ }
+ return false;
+}
+
+bool SciEngine::checkExportBreakpoint(uint16 script, uint16 pubfunct) {
+ if (_debugState._activeBreakpointTypes & BREAK_EXPORT) {
+ uint32 bpaddress = (script << 16 | pubfunct);
+
+ Common::List<Breakpoint>::const_iterator bp;
+ for (bp = _debugState._breakpoints.begin(); bp != _debugState._breakpoints.end(); ++bp) {
+ if (bp->type == BREAK_EXPORT && bp->address == bpaddress) {
+ _console->DebugPrintf("Break on script %d, export %d\n", script, pubfunct);
+ _debugState.debugging = true;
+ _debugState.breakpointWasHit = true;
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+void debugSelectorCall(reg_t send_obj, Selector selector, int argc, StackPtr argp, ObjVarRef &varp, reg_t funcp, SegManager *segMan, SelectorType selectorType) {
+ int activeBreakpointTypes = g_sci->_debugState._activeBreakpointTypes;
+ const char *objectName = segMan->getObjectName(send_obj);
+ const char *selectorName = g_sci->getKernel()->getSelectorName(selector).c_str();
+ Console *con = g_sci->getSciDebugger();
+
+#ifdef VM_DEBUG_SEND
+ debugN("Send to %04x:%04x (%s), selector %04x (%s):", PRINT_REG(send_obj),
+ s->_segMan->getObjectName(send_obj), selector,
+ g_sci->getKernel()->getSelectorName(selector).c_str());
+#endif // VM_DEBUG_SEND
+
+ switch (selectorType) {
+ case kSelectorNone:
+ break;
+ case kSelectorVariable:
+#ifdef VM_DEBUG_SEND
+ if (argc)
+ debugN("Varselector: Write %04x:%04x\n", PRINT_REG(argp[1]));
+ else
+ debugN("Varselector: Read\n");
+#endif // VM_DEBUG_SEND
+
+ // argc == 0: read selector
+ // argc == 1: write selector
+ // argc can be bigger than 1 in some cases, because of a script bug.
+ // Usually, these aren't fatal.
+ if ((activeBreakpointTypes & BREAK_SELECTORREAD) ||
+ (activeBreakpointTypes & BREAK_SELECTORWRITE) ||
+ argc > 1) {
+
+ reg_t selectorValue = *varp.getPointer(segMan);
+ if (!argc && (activeBreakpointTypes & BREAK_SELECTORREAD)) {
+ if (g_sci->checkSelectorBreakpoint(BREAK_SELECTORREAD, send_obj, selector))
+ con->DebugPrintf("Read from selector (%s:%s): %04x:%04x\n",
+ objectName, selectorName,
+ PRINT_REG(selectorValue));
+ } else if (argc && (activeBreakpointTypes & BREAK_SELECTORWRITE)) {
+ if (g_sci->checkSelectorBreakpoint(BREAK_SELECTORWRITE, send_obj, selector))
+ con->DebugPrintf("Write to selector (%s:%s): change %04x:%04x to %04x:%04x\n",
+ objectName, selectorName,
+ PRINT_REG(selectorValue), PRINT_REG(argp[1]));
+ }
+
+ if (argc > 1)
+ debug(kDebugLevelScripts, "Write to selector (%s:%s): change %04x:%04x to %04x:%04x, argc == %d\n",
+ objectName, selectorName,
+ PRINT_REG(selectorValue), PRINT_REG(argp[1]), argc);
+ }
+ break;
+ case kSelectorMethod:
+#ifndef VM_DEBUG_SEND
+ if (activeBreakpointTypes & BREAK_SELECTOREXEC) {
+ if (g_sci->checkSelectorBreakpoint(BREAK_SELECTOREXEC, send_obj, selector)) {
+#else
+ if (true) {
+ if (true) {
+#endif
+ con->DebugPrintf("%s::%s(", objectName, selectorName);
+ for (int i = 0; i < argc; i++) {
+ con->DebugPrintf("%04x:%04x", PRINT_REG(argp[i+1]));
+ if (i + 1 < argc)
+ con->DebugPrintf(", ");
+ }
+ con->DebugPrintf(") at %04x:%04x\n", PRINT_REG(funcp));
+ }
+ }
+ break;
+ } // switch
+}
+
static void _exec_varselectors(EngineState *s) {
// Executes all varselector read/write ops on the TOS
@@ -357,38 +442,21 @@ struct CallsStruct {
int type; /**< Same as ExecStack.type */
};
-bool SciEngine::checkSelectorBreakpoint(BreakpointType breakpointType, reg_t send_obj, int selector) {
- Common::String methodName = _gamestate->_segMan->getObjectName(send_obj);
- methodName += ("::" + getKernel()->getSelectorName(selector));
-
- Common::List<Breakpoint>::const_iterator bpIter;
- for (bpIter = _debugState._breakpoints.begin(); bpIter != _debugState._breakpoints.end(); ++bpIter) {
- if ((*bpIter).type == breakpointType && (*bpIter).name == methodName) {
- _console->DebugPrintf("Break on %s (in [%04x:%04x])\n", methodName.c_str(), PRINT_REG(send_obj));
- _debugState.debugging = true;
- _debugState.breakpointWasHit = true;
- return true;
- }
- }
- return false;
-}
-
ExecStack *send_selector(EngineState *s, reg_t send_obj, reg_t work_obj, StackPtr sp, int framesize, StackPtr argp) {
-// send_obj and work_obj are equal for anything but 'super'
-// Returns a pointer to the TOS exec_stack element
+ // send_obj and work_obj are equal for anything but 'super'
+ // Returns a pointer to the TOS exec_stack element
assert(s);
reg_t funcp;
- int selector;
+ Selector selector;
int argc;
- int origin = s->_executionStack.size()-1; // Origin: Used for debugging
+ int origin = s->_executionStack.size() - 1; // Origin: Used for debugging
+ int activeBreakpointTypes = g_sci->_debugState._activeBreakpointTypes;
// We return a pointer to the new active ExecStack
// The selector calls we catch are stored below:
Common::Stack<CallsStruct> sendCalls;
- int activeBreakpointTypes = g_sci->_debugState._activeBreakpointTypes;
-
while (framesize > 0) {
selector = argp->requireUint16();
argp++;
@@ -397,145 +465,49 @@ ExecStack *send_selector(EngineState *s, reg_t send_obj, reg_t work_obj, StackPt
if (argc > 0x800) // More arguments than the stack could possibly accomodate for
error("send_selector(): More than 0x800 arguments to function call");
-#ifdef VM_DEBUG_SEND
- debugN("Send to %04x:%04x (%s), selector %04x (%s):", PRINT_REG(send_obj),
- s->_segMan->getObjectName(send_obj), selector,
- g_sci->getKernel()->getSelectorName(selector).c_str());
-#endif // VM_DEBUG_SEND
-
ObjVarRef varp;
- switch (lookupSelector(s->_segMan, send_obj, selector, &varp, &funcp)) {
+ CallsStruct call;
+ call.argp = argp;
+ call.argc = argc;
+ call.selector = selector;
+ SelectorType selectorType = lookupSelector(s->_segMan, send_obj, selector, &varp, &funcp);
+ if (activeBreakpointTypes || DebugMan.isDebugChannelEnabled(kDebugLevelScripts))
+ debugSelectorCall(send_obj, selector, argc, argp, varp, funcp, s->_segMan, selectorType);
+
+ switch (selectorType) {
case kSelectorNone:
error("Send to invalid selector 0x%x of object at %04x:%04x", 0xffff & selector, PRINT_REG(send_obj));
break;
-
case kSelectorVariable:
-
-#ifdef VM_DEBUG_SEND
- if (argc)
- debugN("Varselector: Write %04x:%04x\n", PRINT_REG(argp[1]));
- else
- debugN("Varselector: Read\n");
-#endif // VM_DEBUG_SEND
-
- // argc == 0: read selector
- // argc != 0: write selector
- if (!argc) {
- // read selector
- if (activeBreakpointTypes & BREAK_SELECTORREAD) {
- if (g_sci->checkSelectorBreakpoint(BREAK_SELECTORREAD, send_obj, selector))
- debug("[read selector]\n");
- }
- } else {
- // write selector
- if (activeBreakpointTypes & BREAK_SELECTORWRITE) {
- if (g_sci->checkSelectorBreakpoint(BREAK_SELECTORWRITE, send_obj, selector)) {
- reg_t oldReg = *varp.getPointer(s->_segMan);
- reg_t newReg = argp[1];
- warning("[write to selector (%s:%s): change %04x:%04x to %04x:%04x]\n",
- s->_segMan->getObjectName(send_obj), g_sci->getKernel()->getSelectorName(selector).c_str(),
- PRINT_REG(oldReg), PRINT_REG(newReg));
- }
- }
- }
-
- if (argc > 1) {
- // argc can indeed be bigger than 1 in some cases, and it's usually the
- // result of a script bug. Usually these aren't fatal.
-
- const char *objectName = s->_segMan->getObjectName(send_obj);
-
- reg_t oldReg = *varp.getPointer(s->_segMan);
- reg_t newReg = argp[1];
- const char *selectorName = g_sci->getKernel()->getSelectorName(selector).c_str();
- debug(2, "send_selector(): argc = %d while modifying variable selector "
- "%x (%s) of object %04x:%04x (%s) from %04x:%04x to %04x:%04x",
- argc, selector, selectorName, PRINT_REG(send_obj),
- objectName, PRINT_REG(oldReg), PRINT_REG(newReg));
- }
-
- {
- CallsStruct call;
- call.address.var = varp; // register the call
- call.argp = argp;
- call.argc = argc;
- call.selector = selector;
- call.type = EXEC_STACK_TYPE_VARSELECTOR; // Register as a varselector
- sendCalls.push(call);
- }
-
+ call.address.var = varp; // register the call
+ call.type = EXEC_STACK_TYPE_VARSELECTOR; // Register as a varselector
break;
-
case kSelectorMethod:
-
-#ifndef VM_DEBUG_SEND
- if (activeBreakpointTypes & BREAK_SELECTOREXEC) {
- if (g_sci->checkSelectorBreakpoint(BREAK_SELECTOREXEC, send_obj, selector)) {
- debugN("[execute selector]");
-
- int displaySize = 0;
- for (int argNr = 1; argNr <= argc; argNr++) {
- if (argNr == 1)
- debugN(" - ");
- reg_t curParam = argp[argNr];
- if (curParam.isPointer()) {
- debugN("[%04x:%04x] ", PRINT_REG(curParam));
- displaySize += 12;
- } else {
- debugN("[%04x] ", curParam.offset);
- displaySize += 7;
- }
- if (displaySize > 50) {
- if (argNr < argc)
- debugN("...");
- break;
- }
- }
- debugN("\n");
- }
- }
-#else // VM_DEBUG_SEND
- if (activeBreakpointTypes & BREAK_SELECTOREXEC)
- g_sci->checkSelectorBreakpoint(BREAK_SELECTOREXEC, send_obj, selector);
- debugN("Funcselector(");
- for (int i = 0; i < argc; i++) {
- debugN("%04x:%04x", PRINT_REG(argp[i+1]));
- if (i + 1 < argc)
- debugN(", ");
- }
- debugN(") at %04x:%04x\n", PRINT_REG(funcp));
-#endif // VM_DEBUG_SEND
-
- {
- CallsStruct call;
- call.address.func = funcp; // register call
- call.argp = argp;
- call.argc = argc;
- call.selector = selector;
- call.type = EXEC_STACK_TYPE_CALL;
- call.sp = sp;
- sp = CALL_SP_CARRY; // Destroy sp, as it will be carried over
- sendCalls.push(call);
- }
-
+ call.address.func = funcp; // register call
+ call.type = EXEC_STACK_TYPE_CALL;
+ call.sp = sp;
+ sp = CALL_SP_CARRY; // Destroy sp, as it will be carried over
break;
} // switch (lookupSelector())
+ sendCalls.push(call);
+
framesize -= (2 + argc);
argp += argc + 1;
- }
+ } // while (framesize > 0)
// Iterate over all registered calls in the reverse order. This way, the first call is
// placed on the TOS; as soon as it returns, it will cause the second call to be executed.
while (!sendCalls.empty()) {
CallsStruct call = sendCalls.pop();
if (call.type == EXEC_STACK_TYPE_VARSELECTOR) // Write/read variable?
- add_exec_stack_varselector(s->_executionStack, work_obj, call.argc, call.argp,
- call.selector, call.address.var, origin);
- else
+ add_exec_stack_varselector(s->_executionStack, work_obj,
+ call.argc, call.argp, call.selector,
+ call.address.var, origin);
+ else // Invoke function
add_exec_stack_entry(s->_executionStack, call.address.func, call.sp, work_obj,
- call.argc, call.argp,
- call.selector, -1, -1, send_obj, origin, SCI_XS_CALLEE_LOCALS);
+ call.argc, call.argp, call.selector,
+ -1, -1, send_obj, origin, SCI_XS_CALLEE_LOCALS);
}
_exec_varselectors(s);
diff --git a/engines/sci/engine/workarounds.cpp b/engines/sci/engine/workarounds.cpp
index 17c9f9fa0f..bd93f602f8 100644
--- a/engines/sci/engine/workarounds.cpp
+++ b/engines/sci/engine/workarounds.cpp
@@ -90,7 +90,7 @@ const SciWorkaroundEntry uninitializedReadWorkarounds[] = {
{ GID_KQ6, 520, 520, 0, "rm520", "init", -1, 0, { WORKAROUND_FAKE, 0 } }, // going to boiling water trap on beast isle
{ GID_KQ6, -1, 903, 0, "controlWin", "open", -1, 4, { WORKAROUND_FAKE, 0 } }, // when opening the controls window (save, load etc)
{ GID_KQ6, -1, 907, 0, "tomato", "doVerb", -1, 2, { WORKAROUND_FAKE, 0 } }, // when looking at the rotten tomato in the inventory - bug #3059544
- { GID_KQ7, 30, 64996, 0, "User", "handleEvent", -1, 1, { WORKAROUND_FAKE, 0 } }, // called when pushing a keyboard key
+ { GID_KQ7, -1, 64996, 0, "User", "handleEvent", -1, 1, { WORKAROUND_FAKE, 0 } }, // called when pushing a keyboard key
{ GID_LAURABOW, 37, 0, 0, "CB1", "doit", -1, 1, { WORKAROUND_FAKE, 0 } }, // when going up the stairs (bug #3037694)
{ GID_LAURABOW, -1, 967, 0, "myIcon", "cycle", -1, 1, { WORKAROUND_FAKE, 0 } }, // having any portrait conversation coming up (initial bug #3034985)
{ GID_LAURABOW2, -1, 24, 0, "gcWin", "open", -1, 5, { WORKAROUND_FAKE, 0xf } }, // is used as priority for game menu
diff --git a/engines/sci/graphics/frameout.cpp b/engines/sci/graphics/frameout.cpp
index fbfd140e6b..e68f964dab 100644
--- a/engines/sci/graphics/frameout.cpp
+++ b/engines/sci/graphics/frameout.cpp
@@ -123,7 +123,10 @@ void GfxFrameout::kernelUpdatePlane(reg_t object) {
if (it->planeRect.left < 0) {
it->planeOffsetX = -it->planeRect.left;
it->planeRect.left = 0;
+ } else {
+ it->planeOffsetX = 0;
}
+
if (it->planeRect.top < 0)
it->planeRect.top = 0;
// We get bad plane-bottom in sq6
diff --git a/engines/sci/graphics/screen.cpp b/engines/sci/graphics/screen.cpp
index 89463badd0..d544dad26f 100644
--- a/engines/sci/graphics/screen.cpp
+++ b/engines/sci/graphics/screen.cpp
@@ -156,12 +156,14 @@ void GfxScreen::copyToScreen() {
}
void GfxScreen::copyFromScreen(byte *buffer) {
+ // TODO this ignores the pitch
Graphics::Surface *screen = g_system->lockScreen();
memcpy(buffer, screen->pixels, _displayPixels);
g_system->unlockScreen();
}
void GfxScreen::kernelSyncWithFramebuffer() {
+ // TODO this ignores the pitch
Graphics::Surface *screen = g_system->lockScreen();
memcpy(_displayScreen, screen->pixels, _displayPixels);
g_system->unlockScreen();
diff --git a/engines/sword25/gfx/image/pngloader.cpp b/engines/sword25/gfx/image/pngloader.cpp
index e2a8510c32..f6c00b6968 100644
--- a/engines/sword25/gfx/image/pngloader.cpp
+++ b/engines/sword25/gfx/image/pngloader.cpp
@@ -218,7 +218,7 @@ bool PNGLoader::doDecodeImage(const byte *fileDataPtr, uint fileSize, byte *&unc
Common::MemoryReadStream *fileStr = new Common::MemoryReadStream(fileDataPtr, fileSize, DisposeAfterUse::NO);
Graphics::PNG *png = new Graphics::PNG();
if (!png->read(fileStr)) // the fileStr pointer, and thus pFileData will be deleted after this is done
- error("Error while reading PNG image");
+ error("Error while reading PNG image");
Graphics::PixelFormat format = Graphics::PixelFormat(4, 8, 8, 8, 8, 16, 8, 0, 24);
Graphics::Surface *pngSurface = png->getSurface(format);
diff --git a/engines/sword25/gfx/image/renderedimage.cpp b/engines/sword25/gfx/image/renderedimage.cpp
index 0d2ffb5aee..ced3296e57 100644
--- a/engines/sword25/gfx/image/renderedimage.cpp
+++ b/engines/sword25/gfx/image/renderedimage.cpp
@@ -59,7 +59,7 @@ RenderedImage::RenderedImage(const Common::String &filename, bool &result) :
_backSurface = Kernel::getInstance()->getGfx()->getSurface();
- // Datei laden
+ // Load file
byte *pFileData;
uint fileSize;
pFileData = pPackage->getFile(filename, &fileSize);
@@ -68,7 +68,7 @@ RenderedImage::RenderedImage(const Common::String &filename, bool &result) :
return;
}
- // Bildeigenschaften bestimmen
+ // Determine image properties
int pitch;
if (!PNGLoader::imageProperties(pFileData, fileSize, _width, _height)) {
error("Could not read image properties.");
@@ -76,14 +76,14 @@ RenderedImage::RenderedImage(const Common::String &filename, bool &result) :
return;
}
- // Das Bild dekomprimieren
+ // Uncompress the image
if (!PNGLoader::decodeImage(pFileData, fileSize, _data, _width, _height, pitch)) {
error("Could not decode image.");
delete[] pFileData;
return;
}
- // Dateidaten freigeben
+ // Cleanup FileData
delete[] pFileData;
_doCleanup = true;
@@ -134,7 +134,7 @@ bool RenderedImage::fill(const Common::Rect *pFillRect, uint color) {
// -----------------------------------------------------------------------------
bool RenderedImage::setContent(const byte *pixeldata, uint size, uint offset, uint stride) {
- // Überprüfen, ob PixelData ausreichend viele Pixel enthält um ein Bild der Größe Width * Height zu erzeugen
+ // Check if PixelData contains enough pixel to create an image with image size equals width * height
if (size < static_cast<uint>(_width * _height * 4)) {
error("PixelData vector is too small to define a 32 bit %dx%d image.", _width, _height);
return false;
@@ -198,11 +198,11 @@ bool RenderedImage::blit(int posX, int posY, int flipping, Common::Rect *pPartRe
srcImage.w = pPartRect->right - pPartRect->left;
srcImage.h = pPartRect->bottom - pPartRect->top;
- debug(6, "Blit(%d, %d, %d, [%d, %d, %d, %d], %08x, %d, %d)", posX, posY, flipping,
+ debug(6, "Blit(%d, %d, %d, [%d, %d, %d, %d], %08x, %d, %d)", posX, posY, flipping,
pPartRect->left, pPartRect->top, pPartRect->width(), pPartRect->height(), color, width, height);
} else {
- debug(6, "Blit(%d, %d, %d, [%d, %d, %d, %d], %08x, %d, %d)", posX, posY, flipping, 0, 0,
+ debug(6, "Blit(%d, %d, %d, [%d, %d, %d, %d], %08x, %d, %d)", posX, posY, flipping, 0, 0,
srcImage.w, srcImage.h, color, width, height);
}
@@ -324,7 +324,7 @@ bool RenderedImage::blit(int posX, int posY, int flipping, Common::Rect *pPartRe
ino += inoStep;
}
- g_system->copyRectToScreen((byte *)_backSurface->getBasePtr(posX, posY), _backSurface->pitch, posX, posY,
+ g_system->copyRectToScreen((byte *)_backSurface->getBasePtr(posX, posY), _backSurface->pitch, posX, posY,
img->w, img->h);
}
@@ -413,7 +413,7 @@ int *RenderedImage::scaleLine(int size, int srcSize) {
distCtr -= 100;
}
}
-
+
return v;
}
diff --git a/engines/sword25/gfx/image/renderedimage.h b/engines/sword25/gfx/image/renderedimage.h
index 0375c7acbe..e3f23747da 100644
--- a/engines/sword25/gfx/image/renderedimage.h
+++ b/engines/sword25/gfx/image/renderedimage.h
@@ -50,12 +50,12 @@ public:
RenderedImage(const Common::String &filename, bool &result);
/**
- @brief Erzeugt ein leeres BS_RenderedImage
+ @brief Creates an empty BS_RenderedImage
- @param Width die Breite des zu erzeugenden Bildes.
- @param Height die Höhe des zu erzeugenden Bildes
- @param Result gibt dem Aufrufer bekannt, ob der Konstruktor erfolgreich ausgeführt wurde. Wenn es nach dem Aufruf false enthalten sollte,
- dürfen keine Methoden am Objekt aufgerufen werden und das Objekt ist sofort zu zerstören.
+ @param Width The width of the image to be created.
+ @param Height The height of the image to be created
+ @param Result Informs the caller, whether the constructor is executed successfully. If it contains false
+ after the call, do not call methods on the object and destroy the object immediately.
*/
RenderedImage(uint width, uint height, bool &result);
RenderedImage();
@@ -84,25 +84,25 @@ public:
void replaceContent(byte *pixeldata, int width, int height);
virtual uint getPixel(int x, int y);
- virtual bool isBlitSource() const {
+ virtual bool isBlitSource() const {
return true;
}
- virtual bool isBlitTarget() const {
+ virtual bool isBlitTarget() const {
return false;
}
- virtual bool isScalingAllowed() const {
+ virtual bool isScalingAllowed() const {
return true;
}
- virtual bool isFillingAllowed() const {
+ virtual bool isFillingAllowed() const {
return false;
}
- virtual bool isAlphaAllowed() const {
+ virtual bool isAlphaAllowed() const {
return true;
}
- virtual bool isColorModulationAllowed() const {
+ virtual bool isColorModulationAllowed() const {
return true;
}
- virtual bool isSetContentAllowed() const {
+ virtual bool isSetContentAllowed() const {
return true;
}
diff --git a/engines/sword25/gfx/image/swimage.cpp b/engines/sword25/gfx/image/swimage.cpp
index ff06491b36..3b9b939eb3 100644
--- a/engines/sword25/gfx/image/swimage.cpp
+++ b/engines/sword25/gfx/image/swimage.cpp
@@ -47,7 +47,7 @@ SWImage::SWImage(const Common::String &filename, bool &result) :
PackageManager *pPackage = Kernel::getInstance()->getPackage();
assert(pPackage);
- // Datei laden
+ // Load file
byte *pFileData;
uint fileSize;
pFileData = pPackage->getFile(filename, &fileSize);
@@ -56,21 +56,21 @@ SWImage::SWImage(const Common::String &filename, bool &result) :
return;
}
- // Bildeigenschaften bestimmen
+ // Determine image properties
int pitch;
if (!PNGLoader::imageProperties(pFileData, fileSize, _width, _height)) {
error("Could not read image properties.");
return;
}
- // Das Bild dekomprimieren
+ // Uncompress the image
byte *pUncompressedData;
if (!PNGLoader::decodeImage(pFileData, fileSize, pUncompressedData, _width, _height, pitch)) {
error("Could not decode image.");
return;
}
- // Dateidaten freigeben
+ // Cleanup FileData
delete[] pFileData;
_imageDataPtr = (uint *)pUncompressedData;
diff --git a/engines/sword25/gfx/image/vectorimage.cpp b/engines/sword25/gfx/image/vectorimage.cpp
index 094e6a59a8..241e80bad3 100644
--- a/engines/sword25/gfx/image/vectorimage.cpp
+++ b/engines/sword25/gfx/image/vectorimage.cpp
@@ -47,15 +47,15 @@ namespace Sword25 {
#define BEZSMOOTHNESS 0.5
// -----------------------------------------------------------------------------
-// SWF Datentypen
+// SWF datatype
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
-// Bitstream Hilfsklasse
+// Bitstream helper class
// -----------------------------------------------------------------------------
-// Das Parsen von SWF-Dateien erfordert sowohl bitweises Auslesen als auch an
-// Bytegrenzen ausgerichtetes Lesen.
-// Diese Klasse ist speziell dafür ausgestattet.
+// The parsing of SWF files requires both bitwise readout and on Byte boundaries
+// oriented reading.
+// This class is specially equipped for this.
// -----------------------------------------------------------------------------
class VectorImage::SWFBitStream {
@@ -85,10 +85,10 @@ public:
}
inline int32 getSignedBits(uint bitCount) {
- // Bits einlesen
+ // readout bits
uint32 temp = getBits(bitCount);
- // Falls das Sign-Bit gesetzt ist, den Rest des Rückgabewertes mit 1-Bits auffüllen (Sign Extension)
+ // If the sign-bit is set, fill the rest of the return value with 1-bit (sign extension)
if (temp & 1 << (bitCount - 1))
return (0xffffffff << bitCount) | temp;
else
@@ -151,28 +151,28 @@ private:
// -----------------------------------------------------------------------------
-// Konstanten und Hilfsfunktionen
+// Constants and utility functions
// -----------------------------------------------------------------------------
namespace {
// -----------------------------------------------------------------------------
-// Konstanten
+// Constants
// -----------------------------------------------------------------------------
-const uint32 MAX_ACCEPTED_FLASH_VERSION = 3; // Die höchste Flash-Dateiversion, die vom Lader akzeptiert wird
+const uint32 MAX_ACCEPTED_FLASH_VERSION = 3; // The maximum flash file version that is accepted by the loader
// -----------------------------------------------------------------------------
-// Konvertiert SWF-Rechteckdaten in einem Bitstrom in Common::Rect-Objekte
+// Converts SWF rectangle data in a bit stream in Common::Rect objects
// -----------------------------------------------------------------------------
Common::Rect flashRectToBSRect(VectorImage::SWFBitStream &bs) {
bs.flushByte();
- // Feststellen mit wie vielen Bits die einzelnen Komponenten kodiert sind
+ // Determines how many bits of the single components are encoded
uint32 bitsPerValue = bs.getBits(5);
- // Die einzelnen Komponenten einlesen
+ // Readout the single components
int32 xMin = bs.getSignedBits(bitsPerValue);
int32 xMax = bs.getSignedBits(bitsPerValue);
int32 yMin = bs.getSignedBits(bitsPerValue);
@@ -182,7 +182,7 @@ Common::Rect flashRectToBSRect(VectorImage::SWFBitStream &bs) {
}
// -----------------------------------------------------------------------------
-// Berechnet die Bounding-Box eines BS_VectorImageElement
+// Calculate the bounding box of a BS_VectorImageElement
// -----------------------------------------------------------------------------
Common::Rect CalculateBoundingBox(const VectorImageElement &vectorImageElement) {
@@ -214,17 +214,17 @@ Common::Rect CalculateBoundingBox(const VectorImageElement &vectorImageElement)
// -----------------------------------------------------------------------------
-// Konstruktion
+// Construction
// -----------------------------------------------------------------------------
VectorImage::VectorImage(const byte *pFileData, uint fileSize, bool &success, const Common::String &fname) : _pixelData(0), _fname(fname) {
success = false;
- // Bitstream-Objekt erzeugen
- // Im Folgenden werden die Dateidaten aus diesem ausgelesen.
+ // Create bitstream object
+ // In the following the file data will be readout of the bitstream object.
SWFBitStream bs(pFileData, fileSize);
- // SWF-Signatur überprüfen
+ // Check SWF signature
uint32 signature[3];
signature[0] = bs.getByte();
signature[1] = bs.getByte();
@@ -236,37 +236,37 @@ VectorImage::VectorImage(const byte *pFileData, uint fileSize, bool &success, co
return;
}
- // Versionsangabe überprüfen
+ // Check the version
uint32 version = bs.getByte();
if (version > MAX_ACCEPTED_FLASH_VERSION) {
error("File is of version %d. Highest accepted version is %d.", version, MAX_ACCEPTED_FLASH_VERSION);
return;
}
- // Dateigröße auslesen und mit der tatsächlichen Größe vergleichen
+ // Readout filesize and compare with the actual size
uint32 storedFileSize = bs.getUInt32();
if (storedFileSize != fileSize) {
error("File is not a valid SWF-file");
return;
}
- // SWF-Maße auslesen
+ // readout SWF size
Common::Rect movieRect = flashRectToBSRect(bs);
- // Framerate und Frameanzahl auslesen
+ // Get frame rate and frame count
/* uint32 frameRate = */
bs.getUInt16();
/* uint32 frameCount = */
bs.getUInt16();
- // Tags parsen
- // Da wir uns nur für das erste DefineShape-Tag interessieren
+ // Parse tags
+ // Because we are only interested in the first DifneShape-Tag...
bool keepParsing = true;
while (keepParsing) {
- // Tags beginnen immer an Bytegrenzen
+ // Tags always begin on byte boundaries
bs.flushByte();
- // Tagtyp und Länge auslesen
+ // Readout tag type and length
uint16 tagTypeAndLength = bs.getUInt16();
uint32 tagType = tagTypeAndLength >> 6;
uint32 tagLength = tagTypeAndLength & 0x3f;
@@ -286,13 +286,13 @@ VectorImage::VectorImage(const byte *pFileData, uint fileSize, bool &success, co
success = parseDefineShape(3, bs);
return;
default:
- // Unbekannte Tags ignorieren
+ // Ignore unknown tags
bs.skipBytes(tagLength);
}
}
- // Die Ausführung darf nicht an dieser Stelle ankommen: Entweder es wird ein Shape gefunden, dann wird die Funktion mit vorher verlassen, oder
- // es wird keines gefunden, dann tritt eine Exception auf sobald über das Ende der Datei hinaus gelesen wird.
+ // The execution must not arrive at this point: Either a shape is found, then the function will be leaved before, or it is found none, then
+ // an exception occurs as soon as it is read beyond of the end of file.
assert(false);
}
@@ -336,13 +336,13 @@ ArtBpath *VectorImage::storeBez(ArtBpath *bez, int lineStyle, int fillStyle0, in
bool VectorImage::parseDefineShape(uint shapeType, SWFBitStream &bs) {
/*uint32 shapeID = */bs.getUInt16();
- // Bounding Box auslesen
+ // readout bounding box
_boundingBox = flashRectToBSRect(bs);
- // Erstes Image-Element erzeugen
+ // create first image element
_elements.resize(1);
- // Styles einlesen
+ // read styles
uint numFillBits;
uint numLineBits;
if (!parseStyles(shapeType, bs, numFillBits, numLineBits))
@@ -352,7 +352,7 @@ bool VectorImage::parseDefineShape(uint shapeType, SWFBitStream &bs) {
uint fillStyle0 = 0;
uint fillStyle1 = 0;
- // Shaperecord parsen
+ // parse shaperecord
// ------------------
double curX = 0;
@@ -367,7 +367,7 @@ bool VectorImage::parseDefineShape(uint shapeType, SWFBitStream &bs) {
// Non-Edge Record
if (typeFlag == 0) {
- // Feststellen welche Parameter gesetzt werden
+ // Determines which parameters are set
uint32 stateNewStyles = bs.getBits(1);
uint32 stateLineStyle = bs.getBits(1);
uint32 stateFillStyle1 = bs.getBits(1);
@@ -378,10 +378,10 @@ bool VectorImage::parseDefineShape(uint shapeType, SWFBitStream &bs) {
uint prevFillStyle0 = fillStyle0;
uint prevFillStyle1 = fillStyle1;
- // End der Shape-Definition erreicht?
+ // End of the shape definition is reached?
if (!stateNewStyles && !stateLineStyle && !stateFillStyle0 && !stateFillStyle1 && !stateMoveTo) {
endOfShapeDiscovered = true;
- // Parameter dekodieren
+ // Decode parameters
} else {
if (stateMoveTo) {
uint32 moveToBits = bs.getBits(5);
@@ -410,7 +410,7 @@ bool VectorImage::parseDefineShape(uint shapeType, SWFBitStream &bs) {
numLineBits = 0;
}
- // Ein neuen Pfad erzeugen, es sei denn, es wurden nur neue Styles definiert
+ // Create a new path, unless there were only defined new styles
if (stateLineStyle || stateFillStyle0 || stateFillStyle1 || stateMoveTo) {
// Store previous curve if any
if (bezNodes) {
@@ -426,15 +426,15 @@ bool VectorImage::parseDefineShape(uint shapeType, SWFBitStream &bs) {
}
if (stateNewStyles) {
- // An dieser Stelle werden in Flash die alten Style-Definitionen verworfen und mit den neuen überschrieben.
- // Es wird ein neues Element begonnen.
+ // The old style definitions will be discarded and overwritten with the new at this point in Flash.
+ // A new element will be started with a new element.
_elements.resize(_elements.size() + 1);
if (!parseStyles(shapeType, bs, numFillBits, numLineBits))
return false;
}
}
} else {
- // Edge Record
+ // Edge record
uint32 edgeFlag = bs.getBits(1);
uint32 numBits = bs.getBits(4) + 2;
@@ -499,7 +499,7 @@ bool VectorImage::parseDefineShape(uint shapeType, SWFBitStream &bs) {
free(bez);
- // Bounding-Boxes der einzelnen Elemente berechnen
+ // Calculate the bounding boxes of each element
Common::Array<VectorImageElement>::iterator it = _elements.begin();
for (; it != _elements.end(); ++it)
it->_boundingBox = CalculateBoundingBox(*it);
@@ -513,16 +513,16 @@ bool VectorImage::parseDefineShape(uint shapeType, SWFBitStream &bs) {
bool VectorImage::parseStyles(uint shapeType, SWFBitStream &bs, uint &numFillBits, uint &numLineBits) {
bs.flushByte();
- // Fillstyles parsen
+ // Parse fill styles
// -----------------
- // Anzahl an Fillstyles bestimmen
+ // Determine number of fill styles
uint fillStyleCount = bs.getByte();
if (fillStyleCount == 0xff)
fillStyleCount = bs.getUInt16();
- // Alle Fillstyles einlesen, falls ein Fillstyle mit Typ != 0 gefunden wird, wird das Parsen abgebrochen.
- // Es wird nur "solid fill" (Typ 0) unterstützt.
+ // Readout all fill styles. If a fill style with Typ != 0 is found, the parsing is aborted.
+ // Only "solid fill" (Typ 0) is supported.
_elements.back()._fillStyles.reserve(fillStyleCount);
for (uint i = 0; i < fillStyleCount; ++i) {
byte type = bs.getByte();
@@ -543,15 +543,15 @@ bool VectorImage::parseStyles(uint shapeType, SWFBitStream &bs, uint &numFillBit
_elements.back()._fillStyles.push_back(color);
}
- // Linestyles parsen
+ // Line styles parsen
// -----------------
- // Anzahl an Linestyles bestimmen
+ // Determine number of line styles
uint lineStyleCount = bs.getByte();
if (lineStyleCount == 0xff)
lineStyleCount = bs.getUInt16();
- // Alle Linestyles einlesen
+ // Readout all line styles
_elements.back()._lineStyles.reserve(lineStyleCount);
for (uint i = 0; i < lineStyleCount; ++i) {
double width = bs.getUInt16();
@@ -569,7 +569,7 @@ bool VectorImage::parseStyles(uint shapeType, SWFBitStream &bs, uint &numFillBit
_elements.back()._lineStyles.push_back(VectorImageElement::LineStyleType(width, color));
}
- // Bitbreite für die folgenden Styleindizes auslesen
+ // Readout the bit width for the following style indices
numFillBits = bs.getBits(4);
numLineBits = bs.getBits(4);
@@ -608,11 +608,11 @@ bool VectorImage::blit(int posX, int posY,
static int oldWidth = -2;
static int oldHeight = -2;
- // Falls Breite oder Höhe 0 sind, muss nichts dargestellt werden.
+ // If width or height to 0, nothing needs to be shown.
if (width == 0 || height == 0)
return true;
- // Feststellen, ob das alte Bild im Cache nicht wiederbenutzt werden kann und neu Berechnet werden muss
+ // Determine if the old image in the cache can not be reused and must be recalculated
if (!(oldThis == this && oldWidth == width && oldHeight == height)) {
render(width, height);
diff --git a/engines/tinsel/music.cpp b/engines/tinsel/music.cpp
index 943beb474e..3b9833b418 100644
--- a/engines/tinsel/music.cpp
+++ b/engines/tinsel/music.cpp
@@ -388,37 +388,23 @@ void DeleteMidiBuffer() {
MidiMusicPlayer::MidiMusicPlayer() {
MidiDriver::DeviceHandle dev = MidiDriver::detectDevice(MDT_MIDI | MDT_ADLIB | MDT_PREFER_GM);
- bool native_mt32 = ((MidiDriver::getMusicType(dev) == MT_MT32) || ConfMan.getBool("native_mt32"));
+ _nativeMT32 = ((MidiDriver::getMusicType(dev) == MT_MT32) || ConfMan.getBool("native_mt32"));
//bool adlib = (MidiDriver::getMusicType(dev) == MT_ADLIB);
_driver = MidiDriver::createMidi(dev);
assert(_driver);
- if (native_mt32)
+ if (_nativeMT32)
_driver->property(MidiDriver::PROP_CHANNEL_MASK, 0x03FE);
int ret = _driver->open();
if (ret == 0) {
- if (native_mt32)
+ if (_nativeMT32)
_driver->sendMT32Reset();
else
_driver->sendGMReset();
- _driver->setTimerCallback(this, &onTimer);
+ _driver->setTimerCallback(this, &timerCallback);
}
-
- _xmidiParser = MidiParser::createParser_XMIDI();
-}
-
-MidiMusicPlayer::~MidiMusicPlayer() {
- _driver->setTimerCallback(NULL, NULL);
- stop();
- if (_driver) {
- _driver->close();
- delete _driver;
- _driver = 0;
- }
- _xmidiParser->setMidiDriver(NULL);
- delete _xmidiParser;
}
void MidiMusicPlayer::setVolume(int volume) {
@@ -441,15 +427,9 @@ void MidiMusicPlayer::send(uint32 b) {
}
}
-void MidiMusicPlayer::onTimer(void *refCon) {
- MidiMusicPlayer *music = (MidiMusicPlayer *)refCon;
- Common::StackLock lock(music->_mutex);
-
- if (music->_isPlaying)
- music->_parser->onTimer();
-}
-
void MidiMusicPlayer::playXMIDI(byte *midiData, uint32 size, bool loop) {
+ Common::StackLock lock(_mutex);
+
if (_isPlaying)
return;
@@ -467,8 +447,8 @@ void MidiMusicPlayer::playXMIDI(byte *midiData, uint32 size, bool loop) {
// Load XMID resource data
- if (_xmidiParser->loadMusic(midiData, size)) {
- MidiParser *parser = _xmidiParser;
+ MidiParser *parser = MidiParser::createParser_XMIDI();
+ if (parser->loadMusic(midiData, size)) {
parser->setTrack(0);
parser->setMidiDriver(this);
parser->setTimerRate(getBaseTempo());
@@ -479,6 +459,8 @@ void MidiMusicPlayer::playXMIDI(byte *midiData, uint32 size, bool loop) {
_isLooping = loop;
_isPlaying = true;
+ } else {
+ delete parser;
}
}
diff --git a/engines/tinsel/music.h b/engines/tinsel/music.h
index 9436c02032..af089caf24 100644
--- a/engines/tinsel/music.h
+++ b/engines/tinsel/music.h
@@ -64,7 +64,6 @@ void dumpMusic();
class MidiMusicPlayer : public Audio::MidiPlayer {
public:
MidiMusicPlayer();
- ~MidiMusicPlayer();
virtual void setVolume(int volume);
@@ -80,12 +79,6 @@ public:
// The original sets the "sequence timing" to 109 Hz, whatever that
// means. The default is 120.
uint32 getBaseTempo() { return _driver ? (109 * _driver->getBaseTempo()) / 120 : 0; }
-
-protected:
-
- static void onTimer(void *data);
-
- MidiParser *_xmidiParser;
};
class PCMMusicPlayer : public Audio::AudioStream {
diff --git a/engines/tinsel/tinsel.cpp b/engines/tinsel/tinsel.cpp
index ef0fe1c909..1b3173719f 100644
--- a/engines/tinsel/tinsel.cpp
+++ b/engines/tinsel/tinsel.cpp
@@ -859,8 +859,6 @@ TinselEngine::TinselEngine(OSystem *syst, const TinselGameDescription *gameDesc)
_midiMusic = new MidiMusicPlayer();
_pcmMusic = new PCMMusicPlayer();
- _musicVolume = ConfMan.getInt("music_volume");
-
_sound = new SoundManager(this);
_bmv = new BMVPlayer();
diff --git a/engines/tinsel/tinsel.h b/engines/tinsel/tinsel.h
index 009f6fe26d..5c7a1cdfb2 100644
--- a/engines/tinsel/tinsel.h
+++ b/engines/tinsel/tinsel.h
@@ -219,9 +219,6 @@ public:
RectList _clipRects;
private:
- //MidiMusicPlayer *_midiMusic;
- int _musicVolume;
-
void NextGameCycle();
void CreateConstProcesses();
void RestartGame();
diff --git a/engines/touche/midi.cpp b/engines/touche/midi.cpp
index 4349a29bf5..c89375d876 100644
--- a/engines/touche/midi.cpp
+++ b/engines/touche/midi.cpp
@@ -32,9 +32,21 @@
namespace Touche {
-MidiPlayer::MidiPlayer()
- : _driver(0), _parser(0), _midiData(0), _isLooping(false), _isPlaying(false), _masterVolume(0) {
- memset(_channelsTable, 0, sizeof(_channelsTable));
+static const uint8 _gmToRol[256] = {
+ 0x01, 0x02, 0x03, 0x08, 0x04, 0x05, 0x11, 0x14, 0x66, 0x66, 0x66, 0x62, 0x69, 0x68, 0x67, 0x26,
+ 0x09, 0x0A, 0x0B, 0x0E, 0x0F, 0x10, 0x10, 0x10, 0x3C, 0x3D, 0x3D, 0x3D, 0x3D, 0x3E, 0x3F, 0x3F,
+ 0x47, 0x41, 0x42, 0x48, 0x45, 0x46, 0x1D, 0x1E, 0x35, 0x36, 0x37, 0x39, 0x33, 0x34, 0x3A, 0x71,
+ 0x31, 0x32, 0x31, 0x32, 0x23, 0x23, 0x23, 0x7B, 0x59, 0x5B, 0x5F, 0x5A, 0x5D, 0x60, 0x19, 0x1A,
+ 0x4F, 0x50, 0x51, 0x52, 0x55, 0x56, 0x57, 0x53, 0x4B, 0x49, 0x4D, 0x4E, 0x6F, 0x6C, 0x6D, 0x6E,
+ 0x30, 0x19, 0x4E, 0x2B, 0x28, 0x23, 0x19, 0x30, 0x21, 0x25, 0x1C, 0x21, 0x24, 0x22, 0x21, 0x22,
+ 0x2A, 0x25, 0x24, 0x26, 0x2E, 0x22, 0x29, 0x21, 0x40, 0x40, 0x6A, 0x6A, 0x68, 0x10, 0x35, 0x10,
+ 0x7F, 0x6B, 0x69, 0x75, 0x76, 0x72, 0x74, 0x01, 0x01, 0x70, 0x01, 0x7D, 0x7C, 0x01, 0x01, 0x01
+};
+
+
+MidiPlayer::MidiPlayer() {
+
+ // FIXME: Necessary?
memset(_channelsVolume, 0, sizeof(_channelsVolume));
MidiDriver::DeviceHandle dev = MidiDriver::detectDevice(MDT_MIDI | MDT_ADLIB | MDT_PREFER_GM);
@@ -42,9 +54,6 @@ MidiPlayer::MidiPlayer()
_driver = MidiDriver::createMidi(dev);
int ret = _driver->open();
if (ret == 0) {
- _parser = MidiParser::createParser_SMF();
- _parser->setMidiDriver(this);
- _parser->setTimerRate(_driver->getBaseTempo());
_driver->setTimerCallback(this, &timerCallback);
if (_nativeMT32)
@@ -54,25 +63,18 @@ MidiPlayer::MidiPlayer()
}
}
-MidiPlayer::~MidiPlayer() {
- stop();
-
+void MidiPlayer::play(Common::ReadStream &stream, int size, bool loop) {
Common::StackLock lock(_mutex);
- _driver->setTimerCallback(NULL, NULL);
- _driver->close();
- delete _driver;
- _driver = 0;
- _parser->setMidiDriver(NULL);
- delete _parser;
-}
-void MidiPlayer::play(Common::ReadStream &stream, int size, bool loop) {
stop();
- _midiData = (uint8 *)malloc(size);
+ _midiData = (byte *)malloc(size);
if (_midiData) {
stream.read(_midiData, size);
- Common::StackLock lock(_mutex);
+ _parser = MidiParser::createParser_SMF();
+ _parser->setMidiDriver(this);
+ _parser->setTimerRate(_driver->getBaseTempo());
+
_parser->loadMusic(_midiData, size);
_parser->setTrack(0);
_isLooping = loop;
@@ -80,31 +82,22 @@ void MidiPlayer::play(Common::ReadStream &stream, int size, bool loop) {
}
}
-void MidiPlayer::stop() {
- Common::StackLock lock(_mutex);
- if (_isPlaying) {
- _isPlaying = false;
- _parser->unloadMusic();
- free(_midiData);
- _midiData = 0;
- }
-}
-
-void MidiPlayer::updateTimer() {
- Common::StackLock lock(_mutex);
- if (_isPlaying) {
- _parser->onTimer();
- }
-}
-
void MidiPlayer::adjustVolume(int diff) {
setVolume(_masterVolume + diff);
}
void MidiPlayer::setVolume(int volume) {
+ // FIXME: This is almost identical to Audio::MidiPlayer::setVolume,
+ // the only difference is that this implementation will always
+ // transmit the volume change, even if the current _masterVolume
+ // equals the new master volume. This *could* make a difference in
+ // some situations.
+ // So, we should determine whether Touche requires this behavioral
+ // difference; and maybe also if other engines could benefit from it
+ // (as hypothetically, it might fix some subtle bugs?)
_masterVolume = CLIP(volume, 0, 255);
Common::StackLock lock(_mutex);
- for (int i = 0; i < NUM_CHANNELS; ++i) {
+ for (int i = 0; i < kNumChannels; ++i) {
if (_channelsTable[i]) {
_channelsTable[i]->volume(_channelsVolume[i] * _masterVolume / 255);
}
@@ -112,52 +105,10 @@ void MidiPlayer::setVolume(int volume) {
}
void MidiPlayer::send(uint32 b) {
- byte volume, ch = (byte)(b & 0xF);
- switch (b & 0xFFF0) {
- case 0x07B0: // volume change
- volume = (byte)((b >> 16) & 0x7F);
- _channelsVolume[ch] = volume;
- volume = volume * _masterVolume / 255;
- b = (b & 0xFF00FFFF) | (volume << 16);
- break;
- case 0x7BB0: // all notes off
- if (!_channelsTable[ch]) {
- // channel not yet allocated, no need to send the event
- return;
- }
- break;
- default:
- if ((b & 0xF0) == 0xC0 && _nativeMT32) { // program change
- b = (b & 0xFFFF00FF) | (_gmToRol[(b >> 8) & 0x7F] << 8);
- }
- break;
+ if ((b & 0xF0) == 0xC0 && _nativeMT32) { // program change
+ b = (b & 0xFFFF00FF) | (_gmToRol[(b >> 8) & 0x7F] << 8);
}
- if (!_channelsTable[ch]) {
- _channelsTable[ch] = (ch == 9) ? _driver->getPercussionChannel() : _driver->allocateChannel();
- }
- if (_channelsTable[ch]) {
- _channelsTable[ch]->send(b);
- }
-}
-
-void MidiPlayer::metaEvent(byte type, byte *data, uint16 length) {
- switch (type) {
- case 0x2F: // end of Track
- if (_isLooping) {
- _parser->jumpToTick(0);
- } else {
- stop();
- }
- break;
- default:
-// warning("Unhandled meta event: %02x", type);
- break;
- }
-}
-
-void MidiPlayer::timerCallback(void *p) {
- MidiPlayer *player = (MidiPlayer *)p;
- player->updateTimer();
+ Audio::MidiPlayer::send(b);
}
} // Touche namespace
diff --git a/engines/touche/midi.h b/engines/touche/midi.h
index bc5adc6b5f..f0f55e64e6 100644
--- a/engines/touche/midi.h
+++ b/engines/touche/midi.h
@@ -29,7 +29,7 @@
#include "common/util.h"
#include "common/mutex.h"
-#include "audio/mididrv.h"
+#include "audio/midiplayer.h"
class MidiParser;
@@ -39,44 +39,16 @@ namespace Common {
namespace Touche {
-class MidiPlayer : public MidiDriver_BASE {
+class MidiPlayer : public Audio::MidiPlayer {
public:
-
- enum {
- NUM_CHANNELS = 16
- };
-
MidiPlayer();
- ~MidiPlayer();
void play(Common::ReadStream &stream, int size, bool loop = false);
- void stop();
- void updateTimer();
void adjustVolume(int diff);
void setVolume(int volume);
- int getVolume() const { return _masterVolume; }
- void setLooping(bool loop) { _isLooping = loop; }
// MidiDriver_BASE interface
virtual void send(uint32 b);
- virtual void metaEvent(byte type, byte *data, uint16 length);
-
-private:
-
- static void timerCallback(void *p);
-
- MidiDriver *_driver;
- MidiParser *_parser;
- uint8 *_midiData;
- bool _isLooping;
- bool _isPlaying;
- int _masterVolume;
- bool _nativeMT32;
- MidiChannel *_channelsTable[NUM_CHANNELS];
- uint8 _channelsVolume[NUM_CHANNELS];
- Common::Mutex _mutex;
-
- static const uint8 _gmToRol[];
};
} // namespace Touche
diff --git a/engines/touche/staticres.cpp b/engines/touche/staticres.cpp
index a377a6e45f..74aa7954de 100644
--- a/engines/touche/staticres.cpp
+++ b/engines/touche/staticres.cpp
@@ -1822,15 +1822,4 @@ int Graphics::_fontSize = Graphics::_engFontSize;
const uint8 *Graphics::_fontData = Graphics::_engFontData;
-const uint8 MidiPlayer::_gmToRol[] = {
- 0x01, 0x02, 0x03, 0x08, 0x04, 0x05, 0x11, 0x14, 0x66, 0x66, 0x66, 0x62, 0x69, 0x68, 0x67, 0x26,
- 0x09, 0x0A, 0x0B, 0x0E, 0x0F, 0x10, 0x10, 0x10, 0x3C, 0x3D, 0x3D, 0x3D, 0x3D, 0x3E, 0x3F, 0x3F,
- 0x47, 0x41, 0x42, 0x48, 0x45, 0x46, 0x1D, 0x1E, 0x35, 0x36, 0x37, 0x39, 0x33, 0x34, 0x3A, 0x71,
- 0x31, 0x32, 0x31, 0x32, 0x23, 0x23, 0x23, 0x7B, 0x59, 0x5B, 0x5F, 0x5A, 0x5D, 0x60, 0x19, 0x1A,
- 0x4F, 0x50, 0x51, 0x52, 0x55, 0x56, 0x57, 0x53, 0x4B, 0x49, 0x4D, 0x4E, 0x6F, 0x6C, 0x6D, 0x6E,
- 0x30, 0x19, 0x4E, 0x2B, 0x28, 0x23, 0x19, 0x30, 0x21, 0x25, 0x1C, 0x21, 0x24, 0x22, 0x21, 0x22,
- 0x2A, 0x25, 0x24, 0x26, 0x2E, 0x22, 0x29, 0x21, 0x40, 0x40, 0x6A, 0x6A, 0x68, 0x10, 0x35, 0x10,
- 0x7F, 0x6B, 0x69, 0x75, 0x76, 0x72, 0x74, 0x01, 0x01, 0x70, 0x01, 0x7D, 0x7C, 0x01, 0x01, 0x01
-};
-
} // namespace Touche