using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using FDK.ExtensionMethods;
namespace FDK
{
///
/// SoundGroupLevelController holds the current sound level value for each
/// of the unique sound groups, along with an increment by which they can
/// easily be adjusted.
///
/// Configuration changes to the sound group levels are provided to the
/// controller via binding code which allows CConfigIni and
/// SoundGroupLevelController to be unaware of one another.
/// See ConfigIniToSoundGroupLevelControllerBinder for more details.
///
/// Dynamic adjustment of sound group levels during song selection and song
/// playback are managed via a small dependency taken by the respective
/// stage classes. See KeyboardSoundGroupLevelControlHandler and its usages
/// for more details.
///
/// As new sound objects are created, including when reloading sounds due
/// to a changer in audio output device, SoundGroupLevelController ensures
/// that they are provided with the current level for their associated
/// sound group by subscribing to notifications regarding changes to a
/// collection of sound objects provided during construction. This
/// observable collection comes from the sound manager, but without either
/// it or this class being directly aware of one another.
///
/// As sound group levels are changed, SoundGroupLevelController updates
/// all existing sound objects group levels by iterating that same
/// observable collection.
///
public sealed class SoundGroupLevelController
{
private readonly Dictionary _levelBySoundGroup = new Dictionary
{
[ESoundGroup.SoundEffect] = CSound.MaximumGroupLevel,
[ESoundGroup.Voice] = CSound.MaximumGroupLevel,
[ESoundGroup.SongPreview] = CSound.MaximumGroupLevel,
[ESoundGroup.SongPlayback] = CSound.MaximumGroupLevel,
[ESoundGroup.Unknown] = CSound.MaximumGroupLevel
};
private readonly ObservableCollection _sounds;
private int _keyboardSoundLevelIncrement;
public SoundGroupLevelController(ObservableCollection sounds)
{
_sounds = sounds;
_sounds.CollectionChanged += SoundsOnCollectionChanged;
}
public void SetLevel(ESoundGroup soundGroup, int level)
{
var clampedLevel = level.Clamp(CSound.MinimumGroupLevel, CSound.MaximumGroupLevel);
if (_levelBySoundGroup[soundGroup] == clampedLevel)
{
return;
}
_levelBySoundGroup[soundGroup] = clampedLevel;
foreach (var sound in _sounds)
{
if (sound.SoundGroup == soundGroup)
{
SetLevel(sound);
}
}
RaiseLevelChanged(soundGroup, clampedLevel);
}
public void SetKeyboardSoundLevelIncrement(int keyboardSoundLevelIncrement)
{
_keyboardSoundLevelIncrement = keyboardSoundLevelIncrement;
}
public void AdjustLevel(ESoundGroup soundGroup, bool isAdjustmentPositive)
{
var adjustmentIncrement = isAdjustmentPositive
? _keyboardSoundLevelIncrement
: -_keyboardSoundLevelIncrement;
SetLevel(soundGroup, _levelBySoundGroup[soundGroup] + adjustmentIncrement);
}
private void SetLevel(CSound sound)
{
sound.GroupLevel = _levelBySoundGroup[sound.SoundGroup];
}
private void SoundsOnCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
switch (e.Action)
{
case NotifyCollectionChangedAction.Add:
case NotifyCollectionChangedAction.Replace:
foreach (CSound sound in e.NewItems)
{
SetLevel(sound);
}
break;
}
}
private void RaiseLevelChanged(ESoundGroup soundGroup, int level)
{
LevelChanged?.Invoke(this, new LevelChangedEventArgs(soundGroup, level));
}
public class LevelChangedEventArgs : EventArgs
{
public LevelChangedEventArgs(ESoundGroup soundGroup, int level)
{
SoundGroup = soundGroup;
Level = level;
}
public ESoundGroup SoundGroup { get; private set; }
public int Level { get; private set; }
}
public event EventHandler LevelChanged;
}
}