Added XMIDI support to IMuse. IMuse now plays music from Humongous games.

Added some IMuse property options to support some assumptions that seem to be made by Humongous games.

This is still preliminary. It will play music, and it will switch between songs. But I don't know if it's switching to the right song at the right time.

svn-id: r7869
This commit is contained in:
Jamieson Christian 2003-05-23 18:35:53 +00:00
parent ad4eb36093
commit eb09051517
6 changed files with 86 additions and 90 deletions

View File

@ -49,6 +49,8 @@ _base_sounds (0),
_paused (false),
_initialized (false),
_tempoFactor (0),
_player_limit (ARRAYSIZE(_players)),
_recycle_players (false),
_queue_end (0),
_queue_pos (0),
_queue_sound (0),
@ -89,7 +91,7 @@ MidiDriver *IMuseInternal::getMidiDriver() {
return driver;
}
byte *IMuseInternal::findTag(int sound, char *tag, int index) {
byte *IMuseInternal::findStartOfSound (int sound) {
byte *ptr = NULL;
int32 size, pos;
@ -97,7 +99,7 @@ byte *IMuseInternal::findTag(int sound, char *tag, int index) {
ptr = _base_sounds[sound];
if (ptr == NULL) {
debug(1, "IMuseInternal::findTag completely failed finding sound %d", sound);
debug (1, "IMuseInternal::findStartOfSound(): Sound %d doesn't exist!", sound);
return NULL;
}
@ -106,16 +108,18 @@ byte *IMuseInternal::findTag(int sound, char *tag, int index) {
size = READ_BE_UINT32_UNALIGNED(ptr);
ptr += 4;
// Okay, we're looking for one of those things: either
// an 'MThd' tag (for SMF), or a 'FORM' tag (for XMIDI).
size = 48; // Arbitrary; we should find our tag within the first 48 bytes of the resource
pos = 0;
while (pos < size) {
if (!memcmp(ptr + pos, tag, 4) && !index--)
return ptr + pos + 8;
pos += READ_BE_UINT32_UNALIGNED(ptr + pos + 4) + 8;
if (!memcmp (ptr + pos, "MThd", 4) || !memcmp (ptr + pos, "FORM", 4))
return ptr + pos;
++pos; // We could probably iterate more intelligently
}
debug(3, "IMuseInternal::findTag failed finding sound %d", sound);
return NULL;
debug(3, "IMuseInternal::findStartOfSound(): Failed to align on sound %d!", sound);
return 0;
}
bool IMuseInternal::isMT32(int sound) {
@ -219,6 +223,14 @@ bool IMuseInternal::startSound(int sound) {
return false;
}
// Not sure exactly what the old code was doing,
// but we'll go ahead and do a similar check.
mdhd = findStartOfSound (sound);
if (!mdhd) {
debug (2, "IMuseInternal::startSound(): Couldn't find sound %d!", sound);
return false;
}
/*
mdhd = findTag(sound, MDHD_TAG, 0);
if (!mdhd) {
mdhd = findTag(sound, MDPG_TAG, 0);
@ -227,6 +239,7 @@ bool IMuseInternal::startSound(int sound) {
return false;
}
}
*/
// Check which MIDI driver this track should use.
// If it's NULL, it ain't something we can play.
@ -257,7 +270,7 @@ Player *IMuseInternal::allocate_player(byte priority) {
int i;
byte bestpri = 255;
for (i = ARRAYSIZE(_players); i != 0; i--, player++) {
for (i = _player_limit; i != 0; i--, player++) {
if (!player->isActive())
return player;
if (player->getPriority() < bestpri) {
@ -266,7 +279,7 @@ Player *IMuseInternal::allocate_player(byte priority) {
}
}
if (bestpri < priority)
if (bestpri < priority || _recycle_players)
return best;
debug(1, "Denying player request");
@ -410,24 +423,23 @@ Part *IMuseInternal::allocate_part (byte pri, MidiDriver *midi) {
return best;
}
int IMuseInternal::getSoundStatus(int sound) {
Player *player = findActivePlayer (sound);
if (player && !player->isFadingOut())
int IMuseInternal::getSoundStatus (int sound, bool ignoreFadeouts) {
Player *player;
if (sound == -1) {
player = _players;
for (int i = ARRAYSIZE(_players); i; --i, ++player) {
if (player->isActive() && (!ignoreFadeouts || !player->isFadingOut()))
return player->getID();
}
return 0;
}
player = findActivePlayer (sound);
if (player && (!ignoreFadeouts || !player->isFadingOut()))
return 1;
return get_queue_sound_status(sound);
}
// This is exactly the same as getSoundStatus except that
// it treats sounds that are fading out just the same as
// other sounds. This is the method to use when determining
// what resources to expire from memory.
bool IMuseInternal::get_sound_active(int sound) {
Player *player = findActivePlayer (sound);
if (player)
return 1;
return (get_queue_sound_status(sound) != 0);
}
int IMuseInternal::get_queue_sound_status(int sound) {
uint16 *a;
int i, j;
@ -1041,6 +1053,17 @@ uint32 IMuseInternal::property(int prop, uint32 value) {
case IMuse::PROP_OLD_ADLIB_INSTRUMENTS:
_old_adlib_instruments = (value > 0);
break;
case IMuse::PROP_LIMIT_PLAYERS:
if (value > 0 && value <= ARRAYSIZE(_players))
_player_limit = (int) value;
break;
case IMuse::PROP_RECYCLE_PLAYERS:
if (value > 0 && value <= ARRAYSIZE(_players))
_recycle_players = (value != 0);
break;
}
return 0;
}
@ -1674,8 +1697,8 @@ int IMuse::get_master_volume() { in(); int ret = _target->get_master_volume(); o
bool IMuse::startSound(int sound) { in(); bool ret = _target->startSound (sound); out(); return ret; }
int IMuse::stopSound(int sound) { in(); int ret = _target->stopSound (sound); out(); return ret; }
int IMuse::stop_all_sounds() { in(); int ret = _target->stop_all_sounds(); out(); return ret; }
int IMuse::getSoundStatus(int sound) { in(); int ret = _target->getSoundStatus (sound); out(); return ret; }
bool IMuse::get_sound_active(int sound) { in(); bool ret = _target->get_sound_active (sound); out(); return ret; }
int IMuse::getSoundStatus(int sound) { in(); int ret = _target->getSoundStatus (sound, true); out(); return ret; }
bool IMuse::get_sound_active(int sound) { in(); bool ret = _target->getSoundStatus (sound, false) ? 1 : 0; out(); return ret; }
int32 IMuse::doCommand(int a, int b, int c, int d, int e, int f, int g, int h) { in(); int32 ret = _target->doCommand (a,b,c,d,e,f,g,h); out(); return ret; }
int IMuse::clear_queue() { in(); int ret = _target->clear_queue(); out(); return ret; }
void IMuse::setBase(byte **base) { in(); _target->setBase (base); out(); }

View File

@ -47,7 +47,9 @@ public:
PROP_TEMPO_BASE = 1,
PROP_NATIVE_MT32 = 2,
PROP_MULTI_MIDI = 3,
PROP_OLD_ADLIB_INSTRUMENTS = 4
PROP_OLD_ADLIB_INSTRUMENTS = 4,
PROP_LIMIT_PLAYERS = 5,
PROP_RECYCLE_PLAYERS = 6
};
void on_timer (MidiDriver *midi);

View File

@ -366,6 +366,9 @@ private:
int _tempoFactor;
int _player_limit; // Limits how many simultaneous music tracks are played
bool _recycle_players; // Can we stop a player in order to start another one?
uint _queue_end, _queue_pos, _queue_sound;
byte _queue_adding;
@ -390,7 +393,7 @@ private:
CommandQueue _cmd_queue[64];
DeferredCommand _deferredCommands[4];
byte *findTag(int sound, char *tag, int index);
byte *findStartOfSound (int sound);
bool isMT32(int sound);
bool isGM(int sound);
int get_queue_sound_status(int sound);
@ -457,8 +460,7 @@ public:
bool startSound(int sound);
int stopSound(int sound);
int stop_all_sounds();
int getSoundStatus(int sound);
bool get_sound_active(int sound);
int getSoundStatus (int sound, bool ignoreFadeouts = true);
int32 doCommand(int a, int b, int c, int d, int e, int f, int g, int h);
int clear_queue();
void setBase(byte **base);

View File

@ -88,6 +88,14 @@ bool Player::startSound (int sound, MidiDriver *midi) {
void *mdhd;
int i;
// Not sure what the old code was doing,
// but we'll go ahead and do a similar check.
mdhd = _se->findStartOfSound (sound);
if (!mdhd) {
warning ("Player::startSound(): Couldn't find start of sound %d!", sound);
return false;
}
/*
mdhd = _se->findTag(sound, MDHD_TAG, 0);
if (mdhd == NULL) {
mdhd = _se->findTag(sound, MDPG_TAG, 0);
@ -96,7 +104,7 @@ bool Player::startSound (int sound, MidiDriver *midi) {
return false;
}
}
*/
_isMT32 = _se->isMT32(sound);
_isGM = _se->isGM(sound);
@ -114,8 +122,8 @@ bool Player::startSound (int sound, MidiDriver *midi) {
for (i = 0; i < ARRAYSIZE(_parameterFaders); ++i)
_parameterFaders[i].init();
hook_clear();
if (start_seq_sound(sound) != 0) {
_active = false;
_midi = NULL;
@ -163,14 +171,16 @@ int Player::start_seq_sound(int sound) {
setTempo(500000);
setSpeed(128);
ptr = _se->findTag (sound, "MThd", 0);
ptr = _se->findStartOfSound (sound);
if (ptr == NULL)
return -1;
if (_parser)
delete _parser;
ptr -= 8; // findTag puts us past the tag and length
_parser = MidiParser::createParser_SMF();
if (!memcmp (ptr, "FORM", 4))
_parser = MidiParser::createParser_XMIDI();
else
_parser = MidiParser::createParser_SMF();
_parser->setTimerRate ((_midi->getBaseTempo() * _speed) >> 7);
_parser->setMidiDriver (this);
_parser->property (MidiParser::mpSmartJump, 1);

View File

@ -614,6 +614,10 @@ Scumm::Scumm (GameDetector *detector, OSystem *syst)
_imuse->property (IMuse::PROP_OLD_ADLIB_INSTRUMENTS, (_features & GF_SMALL_HEADER) ? 1 : 0);
_imuse->property (IMuse::PROP_MULTI_MIDI, detector->_multi_midi);
_imuse->property (IMuse::PROP_NATIVE_MT32, detector->_native_mt32);
if (_features & GF_HUMONGOUS) {
_imuse->property (IMuse::PROP_LIMIT_PLAYERS, 1);
_imuse->property (IMuse::PROP_RECYCLE_PLAYERS, 1);
}
_imuse->set_music_volume(_sound->_sound_volume_music);
}
}
@ -815,7 +819,7 @@ void Scumm::initScummVars() {
VAR(VAR_VIDEOMODE) = 0x13;
VAR(VAR_HEAPSPACE) = 1400;
VAR(VAR_MOUSEPRESENT) = true; // FIXME - used to be 0, but that seems odd?!?
if ((_features & GF_HUMONGOUS) && (_gameId != GID_PUTTDEMO))
if (_features & GF_HUMONGOUS)
VAR(VAR_SOUNDPARAM) = 1; // soundblaster for music
else
VAR(VAR_SOUNDPARAM) = 0;

View File

@ -236,55 +236,8 @@ void Sound::playSound(int soundID) {
}
// XMIDI
else if ((READ_UINT32_UNALIGNED(ptr) == MKID('MIDI')) && (_scumm->_features & GF_HUMONGOUS)) {
// skip HSHD
ptr += 8 + READ_BE_UINT32_UNALIGNED(ptr+12);
if (READ_UINT32_UNALIGNED(ptr) != MKID('SDAT'))
return; // abort
size = READ_BE_UINT32_UNALIGNED(ptr+4) - 8;
ptr += 8; // don't need SDAT block anymore
// XMIDI playing stuff goes here
// ptr should be pointing to XMIDI file in memory
// HACK (Jamieson630): Just to see if it works.
static MidiParser *parser = 0;
MidiDriver *driver = 0;
if (_scumm && _scumm->_imuse)
driver = _scumm->_imuse->getMidiDriver();
if (driver) {
driver->setTimerCallback (0, 0);
if (parser) {
delete parser;
parser = 0;
}
parser = MidiParser::createParser_XMIDI();
parser->setMidiDriver (driver);
parser->setTimerRate (driver->getBaseTempo());
if (_scumm->_gameId != GID_PUTTDEMO)
parser->property (MidiParser::mpAutoLoop, 1);
parser->loadMusic (ptr, size);
driver->open();
driver->setTimerCallback (parser, &MidiParser::timerCallback);
}
// FIXME: dumping xmi files for testing, remove when working
if (1) {
File out;
char buf[64];
sprintf(buf, "dumps/sound-%d.xmi", soundID);
out.open(buf, "", 1);
if (out.isOpen() == false) {
out.open(buf, "", 2);
if (out.isOpen() == false)
return;
out.write(ptr, size);
}
out.close();
}
return;
// Pass XMIDI on to IMuse unprocessed.
// IMuse can handle XMIDI resources now.
}
else if (READ_UINT32_UNALIGNED(ptr) == MKID('ADL ')) {
// played as MIDI, just to make perhaps the later use
@ -636,11 +589,13 @@ int Sound::isSoundRunning(int sound) {
return pollCD();
if (_scumm->_features & GF_HUMONGOUS) {
if (sound == -2) {
return isSfxFinished();
// FIXME are we playing music?
} else if (sound == -1)
return 1;
if (sound == -2) {
return isSfxFinished();
} else if (sound == -1) {
// getSoundStatus(), with a -1, will return the
// ID number of the first active music it finds.
return _scumm->_imuse->getSoundStatus (sound);
}
}
_scumm->_mixer->stopID(sound);