SoundManager.cs 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233
  1. using Client.MirSounds.Libraries;
  2. using NAudio.Wave;
  3. using NAudio.Wave.SampleProviders;
  4. namespace Client.MirSounds
  5. {
  6. public static class SoundManager
  7. {
  8. private static Dictionary<int, string> _indexList => SoundList.Indexes;
  9. private static List<KeyValuePair<long, int>> _delayList = new List<KeyValuePair<long, int>>();
  10. private static Dictionary<int, CachedSound> _cachedOneShots = new Dictionary<int, CachedSound>();
  11. private static Dictionary<int, LoopProvider> _loopingSounds = new Dictionary<int, LoopProvider>();
  12. private static LoopProvider _music;
  13. private static WaveOutEvent _OneShots;
  14. private static MixingSampleProvider mixer;
  15. private static int _vol;
  16. private static int _musicVol;
  17. public static readonly List<string> SupportedFileTypes;
  18. private static long _checkSoundTime;
  19. public static ISoundLibrary Music => _music;
  20. public static int Vol
  21. {
  22. get { return _vol; }
  23. set
  24. {
  25. if (_vol == value) return;
  26. _vol = value;
  27. AdjustAllVolumes();
  28. }
  29. }
  30. public static int MusicVol
  31. {
  32. get { return _musicVol; }
  33. set
  34. {
  35. if (_musicVol == value) return;
  36. _musicVol = value;
  37. _music?.SetVolume(MusicVol);
  38. }
  39. }
  40. static SoundManager()
  41. {
  42. _checkSoundTime = CMain.Time + 30 * 1000;
  43. SupportedFileTypes = new List<string>
  44. {
  45. ".wav",
  46. ".mp3"
  47. };
  48. SoundList.LoadSoundList();
  49. }
  50. public static void Create()
  51. {
  52. int sampleRate = 44100;
  53. int channelCount = 2;
  54. _OneShots = new WaveOutEvent();
  55. mixer = new MixingSampleProvider(WaveFormat.CreateIeeeFloatWaveFormat(sampleRate, channelCount));
  56. mixer.ReadFully = true;
  57. _OneShots.Init(mixer);
  58. _OneShots.Volume = ScaleVolume(_vol);
  59. _OneShots.Play();
  60. }
  61. public static void PlaySound(int index, bool loop = false, int delay = 0)
  62. {
  63. CheckSoundTimeOut();
  64. if (delay > 0)
  65. {
  66. _delayList.Add(new KeyValuePair<long, int>(CMain.Time + delay, index));
  67. return;
  68. }
  69. if (!_indexList.ContainsKey(index))
  70. {
  71. string filename = index > 20000 ?
  72. string.Format("M{0:0}-{1:0}", (index - 20000) / 10, index % 10) :
  73. string.Format("{0:000}-{1:0}", index / 10, index % 10);
  74. _indexList.Add(index, filename);
  75. }
  76. if (!loop)
  77. {
  78. if (!_cachedOneShots.TryGetValue(index, out CachedSound cachedSound))
  79. {
  80. cachedSound = new CachedSound(index, _indexList[index]);
  81. _cachedOneShots.Add(index, cachedSound);
  82. }
  83. if (cachedSound.AudioData?.Length > 0)
  84. {
  85. AddMixerInput(new OneShotProvider(cachedSound));
  86. cachedSound.ExpireTime = CMain.Time + Settings.SoundCleanMinutes * 60 * 1000;
  87. }
  88. }
  89. else
  90. {
  91. var sound = LoopProvider.TryCreate(index, _indexList[index], MusicVol, loop);
  92. if (sound != null)
  93. {
  94. _loopingSounds.Add(index, sound);
  95. _loopingSounds[index].Play(Vol);
  96. }
  97. }
  98. }
  99. public static void StopSound(int index)
  100. {
  101. if (_loopingSounds.ContainsKey(index))
  102. {
  103. _loopingSounds[index].Stop();
  104. }
  105. }
  106. public static void PlayMusic(int index, bool loop = false)
  107. {
  108. StopMusic();
  109. if (_indexList.TryGetValue(index, out string value))
  110. {
  111. _music = LoopProvider.TryCreate(index, value, MusicVol, loop);
  112. }
  113. }
  114. public static void StopMusic()
  115. {
  116. _music?.Stop();
  117. _music?.Dispose();
  118. }
  119. public static void ProcessDelayedSounds()
  120. {
  121. if (_delayList.Count == 0) return;
  122. var sounds = _delayList.Where(x => x.Key <= CMain.Time).ToList();
  123. foreach (var sound in sounds)
  124. {
  125. _delayList.Remove(sound);
  126. PlaySound(sound.Value);
  127. }
  128. }
  129. private static void AdjustAllVolumes()
  130. {
  131. if (_OneShots != null)
  132. {
  133. _OneShots.Volume = ScaleVolume(Vol);
  134. }
  135. foreach (int key in _loopingSounds.Keys)
  136. {
  137. _loopingSounds[key].SetVolume(Vol);
  138. }
  139. }
  140. private static float ScaleVolume(int volume)
  141. {
  142. float scaled = 0.0f + (float)(volume - 0) / (100 - 0) * (1.0f - 0.0f);
  143. return scaled;
  144. }
  145. private static void AddMixerInput(ISampleProvider input)
  146. {
  147. mixer.AddMixerInput(ConvertToRightChannelCount(input));
  148. }
  149. private static ISampleProvider ConvertToRightChannelCount(ISampleProvider input)
  150. {
  151. if (input.WaveFormat.Channels == mixer.WaveFormat.Channels)
  152. {
  153. return input;
  154. }
  155. if (input.WaveFormat.Channels == 1 && mixer.WaveFormat.Channels == 2)
  156. {
  157. return new MonoToStereoSampleProvider(input);
  158. }
  159. throw new NotImplementedException("Not yet implemented this channel count conversion");
  160. }
  161. private static void CheckSoundTimeOut()
  162. {
  163. if (CMain.Time >= _checkSoundTime)
  164. {
  165. _checkSoundTime = CMain.Time + 30 * 1000;
  166. List<int> keysToRemove = new List<int>();
  167. foreach (var key in _cachedOneShots.Keys)
  168. {
  169. if (CMain.Time > _cachedOneShots[key].ExpireTime)
  170. {
  171. keysToRemove.Add(key);
  172. }
  173. }
  174. keysToRemove.ForEach(key => { _cachedOneShots.Remove(key); });
  175. keysToRemove.Clear();
  176. foreach(var key in _loopingSounds.Keys)
  177. {
  178. if (CMain.Time > _loopingSounds[key].ExpireTime)
  179. {
  180. keysToRemove.Add(key);
  181. }
  182. }
  183. keysToRemove.ForEach(key => { _loopingSounds.Remove(key); });
  184. }
  185. }
  186. public static void Dispose()
  187. {
  188. _OneShots?.Dispose();
  189. _music?.Dispose();
  190. foreach (var sound in _loopingSounds.Values) { sound.Stop(); }
  191. }
  192. }
  193. }