aboutsummaryrefslogtreecommitdiff
path: root/engines/sci/sound
diff options
context:
space:
mode:
authorWillem Jan Palenstijn2013-04-18 23:34:29 +0200
committerWillem Jan Palenstijn2013-05-08 20:39:44 +0200
commit01f3f3a8dd0ad2891939d03b0ce47cbf36ea9bc6 (patch)
tree544b07f3aa41abe7907bcd2040cdad11ebc324bb /engines/sci/sound
parent9cf2c83e5e5a35816ab153bf8443dac691829ea8 (diff)
parenta41d72a44a660c72fdadbc3a8ef580e5e03cb890 (diff)
downloadscummvm-rg350-01f3f3a8dd0ad2891939d03b0ce47cbf36ea9bc6.tar.gz
scummvm-rg350-01f3f3a8dd0ad2891939d03b0ce47cbf36ea9bc6.tar.bz2
scummvm-rg350-01f3f3a8dd0ad2891939d03b0ce47cbf36ea9bc6.zip
Merge branch 'master'
Diffstat (limited to 'engines/sci/sound')
-rw-r--r--engines/sci/sound/drivers/cms.cpp1
-rw-r--r--engines/sci/sound/drivers/gm_names.h4
-rw-r--r--engines/sci/sound/midiparser_sci.cpp23
-rw-r--r--engines/sci/sound/music.cpp7
-rw-r--r--engines/sci/sound/soundcmd.cpp112
-rw-r--r--engines/sci/sound/soundcmd.h4
6 files changed, 98 insertions, 53 deletions
diff --git a/engines/sci/sound/drivers/cms.cpp b/engines/sci/sound/drivers/cms.cpp
index ace96ba499..dbcbf3d431 100644
--- a/engines/sci/sound/drivers/cms.cpp
+++ b/engines/sci/sound/drivers/cms.cpp
@@ -813,4 +813,3 @@ MidiPlayer *MidiPlayer_CMS_create(SciVersion version) {
}
} // End of namespace SCI
-
diff --git a/engines/sci/sound/drivers/gm_names.h b/engines/sci/sound/drivers/gm_names.h
index bfe5ff88c7..fbfa413a4a 100644
--- a/engines/sci/sound/drivers/gm_names.h
+++ b/engines/sci/sound/drivers/gm_names.h
@@ -30,7 +30,7 @@ namespace Sci {
// is defined
#ifndef REDUCE_MEMORY_USAGE
-static const char *GmInstrumentNames[] = {
+static const char *const GmInstrumentNames[] = {
/*000*/ "Acoustic Grand Piano",
/*001*/ "Bright Acoustic Piano",
/*002*/ "Electric Grand Piano",
@@ -162,7 +162,7 @@ static const char *GmInstrumentNames[] = {
};
// The GM Percussion map is downwards compatible to the MT32 map, which is used in SCI
-static const char *GmPercussionNames[] = {
+static const char *const GmPercussionNames[] = {
/*00*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/*10*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/*20*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
diff --git a/engines/sci/sound/midiparser_sci.cpp b/engines/sci/sound/midiparser_sci.cpp
index 95b165468d..ad7ba7ca36 100644
--- a/engines/sci/sound/midiparser_sci.cpp
+++ b/engines/sci/sound/midiparser_sci.cpp
@@ -480,11 +480,18 @@ void MidiParser_SCI::parseNextEvent(EventInfo &info) {
info.basic.param2 = 0;
if (info.channel() == 0xF) {// SCI special case
if (info.basic.param1 != kSetSignalLoop) {
- // at least in kq5/french&mac the first scene in the intro has a song that sets signal to 4 immediately
- // on tick 0. Signal isn't set at that point by sierra sci and it would cause the castle daventry text to
- // get immediately removed, so we currently filter it.
- // Sierra SCI ignores them as well at that time
- if ((_position._play_tick) || (info.delta)) {
+ // At least in kq5/french&mac the first scene in the intro has
+ // a song that sets signal to 4 immediately on tick 0. Signal
+ // isn't set at that point by sierra sci and it would cause the
+ // castle daventry text to get immediately removed, so we
+ // currently filter it. Sierra SCI ignores them as well at that
+ // time. However, this filtering should only be performed for
+ // SCI1 and newer games. Signalling is done differently in SCI0
+ // though, so ignoring these signals in SCI0 games will result
+ // in glitches (e.g. the intro of LB1 Amiga gets stuck - bug
+ // #3297883). Refer to MusicEntry::setSignal() in sound/music.cpp.
+ if (_soundVersion <= SCI_VERSION_0_LATE ||
+ _position._play_tick || info.delta) {
_signalSet = true;
_signalToSet = info.basic.param1;
}
@@ -626,7 +633,11 @@ void MidiParser_SCI::parseNextEvent(EventInfo &info) {
if (info.ext.type == 0x2F) {// end of track reached
if (_pSnd->loop)
_pSnd->loop--;
- if (_pSnd->loop) {
+ // QFG3 abuses the hold flag. Its scripts call kDoSoundSetHold,
+ // but sometimes there's no hold marker in the associated songs
+ // (e.g. song 110, during the intro). The original interpreter
+ // treats this case as an infinite loop (bug #3311911).
+ if (_pSnd->loop || _pSnd->hold > 0) {
// We need to play it again...
jumpToTick(_loopTick);
} else {
diff --git a/engines/sci/sound/music.cpp b/engines/sci/sound/music.cpp
index 2afab3858d..9610b6f847 100644
--- a/engines/sci/sound/music.cpp
+++ b/engines/sci/sound/music.cpp
@@ -63,12 +63,13 @@ void SciMusic::init() {
// SCI sound init
_dwTempo = 0;
- // Default to MIDI in SCI2.1+ games, as many don't have AdLib support.
Common::Platform platform = g_sci->getPlatform();
-
uint32 deviceFlags = MDT_PCSPK | MDT_PCJR | MDT_ADLIB | MDT_MIDI;
- if (getSciVersion() >= SCI_VERSION_2_1)
+ // Default to MIDI in SCI2.1+ games, as many don't have AdLib support.
+ // Also, default to MIDI for Windows versions of SCI1.1 games, as their
+ // soundtrack is written for GM.
+ if (getSciVersion() >= SCI_VERSION_2_1 || g_sci->_features->useAltWinGMSound())
deviceFlags |= MDT_PREFER_GM;
// Currently our CMS implementation only supports SCI1(.1)
diff --git a/engines/sci/sound/soundcmd.cpp b/engines/sci/sound/soundcmd.cpp
index 4ea290ff9e..274c532779 100644
--- a/engines/sci/sound/soundcmd.cpp
+++ b/engines/sci/sound/soundcmd.cpp
@@ -37,6 +37,15 @@ SoundCommandParser::SoundCommandParser(ResourceManager *resMan, SegManager *segM
_music = new SciMusic(_soundVersion);
_music->init();
+ // Check if the user wants synthesized or digital sound effects in SCI1.1
+ // or later games
+ _bMultiMidi = ConfMan.getBool("multi_midi");
+ // In SCI2 and later games, this check should always be true - there was
+ // always only one version of each sound effect or digital music track
+ // (e.g. the menu music in GK1 - there is a sound effect with the same
+ // resource number, but it's totally unrelated to the menu music).
+ if (getSciVersion() >= SCI_VERSION_2)
+ _bMultiMidi = true;
}
SoundCommandParser::~SoundCommandParser() {
@@ -49,11 +58,54 @@ reg_t SoundCommandParser::kDoSoundInit(int argc, reg_t *argv, reg_t acc) {
return acc;
}
-void SoundCommandParser::processInitSound(reg_t obj) {
- int resourceId = readSelectorValue(_segMan, obj, SELECTOR(number));
+int SoundCommandParser::getSoundResourceId(reg_t obj) {
+ int resourceId = obj.segment ? readSelectorValue(_segMan, obj, SELECTOR(number)) : -1;
// Modify the resourceId for the Windows versions that have an alternate MIDI soundtrack, like SSCI did.
- if (g_sci && g_sci->_features->useAltWinGMSound())
- resourceId += 1000;
+ if (g_sci && g_sci->_features->useAltWinGMSound()) {
+ // Check if the alternate MIDI song actually exists...
+ // There are cases where it just doesn't exist (e.g. SQ4, room 530 -
+ // bug #3392767). In these cases, use the DOS tracks instead.
+ if (resourceId && _resMan->testResource(ResourceId(kResourceTypeSound, resourceId + 1000)))
+ resourceId += 1000;
+ }
+
+ return resourceId;
+}
+
+void SoundCommandParser::initSoundResource(MusicEntry *newSound) {
+ if (newSound->resourceId && _resMan->testResource(ResourceId(kResourceTypeSound, newSound->resourceId)))
+ newSound->soundRes = new SoundResource(newSound->resourceId, _resMan, _soundVersion);
+ else
+ newSound->soundRes = 0;
+
+ // In SCI1.1 games, sound effects are started from here. If we can find
+ // a relevant audio resource, play it, otherwise switch to synthesized
+ // effects. If the resource exists, play it using map 65535 (sound
+ // effects map)
+ bool checkAudioResource = getSciVersion() >= SCI_VERSION_1_1;
+ // Hoyle 4 has garbled audio resources in place of the sound resources.
+ // The demo of GK1 has no alternate sound effects.
+ if ((g_sci->getGameId() == GID_HOYLE4) ||
+ (g_sci->getGameId() == GID_GK1 && g_sci->isDemo()))
+ checkAudioResource = false;
+
+ if (checkAudioResource && _resMan->testResource(ResourceId(kResourceTypeAudio, newSound->resourceId))) {
+ // Found a relevant audio resource, create an audio stream if there is
+ // no associated sound resource, or if both resources exist and the
+ // user wants the digital version.
+ if (_bMultiMidi || !newSound->soundRes) {
+ int sampleLen;
+ newSound->pStreamAud = _audio->getAudioStream(newSound->resourceId, 65535, &sampleLen);
+ newSound->soundType = Audio::Mixer::kSpeechSoundType;
+ }
+ }
+
+ if (!newSound->pStreamAud && newSound->soundRes)
+ _music->soundInitSnd(newSound);
+}
+
+void SoundCommandParser::processInitSound(reg_t obj) {
+ int resourceId = getSoundResourceId(obj);
// Check if a track with the same sound object is already playing
MusicEntry *oldSound = _music->getSlot(obj);
@@ -62,11 +114,6 @@ void SoundCommandParser::processInitSound(reg_t obj) {
MusicEntry *newSound = new MusicEntry();
newSound->resourceId = resourceId;
- if (resourceId && _resMan->testResource(ResourceId(kResourceTypeSound, resourceId)))
- newSound->soundRes = new SoundResource(resourceId, _resMan, _soundVersion);
- else
- newSound->soundRes = 0;
-
newSound->soundObj = obj;
newSound->loop = readSelectorValue(_segMan, obj, SELECTOR(loop));
newSound->priority = readSelectorValue(_segMan, obj, SELECTOR(pri)) & 0xFF;
@@ -77,25 +124,7 @@ void SoundCommandParser::processInitSound(reg_t obj) {
debugC(kDebugLevelSound, "kDoSound(init): %04x:%04x number %d, loop %d, prio %d, vol %d", PRINT_REG(obj),
resourceId, newSound->loop, newSound->priority, newSound->volume);
- // In SCI1.1 games, sound effects are started from here. If we can find
- // a relevant audio resource, play it, otherwise switch to synthesized
- // effects. If the resource exists, play it using map 65535 (sound
- // effects map)
- bool checkAudioResource = getSciVersion() >= SCI_VERSION_1_1;
- if (g_sci->getGameId() == GID_HOYLE4)
- checkAudioResource = false; // hoyle 4 has garbled audio resources in place of the sound resources
- // if we play those, we will only make the user deaf and break speakers. Sierra SCI doesn't play anything
- // on soundblaster. FIXME: check, why this is
-
- if (checkAudioResource && _resMan->testResource(ResourceId(kResourceTypeAudio, resourceId))) {
- // Found a relevant audio resource, play it
- int sampleLen;
- newSound->pStreamAud = _audio->getAudioStream(resourceId, 65535, &sampleLen);
- newSound->soundType = Audio::Mixer::kSpeechSoundType;
- } else {
- if (newSound->soundRes)
- _music->soundInitSnd(newSound);
- }
+ initSoundResource(newSound);
_music->pushBackSlot(newSound);
@@ -105,8 +134,6 @@ void SoundCommandParser::processInitSound(reg_t obj) {
writeSelectorValue(_segMan, obj, SELECTOR(state), kSoundInitialized);
else
writeSelector(_segMan, obj, SELECTOR(nodePtr), obj);
-
- writeSelector(_segMan, obj, SELECTOR(handle), obj);
}
}
@@ -119,14 +146,17 @@ reg_t SoundCommandParser::kDoSoundPlay(int argc, reg_t *argv, reg_t acc) {
void SoundCommandParser::processPlaySound(reg_t obj) {
MusicEntry *musicSlot = _music->getSlot(obj);
if (!musicSlot) {
- warning("kDoSound(play): Slot not found (%04x:%04x)", PRINT_REG(obj));
- return;
+ warning("kDoSound(play): Slot not found (%04x:%04x), initializing it manually", PRINT_REG(obj));
+ // The sound hasn't been initialized for some reason, so initialize it
+ // here. Happens in KQ6, room 460, when giving the creature (child) to
+ // the bookworm. Fixes bugs #3413301 and #3421098.
+ processInitSound(obj);
+ musicSlot = _music->getSlot(obj);
+ if (!musicSlot)
+ error("Failed to initialize uninitialized sound slot");
}
- int resourceId = obj.segment ? readSelectorValue(_segMan, obj, SELECTOR(number)) : -1;
- // Modify the resourceId for the Windows versions that have an alternate MIDI soundtrack, like SSCI did.
- if (g_sci && g_sci->_features->useAltWinGMSound())
- resourceId += 1000;
+ int resourceId = getSoundResourceId(obj);
if (musicSlot->resourceId != resourceId) { // another sound loaded into struct
processDisposeSound(obj);
@@ -149,6 +179,9 @@ void SoundCommandParser::processPlaySound(reg_t obj) {
musicSlot->loop = readSelectorValue(_segMan, obj, SELECTOR(loop));
musicSlot->priority = readSelectorValue(_segMan, obj, SELECTOR(priority));
+ // Reset hold when starting a new song. kDoSoundSetHold is always called after
+ // kDoSoundPlay to set it properly, if needed. Fixes bug #3413589.
+ musicSlot->hold = -1;
if (_soundVersion >= SCI_VERSION_1_EARLY)
musicSlot->volume = readSelectorValue(_segMan, obj, SELECTOR(vol));
@@ -618,13 +651,10 @@ reg_t SoundCommandParser::kDoSoundSetPriority(int argc, reg_t *argv, reg_t acc)
}
if (value == -1) {
- uint16 resourceNr = musicSlot->resourceId;
- // Modify the resourceId for the Windows versions that have an alternate MIDI soundtrack, like SSCI did.
- if (g_sci && g_sci->_features->useAltWinGMSound())
- resourceNr += 1000;
+ uint16 resourceId = musicSlot->resourceId;
// Set priority from the song data
- Resource *song = _resMan->findResource(ResourceId(kResourceTypeSound, resourceNr), 0);
+ Resource *song = _resMan->findResource(ResourceId(kResourceTypeSound, resourceId), 0);
if (song->data[0] == 0xf0)
_music->soundSetPriority(musicSlot, song->data[1]);
else
diff --git a/engines/sci/sound/soundcmd.h b/engines/sci/sound/soundcmd.h
index a542a8b384..c1dce014d2 100644
--- a/engines/sci/sound/soundcmd.h
+++ b/engines/sci/sound/soundcmd.h
@@ -32,6 +32,7 @@ namespace Sci {
class Console;
class SciMusic;
class SoundCommandParser;
+class MusicEntry;
//typedef void (SoundCommandParser::*SoundCommand)(reg_t obj, int16 value);
//struct MusicEntryCommand {
@@ -64,6 +65,7 @@ public:
void processPlaySound(reg_t obj);
void processStopSound(reg_t obj, bool sampleFinishedPlaying);
+ void initSoundResource(MusicEntry *newSound);
MusicType getMusicType() const;
@@ -109,10 +111,12 @@ private:
SciMusic *_music;
AudioPlayer *_audio;
SciVersion _soundVersion;
+ bool _bMultiMidi;
void processInitSound(reg_t obj);
void processDisposeSound(reg_t obj);
void processUpdateCues(reg_t obj);
+ int getSoundResourceId(reg_t obj);
};
} // End of namespace Sci