SCI32: Use better audio fading algorithm

Using the one from SCI2.1mid makes fades very slow because SDL has
a larger audio buffer than SSCI DOS. This new algorithm is based on
wall time so will always fade at the correct speed, although the
larger buffers will have a coarser granularity so the fades may
not be as smooth as in the original engine. If anyone cares, the
fade volume could be mixed into individual samples in `readBuffer`
instead of applying just once per complete buffer. SSCI did not
do this, however, so this implementation should be pretty accurate.
This commit is contained in:
Colin Snover 2016-07-01 12:38:59 -05:00
parent e8552cf96c
commit b7dcf5f6c1
2 changed files with 32 additions and 35 deletions

View File

@ -305,7 +305,7 @@ int Audio32::readBuffer(Audio::st_sample_t *buffer, const int numSamples) {
// Channel finished fading and had the // Channel finished fading and had the
// stopChannelOnFade flag set, so no longer exists // stopChannelOnFade flag set, so no longer exists
if (channel.fadeStepsRemaining && processFade(channelIndex)) { if (channel.fadeStartTick && processFade(channelIndex)) {
--channelIndex; --channelIndex;
continue; continue;
} }
@ -602,8 +602,7 @@ uint16 Audio32::play(int16 channelIndex, const ResourceId resourceId, const bool
channel.loop = loop; channel.loop = loop;
channel.robot = false; channel.robot = false;
channel.vmd = false; channel.vmd = false;
channel.lastFadeTick = 0; channel.fadeStartTick = 0;
channel.fadeStepsRemaining = 0;
channel.soundNode = soundNode; channel.soundNode = soundNode;
channel.volume = volume < 0 || volume > kMaxVolume ? (int)kMaxVolume : volume; channel.volume = volume < 0 || volume > kMaxVolume ? (int)kMaxVolume : volume;
// TODO: SCI3 introduces stereo audio // TODO: SCI3 introduces stereo audio
@ -927,12 +926,12 @@ bool Audio32::fadeChannel(const int16 channelIndex, const int16 targetVolume, co
return false; return false;
} }
if (steps) { if (steps && speed) {
channel.fadeVolume = targetVolume; channel.fadeStartTick = g_sci->getTickCount();
channel.fadeSpeed = speed; channel.fadeStartVolume = channel.volume;
channel.fadeStepsRemaining = steps; channel.fadeTargetVolume = targetVolume;
channel.fadeDuration = speed * steps;
channel.stopChannelOnFade = stopAfterFade; channel.stopChannelOnFade = stopAfterFade;
channel.lastFadeTick = g_sci->getTickCount();
} else { } else {
setVolume(channelIndex, targetVolume); setVolume(channelIndex, targetVolume);
} }
@ -944,28 +943,28 @@ bool Audio32::processFade(const int16 channelIndex) {
Common::StackLock lock(_mutex); Common::StackLock lock(_mutex);
AudioChannel &channel = getChannel(channelIndex); AudioChannel &channel = getChannel(channelIndex);
uint32 now = g_sci->getTickCount(); if (channel.fadeStartTick) {
const uint32 fadeElapsed = g_sci->getTickCount() - channel.fadeStartTick;
if (channel.lastFadeTick + channel.fadeSpeed <= now) { if (fadeElapsed > channel.fadeDuration) {
--channel.fadeStepsRemaining; channel.fadeStartTick = 0;
if (!channel.fadeStepsRemaining) {
if (channel.stopChannelOnFade) { if (channel.stopChannelOnFade) {
stop(channelIndex); stop(channelIndex);
return true; return true;
} else { } else {
setVolume(channelIndex, channel.fadeVolume); setVolume(channelIndex, channel.fadeTargetVolume);
} }
} else { return false;
int volume = channel.volume - (channel.volume - channel.fadeVolume) / (channel.fadeStepsRemaining + 1);
if (volume == channel.fadeVolume) {
channel.fadeStepsRemaining = 1;
}
setVolume(channelIndex, volume);
channel.lastFadeTick = now;
} }
int volume;
if (channel.fadeStartVolume > channel.fadeTargetVolume) {
volume = channel.fadeStartVolume - fadeElapsed * (channel.fadeStartVolume - channel.fadeTargetVolume) / channel.fadeDuration;
} else {
volume = channel.fadeStartVolume + fadeElapsed * (channel.fadeTargetVolume - channel.fadeStartVolume) / channel.fadeDuration;
}
setVolume(channelIndex, volume);
return false;
} }
return false; return false;

View File

@ -90,27 +90,25 @@ struct AudioChannel {
bool loop; bool loop;
/** /**
* The time the last fade iteration occurred. * The time, in ticks, that the channel fade began.
* If 0, the channel is not being faded.
*/ */
uint32 lastFadeTick; uint32 fadeStartTick;
/** /**
* The target volume of the fade. * The start volume of a fade.
*/ */
int fadeVolume; int fadeStartVolume;
/** /**
* The number of ticks that should elapse between * The total length of the fade, in ticks.
* each change of volume.
*/ */
int fadeSpeed; uint32 fadeDuration;
/** /**
* The number of iterations the fade should take to * The end volume of a fade.
* complete. If this value is 0, it indicates that the
* channel is not fading.
*/ */
int fadeStepsRemaining; uint32 fadeTargetVolume;
/** /**
* Whether or not the channel should be stopped and * Whether or not the channel should be stopped and