Skip to content

Commit

Permalink
SCI: Switch SCI2 games to use Audio32
Browse files Browse the repository at this point in the history
Upon investigation of Sound code across SCI32 games, it was
determined that there are actually (at least) 3 different
revisions, not just a single SCI2.1 version. This patch only
changes the parts of Sound code that are relevant to the correct
use of Audio32.

Fixes Trac#9736, Trac#9756, Trac#9767, Trac#9791.
  • Loading branch information
csnover committed Jun 19, 2017
1 parent 733eaeb commit d556dcc
Show file tree
Hide file tree
Showing 10 changed files with 95 additions and 121 deletions.
9 changes: 9 additions & 0 deletions engines/sci/engine/features.cpp
Expand Up @@ -143,8 +143,17 @@ SciVersion GameFeatures::detectDoSoundType() {
// SCI0LATE. Although the last SCI0EARLY game (lsl2) uses SCI0LATE resources
_doSoundType = g_sci->getResMan()->detectEarlySound() ? SCI_VERSION_0_EARLY : SCI_VERSION_0_LATE;
#ifdef ENABLE_SCI32
} else if (getSciVersion() >= SCI_VERSION_2_1_MIDDLE &&
g_sci->getGameId() != GID_SQ6 &&
// Assuming MGDX uses SCI2.1early sound mode since SQ6 does
// and it was released earlier, but not verified (Phar Lap
// Windows-only release)
g_sci->getGameId() != GID_MOTHERGOOSEHIRES) {
_doSoundType = SCI_VERSION_2_1_MIDDLE;
} else if (getSciVersion() >= SCI_VERSION_2_1_EARLY) {
_doSoundType = SCI_VERSION_2_1_EARLY;
} else if (getSciVersion() >= SCI_VERSION_2) {
_doSoundType = SCI_VERSION_2;
#endif
} else if (SELECTOR(nodePtr) == -1) {
// No nodePtr selector, so this game is definitely using newer
Expand Down
5 changes: 1 addition & 4 deletions engines/sci/engine/features.h
Expand Up @@ -102,11 +102,8 @@ class GameFeatures {
case GID_SQ6:
return true;
case GID_KQ7:
case GID_QFG4:
// (1) KQ7 1.51 (SCI2.1early) uses the non-standard attenuation, but
// KQ7 1.51 (SCI2.1early) uses the non-standard attenuation, but
// 2.00b (SCI2.1mid) does not
// (2) QFG4 CD is SCI2.1early; QFG4 floppy is SCI2 and does not use
// the SCI2.1 audio system
return getSciVersion() == SCI_VERSION_2_1_EARLY;
default:
return false;
Expand Down
57 changes: 26 additions & 31 deletions engines/sci/engine/kernel_tables.h
Expand Up @@ -81,7 +81,6 @@ struct SciKernelMapSubEntry {
#define SIG_SOUNDSCI0 SCI_VERSION_0_EARLY, SCI_VERSION_0_LATE
#define SIG_SOUNDSCI1EARLY SCI_VERSION_1_EARLY, SCI_VERSION_1_EARLY
#define SIG_SOUNDSCI1LATE SCI_VERSION_1_LATE, SCI_VERSION_1_LATE
#define SIG_SOUNDSCI21 SCI_VERSION_2_1_EARLY, SCI_VERSION_3

#define SIGFOR_ALL 0x3f
#define SIGFOR_DOS 1 << 0
Expand Down Expand Up @@ -152,32 +151,27 @@ static const SciKernelMapSubEntry kDoSound_subops[] = {
{ SIG_SOUNDSCI1LATE, 19, MAP_CALL(DoSoundGlobalReverb), NULL, NULL },
{ SIG_SOUNDSCI1LATE, 20, MAP_CALL(DoSoundUpdate), NULL, NULL },
#ifdef ENABLE_SCI32
{ SIG_SOUNDSCI21, 0, MAP_CALL(DoSoundMasterVolume), "(i)", NULL },
{ SIG_SOUNDSCI21, 1, MAP_CALL(DoSoundMute), "(i)", NULL },
{ SIG_SOUNDSCI21, 2, MAP_EMPTY(DoSoundRestore), NULL, NULL },
{ SIG_SOUNDSCI21, 3, MAP_CALL(DoSoundGetPolyphony), "", NULL },
{ SIG_SOUNDSCI21, 4, MAP_CALL(DoSoundGetAudioCapability), "", NULL },
{ SIG_SOUNDSCI21, 5, MAP_CALL(DoSoundSuspend), "i", NULL },
{ SIG_SOUNDSCI21, 6, MAP_CALL(DoSoundInit), "o", NULL },
{ SIG_SOUNDSCI21, 7, MAP_CALL(DoSoundDispose), "o", NULL },
{ SIG_SOUNDSCI21, 8, MAP_CALL(DoSoundPlay), "o", kDoSoundPlay_workarounds },
// ^^ TODO: if this is really the only change between SCI1LATE AND SCI21, we could rename the
// SIG_SOUNDSCI1LATE #define to SIG_SINCE_SOUNDSCI1LATE and make it being SCI1LATE+. Although
// I guess there are many more changes somewhere
// TODO: Quest for Glory 4 (SCI2.1) uses the old scheme, we need to detect it accordingly
// signature for SCI21 should be "o"
{ SIG_SOUNDSCI21, 9, MAP_CALL(DoSoundStop), "o", NULL },
{ SIG_SOUNDSCI21, 10, MAP_CALL(DoSoundPause), "[o0]i", NULL },
{ SIG_SOUNDSCI21, 11, MAP_CALL(DoSoundFade), "oiiii", kDoSoundFade_workarounds },
{ SIG_SOUNDSCI21, 12, MAP_CALL(DoSoundSetHold), "oi", NULL },
{ SIG_SOUNDSCI21, 13, MAP_EMPTY(DoSoundDummy), NULL, NULL },
{ SIG_SOUNDSCI21, 14, MAP_CALL(DoSoundSetVolume), "oi", NULL },
{ SIG_SOUNDSCI21, 15, MAP_CALL(DoSoundSetPriority), "oi", NULL },
{ SIG_SOUNDSCI21, 16, MAP_CALL(DoSoundSetLoop), "oi", NULL },
{ SIG_SOUNDSCI21, 17, MAP_CALL(DoSoundUpdateCues), "o", NULL },
{ SIG_SOUNDSCI21, 18, MAP_CALL(DoSoundSendMidi), "oiiii", NULL },
{ SIG_SOUNDSCI21, 19, MAP_CALL(DoSoundGlobalReverb), "(i)", NULL },
{ SIG_SOUNDSCI21, 20, MAP_CALL(DoSoundUpdate), "o", NULL },
{ SIG_SCI32, 0, MAP_CALL(DoSoundMasterVolume), "(i)", NULL },
{ SIG_SCI32, 1, MAP_CALL(DoSoundMute), "(i)", NULL },
{ SIG_SCI32, 2, MAP_EMPTY(DoSoundRestore), NULL, NULL },
{ SIG_SCI32, 3, MAP_CALL(DoSoundGetPolyphony), "", NULL },
{ SIG_SCI32, 4, MAP_CALL(DoSoundGetAudioCapability), "", NULL },
{ SIG_SCI32, 5, MAP_CALL(DoSoundSuspend), "i", NULL },
{ SIG_SCI32, 6, MAP_CALL(DoSoundInit), "o", NULL },
{ SIG_SCI32, 7, MAP_CALL(DoSoundDispose), "o", NULL },
{ SIG_SCI32, 8, MAP_CALL(DoSoundPlay), "o", kDoSoundPlay_workarounds },
{ SIG_SCI32, 9, MAP_CALL(DoSoundStop), "o", NULL },
{ SIG_SCI32, 10, MAP_CALL(DoSoundPause), "[o0]i", NULL },
{ SIG_SCI32, 11, MAP_CALL(DoSoundFade), "oiiii", kDoSoundFade_workarounds },
{ SIG_SCI32, 12, MAP_CALL(DoSoundSetHold), "oi", NULL },
{ SIG_SCI32, 13, MAP_EMPTY(DoSoundDummy), NULL, NULL },
{ SIG_SCI32, 14, MAP_CALL(DoSoundSetVolume), "oi", NULL },
{ SIG_SCI32, 15, MAP_CALL(DoSoundSetPriority), "oi", NULL },
{ SIG_SCI32, 16, MAP_CALL(DoSoundSetLoop), "oi", NULL },
{ SIG_SCI32, 17, MAP_CALL(DoSoundUpdateCues), "o", NULL },
{ SIG_SCI32, 18, MAP_CALL(DoSoundSendMidi), "oiiii", NULL },
{ SIG_SCI32, 19, MAP_CALL(DoSoundGlobalReverb), "(i)", NULL },
{ SIG_SCI32, 20, MAP_CALL(DoSoundUpdate), "o", NULL },
#endif
SCI_SUBOPENTRY_TERMINATOR
};
Expand Down Expand Up @@ -233,8 +227,9 @@ static const SciKernelMapSubEntry kDoAudio_subops[] = {
{ SIG_SCI32, 10, MAP_CALL(DoAudioBitDepth), "(i)", NULL },
{ SIG_SCI32, 11, MAP_DUMMY(DoAudioDistort), "(i)", NULL },
{ SIG_SCI32, 12, MAP_CALL(DoAudioMixing), "(i)", NULL },
{ SIG_SCI32, 13, MAP_CALL(DoAudioChannels), "(i)", NULL },
{ SIG_SCI32, 14, MAP_CALL(DoAudioPreload), "(i)", NULL },
{ SIG_SCI2, 13, MAP_EMPTY(DoAudioSetBufferSize), "i", NULL },
{ SIG_SINCE_SCI21, 13, MAP_CALL(DoAudioChannels), "(i)", NULL },
{ SIG_SINCE_SCI21, 14, MAP_CALL(DoAudioPreload), "(i)", NULL },
{ SIG_SINCE_SCI21MID, 15, MAP_CALL(DoAudioFade), "(iiii)(i)(i)", NULL },
{ SIG_SINCE_SCI21MID, 16, MAP_DUMMY(DoAudioFade36), "iiiii(iii)(i)", NULL },
{ SIG_SINCE_SCI21MID, 17, MAP_CALL(DoAudioHasSignal), "", NULL },
Expand Down Expand Up @@ -670,9 +665,9 @@ static SciKernelMapEntry s_kernelMap[] = {
{ MAP_CALL(DisposeList), SIG_EVERYWHERE, "l", NULL, NULL },
{ MAP_CALL(DisposeScript), SIG_EVERYWHERE, "i(i*)", NULL, kDisposeScript_workarounds },
{ MAP_CALL(DisposeWindow), SIG_EVERYWHERE, "i(i)", NULL, NULL },
{ MAP_CALL(DoAudio), SCI_VERSION_NONE, SCI_VERSION_2, SIGFOR_ALL, "i(.*)", NULL, NULL }, // subop
{ MAP_CALL(DoAudio), SIG_SCI16, SIGFOR_ALL, "i(.*)", NULL, NULL }, // subop
#ifdef ENABLE_SCI32
{ "DoAudio", kDoAudio32, SIG_SINCE_SCI21, SIGFOR_ALL, "(.*)", kDoAudio_subops, NULL },
{ "DoAudio", kDoAudio32, SIG_SCI32, SIGFOR_ALL, "(.*)", kDoAudio_subops, NULL },
#endif
{ MAP_CALL(DoAvoider), SIG_EVERYWHERE, "o(i)", NULL, NULL },
{ MAP_CALL(DoBresen), SIG_EVERYWHERE, "o", NULL, NULL },
Expand Down
9 changes: 3 additions & 6 deletions engines/sci/engine/savegame.cpp
Expand Up @@ -435,10 +435,7 @@ void EngineState::saveLoadWithSerializer(Common::Serializer &s) {
g_sci->_gfxPalette32->saveLoadWithSerializer(s);
g_sci->_gfxRemap32->saveLoadWithSerializer(s);
g_sci->_gfxCursor32->saveLoadWithSerializer(s);
// TODO: SCI2 should be using Audio32 too, but is not yet.
if (g_sci->_audio32) {
g_sci->_audio32->saveLoadWithSerializer(s);
}
g_sci->_audio32->saveLoadWithSerializer(s);
g_sci->_video32->saveLoadWithSerializer(s);
} else
#endif
Expand Down Expand Up @@ -714,10 +711,10 @@ void SoundCommandParser::reconstructPlayList() {
initSoundResource(entry);

#ifdef ENABLE_SCI32
if (_soundVersion >= SCI_VERSION_2_1_EARLY && entry->isSample) {
if (_soundVersion >= SCI_VERSION_2 && entry->isSample) {
const reg_t &soundObj = entry->soundObj;

if ((int)readSelectorValue(_segMan, soundObj, SELECTOR(loop)) != -1 &&
if (readSelectorValue(_segMan, soundObj, SELECTOR(loop)) == 0xFFFF &&
readSelector(_segMan, soundObj, SELECTOR(handle)) != NULL_REG) {

writeSelector(_segMan, soundObj, SELECTOR(handle), NULL_REG);
Expand Down
17 changes: 4 additions & 13 deletions engines/sci/resource_audio.cpp
Expand Up @@ -651,9 +651,7 @@ SoundResource::SoundResource(uint32 resourceNr, ResourceManager *resMan, SciVers

Channel *channel, *sampleChannel;

switch (_soundVersion) {
case SCI_VERSION_0_EARLY:
case SCI_VERSION_0_LATE:
if (_soundVersion <= SCI_VERSION_0_LATE) {
// SCI0 only has a header of 0x11/0x21 byte length and the actual midi track follows afterwards
_trackCount = 1;
_tracks = new Track[_trackCount];
Expand Down Expand Up @@ -693,11 +691,7 @@ SoundResource::SoundResource(uint32 resourceNr, ResourceManager *resMan, SciVers
_tracks->digitalSampleEnd = 0;
sampleChannel->data += 44; // Skip over header
}
break;

case SCI_VERSION_1_EARLY:
case SCI_VERSION_1_LATE:
case SCI_VERSION_2_1_EARLY: {
} else if (_soundVersion >= SCI_VERSION_1_EARLY && _soundVersion <= SCI_VERSION_2_1_MIDDLE) {
SciSpan<const byte> data = *resource;
// Count # of tracks
_trackCount = 0;
Expand Down Expand Up @@ -799,11 +793,8 @@ SoundResource::SoundResource(uint32 resourceNr, ResourceManager *resMan, SciVers
}
++data; // Skipping 0xFF that closes channels list
}
break;
}

default:
error("SoundResource: SCI version %d is unsupported", _soundVersion);
} else {
error("SoundResource: SCI version %s is unsupported", getSciVersionDesc(_soundVersion));
}
}

Expand Down
2 changes: 1 addition & 1 deletion engines/sci/sci.cpp
Expand Up @@ -315,7 +315,7 @@ Common::Error SciEngine::run() {
_guestAdditions = new GuestAdditions(_gamestate, _features, _kernel);
_eventMan = new EventManager(_resMan->detectFontExtended());
#ifdef ENABLE_SCI32
if (getSciVersion() >= SCI_VERSION_2_1_EARLY) {
if (getSciVersion() >= SCI_VERSION_2) {
_audio32 = new Audio32(_resMan);
} else
#endif
Expand Down
21 changes: 19 additions & 2 deletions engines/sci/sound/audio32.cpp
Expand Up @@ -114,7 +114,9 @@ Audio32::Audio32(ResourceManager *resMan) :
_monitoredBufferSize(0),
_numMonitoredSamples(0) {

if (getSciVersion() < SCI_VERSION_3) {
if (getSciVersion() < SCI_VERSION_2_1_EARLY) {
_channels.resize(10);
} else if (getSciVersion() < SCI_VERSION_3) {
_channels.resize(5);
} else {
_channels.resize(8);
Expand Down Expand Up @@ -311,7 +313,22 @@ int Audio32::readBuffer(Audio::st_sample_t *const buffer, const int numSamples)
Audio::st_volume_t leftVolume, rightVolume;

if (channel.pan == -1 || !isStereo()) {
leftVolume = rightVolume = channel.volume * Audio::Mixer::kMaxChannelVolume / kMaxVolume;
int volume = channel.volume;
if (getSciVersion() == SCI_VERSION_2) {
// NOTE: In SSCI, audio is decompressed into a temporary
// buffer, then the samples in that buffer are looped over,
// shifting each sample right 3, 2, or 1 bits to reduce the
// volume.
if (volume > 0 && volume <= 42) {
volume = 15;
} else if (volume > 42 && volume <= 84) {
volume = 31;
} else if (volume > 84 && volume < kMaxVolume) {
volume = 63;
}
}

leftVolume = rightVolume = volume * Audio::Mixer::kMaxChannelVolume / kMaxVolume;
} else {
// TODO: This should match the SCI3 algorithm,
// which seems to halve the volume of each
Expand Down
47 changes: 12 additions & 35 deletions engines/sci/sound/midiparser_sci.cpp
Expand Up @@ -752,18 +752,12 @@ bool MidiParser_SCI::processEvent(const EventInfo &info, bool fireEvents) {
case kUpdateCue:
if (!_jumpingToTick) {
int inc;
switch (_soundVersion) {
case SCI_VERSION_0_EARLY:
case SCI_VERSION_0_LATE:
if (_soundVersion <= SCI_VERSION_0_LATE) {
inc = info.basic.param2;
break;
case SCI_VERSION_1_EARLY:
case SCI_VERSION_1_LATE:
case SCI_VERSION_2_1_EARLY:
} else if (_soundVersion >= SCI_VERSION_1_EARLY && _soundVersion <= SCI_VERSION_2_1_MIDDLE) {
inc = 1;
break;
default:
error("unsupported _soundVersion");
} else {
error("Unsupported _soundVersion %s", getSciVersionDesc(_soundVersion));
}
_pSnd->dataInc += inc;
debugC(4, kDebugLevelSound, "datainc %04x", inc);
Expand Down Expand Up @@ -895,49 +889,32 @@ void MidiParser_SCI::allNotesOff() {
void MidiParser_SCI::setMasterVolume(byte masterVolume) {
assert(masterVolume <= MUSIC_MASTERVOLUME_MAX);
_masterVolume = masterVolume;
switch (_soundVersion) {
case SCI_VERSION_0_EARLY:
case SCI_VERSION_0_LATE:
if (_soundVersion <= SCI_VERSION_0_LATE) {
// update driver master volume
setVolume(_volume);
break;

case SCI_VERSION_1_EARLY:
case SCI_VERSION_1_LATE:
case SCI_VERSION_2_1_EARLY:
} else if (_soundVersion >= SCI_VERSION_1_EARLY && _soundVersion <= SCI_VERSION_2_1_MIDDLE) {
// directly set master volume (global volume is merged with channel volumes)
((MidiPlayer *)_driver)->setVolume(masterVolume);
break;

default:
error("MidiParser_SCI::setVolume: Unsupported soundVersion");
} else {
error("MidiParser_SCI::setVolume: Unsupported soundVersion %s", getSciVersionDesc(_soundVersion));
}
}

void MidiParser_SCI::setVolume(byte volume) {
assert(volume <= MUSIC_VOLUME_MAX);
_volume = volume;

switch (_soundVersion) {
case SCI_VERSION_0_EARLY:
case SCI_VERSION_0_LATE: {
if (_soundVersion <= SCI_VERSION_0_LATE) {
// SCI0 adlib driver doesn't support channel volumes, so we need to go this way
int16 globalVolume = _volume * _masterVolume / MUSIC_VOLUME_MAX;
((MidiPlayer *)_driver)->setVolume(globalVolume);
break;
}

case SCI_VERSION_1_EARLY:
case SCI_VERSION_1_LATE:
case SCI_VERSION_2_1_EARLY:
} else if (_soundVersion >= SCI_VERSION_1_EARLY && _soundVersion <= SCI_VERSION_2_1_MIDDLE) {
// Send previous channel volumes again to actually update the volume
for (int i = 0; i < 15; i++)
if (_channelRemap[i] != -1)
sendToDriver(0xB0 + i, 7, _channelVolume[i]);
break;

default:
error("MidiParser_SCI::setVolume: Unsupported soundVersion");
} else {
error("MidiParser_SCI::setVolume: Unsupported soundVersion %s", getSciVersionDesc(_soundVersion));
}
}

Expand Down
12 changes: 8 additions & 4 deletions engines/sci/sound/music.cpp
Expand Up @@ -215,7 +215,7 @@ void SciMusic::pauseAll(bool pause) {
#ifdef ENABLE_SCI32
// The entire DAC will have been paused by the caller;
// do not pause the individual samples too
if (_soundVersion >= SCI_VERSION_2_1_EARLY && (*i)->isSample) {
if (_soundVersion >= SCI_VERSION_2 && (*i)->isSample) {
continue;
}
#endif
Expand Down Expand Up @@ -483,7 +483,11 @@ void SciMusic::soundPlay(MusicEntry *pSnd) {

if (pSnd->isSample) {
#ifdef ENABLE_SCI32
if (_soundVersion >= SCI_VERSION_2_1_EARLY) {
if (_soundVersion >= SCI_VERSION_2) {
// TODO: Sound number, loop state, and volume come from soundObj
// in SSCI. Getting them from MusicEntry could cause a bug if the
// soundObj was updated by a game script and not copied back to
// MusicEntry.
g_sci->_audio32->restart(ResourceId(kResourceTypeAudio, pSnd->resourceId), true, pSnd->loop != 0 && pSnd->loop != 1, pSnd->volume, pSnd->soundObj, false);
return;
} else
Expand Down Expand Up @@ -567,7 +571,7 @@ void SciMusic::soundStop(MusicEntry *pSnd) {
pSnd->isQueued = false;
if (pSnd->isSample) {
#ifdef ENABLE_SCI32
if (_soundVersion >= SCI_VERSION_2_1_EARLY) {
if (_soundVersion >= SCI_VERSION_2) {
g_sci->_audio32->stop(ResourceId(kResourceTypeAudio, pSnd->resourceId), pSnd->soundObj);
} else {
#endif
Expand Down Expand Up @@ -642,7 +646,7 @@ void SciMusic::soundKill(MusicEntry *pSnd) {

if (pSnd->isSample) {
#ifdef ENABLE_SCI32
if (_soundVersion >= SCI_VERSION_2_1_EARLY) {
if (_soundVersion >= SCI_VERSION_2) {
g_sci->_audio32->stop(ResourceId(kResourceTypeAudio, pSnd->resourceId), pSnd->soundObj);
} else {
#endif
Expand Down

0 comments on commit d556dcc

Please sign in to comment.