PageRenderTime 81ms CodeModel.GetById 23ms RepoModel.GetById 1ms app.codeStats 0ms

/SimsVille/ContentManager/Audio.cs

https://gitlab.com/simscolony/FreeSims
C# | 290 lines | 200 code | 39 blank | 51 comment | 35 complexity | 1efd0c1f43793ede030cbe4eb0d8f9dc MD5 | raw file
  1. /*
  2. * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
  3. * If a copy of the MPL was not distributed with this file, You can obtain one at
  4. * http://mozilla.org/MPL/2.0/.
  5. */
  6. using System;
  7. using System.Collections.Generic;
  8. using System.Linq;
  9. using System.Text;
  10. using System.Diagnostics;
  11. using FSO.Content.Framework;
  12. using FSO.Content.Model;
  13. using System.Text.RegularExpressions;
  14. using FSO.Common.Content;
  15. using System.IO;
  16. using System.Runtime.InteropServices;
  17. using FSO.Files.Formats.DBPF;
  18. using FSO.Files.XA;
  19. using FSO.Files.UTK;
  20. using FSO.Files.HIT;
  21. using Microsoft.Xna.Framework.Audio;
  22. namespace FSO.Content
  23. {
  24. /// <summary>
  25. /// Manager for the audio content.
  26. /// </summary>
  27. public class Audio
  28. {
  29. private Content ContentManager;
  30. /** Stations **/
  31. private List<AudioReference> Stations;
  32. private Dictionary<uint, AudioReference> StationsById;
  33. private List<AudioReference> Modes;
  34. /** Audio DBPFs **/
  35. public DBPFFile TSOAudio; //TSOAudio.dat
  36. public DBPFFile tsov2; //tsov2.dat
  37. public DBPFFile Stings; //Stings.dat
  38. public DBPFFile EP5Samps; //EP5Samps.dat
  39. public DBPFFile EP2; //EP2.dat
  40. public DBPFFile Hitlists; //HitListsTemp.dat
  41. public Dictionary<uint, Track> TracksById;
  42. private Dictionary<uint, Hitlist> HitlistsById;
  43. /** Audio Cache **/
  44. public Dictionary<uint, SoundEffect> SFXCache;
  45. public Dictionary<string, string> StationPaths
  46. {
  47. get
  48. {
  49. return _StationPaths;
  50. }
  51. }
  52. public Dictionary<int, string> MusicModes
  53. {
  54. get
  55. {
  56. return _MusicModes;
  57. }
  58. }
  59. public Audio(Content contentManager)
  60. {
  61. this.ContentManager = contentManager;
  62. }
  63. /// <summary>
  64. /// Initializes the audio manager.
  65. /// </summary>
  66. public void Init()
  67. {
  68. this.Stations = new List<AudioReference>();
  69. this.StationsById = new Dictionary<uint, AudioReference>();
  70. this.Modes = new List<AudioReference>();
  71. var stationsRegEx = new Regex(@"music/stations/.*\.mp3");
  72. foreach (var file in ContentManager.AllFiles)
  73. {
  74. if (stationsRegEx.IsMatch(file))
  75. {
  76. var reference = new AudioReference { Type = AudioType.RADIO_STATION, FilePath = ContentManager.GetPath(file) };
  77. Stations.Add(reference);
  78. var idString = Path.GetFileNameWithoutExtension(file);
  79. idString = idString.Substring(idString.LastIndexOf("_") + 1);
  80. var id = Convert.ToUInt32(idString, 16);
  81. reference.ID = id;
  82. StationsById.Add(id, reference);
  83. }
  84. }
  85. if (File.Exists(ContentManager.GetPath("TSOAudio.dat")))
  86. TSOAudio = new DBPFFile(ContentManager.GetPath("TSOAudio.dat"));
  87. if (File.Exists(ContentManager.GetPath("tsov2.dat")))
  88. tsov2 = new DBPFFile(ContentManager.GetPath("tsov2.dat"));
  89. if (File.Exists(ContentManager.GetPath("Stings.dat")))
  90. Stings = new DBPFFile(ContentManager.GetPath("Stings.dat"));
  91. if (File.Exists(ContentManager.GetPath("EP5Samps.dat")))
  92. EP5Samps = new DBPFFile(ContentManager.GetPath("EP5Samps.dat"));
  93. if (File.Exists(ContentManager.GetPath("EP2.dat")))
  94. EP2 = new DBPFFile(ContentManager.GetPath("EP2.dat"));
  95. if (File.Exists(ContentManager.GetPath("HitListsTemp.dat")))
  96. Hitlists = new DBPFFile(ContentManager.GetPath("HitListsTemp.dat"));
  97. SFXCache = new Dictionary<uint, SoundEffect>();
  98. TracksById = new Dictionary<uint, Track>();
  99. HitlistsById = new Dictionary<uint, Hitlist>();
  100. if (TSOAudio != null)
  101. AddTracksFrom(TSOAudio);
  102. }
  103. /// <summary>
  104. /// Gets a track from a DBPF using its InstanceID.
  105. /// </summary>
  106. /// <param name="dbpf">The DBPF to search.</param>
  107. private void AddTracksFrom(DBPFFile dbpf)
  108. {
  109. var tracks = dbpf.GetItemsByType(DBPFTypeID.TRK);
  110. for (var i=0; i<tracks.Count; i++)
  111. {
  112. TracksById.Add(tracks[i].Key, new Track(tracks[i].Value));
  113. }
  114. }
  115. /// <summary>
  116. /// Gets a audio file from a DBPF using its InstanceID.
  117. /// </summary>
  118. /// <param name="InstanceID">The InstanceID of the audio.</param>
  119. /// <param name="dbpf">The DBPF to search.</param>
  120. /// <returns>The audio as a stream of bytes.</returns>
  121. private byte[] GetAudioFrom(uint InstanceID, DBPFFile dbpf)
  122. {
  123. if (InstanceID == 0)
  124. return null;
  125. //all game sfx has type id 0x2026960B
  126. byte[] dat = dbpf.GetItemByID((ulong)DBPFTypeID.SoundFX + (((ulong)InstanceID)<<32));
  127. if (dat != null)
  128. {
  129. string head = new string(new char[] { (char)dat[0], (char)dat[1], (char)dat[2], (char)dat[3] });
  130. if (head.StartsWith("XA"))
  131. return new XAFile(dat).DecompressedData;
  132. else if (head.StartsWith("UTM0"))
  133. {
  134. var utk = new UTKFile2(dat);
  135. utk.UTKDecode();
  136. return utk.DecompressedWav;
  137. }
  138. else
  139. return dat; //either wav or mp3.
  140. }
  141. //else
  142. //Debug.WriteLine("Couldn't find sound!");
  143. return null;
  144. }
  145. /// <summary>
  146. /// Gets a Hitlist from a DBPF using its InstanceID.
  147. /// </summary>
  148. /// <param name="InstanceID">The InstanceID of the Hitlist.</param>
  149. /// <param name="dbpf">The DBPF to search.</param>
  150. /// <returns>A Hitlist instance.</returns>
  151. private Hitlist GetHitlistFrom(uint InstanceID, DBPFFile dbpf)
  152. {
  153. var hit = dbpf.GetItemByID((ulong)DBPFTypeID.HIT + (((ulong)InstanceID) << 32));
  154. if (hit != null) return new Hitlist(hit);
  155. return null;
  156. }
  157. /// <summary>
  158. /// Gets a Hitlist from a DBPF using its InstanceID.
  159. /// </summary>
  160. /// <param name="InstanceID">The InstanceID of the Hitlist.</param>
  161. /// <returns>A Hitlist instance.</returns>
  162. public Hitlist GetHitlist(uint InstanceID)
  163. {
  164. if (HitlistsById.ContainsKey(InstanceID)) return HitlistsById[InstanceID];
  165. var hit1 = GetHitlistFrom(InstanceID, Hitlists);
  166. if (hit1 != null)
  167. {
  168. HitlistsById.Add(InstanceID, hit1);
  169. return HitlistsById[InstanceID];
  170. }
  171. var hit2 = GetHitlistFrom(InstanceID, TSOAudio);
  172. if (hit2 != null)
  173. {
  174. HitlistsById.Add(InstanceID, hit2);
  175. return HitlistsById[InstanceID];
  176. }
  177. return null; //found nothing :'(
  178. }
  179. /// <summary>
  180. /// Gets a sound effect from the sound effects cache.
  181. /// </summary>
  182. /// <param name="InstanceID">The InstanceID of the sound effect.</param>
  183. /// <returns>The sound effect as a GCHandle instance.</returns>
  184. public SoundEffect GetSFX(uint InstanceID)
  185. {
  186. if (SFXCache.ContainsKey(InstanceID)) return SFXCache[InstanceID];
  187. byte[] data = GetAudioFrom(InstanceID, TSOAudio);
  188. if (data == null) data = GetAudioFrom(InstanceID, tsov2);
  189. if (data == null) data = GetAudioFrom(InstanceID, Stings);
  190. if (data == null) data = GetAudioFrom(InstanceID, EP5Samps);
  191. if (data == null) data = GetAudioFrom(InstanceID, EP2);
  192. if (data != null)
  193. {
  194. var stream = new MemoryStream(data);
  195. var sfx = SoundEffect.FromStream(stream);
  196. stream.Close();
  197. SFXCache.Add(InstanceID, sfx);
  198. return sfx; //remember to clear the sfx cache between lots!
  199. }
  200. else
  201. {
  202. //GCHandle pinnedArray = GCHandle.Alloc(new byte[1], GCHandleType.Weak);
  203. return null;// pinnedArray; //we couldn't find anything! can't return null so do this... not the best idea tbh
  204. }
  205. }
  206. /// <summary>
  207. /// Compiles the radio stations in the game to a list of AudioReference instances.
  208. /// </summary>
  209. /// <returns>The radio stations in the game as a list of AudioReference instances.</returns>
  210. public List<AudioReference> List()
  211. {
  212. var result = new List<AudioReference>();
  213. result.AddRange(Stations);
  214. return result;
  215. }
  216. private Dictionary<string, string> _StationPaths = new Dictionary<string, string>
  217. {
  218. {"KBEA", "Music/Stations/Beach/"},
  219. {"KCLA", "Music/Stations/Classica/"},
  220. {"KCOU", "Music/Stations/Country/"},
  221. {"KCDA", "Music/Stations/CountryD/"},
  222. {"KDIS", "Music/Stations/Disco/"},
  223. {"KEZE", "Music/Stations/EZ/"},
  224. {"KEZX", "Music/Stations/EZX/"},
  225. {"KLAT", "Music/Stations/Latin/"},
  226. {"KRAP", "Music/Stations/Rap/"},
  227. {"KRAV", "Music/Stations/Rave/"},
  228. {"KROC", "Music/Stations/Rock/"},
  229. // These ones aren't radio stations - they're UI music
  230. {"KMAP", "Music/Modes/Map/"},
  231. {"KSEL", "Music/Modes/Select/"},
  232. {"KCRE", "Music/Modes/Create/"},
  233. //tv
  234. { "KACT", "sounddata/tvstations/tv_action/" },
  235. { "KCOM", "sounddata/tvstations/tv_comedy_cartoon/" },
  236. { "KMYS", "sounddata/tvstations/tv_mystery/" },
  237. { "KROM", "sounddata/tvstations/tv_romance/" },
  238. // More music
  239. {"KHOR", "Music/Stations/Horror/"},
  240. {"KOLD", "Music/Stations/OldWorld/"},
  241. {"KSCI", "Music/Stations/SciFi/"},
  242. };
  243. private Dictionary<int, string> _MusicModes = new Dictionary<int, string>
  244. {
  245. { 11, "KSEL" },
  246. { 12, "KCRE" },
  247. { 13, "KMAP" },
  248. { 9, "" }
  249. };
  250. }
  251. }