diff options
Diffstat (limited to 'engines/sci/sound/soundcmd.cpp')
| -rw-r--r-- | engines/sci/sound/soundcmd.cpp | 102 | 
1 files changed, 52 insertions, 50 deletions
| diff --git a/engines/sci/sound/soundcmd.cpp b/engines/sci/sound/soundcmd.cpp index 5d32f40f18..b0102a002b 100644 --- a/engines/sci/sound/soundcmd.cpp +++ b/engines/sci/sound/soundcmd.cpp @@ -116,7 +116,7 @@ void SoundCommandParser::processInitSound(reg_t obj) {  	newSound->resourceId = resourceId;  	newSound->soundObj = obj;  	newSound->loop = readSelectorValue(_segMan, obj, SELECTOR(loop)); -	newSound->priority = readSelectorValue(_segMan, obj, SELECTOR(pri)) & 0xFF; +	newSound->priority = readSelectorValue(_segMan, obj, SELECTOR(priority)) & 0xFF;  	if (_soundVersion >= SCI_VERSION_1_EARLY)  		newSound->volume = CLIP<int>(readSelectorValue(_segMan, obj, SELECTOR(vol)), 0, MUSIC_VOLUME_MAX);  	newSound->reverb = -1;	// initialize to SCI invalid, it'll be set correctly in soundInitSnd() below @@ -189,6 +189,10 @@ void SoundCommandParser::processPlaySound(reg_t obj) {  			resourceId, musicSlot->loop, musicSlot->priority, musicSlot->volume);  	_music->soundPlay(musicSlot); + +	// Reset any left-over signals +	musicSlot->signal = 0; +	musicSlot->fadeStep = 0;  }  reg_t SoundCommandParser::kDoSoundRestore(int argc, reg_t *argv, reg_t acc) { @@ -255,7 +259,7 @@ void SoundCommandParser::processStopSound(reg_t obj, bool sampleFinishedPlaying)  		writeSelectorValue(_segMan, obj, SELECTOR(signal), SIGNAL_OFFSET);  	musicSlot->dataInc = 0; -	musicSlot->signal = 0; +	musicSlot->signal = SIGNAL_OFFSET;  	_music->soundStop(musicSlot);  } @@ -340,6 +344,12 @@ reg_t SoundCommandParser::kDoSoundMasterVolume(int argc, reg_t *argv, reg_t acc)  reg_t SoundCommandParser::kDoSoundFade(int argc, reg_t *argv, reg_t acc) {  	reg_t obj = argv[0]; +	// The object can be null in several SCI0 games (e.g. Camelot, KQ1, KQ4, MUMG). +	// Check bugs #3035149, #3036942 and #3578335. +	// In this case, we just ignore the call. +	if (obj.isNull() && argc == 1) +		return acc; +  	MusicEntry *musicSlot = _music->getSlot(obj);  	if (!musicSlot) {  		debugC(kDebugLevelSound, "kDoSound(fade): Slot not found (%04x:%04x)", PRINT_REG(obj)); @@ -367,44 +377,27 @@ reg_t SoundCommandParser::kDoSoundFade(int argc, reg_t *argv, reg_t acc) {  	case 4: // SCI01+  	case 5: // SCI1+ (SCI1 late sound scheme), with fade and continue -		if (argc == 5) { -			// TODO: We currently treat this argument as a boolean, but may -			// have to handle different non-zero values differently. (e.g., -			// some KQ6 scripts pass 3 here). -			// There is a script bug in KQ6, room 460 (the room with the flying -			// books). An object is passed here, which should not be treated as -			// a true flag. Fixes bugs #3555404 and #3291115. -			musicSlot->stopAfterFading = (argv[4].isNumber() && argv[4].toUint16() != 0); -		} else { -			musicSlot->stopAfterFading = false; -		} -  		musicSlot->fadeTo = CLIP<uint16>(argv[1].toUint16(), 0, MUSIC_VOLUME_MAX);  		// Check if the song is already at the requested volume. If it is, don't  		// perform any fading. Happens for example during the intro of Longbow. -		if (musicSlot->fadeTo != musicSlot->volume) { -			// sometimes we get objects in that position, fix it up (ffs. workarounds) -			if (!argv[1].getSegment()) -				musicSlot->fadeStep = volume > musicSlot->fadeTo ? -argv[3].toUint16() : argv[3].toUint16(); -			else -				musicSlot->fadeStep = volume > musicSlot->fadeTo ? -5 : 5; -			musicSlot->fadeTickerStep = argv[2].toUint16() * 16667 / _music->soundGetTempo(); -		} else { -			// Stop the music, if requested. Fixes bug #3555404. -			if (musicSlot->stopAfterFading) -				processStopSound(obj, false); -		} +		if (musicSlot->fadeTo == musicSlot->volume) +			return acc; +		// Sometimes we get objects in that position, so fix the value (refer to workarounds.cpp) +		if (!argv[1].getSegment()) +			musicSlot->fadeStep = volume > musicSlot->fadeTo ? -argv[3].toUint16() : argv[3].toUint16(); +		else +			musicSlot->fadeStep = volume > musicSlot->fadeTo ? -5 : 5; +		musicSlot->fadeTickerStep = argv[2].toUint16() * 16667 / _music->soundGetTempo();  		musicSlot->fadeTicker = 0; -		// WORKAROUND/HACK: In the labyrinth in KQ6, when falling in the pit and -		// lighting the lantern, the game scripts perform a fade in of the game -		// music, but set it to stop after fading. Remove that flag here. This is -		// marked as both a workaround and a hack because this issue could be a -		// problem with our fading code and an incorrect handling of that -		// parameter, or a script bug in that scene. Fixes bug #3267956. -		if (g_sci->getGameId() == GID_KQ6 && g_sci->getEngineState()->currentRoomNumber() == 406 && -			musicSlot->resourceId == 400) +		// argv[4] is a boolean. Scripts sometimes pass strange values, +		// but SSCI only checks for zero/non-zero. (Verified in KQ6.) +		// KQ6 room 460 even passes an object, but treating this as 'true' +		// seems fine in that case. +		if (argc == 5) +			musicSlot->stopAfterFading = !argv[4].isNull(); +		else  			musicSlot->stopAfterFading = false;  		break; @@ -435,7 +428,7 @@ reg_t SoundCommandParser::kDoSoundUpdate(int argc, reg_t *argv, reg_t acc) {  	int16 objVol = CLIP<int>(readSelectorValue(_segMan, obj, SELECTOR(vol)), 0, 255);  	if (objVol != musicSlot->volume)  		_music->soundSetVolume(musicSlot, objVol); -	uint32 objPrio = readSelectorValue(_segMan, obj, SELECTOR(pri)); +	uint32 objPrio = readSelectorValue(_segMan, obj, SELECTOR(priority));  	if (objPrio != musicSlot->priority)  		_music->soundSetPriority(musicSlot, objPrio);  	return acc; @@ -495,12 +488,15 @@ void SoundCommandParser::processUpdateCues(reg_t obj) {  				processStopSound(obj, false);  		}  	} else { -		// Slot actually has no data (which would mean that a sound-resource w/ -		// unsupported data is used. -		//  (example lsl5 - sound resource 744 - it's Roland exclusive -		writeSelectorValue(_segMan, obj, SELECTOR(signal), SIGNAL_OFFSET); -		// If we don't set signal here, at least the switch to the mud wrestling -		// room in lsl5 will not work. +		// The sound slot has no data for the currently selected sound card. +		// An example can be found during the mud wrestling scene in LSL5, room +		// 730: sound 744 (a splat sound heard when Lana Luscious jumps in the +		// mud) only contains MIDI channel data. If a non-MIDI sound card is +		// selected (like Adlib), then the scene freezes. We also need to stop +		// the sound at this point, otherwise KQ6 Mac breaks because the rest +		// of the object needs to be reset to avoid a continuous stream of +		// sound cues. +		processStopSound(obj, true);	// this also sets the signal selector  	}  	if (musicSlot->fadeCompleted) { @@ -509,6 +505,8 @@ void SoundCommandParser::processUpdateCues(reg_t obj) {  		// fireworks).  		// It is also needed in other games, e.g. LSL6 when talking to the  		// receptionist (bug #3192166). +		// CHECKME: At least kq5cd/win and kq6 set signal to 0xFE here, but +		// kq5cd/dos does not set signal at all. Needs more investigation.  		writeSelectorValue(_segMan, obj, SELECTOR(signal), SIGNAL_OFFSET);  		if (_soundVersion <= SCI_VERSION_0_LATE) {  			processStopSound(obj, false); @@ -532,17 +530,21 @@ void SoundCommandParser::processUpdateCues(reg_t obj) {  }  reg_t SoundCommandParser::kDoSoundSendMidi(int argc, reg_t *argv, reg_t acc) { +	// The 4 parameter variant of this call is used in at least LSL1VGA, room +	// 110 (Lefty's bar), to distort the music when Larry is drunk and stands +	// up - bug #3614447.  	reg_t obj = argv[0];  	byte channel = argv[1].toUint16() & 0xf; -	byte midiCmd = argv[2].toUint16() & 0xff; +	byte midiCmd = (argc == 5) ? argv[2].toUint16() & 0xff : 0xB0;	// 0xB0: controller +	uint16 controller = (argc == 5) ? argv[3].toUint16() : argv[2].toUint16(); +	uint16 param = (argc == 5) ? argv[4].toUint16() : argv[3].toUint16(); -	// TODO: first there is a 4-parameter variant of this call which needs to get reversed -	//        second the current code isn't 100% accurate, sierra sci does checks on the 4th parameter -	if (argc == 4) -		return acc; - -	uint16 controller = argv[3].toUint16(); -	uint16 param = argv[4].toUint16(); +	if (argc == 4 && controller == 0xFF) { +		midiCmd = 0xE0;	// 0xE0: pitch wheel +		uint16 pitch = CLIP<uint16>(argv[3].toSint16() + 0x2000, 0x0000, 0x3FFF); +		controller = pitch & 0x7F; +		param = pitch >> 7; +	}  	debugC(kDebugLevelSound, "kDoSound(sendMidi): %04x:%04x, %d, %d, %d, %d", PRINT_REG(obj), channel, midiCmd, controller, param);  	if (channel) @@ -739,7 +741,7 @@ void SoundCommandParser::updateSci0Cues() {  	}  	if (noOnePlaying && pWaitingForPlay) { -		// If there is a queued entry, play it now ffs: SciMusic::soundPlay() +		// If there is a queued entry, play it now - check SciMusic::soundPlay()  		pWaitingForPlay->isQueued = false;  		_music->soundPlay(pWaitingForPlay);  	} | 
