aboutsummaryrefslogtreecommitdiff
path: root/engines/kyra
diff options
context:
space:
mode:
authorJohannes Schickel2009-05-27 14:40:37 +0000
committerJohannes Schickel2009-05-27 14:40:37 +0000
commit2bcf5c0552cf0778eb2642608134c6c0e4f3028e (patch)
tree50a6e0782d9137fd9a58ae304c4d57918a603ce3 /engines/kyra
parente0a059394975b0dc9c52f3152488ee3bad0594c0 (diff)
downloadscummvm-rg350-2bcf5c0552cf0778eb2642608134c6c0e4f3028e.tar.gz
scummvm-rg350-2bcf5c0552cf0778eb2642608134c6c0e4f3028e.tar.bz2
scummvm-rg350-2bcf5c0552cf0778eb2642608134c6c0e4f3028e.zip
- Moved Sound implementation declarations to the newly added file sound_intern.h
- Added support for PC Speaker sound in all Kyra1, Kyra2 and Lands of Lore - Slight cleanup svn-id: r40939
Diffstat (limited to 'engines/kyra')
-rw-r--r--engines/kyra/kyra_hof.cpp4
-rw-r--r--engines/kyra/kyra_hof.h2
-rw-r--r--engines/kyra/kyra_v1.cpp30
-rw-r--r--engines/kyra/lol.cpp2
-rw-r--r--engines/kyra/module.mk1
-rw-r--r--engines/kyra/script_hof.cpp7
-rw-r--r--engines/kyra/sound.h245
-rw-r--r--engines/kyra/sound_adlib.cpp2
-rw-r--r--engines/kyra/sound_intern.h353
-rw-r--r--engines/kyra/sound_lol.cpp2
-rw-r--r--engines/kyra/sound_midi.cpp57
-rw-r--r--engines/kyra/sound_pcspk.cpp390
-rw-r--r--engines/kyra/sound_towns.cpp2
-rw-r--r--engines/kyra/staticres.cpp32
14 files changed, 852 insertions, 277 deletions
diff --git a/engines/kyra/kyra_hof.cpp b/engines/kyra/kyra_hof.cpp
index eabc3ecb93..7e032fb46d 100644
--- a/engines/kyra/kyra_hof.cpp
+++ b/engines/kyra/kyra_hof.cpp
@@ -1529,7 +1529,9 @@ void KyraEngine_HoF::snd_playSoundEffect(int track, int volume) {
if (_sound->getSfxType() == Sound::kMidiMT32)
track = track < _mt32SfxMapSize ? _mt32SfxMap[track] - 1 : -1;
else if (_sound->getSfxType() == Sound::kMidiGM)
- track = track < _gmSfxMapSize ? _gmSfxMap[track] - 1: -1;
+ track = track < _gmSfxMapSize ? _gmSfxMap[track] - 1 : -1;
+ else if (_sound->getSfxType() == Sound::kPCSpkr)
+ track = track < _pcSpkSfxMapSize ? _pcSpkSfxMap[track] - 1 : -1;
if (track != -1)
KyraEngine_v1::snd_playSoundEffect(track);
diff --git a/engines/kyra/kyra_hof.h b/engines/kyra/kyra_hof.h
index 09a5906e31..6edcd364bc 100644
--- a/engines/kyra/kyra_hof.h
+++ b/engines/kyra/kyra_hof.h
@@ -309,6 +309,8 @@ protected:
static const int _mt32SfxMapSize;
static const int8 _gmSfxMap[];
static const int _gmSfxMapSize;
+ static const int8 _pcSpkSfxMap[];
+ static const int _pcSpkSfxMapSize;
AudioDataStruct _soundData[3];
protected:
diff --git a/engines/kyra/kyra_v1.cpp b/engines/kyra/kyra_v1.cpp
index d642918667..d5e0308a09 100644
--- a/engines/kyra/kyra_v1.cpp
+++ b/engines/kyra/kyra_v1.cpp
@@ -29,7 +29,7 @@
#include "sound/mixer.h"
#include "kyra/kyra_v1.h"
-#include "kyra/sound.h"
+#include "kyra/sound_intern.h"
#include "kyra/resource.h"
#include "kyra/screen.h"
#include "kyra/text.h"
@@ -103,7 +103,7 @@ Common::Error KyraEngine_v1::init() {
if (!_flags.useDigSound) {
// We prefer AdLib over MIDI, since generally AdLib is better supported
- int midiDriver = MidiDriver::detectMusicDriver(MDT_MIDI | MDT_ADLIB);
+ int midiDriver = MidiDriver::detectMusicDriver(MDT_PCSPK | MDT_MIDI | MDT_ADLIB);
if (_flags.platform == Common::kPlatformFMTowns) {
if (_flags.gameID == GI_KYRA1)
@@ -119,17 +119,31 @@ Common::Error KyraEngine_v1::init() {
_sound = new SoundAdlibPC(this, _mixer);
assert(_sound);
} else {
- bool native_mt32 = ((midiDriver == MD_MT32) || ConfMan.getBool("native_mt32"));
+ Sound::kType type;
+
+ if (midiDriver == MD_MT32 || ConfMan.getBool("native_mt32"))
+ type = Sound::kMidiMT32;
+ else if (midiDriver == MD_PCSPK)
+ type = Sound::kPCSpkr;
+ else
+ type = Sound::kMidiGM;
+
+
+ MidiDriver *driver = 0;
+
+ if (midiDriver == MD_PCSPK) {
+ driver = new MidiDriver_PCSpeaker(_mixer);
+ } else {
+ driver = MidiDriver::createMidi(midiDriver);
+ if (type == Sound::kMidiMT32)
+ driver->property(MidiDriver::PROP_CHANNEL_MASK, 0x03FE);
+ }
- MidiDriver *driver = MidiDriver::createMidi(midiDriver);
assert(driver);
- if (native_mt32)
- driver->property(MidiDriver::PROP_CHANNEL_MASK, 0x03FE);
- SoundMidiPC *soundMidiPc = new SoundMidiPC(this, _mixer, driver);
+ SoundMidiPC *soundMidiPc = new SoundMidiPC(this, _mixer, driver, type);
_sound = soundMidiPc;
assert(_sound);
- soundMidiPc->hasNativeMT32(native_mt32);
// Unlike some SCUMM games, it's not that the MIDI sounds are
// missing. It's just that at least at the time of writing they
diff --git a/engines/kyra/lol.cpp b/engines/kyra/lol.cpp
index 887c7a4e62..6a8bb3d3ff 100644
--- a/engines/kyra/lol.cpp
+++ b/engines/kyra/lol.cpp
@@ -432,7 +432,7 @@ Common::Error LoLEngine::init() {
KyraEngine_v1::init();
initStaticResource();
- _envSfxDistThreshold = (MidiDriver::detectMusicDriver(MDT_MIDI | MDT_ADLIB) == MD_ADLIB || ConfMan.getBool("multi_midi")) ? 15 : 3;
+ _envSfxDistThreshold = _sound->getSfxType() == Sound::kAdlib ? 15 : 3;
_gui = new GUI_LoL(this);
assert(_gui);
diff --git a/engines/kyra/module.mk b/engines/kyra/module.mk
index 6ff6cf115e..7b0c0dfb68 100644
--- a/engines/kyra/module.mk
+++ b/engines/kyra/module.mk
@@ -52,6 +52,7 @@ MODULE_OBJS := \
sound_adlib.o \
sound_digital.o \
sound_midi.o \
+ sound_pcspk.o \
sound_towns.o \
sound.o \
sound_lok.o \
diff --git a/engines/kyra/script_hof.cpp b/engines/kyra/script_hof.cpp
index 0327516b2e..23ec3bd406 100644
--- a/engines/kyra/script_hof.cpp
+++ b/engines/kyra/script_hof.cpp
@@ -829,7 +829,8 @@ int KyraEngine_HoF::o2_showLetter(EMCState *script) {
int KyraEngine_HoF::o2_playFireflyScore(EMCState *script) {
debugC(3, kDebugLevelScriptFuncs, "KyraEngine_HoF::o2_playFireflyScore(%p) ()", (const void *)script);
- if (_sound->getSfxType() == Sound::kAdlib || _sound->getSfxType() == Sound::kMidiMT32 || _sound->getSfxType() == Sound::kMidiGM) {
+ if (_sound->getSfxType() == Sound::kAdlib || _sound->getSfxType() == Sound::kPCSpkr ||
+ _sound->getSfxType() == Sound::kMidiMT32 || _sound->getSfxType() == Sound::kMidiGM) {
snd_playWanderScoreViaMap(86, 1);
return 1;
} else {
@@ -1328,6 +1329,8 @@ int KyraEngine_HoF::o2_getSfxDriver(EMCState *script) {
debugC(3, kDebugLevelScriptFuncs, "KyraEngine_HoF::o2_getSfxDriver(%p) ()", (const void *)script);
if (_sound->getSfxType() == Sound::kAdlib)
return 1;
+ else if (_sound->getSfxType() == Sound::kPCSpkr)
+ return 4;
else if (_sound->getSfxType() == Sound::kMidiMT32)
return 6;
else if (_sound->getSfxType() == Sound::kMidiGM)
@@ -1346,6 +1349,8 @@ int KyraEngine_HoF::o2_getMusicDriver(EMCState *script) {
debugC(3, kDebugLevelScriptFuncs, "KyraEngine_HoF::o2_getMusicDriver(%p) ()", (const void *)script);
if (_sound->getMusicType() == Sound::kAdlib)
return 1;
+ else if (_sound->getMusicType() == Sound::kPCSpkr)
+ return 4;
else if (_sound->getMusicType() == Sound::kMidiMT32)
return 6;
else if (_sound->getMusicType() == Sound::kMidiGM)
diff --git a/engines/kyra/sound.h b/engines/kyra/sound.h
index edacdb0411..eb40e40ab9 100644
--- a/engines/kyra/sound.h
+++ b/engines/kyra/sound.h
@@ -45,13 +45,9 @@
#include "kyra/kyra_v1.h"
#include "common/scummsys.h"
-#include "common/file.h"
-#include "common/mutex.h"
-#include "common/ptr.h"
+#include "common/str.h"
-#include "sound/midiparser.h"
#include "sound/mixer.h"
-#include "sound/softsynth/ym2612.h"
namespace Audio {
class AudioStream;
@@ -74,7 +70,8 @@ public:
kMidiMT32,
kMidiGM,
kTowns,
- kPC98
+ kPC98,
+ kPCSpkr
};
virtual kType getMusicType() const = 0;
@@ -261,242 +258,6 @@ private:
static const SpeechCodecs _supportedCodecs[];
};
-class AdlibDriver;
-
-/**
- * AdLib implementation of the sound output device.
- *
- * It uses a special sound file format special to
- * Dune II, Kyrandia 1 and 2. While Dune II and
- * Kyrandia 1 are using exact the same format, the
- * one of Kyrandia 2 slightly differs.
- *
- * See AdlibDriver for more information.
- * @see AdlibDriver
- */
-class SoundAdlibPC : public Sound {
-public:
- SoundAdlibPC(KyraEngine_v1 *vm, Audio::Mixer *mixer);
- ~SoundAdlibPC();
-
- kType getMusicType() const { return kAdlib; }
-
- bool init();
- void process();
-
- void loadSoundFile(uint file);
- void loadSoundFile(Common::String file);
-
- void playTrack(uint8 track);
- void haltTrack();
- bool isPlaying();
-
- void playSoundEffect(uint8 track);
-
- void beginFadeOut();
-private:
- void internalLoadFile(Common::String file);
-
- void play(uint8 track);
-
- void unk1();
- void unk2();
-
- AdlibDriver *_driver;
-
- bool _v2;
- uint8 _trackEntries[500];
- uint8 *_soundDataPtr;
- int _sfxPlayingSound;
-
- Common::String _soundFileLoaded;
-
- uint8 _sfxPriority;
- uint8 _sfxFourthByteOfSong;
-
- int _numSoundTriggers;
- const int *_soundTriggers;
-
- static const int _kyra1NumSoundTriggers;
- static const int _kyra1SoundTriggers[];
-};
-
-class MidiOutput;
-
-/**
- * MIDI output device.
- *
- * This device supports both MT-32 MIDI, as used in
- * Kyrandia 1 and 2, and GM MIDI, as used in Kyrandia 2.
- */
-class SoundMidiPC : public Sound {
-public:
- SoundMidiPC(KyraEngine_v1 *vm, Audio::Mixer *mixer, MidiDriver *driver);
- ~SoundMidiPC();
-
- kType getMusicType() const { return _nativeMT32 ? kMidiMT32 : kMidiGM; }
-
- bool init();
-
- void updateVolumeSettings();
-
- void loadSoundFile(uint file);
- void loadSoundFile(Common::String file);
- void loadSfxFile(Common::String file);
-
- void playTrack(uint8 track);
- void haltTrack();
- bool isPlaying();
-
- void playSoundEffect(uint8 track);
- void stopAllSoundEffects();
-
- void beginFadeOut();
-
- void hasNativeMT32(bool nativeMT32);
-private:
- static void onTimer(void *data);
-
- // Our channel handling
- int _musicVolume, _sfxVolume;
-
- uint32 _fadeStartTime;
- bool _fadeMusicOut;
-
- // Midi file related
- Common::String _mFileName, _sFileName;
- byte *_musicFile, *_sfxFile;
-
- MidiParser *_music;
- MidiParser *_sfx[3];
-
- // misc
- bool _nativeMT32;
- bool _useC55;
- MidiDriver *_driver;
- MidiOutput *_output;
-
- Common::Mutex _mutex;
-};
-
-class Towns_EuphonyDriver;
-class TownsPC98_OpnDriver;
-
-class SoundTowns : public MidiDriver, public Sound {
-public:
- SoundTowns(KyraEngine_v1 *vm, Audio::Mixer *mixer);
- ~SoundTowns();
-
- kType getMusicType() const { return kTowns; }
-
- bool init();
- void process();
-
- void loadSoundFile(uint file);
- void loadSoundFile(Common::String) {}
-
- void playTrack(uint8 track);
- void haltTrack();
-
- void playSoundEffect(uint8);
-
- void beginFadeOut();
-
- //MidiDriver interface implementation
- int open();
- void close();
- void send(uint32 b);
- void metaEvent(byte type, byte *data, uint16 length) {}
-
- void setTimerCallback(void *timerParam, void (*timerProc)(void *)) { }
- uint32 getBaseTempo(void);
-
- //Channel allocation functions
- MidiChannel *allocateChannel() { return 0; }
- MidiChannel *getPercussionChannel() { return 0; }
-
- static float calculatePhaseStep(int8 semiTone, int8 semiToneRootkey,
- uint32 sampleRate, uint32 outputRate, int32 pitchWheel);
-
-private:
- bool loadInstruments();
- void playEuphonyTrack(uint32 offset, int loop);
-
- static void onTimer(void *data);
-
- int _lastTrack;
- Audio::AudioStream *_currentSFX;
- Audio::SoundHandle _sfxHandle;
-
- uint _sfxFileIndex;
- uint8 *_sfxFileData;
-
- Towns_EuphonyDriver * _driver;
- MidiParser * _parser;
-
- Common::Mutex _mutex;
-
- const uint8 *_sfxBTTable;
- const uint8 *_sfxWDTable;
-};
-
-class SoundPC98 : public Sound {
-public:
- SoundPC98(KyraEngine_v1 *vm, Audio::Mixer *mixer);
- ~SoundPC98();
-
- virtual kType getMusicType() const { return kPC98; }
-
- bool init();
-
- void process() {}
- void loadSoundFile(uint file) {}
- void loadSoundFile(Common::String) {}
-
- void playTrack(uint8 track);
- void haltTrack();
- void beginFadeOut();
-
- int32 voicePlay(const char *file, Audio::SoundHandle *handle, uint8 volume, bool isSfx) { return -1; }
- void playSoundEffect(uint8);
-
-protected:
- int _lastTrack;
- uint8 *_musicTrackData;
- uint8 *_sfxTrackData;
- TownsPC98_OpnDriver *_driver;
-};
-
-class SoundTownsPC98_v2 : public Sound {
-public:
- SoundTownsPC98_v2(KyraEngine_v1 *vm, Audio::Mixer *mixer);
- ~SoundTownsPC98_v2();
-
- kType getMusicType() const { return _vm->gameFlags().platform == Common::kPlatformFMTowns ? kTowns : kPC98; }
-
- bool init();
- void process();
-
- void loadSoundFile(uint file) {}
- void loadSoundFile(Common::String file);
-
- void playTrack(uint8 track);
- void haltTrack();
- void beginFadeOut();
-
- int32 voicePlay(const char *file, Audio::SoundHandle *handle, uint8 volume, bool isSfx);
- void playSoundEffect(uint8 track);
-
-protected:
- Audio::AudioStream *_currentSFX;
- int _lastTrack;
- bool _useFmSfx;
-
- uint8 *_musicTrackData;
- uint8 *_sfxTrackData;
- TownsPC98_OpnDriver *_driver;
-};
-
class MixedSoundDriver : public Sound {
public:
MixedSoundDriver(KyraEngine_v1 *vm, Audio::Mixer *mixer, Sound *music, Sound *sfx) : Sound(vm, mixer), _music(music), _sfx(sfx) {}
diff --git a/engines/kyra/sound_adlib.cpp b/engines/kyra/sound_adlib.cpp
index d3dfd2b6af..78500eead7 100644
--- a/engines/kyra/sound_adlib.cpp
+++ b/engines/kyra/sound_adlib.cpp
@@ -43,7 +43,7 @@
#include "common/system.h"
#include "common/mutex.h"
#include "kyra/resource.h"
-#include "kyra/sound.h"
+#include "kyra/sound_intern.h"
#include "sound/mixer.h"
#include "sound/fmopl.h"
diff --git a/engines/kyra/sound_intern.h b/engines/kyra/sound_intern.h
new file mode 100644
index 0000000000..cb33c66f47
--- /dev/null
+++ b/engines/kyra/sound_intern.h
@@ -0,0 +1,353 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef KYRA_SOUND_INTERN_H
+#define KYRA_SOUND_INTERN_H
+
+#include "kyra/sound.h"
+
+#include "common/mutex.h"
+
+#include "sound/softsynth/ym2612.h"
+#include "sound/softsynth/emumidi.h"
+#include "sound/midiparser.h"
+
+namespace Audio {
+class PCSpeaker;
+} // end of namespace Audio
+
+namespace Kyra {
+class AdlibDriver;
+
+/**
+ * AdLib implementation of the sound output device.
+ *
+ * It uses a special sound file format special to
+ * Dune II, Kyrandia 1 and 2. While Dune II and
+ * Kyrandia 1 are using exact the same format, the
+ * one of Kyrandia 2 slightly differs.
+ *
+ * See AdlibDriver for more information.
+ * @see AdlibDriver
+ */
+class SoundAdlibPC : public Sound {
+public:
+ SoundAdlibPC(KyraEngine_v1 *vm, Audio::Mixer *mixer);
+ ~SoundAdlibPC();
+
+ kType getMusicType() const { return kAdlib; }
+
+ bool init();
+ void process();
+
+ void loadSoundFile(uint file);
+ void loadSoundFile(Common::String file);
+
+ void playTrack(uint8 track);
+ void haltTrack();
+ bool isPlaying();
+
+ void playSoundEffect(uint8 track);
+
+ void beginFadeOut();
+private:
+ void internalLoadFile(Common::String file);
+
+ void play(uint8 track);
+
+ void unk1();
+ void unk2();
+
+ AdlibDriver *_driver;
+
+ bool _v2;
+ uint8 _trackEntries[500];
+ uint8 *_soundDataPtr;
+ int _sfxPlayingSound;
+
+ Common::String _soundFileLoaded;
+
+ uint8 _sfxPriority;
+ uint8 _sfxFourthByteOfSong;
+
+ int _numSoundTriggers;
+ const int *_soundTriggers;
+
+ static const int _kyra1NumSoundTriggers;
+ static const int _kyra1SoundTriggers[];
+};
+
+class MidiOutput;
+
+/**
+ * MIDI output device.
+ *
+ * This device supports both MT-32 MIDI, as used in
+ * Kyrandia 1 and 2, and GM MIDI, as used in Kyrandia 2.
+ */
+class SoundMidiPC : public Sound {
+public:
+ SoundMidiPC(KyraEngine_v1 *vm, Audio::Mixer *mixer, MidiDriver *driver, kType type);
+ ~SoundMidiPC();
+
+ kType getMusicType() const { return _type; }
+
+ bool init();
+
+ void updateVolumeSettings();
+
+ void loadSoundFile(uint file);
+ void loadSoundFile(Common::String file);
+ void loadSfxFile(Common::String file);
+
+ void playTrack(uint8 track);
+ void haltTrack();
+ bool isPlaying();
+
+ void playSoundEffect(uint8 track);
+ void stopAllSoundEffects();
+
+ void beginFadeOut();
+private:
+ static void onTimer(void *data);
+
+ // Our channel handling
+ int _musicVolume, _sfxVolume;
+
+ uint32 _fadeStartTime;
+ bool _fadeMusicOut;
+
+ // Midi file related
+ Common::String _mFileName, _sFileName;
+ byte *_musicFile, *_sfxFile;
+
+ MidiParser *_music;
+ MidiParser *_sfx[3];
+
+ // misc
+ kType _type;
+ Common::String getFileName(const Common::String &str);
+
+ bool _nativeMT32;
+ MidiDriver *_driver;
+ MidiOutput *_output;
+
+ Common::Mutex _mutex;
+};
+
+class Towns_EuphonyDriver;
+class TownsPC98_OpnDriver;
+
+class SoundTowns : public MidiDriver, public Sound {
+public:
+ SoundTowns(KyraEngine_v1 *vm, Audio::Mixer *mixer);
+ ~SoundTowns();
+
+ kType getMusicType() const { return kTowns; }
+
+ bool init();
+ void process();
+
+ void loadSoundFile(uint file);
+ void loadSoundFile(Common::String) {}
+
+ void playTrack(uint8 track);
+ void haltTrack();
+
+ void playSoundEffect(uint8);
+
+ void beginFadeOut();
+
+ //MidiDriver interface implementation
+ int open();
+ void close();
+ void send(uint32 b);
+ void metaEvent(byte type, byte *data, uint16 length) {}
+
+ void setTimerCallback(void *timerParam, void (*timerProc)(void *)) { }
+ uint32 getBaseTempo(void);
+
+ //Channel allocation functions
+ MidiChannel *allocateChannel() { return 0; }
+ MidiChannel *getPercussionChannel() { return 0; }
+
+ static float calculatePhaseStep(int8 semiTone, int8 semiToneRootkey,
+ uint32 sampleRate, uint32 outputRate, int32 pitchWheel);
+
+private:
+ bool loadInstruments();
+ void playEuphonyTrack(uint32 offset, int loop);
+
+ static void onTimer(void *data);
+
+ int _lastTrack;
+ Audio::AudioStream *_currentSFX;
+ Audio::SoundHandle _sfxHandle;
+
+ uint _sfxFileIndex;
+ uint8 *_sfxFileData;
+
+ Towns_EuphonyDriver * _driver;
+ MidiParser * _parser;
+
+ Common::Mutex _mutex;
+
+ const uint8 *_sfxBTTable;
+ const uint8 *_sfxWDTable;
+};
+
+class SoundPC98 : public Sound {
+public:
+ SoundPC98(KyraEngine_v1 *vm, Audio::Mixer *mixer);
+ ~SoundPC98();
+
+ virtual kType getMusicType() const { return kPC98; }
+
+ bool init();
+
+ void process() {}
+ void loadSoundFile(uint file) {}
+ void loadSoundFile(Common::String) {}
+
+ void playTrack(uint8 track);
+ void haltTrack();
+ void beginFadeOut();
+
+ int32 voicePlay(const char *file, Audio::SoundHandle *handle, uint8 volume, bool isSfx) { return -1; }
+ void playSoundEffect(uint8);
+
+protected:
+ int _lastTrack;
+ uint8 *_musicTrackData;
+ uint8 *_sfxTrackData;
+ TownsPC98_OpnDriver *_driver;
+};
+
+class SoundTownsPC98_v2 : public Sound {
+public:
+ SoundTownsPC98_v2(KyraEngine_v1 *vm, Audio::Mixer *mixer);
+ ~SoundTownsPC98_v2();
+
+ kType getMusicType() const { return _vm->gameFlags().platform == Common::kPlatformFMTowns ? kTowns : kPC98; }
+
+ bool init();
+ void process();
+
+ void loadSoundFile(uint file) {}
+ void loadSoundFile(Common::String file);
+
+ void playTrack(uint8 track);
+ void haltTrack();
+ void beginFadeOut();
+
+ int32 voicePlay(const char *file, Audio::SoundHandle *handle, uint8 volume, bool isSfx);
+ void playSoundEffect(uint8 track);
+
+protected:
+ Audio::AudioStream *_currentSFX;
+ int _lastTrack;
+ bool _useFmSfx;
+
+ uint8 *_musicTrackData;
+ uint8 *_sfxTrackData;
+ TownsPC98_OpnDriver *_driver;
+};
+
+// PC Speaker MIDI driver
+class MidiDriver_PCSpeaker : public MidiDriver_Emulated {
+public:
+ MidiDriver_PCSpeaker(Audio::Mixer *mixer);
+ ~MidiDriver_PCSpeaker();
+
+ // MidiDriver interface
+ void close() {}
+
+ void send(uint32 data);
+
+ MidiChannel *allocateChannel() { return 0; }
+ MidiChannel *getPercussionChannel() { return 0; }
+
+ // MidiDriver_Emulated interface
+ void generateSamples(int16 *buffer, int numSamples);
+
+ // AudioStream interface
+ bool isStereo() const { return false; }
+ int getRate() const { return _rate; }
+private:
+ Common::Mutex _mutex;
+ Audio::PCSpeaker *_speaker;
+ int _rate;
+
+ struct Channel {
+ uint8 volume;
+ uint8 pitchBendLow, pitchBendHigh;
+ uint8 expression;
+ uint8 hold;
+ uint8 modulation;
+ uint8 voiceProtect;
+ uint8 noteCount;
+ } _channel[16];
+
+ void resetController(int channel);
+
+ struct Note {
+ bool enabled;
+ uint8 hardwareChannel;
+ uint8 midiChannel;
+ uint8 note1, note2;
+ uint8 velocity;
+ bool processHold;
+ uint8 flags;
+ uint8 hardwareFlags;
+ uint16 priority;
+ int16 modulation;
+ uint16 precedence;
+ } _note[2];
+
+ void noteOn(int channel, int note, int velocity);
+ void noteOff(int channel, int note);
+
+ void turnNoteOn(int note);
+ void overwriteNote(int note);
+ void turnNoteOff(int note);
+
+ void setupTone(int note);
+
+ uint16 _countdown;
+ uint8 _hardwareChannel[1];
+ bool _modulationFlag;
+
+ uint8 _timerValue;
+ void onTimer();
+
+ static const uint8 _velocityTable[];
+ static const uint8 _noteTable1[];
+ static const uint8 _noteTable2[];
+};
+
+} // end of namespace Kyra
+
+#endif
+
diff --git a/engines/kyra/sound_lol.cpp b/engines/kyra/sound_lol.cpp
index 72624ef789..e641c3ecac 100644
--- a/engines/kyra/sound_lol.cpp
+++ b/engines/kyra/sound_lol.cpp
@@ -29,6 +29,8 @@
#include "kyra/lol.h"
#include "kyra/resource.h"
+#include "sound/audiostream.h"
+
namespace Kyra {
bool LoLEngine::snd_playCharacterSpeech(int id, int8 speaker, int) {
diff --git a/engines/kyra/sound_midi.cpp b/engines/kyra/sound_midi.cpp
index 039ee76eba..218b0d161d 100644
--- a/engines/kyra/sound_midi.cpp
+++ b/engines/kyra/sound_midi.cpp
@@ -23,7 +23,7 @@
*
*/
-#include "kyra/sound.h"
+#include "kyra/sound_intern.h"
#include "kyra/resource.h"
#include "common/system.h"
@@ -438,7 +438,7 @@ void MidiOutput::stopNotesOnChannel(int channel) {
#pragma mark -
-SoundMidiPC::SoundMidiPC(KyraEngine_v1 *vm, Audio::Mixer *mixer, MidiDriver *driver) : Sound(vm, mixer) {
+SoundMidiPC::SoundMidiPC(KyraEngine_v1 *vm, Audio::Mixer *mixer, MidiDriver *driver, kType type) : Sound(vm, mixer) {
_driver = driver;
_output = 0;
@@ -453,6 +453,20 @@ SoundMidiPC::SoundMidiPC(KyraEngine_v1 *vm, Audio::Mixer *mixer, MidiDriver *dri
_musicVolume = _sfxVolume = 0;
_fadeMusicOut = false;
+
+ _type = type;
+ assert(_type == kMidiMT32 || _type == kMidiGM || _type == kPCSpkr);
+
+ // Only General MIDI isn't a Roland MT-32 MIDI implemenation,
+ // even the PC Speaker driver is a Roland MT-32 based MIDI implementation.
+ // Thus we set "_nativeMT32" for all types except Gerneral MIDI to true.
+ _nativeMT32 = (_type != kMidiGM);
+
+ // KYRA1 does not include any General MIDI tracks, thus we have
+ // to overwrite the internal type with MT32 to get the correct
+ // file extension.
+ if (_vm->game() == GI_KYRA1 && _type == kMidiGM)
+ _type = kMidiMT32;
}
SoundMidiPC::~SoundMidiPC() {
@@ -469,23 +483,10 @@ SoundMidiPC::~SoundMidiPC() {
delete[] _sfxFile;
delete[] _musicFile;
-
- _nativeMT32 = false;
- _useC55 = false;
-}
-
-void SoundMidiPC::hasNativeMT32(bool nativeMT32) {
- _nativeMT32 = nativeMT32;
-
- // C55 is XMIDI for General MIDI instruments
- if (!_nativeMT32 && _vm->game() != GI_KYRA1)
- _useC55 = true;
- else
- _useC55 = false;
}
bool SoundMidiPC::init() {
- _output = new MidiOutput(_vm->_system, _driver, _nativeMT32, !_useC55);
+ _output = new MidiOutput(_vm->_system, _driver, _nativeMT32, (_type != kMidiGM));
assert(_output);
updateVolumeSettings();
@@ -502,7 +503,7 @@ bool SoundMidiPC::init() {
_output->setTimerCallback(this, SoundMidiPC::onTimer);
- if (_nativeMT32) {
+ if (_nativeMT32 && _type == kMidiMT32) {
const char *midiFile = 0;
const char *pakFile = 0;
if (_vm->gameFlags().gameID == GI_KYRA1) {
@@ -581,9 +582,7 @@ void SoundMidiPC::loadSoundFile(uint file) {
void SoundMidiPC::loadSoundFile(Common::String file) {
Common::StackLock lock(_mutex);
-
- file += _useC55 ? ".C55" : ".XMI";
- file.toUppercase();
+ file = getFileName(file);
if (_mFileName == file)
return;
@@ -624,8 +623,7 @@ void SoundMidiPC::loadSfxFile(Common::String file) {
if (_vm->gameFlags().gameID == GI_KYRA1)
return;
- file += _useC55 ? ".C55" : ".XMI";
- file.toUppercase();
+ file = getFileName(file);
if (_sFileName == file)
return;
@@ -740,5 +738,20 @@ void SoundMidiPC::onTimer(void *data) {
}
}
+Common::String SoundMidiPC::getFileName(const Common::String &str) {
+ Common::String file = str;
+ if (_type == kMidiMT32)
+ file += ".XMI";
+ else if (_type == kMidiGM)
+ file += ".C55";
+ else if (_type == kPCSpkr)
+ file += ".PCS";
+
+ if (_vm->resource()->exists(file.c_str()))
+ return file;
+
+ return str + ".XMI";
+}
+
} // end of namespace Kyra
diff --git a/engines/kyra/sound_pcspk.cpp b/engines/kyra/sound_pcspk.cpp
new file mode 100644
index 0000000000..98569db5e2
--- /dev/null
+++ b/engines/kyra/sound_pcspk.cpp
@@ -0,0 +1,390 @@
+/*
+ * 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.
+ *
+ * LGPL License
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library 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
+ * Lesser General Public License for more details.
+
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "kyra/sound_intern.h"
+
+#include "sound/mixer.h"
+#include "sound/softsynth/pcspk.h"
+
+namespace Kyra {
+
+MidiDriver_PCSpeaker::MidiDriver_PCSpeaker(Audio::Mixer *mixer)
+ : MidiDriver_Emulated(mixer), _rate(mixer->getOutputRate()) {
+ _timerValue = 0;
+ memset(_channel, 0, sizeof(_channel));
+ memset(_note, 0, sizeof(_note));
+
+ for (int i = 0; i < 2; ++i)
+ _note[i].hardwareChannel = 0xFF;
+
+ _speaker = new Audio::PCSpeaker(_rate);
+ assert(_speaker);
+ _mixer->playInputStream(Audio::Mixer::kMusicSoundType, &_mixerSoundHandle, this, -1, Audio::Mixer::kMaxChannelVolume, 0, false, true);
+
+ _countdown = 0xFFFF;
+ _hardwareChannel[0] = 0xFF;
+ _modulationFlag = false;
+}
+
+MidiDriver_PCSpeaker::~MidiDriver_PCSpeaker() {
+ _mixer->stopHandle(_mixerSoundHandle);
+ delete _speaker;
+ _speaker = 0;
+}
+
+void MidiDriver_PCSpeaker::send(uint32 data) {
+ Common::StackLock lock(_mutex);
+
+ uint8 channel = data & 0x0F;
+ uint8 param1 = (data >> 8) & 0xFF;
+ uint8 param2 = (data >> 16) & 0xFF;
+
+ uint8 flags = 0;
+
+ switch (data & 0xF0) {
+ case 0x80: // note off
+ noteOff(channel, param1);
+ return;
+
+ case 0x90: // note on
+ if (channel > 1)
+ return;
+
+ if (param2)
+ noteOn(channel, param1, param2);
+ else
+ noteOff(channel, param1);
+ return;
+
+ case 0xB0: // controller
+ switch (param1) {
+ case 0x01: // modulation
+ _channel[channel].modulation = param2;
+ flags = 0x00;
+ break;
+
+ case 0x07: // volume
+ _channel[channel].volume = param2;
+ flags = 0x40;
+ break;
+
+ case 0x40: // hold
+ _channel[channel].hold = param2;
+ if (param2 < 0x40)
+ resetController(channel);
+ return;
+
+ case 0x70: // voice protect
+ _channel[channel].voiceProtect = param2;
+ return;
+
+ case 0x79: // all notes off
+ _channel[channel].hold = 0;
+ resetController(channel);
+ _channel[channel].modulation = 0;
+ _channel[channel].expression = 0x7F;
+ _channel[channel].pitchBendLow = 0;
+ _channel[channel].pitchBendHigh = 0x40;
+ flags = 0x41;
+ break;
+
+ case 0xB0: // expression
+ _channel[channel].expression = param2;
+ flags = 0x40;
+ break;
+
+ default:
+ return;
+ }
+ break;
+
+ case 0xE0: // pitch bend
+ flags = 0x01;
+ _channel[channel].pitchBendLow = param1;
+ _channel[channel].pitchBendHigh = param2;
+ break;
+
+ default:
+ return;
+ }
+
+ for (int i = 0; i < 2; ++i) {
+ if (_note[i].enabled && _note[i].midiChannel == channel) {
+ _note[i].flags |= flags;
+ setupTone(i);
+ }
+ }
+}
+
+void MidiDriver_PCSpeaker::resetController(int channel) {
+ for (int i = 0; i < 2; ++i) {
+ if (_note[i].enabled && _note[i].midiChannel == channel && _note[i].processHold)
+ noteOff(channel, _note[i].note2);
+ }
+}
+
+void MidiDriver_PCSpeaker::noteOn(int channel, int note, int velocity) {
+ int n = 0;
+
+ while (n < 2 && _note[n].enabled)
+ ++n;
+
+ if (n >= 2)
+ return;
+
+ _note[n].midiChannel = channel;
+ _note[n].note1 = _note[n].note2 = note;
+ _note[n].velocity = _velocityTable[((uint8)velocity) >> 3];
+ _note[n].enabled = true;
+ _note[n].processHold = false;
+ _note[n].hardwareFlags = 0x20;
+ _note[n].priority = 0x7FFF;
+ _note[n].flags = 0x41;
+
+ turnNoteOn(n);
+}
+
+void MidiDriver_PCSpeaker::turnNoteOn(int note) {
+ if (_hardwareChannel[0] == 0xFF) {
+ _note[note].hardwareChannel = 0;
+ ++_channel[_note[note].midiChannel].noteCount;
+ _hardwareChannel[0] = _note[note].midiChannel;
+ _note[note].flags = 0x41;
+
+ setupTone(note);
+ } else {
+ overwriteNote(note);
+ }
+}
+
+void MidiDriver_PCSpeaker::overwriteNote(int note) {
+ int totalNotes = 0;
+ for (int i = 0; i < 2; ++i) {
+ if (_note[i].enabled) {
+ ++totalNotes;
+ const int channel = _note[i].midiChannel;
+
+ uint16 priority = 0xFFFF;
+ if (_channel[channel].voiceProtect < 0x40)
+ priority = _note[i].priority;
+
+ if (_channel[channel].noteCount > priority)
+ priority = 0;
+ else
+ priority -= _channel[channel].noteCount;
+
+ _note[i].precedence = priority;
+ }
+ }
+
+ if (totalNotes <= 1)
+ return;
+
+ do {
+ uint16 maxValue = 0;
+ uint16 minValue = 0xFFFF;
+ int newNote = 0;
+
+ for (int i = 0; i < 2; ++i) {
+ if (_note[i].enabled) {
+ if (_note[i].hardwareChannel == 0xFF) {
+ if (_note[i].precedence >= maxValue) {
+ maxValue = _note[i].precedence;
+ newNote = i;
+ }
+ } else {
+ if (_note[i].precedence <= minValue) {
+ minValue = _note[i].precedence;
+ note = i;
+ }
+ }
+ }
+ }
+
+ if (maxValue < minValue)
+ return;
+
+ turnNoteOff(_note[note].hardwareChannel);
+ _note[note].enabled = false;
+
+ _note[newNote].hardwareChannel = _note[note].hardwareChannel;
+ ++_channel[_note[newNote].midiChannel].noteCount;
+ _hardwareChannel[_note[note].hardwareChannel] = _note[newNote].midiChannel;
+ _note[newNote].flags = 0x41;
+
+ setupTone(newNote);
+ } while (--totalNotes);
+}
+
+void MidiDriver_PCSpeaker::noteOff(int channel, int note) {
+ for (int i = 0; i < 2; ++i) {
+ if (_note[i].enabled && _note[i].note1 == note && _note[i].midiChannel == channel) {
+ if (_channel[i].hold < 0x40) {
+ turnNoteOff(i);
+ _note[i].enabled = false;
+ } else {
+ _note[i].processHold = true;
+ }
+ }
+ }
+}
+
+void MidiDriver_PCSpeaker::turnNoteOff(int note) {
+ if (_note[note].hardwareChannel != 0xFF) {
+ _note[note].hardwareFlags &= 0xDF;
+ _note[note].flags |= 1;
+
+ setupTone(note);
+
+ --_channel[_note[note].midiChannel].noteCount;
+
+ _hardwareChannel[_note[note].hardwareChannel] = 0xFF;
+ _note[note].hardwareChannel = 0xFF;
+ }
+}
+
+void MidiDriver_PCSpeaker::setupTone(int note) {
+ if (_note[note].hardwareChannel == 0xFF)
+ return;
+
+ if (_note[note].flags & 0x40)
+ _note[note].flags &= 0xBF;
+ if (!(_note[note].flags & 0x01))
+ return;
+
+ if (!(_note[note].hardwareFlags & 0x20)) {
+ _speaker->stop();
+ } else {
+ const int midiChannel = _note[note].midiChannel;
+ uint16 pitchBend = (_channel[midiChannel].pitchBendHigh << 7) | _channel[midiChannel].pitchBendLow;
+
+ int noteValue = _note[note].note2;
+
+ noteValue -= 24;
+ do {
+ noteValue += 12;
+ } while (noteValue < 0);
+
+ noteValue += 12;
+ do {
+ noteValue -= 12;
+ } while (noteValue > 95);
+
+ int16 modulation = _note[note].modulation;
+
+ int tableIndex = MAX(noteValue - 12, 0);
+ uint16 note1 = (_noteTable2[tableIndex] << 8) | _noteTable1[tableIndex];
+ tableIndex = MIN(noteValue + 12, 95);
+ uint16 note2 = (_noteTable2[tableIndex] << 8) | _noteTable1[tableIndex];
+ uint16 note3 = (_noteTable2[noteValue] << 8) | _noteTable1[noteValue];
+
+ int32 countdown = pitchBend - 0x2000;
+ countdown += modulation;
+
+ if (countdown >= 0)
+ countdown *= (note2 - note3);
+ else
+ countdown *= (note3 - note1);
+
+ countdown /= 0x2000;
+ countdown += note3;
+
+ countdown = uint16(countdown & 0xFFFF);
+ if (countdown != _countdown)
+ _countdown = countdown;
+
+ _speaker->play(Audio::PCSpeaker::kWaveFormSquare, 1193180 / _countdown, -1);
+ }
+
+ _note[note].flags &= 0xFE;
+}
+
+void MidiDriver_PCSpeaker::generateSamples(int16 *buffer, int numSamples) {
+ Common::StackLock lock(_mutex);
+ _speaker->readBuffer(buffer, numSamples);
+}
+
+void MidiDriver_PCSpeaker::onTimer() {
+ /*Common::StackLock lock(_mutex);
+
+ _timerValue += 20;
+ if (_timerValue < 120)
+ return;
+ _timerValue -= 120;
+
+ _modulationFlag = !_modulationFlag;
+ for (int i = 0; i < 2; ++i) {
+ if (_note[i].enabled) {
+ uint16 modValue = 5 * _channel[_note[i].midiChannel].modulation;
+ if (_modulationFlag)
+ modValue = -modValue;
+ _note[i].modulation = modValue;
+ _note[i].flags |= 1;
+
+ setupTone(i);
+ }
+ }*/
+}
+
+const uint8 MidiDriver_PCSpeaker::_velocityTable[] = {
+ 0x52, 0x55, 0x58, 0x5B, 0x5E, 0x61, 0x64, 0x67,
+ 0x6A, 0x6D, 0x70, 0x73, 0x76, 0x79, 0x7C, 0x7F
+};
+
+const uint8 MidiDriver_PCSpeaker::_noteTable1[] = {
+ 0x88, 0xB5, 0x4E, 0x40, 0x41, 0xCD, 0xC4, 0x3D,
+ 0x43, 0x7C, 0x2A, 0xD6, 0x88, 0xB5, 0xFF, 0xD1,
+ 0x20, 0xA7, 0xE2, 0x1E, 0xCE, 0xBE, 0xF2, 0x8A,
+ 0x44, 0x41, 0x7F, 0xE8, 0x90, 0x63, 0x63, 0x8F,
+ 0xE7, 0x5F, 0x01, 0xBD, 0xA2, 0xA0, 0xBF, 0xF4,
+ 0x48, 0xB1, 0x31, 0xC7, 0x70, 0x2F, 0xFE, 0xE0,
+ 0xD1, 0xD0, 0xDE, 0xFB, 0x24, 0x58, 0x98, 0xE3,
+ 0x39, 0x97, 0xFF, 0x6F, 0xE8, 0x68, 0xEF, 0x7D,
+ 0x11, 0xAC, 0x4C, 0xF1, 0x9C, 0x4B, 0xFF, 0xB7,
+ 0x74, 0x34, 0xF7, 0xBE, 0x88, 0x56, 0x26, 0xF8,
+ 0xCE, 0xA5, 0x7F, 0x5B, 0x3A, 0x1A, 0xFB, 0xDF,
+ 0xC4, 0xAB, 0x93, 0x7C, 0x67, 0x52, 0x3F, 0x2D
+};
+
+const uint8 MidiDriver_PCSpeaker::_noteTable2[] = {
+ 0x8E, 0x86, 0xFD, 0xF0, 0xE2, 0xD5, 0xC9, 0xBE,
+ 0xB3, 0xA9, 0xA0, 0x96, 0x8E, 0x86, 0x7E, 0x77,
+ 0x71, 0x6A, 0x64, 0x5F, 0x59, 0x54, 0x4F, 0x4B,
+ 0x47, 0x43, 0x3F, 0x3B, 0x38, 0x35, 0x32, 0x2F,
+ 0x2C, 0x2A, 0x28, 0x25, 0x23, 0x21, 0x1F, 0x1D,
+ 0x1C, 0x1A, 0x19, 0x17, 0x16, 0x15, 0x13, 0x12,
+ 0x11, 0x10, 0x0F, 0x0E, 0x0E, 0x0D, 0x0C, 0x0B,
+ 0x0B, 0x0A, 0x09, 0x09, 0x08, 0x08, 0x07, 0x07,
+ 0x07, 0x06, 0x06, 0x05, 0x05, 0x05, 0x04, 0x04,
+ 0x04, 0x04, 0x03, 0x03, 0x03, 0x03, 0x03, 0x02,
+ 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01
+};
+
+} // end of namespace Kyra
+
diff --git a/engines/kyra/sound_towns.cpp b/engines/kyra/sound_towns.cpp
index 443506a511..d6a1bacafc 100644
--- a/engines/kyra/sound_towns.cpp
+++ b/engines/kyra/sound_towns.cpp
@@ -25,7 +25,7 @@
#include "common/system.h"
#include "kyra/resource.h"
-#include "kyra/sound.h"
+#include "kyra/sound_intern.h"
#include "kyra/screen.h"
#include "sound/audiocd.h"
diff --git a/engines/kyra/staticres.cpp b/engines/kyra/staticres.cpp
index 02c432df2a..4572ffee69 100644
--- a/engines/kyra/staticres.cpp
+++ b/engines/kyra/staticres.cpp
@@ -2390,6 +2390,38 @@ const int8 KyraEngine_HoF::_gmSfxMap[] = {
const int KyraEngine_HoF::_gmSfxMapSize = ARRAYSIZE(KyraEngine_HoF::_gmSfxMap);
+const int8 KyraEngine_HoF::_pcSpkSfxMap[] = {
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, 0, 1, 2, 3, 4,
+ 5, 6, -1, 7, 8, 9, 10, -1,
+ 6, -1, -1, 11, -1, 12, -1, -1,
+ -1, -1, -1, 13, -1, 39, 14, 15,
+ 3, 16, 16, -1, -1, -1, 17, 18,
+ 5, -1, -1, -1, -1, -1, 19, 20,
+ 21, -1, 22, 23, -1, -1, -1, -1,
+ -1, -1, 39, -1, 24, 24, 25, 26,
+ 27, 28, 29, 30, 31, 32, -1, -1,
+ -1, 2, -1, -1, -1, -1, -1, 21,
+ 10, -1, -1, -1, -1, 17, -1, 17,
+ 40, -1, 18, 38, -1, 40, 33, -1,
+ 34, 35, 36, 37, 38, 39, 40, 41,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 42, 43, 44, 45, -1, -1,
+ -1, -1, -1, -1, 46, -1, 5, 47,
+ 48, -1, -1, -1, -1, -1, 49, 50,
+ -1, 40, -1, 24, -1, -1, 43, -1,
+ -1, 38, -1, -1, -1, 51, -1, -1,
+ -1, -1, -1, -1, -1, 9, -1, 52,
+ 53, 40, -1, -1, -1, -1, -1, -1,
+ -1, -1, 50, -1, -1, -1, 11, 54,
+ 5, -1, -1, -1, -1, 11, 7, 55,
+ 8, 36, -1, -1, -1, -1, -1, -1,
+ 11, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 24
+};
+
+const int KyraEngine_HoF::_pcSpkSfxMapSize = ARRAYSIZE(KyraEngine_HoF::_pcSpkSfxMap);
+
void KyraEngine_HoF::initInventoryButtonList() {
delete[] _inventoryButtons;