Fixes for progress bar and applause sounds (#906)
* Control score sounds from UpdateGame instead of the thread pool _PlayProgressBarSound started a Task that waited for the progress bar duration and then closed whatever stream was stored in _ProgressBarSoundStream. When switching rounds on the score screen before that time had passed, an old task closed the progress bar sound of the new round too early and played the applause of the previous round, while the applause of the new round never played. Remember when the progress bar sound was started and check it in UpdateGame on the main thread instead. Starting a new progress bar sound and leaving the screen now also stop a running applause. * Sync progress bar sound with the score bar animation The sound duration was computed from the points (10,000 points = 5 seconds), while the bar animation duration depends on the bar size in the theme and only starts when the bar is first drawn. Both only matched approximately and drifted apart with other themes. Add CProgressBar.AnimatesMovement and CProgressBar.IsAnimating. The score screen now stops the progress bar sound and starts the applause as soon as no visible score bar is animating anymore. If the theme has no movement animation, the previous duration is used. * Make stream id allocation in CPlaybackBase thread-safe Load assigned stream ids with _NextId++ outside of the lock. Load is also called from other threads, so two streams could get the same id and a later Close or Play could hit the wrong stream. Use Interlocked.Increment instead. Ids still start at 0. * Do not play the progress bar sound for 0 points With 0 points the score bars do not move, so the progress bar sound started and stopped again right away, which could be heard as a short click. Do not start it at all if the highest score is 0.
This commit is contained in:
1 parent
d5e5f3fbeb
commit
d48426b04d
3 files changed
+69
-32
No files matched your search
@@ -160,7 +160,7 @@ namespace Vocaluxe.Lib.Sound.Playback
|
||||
return -1;
|
||||
}
|
||||
|
||||
var stream = _CreateStream(_NextId++, medium, loop, effect);
|
||||
var stream = _CreateStream(Interlocked.Increment(ref _NextId) - 1, medium, loop, effect);
|
||||
|
||||
if (stream.Open(prescan))
|
||||
{
|
||||
|
||||
@@ -17,8 +17,8 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
using Vocaluxe.Base;
|
||||
using Vocaluxe.Base.Server;
|
||||
@@ -155,6 +155,8 @@ namespace Vocaluxe.Screens
|
||||
|
||||
public override bool UpdateGame()
|
||||
{
|
||||
_UpdateProgressBarSound();
|
||||
|
||||
var players = new SPlayer[CGame.NumPlayers];
|
||||
if (_Round >= 0)
|
||||
{
|
||||
@@ -295,39 +297,73 @@ namespace Vocaluxe.Screens
|
||||
}
|
||||
|
||||
private int _ProgressBarSoundStream = -1;
|
||||
private readonly Stopwatch _ProgressBarSoundTimer = new Stopwatch();
|
||||
private double _ProgressBarSoundDuration;
|
||||
private int _ProgressBarSoundMaxPoints;
|
||||
|
||||
private void _PlayProgressBarSound(int maxPoints)
|
||||
{
|
||||
// Stop any previous ProgressBar sound
|
||||
_StopScoreSounds();
|
||||
|
||||
// Do not play in Karaoke Mode
|
||||
if (CScreenSong.GetAudioMode() == EAudioMode.TR_AUDIOMODE_KARAOKE)
|
||||
if (CScreenSong.GetAudioMode() == EAudioMode.TR_AUDIOMODE_KARAOKE || maxPoints <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Stop any previous ProgressBar sound
|
||||
if (_ProgressBarSoundStream != -1)
|
||||
{
|
||||
CSound.Close(_ProgressBarSoundStream);
|
||||
_ProgressBarSoundStream = -1;
|
||||
}
|
||||
|
||||
// Calculate duration: 10,000 points = 5 seconds
|
||||
var duration = Math.Min(maxPoints / 10000.0, 1.0) * 5;
|
||||
_ProgressBarSoundDuration = Math.Min(maxPoints / 10000.0, 1.0) * 5;
|
||||
_ProgressBarSoundMaxPoints = maxPoints;
|
||||
|
||||
// Play the sound
|
||||
_ProgressBarSoundStream = PlaySound(ESounds.ProgressBar, CConfig.SoundEffectVolume);
|
||||
_ProgressBarSoundTimer.Restart();
|
||||
}
|
||||
|
||||
// Schedule stop after duration and start Applause sound
|
||||
Task.Run(async () =>
|
||||
private void _UpdateProgressBarSound()
|
||||
{
|
||||
if (!_ProgressBarSoundTimer.IsRunning || !_IsProgressBarAnimationFinished())
|
||||
{
|
||||
await Task.Delay((int)(duration * 1000));
|
||||
if (_ProgressBarSoundStream != -1)
|
||||
{
|
||||
CSound.Close(_ProgressBarSoundStream);
|
||||
_ProgressBarSoundStream = -1;
|
||||
_PlayApplauseSound(maxPoints);
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
_ProgressBarSoundTimer.Reset();
|
||||
_CloseStream(ref _ProgressBarSoundStream);
|
||||
_PlayApplauseSound(_ProgressBarSoundMaxPoints);
|
||||
}
|
||||
|
||||
private bool _IsProgressBarAnimationFinished()
|
||||
{
|
||||
var animatedProgressBars = Enumerable.Range(0, CGame.NumPlayers)
|
||||
.Select(p => _ProgressBars[_ProgressBarPoints[p, CGame.NumPlayers - 1]])
|
||||
.Where(progressBar => progressBar.Visible && progressBar.AnimatesMovement)
|
||||
.ToList();
|
||||
|
||||
if (animatedProgressBars.Count == 0)
|
||||
{
|
||||
return _ProgressBarSoundTimer.Elapsed.TotalSeconds >= _ProgressBarSoundDuration;
|
||||
}
|
||||
|
||||
return !animatedProgressBars.Any(progressBar => progressBar.IsAnimating);
|
||||
}
|
||||
|
||||
private void _StopScoreSounds()
|
||||
{
|
||||
_ProgressBarSoundTimer.Reset();
|
||||
_CloseStream(ref _ProgressBarSoundStream);
|
||||
_CloseStream(ref _ApplauseStream);
|
||||
}
|
||||
|
||||
private static void _CloseStream(ref int stream)
|
||||
{
|
||||
if (stream == -1)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
CSound.Close(stream);
|
||||
stream = -1;
|
||||
}
|
||||
|
||||
private int _ApplauseStream = -1;
|
||||
@@ -531,17 +567,7 @@ namespace Vocaluxe.Screens
|
||||
|
||||
private void _LeaveScreen()
|
||||
{
|
||||
if (_ApplauseStream != -1)
|
||||
{
|
||||
CSound.Close(_ApplauseStream);
|
||||
_ApplauseStream = -1;
|
||||
}
|
||||
|
||||
if (_ProgressBarSoundStream != -1)
|
||||
{
|
||||
CSound.Close(_ProgressBarSoundStream);
|
||||
_ProgressBarSoundStream = -1;
|
||||
}
|
||||
_StopScoreSounds();
|
||||
|
||||
if (CScreenSong.GetAudioMode() == EAudioMode.TR_AUDIOMODE_KARAOKE)
|
||||
{
|
||||
|
||||
@@ -144,6 +144,17 @@ namespace VocaluxeLib.Menu
|
||||
_ProgressTarget = value;
|
||||
}
|
||||
}
|
||||
|
||||
public bool AnimatesMovement
|
||||
{
|
||||
get { return _AnimateMovement == EOffOn.TR_CONFIG_ON; }
|
||||
}
|
||||
|
||||
public bool IsAnimating
|
||||
{
|
||||
get { return AnimatesMovement && _ProgressCurrent != _ProgressTarget; }
|
||||
}
|
||||
|
||||
private float _ProgressCurrent;
|
||||
private float _ProgressLast;
|
||||
|
||||
|
||||
Reference in new issue
Block a user