2
0

Sound.cs 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
  1. using System.Collections.Generic;
  2. using System.IO;
  3. using System.Linq;
  4. namespace OpenVIII.AV
  5. {
  6. public static partial class Sound
  7. {
  8. #region Fields
  9. public const int MaxChannels = 20;
  10. private static int _currentChannel;
  11. private static IReadOnlyList<Entry> _entries;
  12. #endregion Fields
  13. #region Properties
  14. public static int CurrentChannel
  15. {
  16. get => _currentChannel;
  17. set
  18. {
  19. if (value >= MaxChannels)
  20. {
  21. value = 0;
  22. }
  23. else if (value < 0)
  24. {
  25. value = MaxChannels - 1;
  26. }
  27. _currentChannel = value;
  28. }
  29. }
  30. public static int EntriesCount => _entries?.Count ?? 0;
  31. /// <summary>
  32. /// This is for short lived sound effects. The Larger the array is the more sounds can be
  33. /// played at once. If you want sounds to loop of have volume you'll need to have a
  34. /// SoundEffectInstance added to ffcc, and have those sounds be played like music where they
  35. /// loop in the background till stop.
  36. /// </summary>
  37. public static Audio[] SoundChannels { get; } = new Audio[MaxChannels];
  38. #endregion Properties
  39. #region Methods
  40. public static void Init()
  41. {
  42. Memory.Log.WriteLine($"{nameof(Sound)} :: {nameof(Init)}");
  43. var path = Path.Combine(Memory.FF8DirData, "Sound", "audio.fmt");
  44. Stream s = null;
  45. if (File.Exists(path))
  46. {
  47. s = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
  48. }
  49. else
  50. {
  51. var other = ArchiveZzz.Load(Memory.Archives.ZZZ_OTHER);
  52. if (other.GetBinaryFile("audio.dat", true) != null) //cache's audio.dat
  53. s = new MemoryStream(other.GetBinaryFile("audio.fmt"), false);
  54. }
  55. if (s == null) return;
  56. _entries = Entry.Read(s);
  57. Memory.Log.WriteLine($"{nameof(Sound)} :: {nameof(Init)} loaded {EntriesCount} {nameof(Entry)}(s)");
  58. }
  59. public static void KillAudio() => SoundChannels?.Where(x => x != null && !x.IsDisposed).ForEach(action => action.Dispose());
  60. /// <summary>
  61. /// Play sound effect
  62. /// </summary>
  63. /// <param name="soundId">
  64. /// ID number of sound
  65. /// <para>The real game uses soundID + 1, so you may need to -1 from any scripts.</para>
  66. /// </param>
  67. /// <param name="persist">
  68. /// <para>If set sound will not be saved to SoundChannels</para>
  69. /// <para>
  70. /// It will be up to the calling object to keep track of the sound object that is returned.
  71. /// </para>
  72. /// </param>
  73. /// <param name="loop">If loop, sound will loop from the set sample number.</param>
  74. public static Audio Play(int soundId, float volume = 1.0f, float pitch = 0.0f, float pan = 0.0f, bool persist = false, bool loop = false)
  75. {
  76. if (_entries == null || _entries[soundId].Size == 0)
  77. {
  78. return null;
  79. }
  80. var ffcc = Audio.Load(_entries[soundId], loop ? 0 : -1);
  81. if (!persist)
  82. SoundChannels[CurrentChannel++] = ffcc;
  83. ffcc.Play(volume, pitch, pan);
  84. return ffcc;
  85. }
  86. #endregion Methods
  87. }
  88. }