[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