aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--kyra/kyra.cpp76
-rw-r--r--kyra/kyra.h17
-rw-r--r--kyra/sound.cpp165
-rw-r--r--kyra/sound.h88
-rw-r--r--kyra/staticres.cpp15
-rw-r--r--sound/midiparser_xmidi.cpp6
6 files changed, 298 insertions, 69 deletions
diff --git a/kyra/kyra.cpp b/kyra/kyra.cpp
index ea67e701e1..ec4caac12f 100644
--- a/kyra/kyra.cpp
+++ b/kyra/kyra.cpp
@@ -142,7 +142,8 @@ int KyraEngine::init(GameDetector &detector) {
_system->initSize(320, 200);
_system->endGFXTransaction();
- int midiDrv = MidiDriver::detectMusicDriver(MDT_NATIVE | MDT_ADLIB | MDT_PREFER_NATIVE);
+ // for now we prefer MIDI-to-Adlib conversion over native midi
+ int midiDrv = MidiDriver::detectMusicDriver(MDT_NATIVE | MDT_ADLIB/* | MDT_PREFER_NATIVE*/);
bool native_mt32 = (ConfMan.getBool("native_mt32") || (midiDrv == MD_MT32));
MidiDriver *driver = MidiDriver::createMidi(midiDrv);
@@ -158,7 +159,7 @@ int KyraEngine::init(GameDetector &detector) {
assert(_midi);
_midi->hasNativeMT32(native_mt32);
_midi->setVolume(255);
-
+
_res = new Resource(this);
assert(_res);
_screen = new Screen(this, _system);
@@ -504,13 +505,14 @@ void KyraEngine::seq_intro() {
_skipIntroFlag = true; // only true if user already played the game once
_seq_copyViewOffs = true;
_screen->setFont(Screen::FID_8_FNT);
-// snd_kyraPlayTheme(0);
+ snd_playTheme(MUSIC_INTRO, 2);
+ snd_setSoundEffectFile(MUSIC_INTRO);
setTalkCoords(144);
for (int i = 0; i < ARRAYSIZE(introProcTable) && !seq_skipSequence(); ++i) {
(this->*introProcTable[i])();
}
setTalkCoords(136);
- waitTicks(0x1E);
+ waitTicks(30);
_seq_copyViewOffs = false;
}
@@ -947,13 +949,14 @@ bool KyraEngine::seq_playSpecialSequence(const uint8 *seqData, bool skipSeq) {
}
break;
case 24: { // sound related
- seqData++;
- warning("Sequence opcode 24 skipped");
+ uint8 param = *seqData++;
+ waitTicks(3);
+ snd_playSoundEffect(param);
}
break;
case 25: { // sound related
- seqData++;
- warning("Sequence opcode 25 skipped");
+ uint8 param = *seqData++;
+ snd_seqMessage(param);
}
break;
case 26:
@@ -981,4 +984,61 @@ bool KyraEngine::seq_playSpecialSequence(const uint8 *seqData, bool skipSeq) {
return seqSkippedFlag;
}
+void KyraEngine::snd_playTheme(int file, int track) {
+ debug(9, "KyraEngine::snd_playTheme(%d)", file);
+ assert(file < _xmidiFilesCount);
+ _midi->playMusic("INTRO.XMI");
+ _midi->playTrack(track, false);
+}
+
+void KyraEngine::snd_playTrack(int track) {
+ debug(9, "KyraEngine::snd_playTrack(%d)", track);
+ _midi->playTrack(track, false);
+}
+
+void KyraEngine::snd_setSoundEffectFile(int file) {
+ debug(9, "KyraEngine::snd_setSoundEffectFile(%d)", file);
+ assert(file < _xmidiFilesCount);
+ _midi->loadSoundEffectFile(_xmidiFiles[file]);
+}
+
+void KyraEngine::snd_playSoundEffect(int track) {
+ debug(9, "KyraEngine::snd_playSoundEffect(%d)", track);
+ _midi->playSoundEffect(track);
+}
+
+void KyraEngine::snd_startTrack() {
+ debug(9, "KyraEngine::snd_startTrack()");
+ _midi->startTrack();
+}
+
+void KyraEngine::snd_haltTrack() {
+ debug(9, "KyraEngine::snd_haltTrack()");
+ _midi->haltTrack();
+}
+
+void KyraEngine::snd_seqMessage(int msg) {
+ debug(9, "KyraEngine::snd_seqMessage(%.02d)", msg);
+ switch (msg) {
+ case 0:
+ // nothing to do here...
+ break;
+ case 1:
+ _midi->beginFadeOut();
+ break;
+ case 56:
+ snd_playTheme(MUSIC_INTRO, 3);
+ break;
+ case 57:
+ snd_playTheme(MUSIC_INTRO, 4);
+ break;
+ case 58:
+ snd_playTheme(MUSIC_INTRO, 5);
+ break;
+ default:
+ warning("Unknown seq. message: %.02d", msg);
+ break;
+ }
+}
+
} // End of namespace Kyra
diff --git a/kyra/kyra.h b/kyra/kyra.h
index d080cc9bb3..4463a5e517 100644
--- a/kyra/kyra.h
+++ b/kyra/kyra.h
@@ -88,12 +88,17 @@ class Resource;
class Screen;
class KyraEngine : public Engine {
+ friend class MusicPlayer;
public:
enum {
TALK_SUBSTRING_LEN = 80,
TALK_SUBSTRING_NUM = 3
};
+
+ enum {
+ MUSIC_INTRO = 0
+ };
KyraEngine(GameDetector *detector, OSystem *system);
~KyraEngine();
@@ -149,6 +154,14 @@ protected:
uint16 wsa_getNumFrames(WSAMovieV1 *wsa) const;
void wsa_play(WSAMovieV1 *wsa, int frameNum, int x, int y, int pageNum);
void wsa_processFrame(WSAMovieV1 *wsa, int frameNum, uint8 *dst);
+
+ void snd_playTheme(int file, int track = 0);
+ void snd_playTrack(int track);
+ void snd_startTrack();
+ void snd_haltTrack();
+ void snd_setSoundEffectFile(int file);
+ void snd_playSoundEffect(int track);
+ void snd_seqMessage(int msg);
uint8 _game;
bool _fastMode;
@@ -191,7 +204,9 @@ protected:
static const char *_seq_WSATable[];
static const char *_seq_CPSTable[];
static const char *_seq_COLTable[];
- static const char *_seq_textsTableEN[];
+ static const char *_seq_textsTableEN[];
+ static const char *_xmidiFiles[];
+ static const int _xmidiFilesCount;
};
} // End of namespace Kyra
diff --git a/kyra/sound.cpp b/kyra/sound.cpp
index 8448726c75..6b75e1033e 100644
--- a/kyra/sound.cpp
+++ b/kyra/sound.cpp
@@ -20,19 +20,28 @@
*/
#include "common/stdafx.h"
+#include "common/system.h"
#include "kyra/resource.h"
#include "kyra/sound.h"
namespace Kyra {
-MusicPlayer::MusicPlayer(MidiDriver* driver, KyraEngine* engine) {
+MusicPlayer::MusicPlayer(MidiDriver *driver, KyraEngine *engine) {
_engine = engine;
_driver = driver;
_passThrough = false;
- _isPlaying = _nativeMT32 = false;
+ _eventFromMusic = false;
+ _fadeMusicOut = _sfxIsPlaying = false;
+ _isPlaying = _isLooping = _nativeMT32 = false;
+ _soundEffect = _parser = 0;
+ _soundEffectSource = _parserSource = 0;
- memset(_channel, 0, sizeof(MidiChannel*) * 16);
- memset(_channelVolume, 255, sizeof(uint8) * 16);
+ memset(_channel, 0, sizeof(MidiChannel*) * 32);
+ memset(_channelVolume, 50, sizeof(uint8) * 16);
+ _channelVolume[10] = 100;
+ for (int i = 0; i < 16; ++i) {
+ _virChannel[i] = i;
+ }
_volume = 0;
int ret = open();
@@ -56,9 +65,13 @@ void MusicPlayer::setVolume(int volume) {
return;
_volume = volume;
- for (int i = 0; i < 16; ++i) {
+ for (int i = 0; i < 32; ++i) {
if (_channel[i]) {
- _channel[i]->volume(_channelVolume[i] * _volume / 255);
+ if (i >= 16) {
+ _channel[i]->volume(_channelVolume[i - 16] * _volume / 255);
+ } else {
+ _channel[i]->volume(_channelVolume[i] * _volume / 255);
+ }
}
}
}
@@ -84,11 +97,23 @@ void MusicPlayer::close() {
void MusicPlayer::send(uint32 b) {
if (_passThrough) {
+ if ((b & 0xFFF0) == 0x007BB0)
+ return;
_driver->send(b);
return;
}
uint8 channel = (byte)(b & 0x0F);
+ if (((b & 0xFFF0) == 0x6FB0 || (b & 0xFFF0) == 0x6EB0) && channel != 9) {
+ if (_virChannel[channel] == channel) {
+ _virChannel[channel] = channel + 16;
+ if (!_channel[_virChannel[channel]])
+ _channel[_virChannel[channel]] = _driver->allocateChannel();
+ _channel[_virChannel[channel]]->volume(_channelVolume[channel] * _volume / 255);
+ }
+ return;
+ }
+
if ((b & 0xFFF0) == 0x07B0) {
// Adjust volume changes by master volume
uint8 volume = (uint8)((b >> 16) & 0x7F);
@@ -104,24 +129,36 @@ void MusicPlayer::send(uint32 b) {
return;
}
- if (!_channel[channel])
- _channel[channel] = (channel == 9) ? _driver->getPercussionChannel() : _driver->allocateChannel();
- if (_channel[channel])
- _channel[channel]->send(b);
+ if (!_channel[_virChannel[channel]]) {
+ _channel[_virChannel[channel]] = (channel == 9) ? _driver->getPercussionChannel() : _driver->allocateChannel();
+ _channel[_virChannel[channel]]->volume(_channelVolume[channel] * _volume / 255);
+ }
+ if (_channel[_virChannel[channel]])
+ _channel[_virChannel[channel]]->send(b);
}
void MusicPlayer::metaEvent(byte type, byte *data, uint16 length) {
switch (type) {
case 0x2F: // End of Track
- _parser->jumpToTick(0);
+ if (_eventFromMusic) {
+ if (!_isLooping) {
+ _isPlaying = false;
+ }
+ // remap all channels
+ for (int i = 0; i < 16; ++i) {
+ _virChannel[i] = i;
+ }
+ } else {
+ _sfxIsPlaying = false;
+ }
break;
default:
- warning("Unhandled meta event: 0x%02x", type);
+ _driver->metaEvent(type, data, length);
break;
}
}
-void MusicPlayer::playMusic(const char* file) {
+void MusicPlayer::playMusic(const char *file) {
uint32 size;
uint8 *data = (_engine->resource())->fileData(file, &size);
@@ -133,10 +170,10 @@ void MusicPlayer::playMusic(const char* file) {
playMusic(data, size);
}
-void MusicPlayer::playMusic(uint8* data, uint32 size) {
- if (_isPlaying)
- stopMusic();
+void MusicPlayer::playMusic(uint8 *data, uint32 size) {
+ stopMusic();
+ _parserSource = data;
_parser = MidiParser::createParser_XMIDI();
assert(_parser);
@@ -150,31 +187,117 @@ void MusicPlayer::playMusic(uint8* data, uint32 size) {
_parser->setTrack(0);
_parser->setMidiDriver(this);
_parser->setTimerRate(getBaseTempo());
+ _parser->property(MidiParser::mpAutoLoop, false);
+}
- _isPlaying = true;
+void MusicPlayer::loadSoundEffectFile(const char *file) {
+ uint32 size;
+ uint8 *data = (_engine->resource())->fileData(file, &size);
+
+ if (!data) {
+ warning("couldn't load '%s'", file);
+ return;
+ }
+
+ loadSoundEffectFile(data, size);
+}
+
+void MusicPlayer::loadSoundEffectFile(uint8 *data, uint32 size) {
+ stopSoundEffect();
+
+ _soundEffectSource = data;
+ _soundEffect = MidiParser::createParser_XMIDI();
+ assert(_soundEffect);
+
+ if (!_soundEffect->loadMusic(data, size)) {
+ warning("Error reading track!");
+ delete _parser;
+ _parser = 0;
+ return;
+ }
+
+ _soundEffect->setTrack(0);
+ _soundEffect->setMidiDriver(this);
+ _soundEffect->setTimerRate(getBaseTempo());
+ _soundEffect->property(MidiParser::mpAutoLoop, false);
}
void MusicPlayer::stopMusic() {
+ _isLooping = false;
_isPlaying = false;
if (_parser) {
_parser->unloadMusic();
delete _parser;
- _parser = NULL;
+ _parser = 0;
+ delete [] _parserSource;
+ _parserSource = 0;
+ }
+}
+
+void MusicPlayer::stopSoundEffect() {
+ _sfxIsPlaying = false;
+ if (_soundEffect) {
+ _soundEffect->unloadMusic();
+ delete _soundEffect;
+ _soundEffect = 0;
+ delete [] _soundEffectSource;
+ _soundEffectSource = 0;
}
}
void MusicPlayer::onTimer(void *refCon) {
MusicPlayer *music = (MusicPlayer *)refCon;
- if (music->_isPlaying)
- music->_parser->onTimer();
+
+ // this should be set to the fadeToBlack value
+ const static uint32 musicFadeTime = 2 * 1000;
+ if (music->_fadeMusicOut && music->_fadeStartTime + musicFadeTime > music->_engine->_system->getMillis()) {
+ byte volume = (byte)((musicFadeTime - (music->_engine->_system->getMillis() - music->_fadeStartTime)) * 255 / musicFadeTime);
+ music->setVolume(volume);
+ } else if(music->_fadeStartTime) {
+ music->setVolume(255);
+ music->_fadeStartTime = 0;
+ music->_fadeMusicOut = false;
+ }
+
+ if (music->_isPlaying) {
+ if (music->_parser) {
+ music->_eventFromMusic = true;
+ music->_parser->onTimer();
+ }
+ }
+
+ if (music->_sfxIsPlaying) {
+ if (music->_soundEffect) {
+ music->_eventFromMusic = false;
+ music->_soundEffect->onTimer();
+ }
+ }
}
-void MusicPlayer::playTrack(uint8 track) {
+void MusicPlayer::playTrack(uint8 track, bool loop) {
if (_parser) {
_isPlaying = true;
+ _isLooping = loop;
_parser->setTrack(track);
_parser->jumpToTick(0);
+ _parser->setTempo(1);
+ _parser->property(MidiParser::mpAutoLoop, loop);
}
}
+void MusicPlayer::playSoundEffect(uint8 track) {
+ if (_soundEffect) {
+ _sfxIsPlaying = true;
+ _soundEffect->setTrack(track);
+ _soundEffect->jumpToTick(0);
+ _soundEffect->property(MidiParser::mpAutoLoop, false);
+ }
+}
+
+void MusicPlayer::beginFadeOut() {
+ // this should be something like fade out...
+ _fadeMusicOut = true;
+ _fadeStartTime = _engine->_system->getMillis();
+}
+
} // end of namespace Kyra
diff --git a/kyra/sound.h b/kyra/sound.h
index cf262515cd..e5e1dc0ed2 100644
--- a/kyra/sound.h
+++ b/kyra/sound.h
@@ -29,53 +29,73 @@
#include "kyra/kyra.h"
namespace Kyra {
- class MusicPlayer : public MidiDriver {
- public:
+class MusicPlayer : public MidiDriver {
+public:
- MusicPlayer(MidiDriver* driver, KyraEngine* engine);
- ~MusicPlayer();
+ MusicPlayer(MidiDriver *driver, KyraEngine *engine);
+ ~MusicPlayer();
- void setVolume(int volume);
- int getVolume() { return _volume; }
+ void setVolume(int volume);
+ int getVolume() { return _volume; }
- void hasNativeMT32(bool nativeMT32) { _nativeMT32 = nativeMT32; }
+ void hasNativeMT32(bool nativeMT32) { _nativeMT32 = nativeMT32; }
+ bool isMT32() { return _nativeMT32; }
- void playMusic(const char* file);
- void playMusic(uint8* data, uint32 size);
- void stopMusic();
+ void playMusic(const char* file);
+ void playMusic(uint8* data, uint32 size);
+ void stopMusic();
- void playTrack(uint8 track);
- void setPassThrough(bool b) { _passThrough = b; }
+ void playTrack(uint8 track, bool looping = true);
+ void haltTrack() { _isPlaying = false; }
+ void startTrack() { _isPlaying = true; }
+ void setPassThrough(bool b) { _passThrough = b; }
- //MidiDriver interface implementation
- int open();
- void close();
- void send(uint32 b);
- void metaEvent(byte type, byte *data, uint16 length);
+ void loadSoundEffectFile(const char* file);
+ void loadSoundEffectFile(uint8* data, uint32 size);
+ void stopSoundEffect();
- void setTimerCallback(void *timerParam, void (*timerProc)(void *)) { }
- uint32 getBaseTempo(void) { return _driver ? _driver->getBaseTempo() : 0; }
+ void playSoundEffect(uint8 track);
- //Channel allocation functions
- MidiChannel *allocateChannel() { return 0; }
- MidiChannel *getPercussionChannel() { return 0; }
+ void beginFadeOut();
- protected:
+ //MidiDriver interface implementation
+ int open();
+ void close();
+ void send(uint32 b);
+ void metaEvent(byte type, byte *data, uint16 length);
- static void onTimer(void *data);
+ void setTimerCallback(void *timerParam, void (*timerProc)(void *)) { }
+ uint32 getBaseTempo(void) { return _driver ? _driver->getBaseTempo() : 0; }
- MidiChannel* _channel[16];
- uint8 _channelVolume[16];
- MidiDriver* _driver;
- bool _nativeMT32;
- bool _passThrough;
- uint8 _volume;
- bool _isPlaying;
- MidiParser* _parser;
- KyraEngine* _engine;
+ //Channel allocation functions
+ MidiChannel *allocateChannel() { return 0; }
+ MidiChannel *getPercussionChannel() { return 0; }
+
+protected:
+
+ static void onTimer(void *data);
+
+ MidiChannel* _channel[32];
+ int _virChannel[16];
+ uint8 _channelVolume[16];
+ MidiDriver* _driver;
+ bool _nativeMT32;
+ bool _passThrough;
+ uint8 _volume;
+ bool _isPlaying;
+ bool _sfxIsPlaying;
+ uint32 _fadeStartTime;
+ bool _fadeMusicOut;
+ bool _isLooping;
+ bool _eventFromMusic;
+ MidiParser *_parser;
+ byte *_parserSource;
+ MidiParser *_soundEffect;
+ byte *_soundEffectSource;
+ KyraEngine *_engine;
+};
- };
} // end of namespace Kyra
#endif
diff --git a/kyra/staticres.cpp b/kyra/staticres.cpp
index 7f24f915f3..d11323a025 100644
--- a/kyra/staticres.cpp
+++ b/kyra/staticres.cpp
@@ -452,4 +452,19 @@ const char *KyraEngine::_seq_textsTableEN[] = {
""
};
+const char *KyraEngine::_xmidiFiles[] = {
+ "INTRO.XMI",
+ "KYRA1A.XMI",
+ "KYRA1B.XMI",
+ "KYRA2A.XMI",
+ "KYRA3A.XMI",
+ "KYRA4A.XMI",
+ "KYRA4B.XMI",
+ "KYRA5A.XMI",
+ "KYRA5B.XMI",
+ "KYRAMISC.XMI"
+};
+
+const int KyraEngine::_xmidiFilesCount = ARRAYSIZE(_xmidiFiles);
+
} // End of namespace Kyra
diff --git a/sound/midiparser_xmidi.cpp b/sound/midiparser_xmidi.cpp
index 3ee08ccb7d..9ad5bfafb9 100644
--- a/sound/midiparser_xmidi.cpp
+++ b/sound/midiparser_xmidi.cpp
@@ -51,11 +51,7 @@ public:
// This is a special XMIDI variable length quantity
uint32 MidiParser_XMIDI::readVLQ2(byte * &pos) {
uint32 value = 0;
- int i;
-
- for (i = 0; i < 4; ++i) {
- if (pos[0] & 0x80)
- break;
+ while (!(pos[0] & 0x80)) {
value += *pos++;
}
return value;