[Scummvm-git-logs] scummvm master -> 5d59972e3b59e40c09b5f83729c0f0ca4fb7e89c

aquadran aquadran at gmail.com
Mon Dec 7 20:47:41 UTC 2020


This automated email contains information about 1 new commit which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .

Summary:
5d59972e3b SCUMM: COMI: rebalance audio mix and implement music ducking during speech (#2653)


Commit: 5d59972e3b59e40c09b5f83729c0f0ca4fb7e89c
    https://github.com/scummvm/scummvm/commit/5d59972e3b59e40c09b5f83729c0f0ca4fb7e89c
Author: AndywinXp (andywinxp at gmail.com)
Date: 2020-12-07T21:47:37+01:00

Commit Message:
SCUMM: COMI: rebalance audio mix and implement music ducking during speech (#2653)

* SCUMM: COMI: implement volume ducking for music tracks during speech audio
* SCUMM: COMI: balance the default audio mix

Changed paths:
    engines/scumm/imuse_digi/dimuse.cpp
    engines/scumm/imuse_digi/dimuse.h
    engines/scumm/imuse_digi/dimuse_track.cpp
    engines/scumm/imuse_digi/dimuse_track.h


diff --git a/engines/scumm/imuse_digi/dimuse.cpp b/engines/scumm/imuse_digi/dimuse.cpp
index 3461f63fcc..80b8edcee8 100644
--- a/engines/scumm/imuse_digi/dimuse.cpp
+++ b/engines/scumm/imuse_digi/dimuse.cpp
@@ -100,6 +100,7 @@ void IMuseDigital::resetState() {
 	_stopingSequence = 0;
 	_radioChatterSFX = 0;
 	_triggerUsed = false;
+	_speechIsPlaying = false;
 }
 
 static void syncWithSerializer(Common::Serializer &s, Track &t) {
@@ -203,6 +204,18 @@ void IMuseDigital::saveLoadEarly(Common::Serializer &s) {
 void IMuseDigital::callback() {
 	Common::StackLock lock(_mutex, "IMuseDigital::callback()");
 
+	_speechIsPlaying = false;
+	// Check for any track playing a speech line
+	if (_vm->_game.id == GID_CMI) {
+		for (int l = 0; l < MAX_DIGITAL_TRACKS; l++) {
+			if (_track[l]->used && _track[l]->soundId == kTalkSoundID) {
+				// Set flag and break
+				_speechIsPlaying = true;
+				break;
+			}
+		}
+	}
+
 	for (int l = 0; l < MAX_DIGITAL_TRACKS + MAX_DIGITAL_FADETRACKS; l++) {
 		Track *track = _track[l];
 		if (track->used) {
@@ -278,6 +291,30 @@ void IMuseDigital::callback() {
  				debug(5, "Fade: sound(%d), Vol(%d) in track(%d)", track->soundId, track->vol / 1000, track->trackId);
 			}
 
+			// Music gain reduction during speech
+			if (_vm->_game.id == GID_CMI && track->volGroupId == IMUSE_VOLGRP_MUSIC) {
+				if (_speechIsPlaying) {
+					// Check if we have to fade down or the reduction volume is already at the right value
+					if (track->gainReduction >= track->gainRedFadeDest) {
+						track->gainRedFadeUsed = false;
+						track->gainReduction = track->gainRedFadeDest; // Clip to destination volume
+					} else {
+						track->gainRedFadeUsed = true;
+					}
+					// Gradually bring up the gain reduction (20 ms)
+					if (track->gainRedFadeUsed && track->gainReduction < track->gainRedFadeDest) {
+						int tempReduction = transformVolumeEqualPowToLinear(track->gainReduction, 2); // Equal power to linear...
+						tempReduction += (track->gainRedFadeDest - track->gainReduction) * 60 * (1000 / _callbackFps) / (1000 * 20); // Add step...
+						track->gainReduction = transformVolumeLinearToEqualPow(tempReduction, 2); // Linear to equal power...
+						debug(5, "Gain reduction: sound(%d), reduction amount(%d) in track(%d)", track->soundId, track->gainReduction / 1000, track->trackId);
+					}
+				} else if (!_speechIsPlaying && track->gainReduction > 0) {
+					// Just like the original interpreter, disable gain reduction immediately without a fade
+					track->gainReduction = 0;
+					debug(5, "Gain reduction: no speech playing reduction stopped for sound(%d) in track(%d)", track->soundId, track->trackId);
+				}
+			}
+
 			if (!track->souStreamUsed) {
 				assert(track->stream);
 				byte *tmpSndBufferPtr = NULL;
@@ -387,8 +424,24 @@ void IMuseDigital::callback() {
 				} while (feedSize != 0);
 			}
 			if (_mixer->isReady()) {
-				_mixer->setChannelVolume(track->mixChanHandle, track->getVol());
-				_mixer->setChannelBalance(track->mixChanHandle, track->getPan());
+				int effVol = track->getVol();
+				int effPan = track->getPan();
+				if (_vm->_game.id == GID_CMI && track->volGroupId == IMUSE_VOLGRP_MUSIC) {
+					effVol -= track->gainReduction / 1000;
+					if (effVol < 0) // In case a music crossfading happens during gain reduction...
+						effVol = 0;
+					effVol = int(round(effVol * 1.9)); // Adjust default music mix for COMI
+				} else if (_vm->_game.id == GID_CMI && track->volGroupId == IMUSE_VOLGRP_VOICE) {
+					// Just in case the speakingActor is not being set...
+					// This allows for a fallback to pan = 64 (center) and volume = 127 (full)
+					if (track->speakingActor != nullptr) {
+						effVol = track->speakingActor->_talkVolume;
+						effVol = int(round(effVol * 1.04));
+						effPan = (track->speakingActor->_talkPan != 64) ? 2 * track->speakingActor->_talkPan - 127 : 0;
+					}
+				}
+				_mixer->setChannelVolume(track->mixChanHandle, effVol);
+				_mixer->setChannelBalance(track->mixChanHandle, effPan);
 			}
 		}
 	}
diff --git a/engines/scumm/imuse_digi/dimuse.h b/engines/scumm/imuse_digi/dimuse.h
index df173867fb..12871efd06 100644
--- a/engines/scumm/imuse_digi/dimuse.h
+++ b/engines/scumm/imuse_digi/dimuse.h
@@ -88,6 +88,7 @@ private:
 	int32 _curMusicCue;		// current cue for current music. used in FT
 	int _stopingSequence;
 	bool _radioChatterSFX;
+	bool _speechIsPlaying;
 
 	static void timer_handler(void *refConf);
 	void callback();
diff --git a/engines/scumm/imuse_digi/dimuse_track.cpp b/engines/scumm/imuse_digi/dimuse_track.cpp
index b242b57010..94e6475a23 100644
--- a/engines/scumm/imuse_digi/dimuse_track.cpp
+++ b/engines/scumm/imuse_digi/dimuse_track.cpp
@@ -134,6 +134,12 @@ void IMuseDigital::startSound(int soundId, const char *soundName, int soundType,
 				freq = (freq * a->_talkFrequency) / 256;
 				track->pan = a->_talkPan;
 				track->vol = a->_talkVolume * 1000;
+				// Keep track of the current actor in COMI:
+				// This is necessary since pan and volume settings for actors
+				// are often changed AFTER the speech sound is started,
+				// so this is a way to keep track of the changes in real time.
+				if (_vm->_game.id == GID_CMI)
+					track->speakingActor = a;
 			}
 
 			// The volume is set to zero, when using subtitles only setting in COMI
@@ -244,6 +250,15 @@ void IMuseDigital::setPan(int soundId, int pan) {
 	Common::StackLock lock(_mutex, "IMuseDigital::setPan()");
 	debug(5, "IMuseDigital::setPan(%d, %d)", soundId, pan);
 
+	// Sometimes, COMI scumm scripts try to set pan values in the range 0-255
+	// instead of 0-128. I sincerely have no idea why and what exactly is the 
+	// correct way of handling these cases (does it happen on a sound by sound basis?).
+	// Until someone properly reverse engineers the engine, this fix works fine for
+	// those sounds (e.g. the cannon fire SFX in Part 1 minigame, the bell sound
+	// in Plunder Town).
+	if (_vm->_game.id == GID_CMI && pan > 127)
+		pan = pan / 2;
+
 	for (int l = 0; l < MAX_DIGITAL_TRACKS; l++) {
 		Track *track = _track[l];
 		if (track->used && !track->toBeRemoved && (track->soundId == soundId)) {
@@ -439,9 +454,6 @@ int IMuseDigital::transformVolumeLinearToEqualPow(int volume, int mode) {
 		case 5:  // Logarithmic 3
 			eqPowValue = 1 + 0.7 * log10(mappedValue);
 			break;
-		case 6:  // Half sine curve
-			eqPowValue = (1.0 - cos(mappedValue * M_PI)) / 2.0;
-			break;
 		default: // Fallback to linear
 			eqPowValue = mappedValue;
 			break;
@@ -484,9 +496,6 @@ int IMuseDigital::transformVolumeEqualPowToLinear(int volume, int mode) {
 		case 5:  // Logarithmic 3
 			linearValue = 0.0372759 * pow(M_E, 3.28941 * mappedValue);
 			break;
-		case 6:  // Half sine curve
-			linearValue = (2 * asin(sqrt(mappedValue))) / M_PI; // Ricontrolla
-			break;
 		default: // Fallback to linear
 			linearValue = mappedValue;
 			break;
diff --git a/engines/scumm/imuse_digi/dimuse_track.h b/engines/scumm/imuse_digi/dimuse_track.h
index 9f62fe95b9..3be31cb7f3 100644
--- a/engines/scumm/imuse_digi/dimuse_track.h
+++ b/engines/scumm/imuse_digi/dimuse_track.h
@@ -45,47 +45,53 @@ enum {
 };
 
 struct Track {
-	int trackId;		// used to identify track by value (0-15)
-
-	int8 pan;			// panning value of sound
-	int32 vol;			// volume level (values 0-127 * 1000)
-	int32 volFadeDest;	// volume level which fading target (values 0-127 * 1000)
-	int32 volFadeStep;	// delta of step while changing volume at each imuse callback
-	int32 volFadeDelay;	// time in ms how long fading volume must be
-	bool volFadeUsed;	// flag if fading is in progress
-
-	int32 soundId;		// sound id used by scumm script
-	char soundName[15]; // sound name but also filename of sound in bundle data
-	bool used;			// flag mean that track is used
-	bool toBeRemoved;   // flag mean that track need to be free
-	bool souStreamUsed;	// flag mean that track use stream from sou file
-	bool sndDataExtComp;// flag mean that sound data is compressed by scummvm tools
-	int32 soundPriority;// priority level of played sound (0-127)
-	int32 regionOffset; // offset to sound data relative to begining of current region
-	int32 dataOffset;	// offset to sound data relative to begining of 'DATA' chunk
-	int32 curRegion;	// id of current used region
-	int32 curHookId;	// id of current used hook id
-	int32 volGroupId;	// id of volume group (IMUSE_VOLGRP_VOICE, IMUSE_VOLGRP_SFX, IMUSE_VOLGRP_MUSIC)
-	int32 soundType;	// type of sound data (IMUSE_BUNDLE, IMUSE_RESOURCE)
-	int32 feedSize;		// size of sound data needed to be filled at each callback iteration
-	int32 dataMod12Bit;	// value used between all callback to align 12 bit source of data
-	int32 mixerFlags;	// flags for sound mixer's channel (kFlagStereo, kFlag16Bits, kFlagUnsigned)
+	int trackId;		   // used to identify track by value (0-15)
+						   
+	int8 pan;			   // panning value of sound
+	int32 vol;			   // volume level (values 0-127 * 1000)
+	int32 volFadeDest;	   // volume level which fading target (values 0-127 * 1000)
+	int32 volFadeStep;	   // delta of step while changing volume at each imuse callback
+	int32 volFadeDelay;	   // time in ms how long fading volume must be
+	bool volFadeUsed;	   // flag if fading is in progress
+	int32 gainReduction;   // amount of volume to subtract
+	int32 gainRedFadeDest; // target of fade for gain reduction
+	bool gainRedFadeUsed;  // flag if fading is in progress
+	int32 soundId;		   // sound id used by scumm script
+	char soundName[15];    // sound name but also filename of sound in bundle data
+	bool used;			   // flag mean that track is used
+	bool toBeRemoved;      // flag mean that track need to be free
+	bool souStreamUsed;	   // flag mean that track use stream from sou file
+	bool sndDataExtComp;   // flag mean that sound data is compressed by scummvm tools
+	int32 soundPriority;   // priority level of played sound (0-127)
+	int32 regionOffset;    // offset to sound data relative to begining of current region
+	int32 dataOffset;	   // offset to sound data relative to begining of 'DATA' chunk
+	int32 curRegion;	   // id of current used region
+	int32 curHookId;	   // id of current used hook id
+	int32 volGroupId;	   // id of volume group (IMUSE_VOLGRP_VOICE, IMUSE_VOLGRP_SFX, IMUSE_VOLGRP_MUSIC)
+	int32 soundType;	   // type of sound data (IMUSE_BUNDLE, IMUSE_RESOURCE)
+	int32 feedSize;		   // size of sound data needed to be filled at each callback iteration
+	int32 dataMod12Bit;	   // value used between all callback to align 12 bit source of data
+	int32 mixerFlags;	   // flags for sound mixer's channel (kFlagStereo, kFlag16Bits, kFlagUnsigned)
 
 	ImuseDigiSndMgr::SoundDesc *soundDesc;	// sound handle used by iMuse sound manager
-	Audio::SoundHandle mixChanHandle;					// sound mixer's channel handle
+	Audio::SoundHandle mixChanHandle;		// sound mixer's channel handle
 	Audio::QueuingAudioStream *stream;		// sound mixer's audio stream handle for *.la1 and *.bun
+	Actor *speakingActor;					// actor reference for CMI speech
 
 	Track() : soundId(-1), used(false), stream(nullptr) {
 	}
 
 	void reset() {
 		trackId = 0;
-		pan = 0;
+		pan = 64;
 		vol = 0;
 		volFadeDest = 0;
 		volFadeStep = 0;
 		volFadeDelay = 0;
 		volFadeUsed = false;
+		gainReduction = 0;
+		gainRedFadeDest = 127 * 290; // About 4 dB of gain reduction
+		gainRedFadeUsed = false;
 		soundId = 0;
 		memset(soundName, 0, sizeof(soundName));
 		used = false;
@@ -103,6 +109,7 @@ struct Track {
 		mixerFlags = 0;
 		soundDesc = nullptr;
 		stream = nullptr;
+		speakingActor = nullptr;
 	}
 
 	int getPan() const { return (pan != 64) ? 2 * pan - 127 : 0; }




More information about the Scummvm-git-logs mailing list