init_debugger_Audio.cs 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Text;
  4. using System.IO;
  5. #if _WINDOWS && !_X64
  6. using DirectMidi;
  7. #endif
  8. using System.Runtime.InteropServices;
  9. using NAudio.Vorbis;
  10. using FFmpeg.AutoGen;
  11. using System.Diagnostics;
  12. using System.Linq;
  13. namespace FF8
  14. {
  15. #pragma warning disable IDE1006 // Naming Styles
  16. public static class init_debugger_Audio
  17. #pragma warning restore IDE1006 // Naming Styles
  18. {
  19. #if _WINDOWS && !_X64
  20. private static CDirectMusic cdm;
  21. private static CDLSLoader loader;
  22. private static CSegment segment;
  23. private static CAPathPerformance path;
  24. public static CPortPerformance cport; //public explicit
  25. private static COutputPort outport;
  26. private static CCollection ccollection;
  27. private static CInstrument[] instruments;
  28. #endif
  29. private static byte[] getBytes(object aux)
  30. {
  31. int length = Marshal.SizeOf(aux);
  32. IntPtr ptr = Marshal.AllocHGlobal(length);
  33. byte[] myBuffer = new byte[length];
  34. Marshal.StructureToPtr(aux, ptr, true);
  35. Marshal.Copy(ptr, myBuffer, 0, length);
  36. Marshal.FreeHGlobal(ptr);
  37. return myBuffer;
  38. }
  39. [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
  40. private struct SoundEntry
  41. {
  42. public UInt32 Size;
  43. public UInt32 Offset;
  44. private UInt32 output_TotalSize => Size + 70; // Total bytes of file -8 because for some reason 8 bytes don't count
  45. private const UInt32 output_HeaderSize = 50; //Total bytes of Header
  46. private UInt32 output_DataSize => Size; //Total bytes of Data Section
  47. //public byte[] UNK; //12
  48. //public WAVEFORMATEX WAVFORMATEX; //18 header starts here
  49. //public ushort SamplesPerBlock; //2
  50. //public ushort ADPCM; //2
  51. //public ADPCMCOEFSET[] ADPCMCoefSets; //array should be of [ADPCM] size //7*4 = 28
  52. public byte[] HeaderData;
  53. public void fillHeader(BinaryReader br)
  54. {
  55. if (HeaderData == null)
  56. {
  57. HeaderData = new byte[output_HeaderSize + 28];
  58. using (MemoryStream ms = new MemoryStream(HeaderData))
  59. {
  60. ms.Write(System.Text.Encoding.ASCII.GetBytes("RIFF"), 0, 4);
  61. ms.Write(getBytes(output_TotalSize), 0, 4);
  62. ms.Write(System.Text.Encoding.ASCII.GetBytes("WAVEfmt "), 0, 8);
  63. ms.Write(getBytes(output_HeaderSize), 0, 4);
  64. ms.Write(br.ReadBytes((int)output_HeaderSize), 0, (int)output_HeaderSize);
  65. ms.Write(System.Text.Encoding.ASCII.GetBytes("data"), 0, 4);
  66. ms.Write(getBytes(output_DataSize), 0, 4);
  67. }
  68. }
  69. }
  70. }
  71. #pragma warning disable CS0649
  72. [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
  73. public struct WAVEFORMATEX
  74. {
  75. public ushort wFormatTag;
  76. public ushort nChannels;
  77. public uint nSamplesPerSec;
  78. public uint nAvgBytesPerSec;
  79. public ushort nBlockAlign;
  80. public ushort wBitsPerSample;
  81. public ushort cbSize;
  82. }
  83. [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
  84. private struct ADPCMCOEFSET
  85. {
  86. public short iCoef1;
  87. public short iCoef2;
  88. };
  89. #pragma warning restore CS0649
  90. private static SoundEntry[] soundEntries;
  91. public static int soundEntriesCount;
  92. public const int S_OK = 0x00000000;
  93. public const int MaxSoundChannels = 20;
  94. /// <summary>
  95. /// This is for short lived sound effects. The Larger the array is the more sounds can be
  96. /// played at once. If you want sounds to loop of have volume you'll need to have a
  97. /// SoundEffectInstance added to ffcc, and have those sounds be played like music where they
  98. /// loop in the background till stop.
  99. /// </summary>
  100. public static Ffcc[] SoundChannels { get; } = new Ffcc[MaxSoundChannels];
  101. public static int CurrentSoundChannel
  102. {
  103. get => _currentSoundChannel;
  104. set
  105. {
  106. if (value >= MaxSoundChannels)
  107. {
  108. value = 0;
  109. }
  110. else if (value < 0)
  111. {
  112. value = MaxSoundChannels - 1;
  113. }
  114. _currentSoundChannel = value;
  115. }
  116. }
  117. public static void Init()
  118. {
  119. string dmusic_pt = "", RaW_ogg_pt = "", music_pt = "", music_wav_pt = "";
  120. //Roses and Wine V07 moves most of the sgt files to dmusic_backup
  121. //it leaves a few files behind. I think because RaW doesn't replace everything.
  122. //ogg files stored in:
  123. RaW_ogg_pt = Extended.GetUnixFullPath(Path.Combine(Memory.FF8DIR, "RaW/GLOBAL/Music"));
  124. if (!Directory.Exists(RaW_ogg_pt))
  125. {
  126. RaW_ogg_pt = null;
  127. }
  128. // From what I gather the OGG files and the sgt files have the same numerical prefix. I
  129. // might try to add the functionality to the debug screen monday.
  130. dmusic_pt = Extended.GetUnixFullPath(Path.Combine(Memory.FF8DIRdata, "Music","dmusic_backup"));
  131. if (!Directory.Exists(dmusic_pt))
  132. {
  133. dmusic_pt = null;
  134. }
  135. music_pt = Extended.GetUnixFullPath(Path.Combine(Memory.FF8DIRdata, "Music","dmusic"));
  136. if (!Directory.Exists(music_pt))
  137. {
  138. music_pt = null;
  139. }
  140. music_wav_pt = Extended.GetUnixFullPath(Path.Combine(Memory.FF8DIRdata, "Music"));
  141. if (!Directory.Exists(music_wav_pt))
  142. {
  143. music_wav_pt = null;
  144. }
  145. // goal of dicmusic is to be able to select a track by prefix. it adds an list of files
  146. // with the same prefix. so you can later on switch out which one you want.
  147. if (RaW_ogg_pt != null)
  148. {
  149. Memory.musices = Directory.GetFiles(RaW_ogg_pt).Where(x=> x.EndsWith(".ogg",StringComparison.OrdinalIgnoreCase)).ToArray();
  150. foreach (string m in Memory.musices)
  151. {
  152. if (ushort.TryParse(Path.GetFileName(m).Substring(0, 3), out ushort key))
  153. {
  154. //mismatched prefix's go here
  155. if (key == 512)
  156. {
  157. key = 0; //loser.ogg and sgt don't match.
  158. }
  159. if (!Memory.dicMusic.ContainsKey(key))
  160. {
  161. Memory.dicMusic.Add(key, new List<string> { m });
  162. }
  163. else
  164. {
  165. Memory.dicMusic[key].Add(m);
  166. }
  167. }
  168. }
  169. }
  170. if (dmusic_pt != null)
  171. {
  172. Memory.musices = Directory.GetFiles(dmusic_pt).Where(x => x.EndsWith(".sgt", StringComparison.OrdinalIgnoreCase)).ToArray();
  173. foreach (string m in Memory.musices)
  174. {
  175. if (ushort.TryParse(Path.GetFileName(m).Substring(0, 3), out ushort key))
  176. {
  177. if (!Memory.dicMusic.ContainsKey(key))
  178. {
  179. Memory.dicMusic.Add(key, new List<string> { m });
  180. }
  181. else
  182. {
  183. Memory.dicMusic[key].Add(m);
  184. }
  185. }
  186. else
  187. {
  188. if (!Memory.dicMusic.ContainsKey(999)) //gets any music w/o prefix
  189. {
  190. Memory.dicMusic.Add(999, new List<string> { m });
  191. }
  192. else
  193. {
  194. Memory.dicMusic[999].Add(m);
  195. }
  196. }
  197. }
  198. }
  199. if (music_pt != null)
  200. {
  201. Memory.musices = Directory.GetFiles(music_pt).Where(x => x.EndsWith(".sgt", StringComparison.OrdinalIgnoreCase)).ToArray();
  202. foreach (string m in Memory.musices)
  203. {
  204. if (ushort.TryParse(Path.GetFileName(m).Substring(0, 3), out ushort key))
  205. {
  206. if (!Memory.dicMusic.ContainsKey(key))
  207. {
  208. Memory.dicMusic.Add(key, new List<string> { m });
  209. }
  210. else
  211. {
  212. Memory.dicMusic[key].Add(m);
  213. }
  214. }
  215. else
  216. {
  217. if (!Memory.dicMusic.ContainsKey(999)) //gets any music w/o prefix
  218. {
  219. Memory.dicMusic.Add(999, new List<string> { m });
  220. }
  221. else
  222. {
  223. Memory.dicMusic[999].Add(m);
  224. }
  225. }
  226. }
  227. }
  228. if (music_wav_pt != null)
  229. {
  230. Memory.musices = Directory.GetFiles(music_wav_pt).Where(x => x.EndsWith(".wav", StringComparison.OrdinalIgnoreCase)).ToArray();
  231. foreach (string m in Memory.musices)
  232. {
  233. if (ushort.TryParse(Path.GetFileName(m).Substring(0, 3), out ushort key))
  234. {
  235. if (!Memory.dicMusic.ContainsKey(key))
  236. {
  237. Memory.dicMusic.Add(key, new List<string> { m });
  238. }
  239. else
  240. {
  241. Memory.dicMusic[key].Add(m);
  242. }
  243. }
  244. else
  245. {
  246. if (!Memory.dicMusic.ContainsKey(999)) //gets any music w/o prefix
  247. {
  248. Memory.dicMusic.Add(999, new List<string> { m });
  249. }
  250. else
  251. {
  252. Memory.dicMusic[999].Add(m);
  253. }
  254. }
  255. }
  256. }
  257. }
  258. //I messed around here as figuring out how things worked probably didn't need to mess with this.
  259. public static void Init_SoundAudio()
  260. {
  261. string path = Path.Combine(Memory.FF8DIRdata, "Sound","audio.fmt");
  262. if(File.Exists(path))
  263. using (FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read))
  264. using (BinaryReader br = new BinaryReader(fs))
  265. {
  266. soundEntries = new SoundEntry[br.ReadUInt32()];
  267. fs.Seek(36, SeekOrigin.Current);
  268. for (int i = 0; i < soundEntries.Length - 1; i++)
  269. {
  270. UInt32 sz = br.ReadUInt32();
  271. if (sz == 0)
  272. {
  273. fs.Seek(34, SeekOrigin.Current); continue;
  274. }
  275. soundEntries[i] = new SoundEntry
  276. {
  277. Size = sz,
  278. Offset = br.ReadUInt32()
  279. };
  280. fs.Seek(12, SeekOrigin.Current);
  281. soundEntries[i].fillHeader(br);
  282. }
  283. }
  284. soundEntriesCount = soundEntries ==null ? 0: soundEntries.Length;
  285. }
  286. public static void PlaySound(int soundID)
  287. {
  288. if (soundEntries == null || soundEntries[soundID].Size == 0)
  289. {
  290. return;
  291. }
  292. SoundChannels[CurrentSoundChannel] = new Ffcc(
  293. new Ffcc.Buffer_Data { DataSeekLoc = soundEntries[soundID].Offset, DataSize = soundEntries[soundID].Size, HeaderSize = (uint)soundEntries[soundID].HeaderData.Length },
  294. soundEntries[soundID].HeaderData,
  295. Path.Combine(Memory.FF8DIRdata, "Sound","audio.dat"));
  296. SoundChannels[CurrentSoundChannel++].Play();
  297. }
  298. public static void StopSound()
  299. {
  300. //waveout.Stop();
  301. }
  302. public static void Update()
  303. {
  304. //checks to see if music buffer is running low and getframe triggers a refill.
  305. //if (ffccMusic != null && !ffccMusic.Ahead)
  306. //{
  307. // ffccMusic.Next();
  308. //}
  309. //if played in task we don't need to do this.
  310. }
  311. //callable test
  312. public static byte[] ReadFullyByte(Stream stream)
  313. {
  314. // following formula goal is to calculate the number of bytes to make buffer. might be wrong.
  315. long size = stream.Length; // stream.Length should be in bytes. will error later if short.
  316. int start = 0;
  317. byte[] buffer = new byte[size];
  318. int read = 0;
  319. //do
  320. //{
  321. read = stream.Read(buffer, start, buffer.Length);
  322. start++;
  323. //}
  324. //while (read == 0 && start < size);
  325. if (read == 0)
  326. {
  327. return null;
  328. }
  329. if (read < size)
  330. {
  331. Array.Resize<byte>(ref buffer, read);
  332. }
  333. return buffer;
  334. }
  335. public static byte[] ReadFullyFloat(VorbisWaveReader stream)
  336. {
  337. // following formula goal is to calculate the number of bytes to make buffer. might be wrong.
  338. long size = (stream.Length / sizeof(float)) + 100; //unsure why but read was > than size so added 100; will error if the size is too small.
  339. float[] buffer = new float[size];
  340. int read = stream.Read(buffer, 0, buffer.Length);
  341. return GetSamplesWaveData(buffer, read);
  342. }
  343. public static byte[] GetSamplesWaveData(byte[] samples, int samplesCount)
  344. {
  345. float[] f = new float[(samplesCount / sizeof(float))];
  346. int i = 0;
  347. for (int n = 0; n < samples.Length; n += sizeof(float))
  348. {
  349. f[i++] = BitConverter.ToSingle(samples, n);
  350. }
  351. return GetSamplesWaveData(f, samplesCount / sizeof(float));
  352. }
  353. public static byte[] GetSamplesWaveData(float[] samples, int samplesCount)
  354. { // converts 32 bit float samples to 16 bit pcm. I think :P
  355. // https://stackoverflow.com/questions/31957211/how-to-convert-an-array-of-int16-sound-samples-to-a-byte-array-to-use-in-monogam/42151979#42151979
  356. byte[] pcm = new byte[samplesCount * 2];
  357. int sampleIndex = 0,
  358. pcmIndex = 0;
  359. while (sampleIndex < samplesCount)
  360. {
  361. short outsample = (short)(samples[sampleIndex] * short.MaxValue);
  362. pcm[pcmIndex] = (byte)(outsample & 0xff);
  363. pcm[pcmIndex + 1] = (byte)((outsample >> 8) & 0xff);
  364. sampleIndex++;
  365. pcmIndex += 2;
  366. }
  367. return pcm;
  368. }
  369. private static bool musicplaying = false;
  370. private static int lastplayed = -1;
  371. public static void PlayStopMusic()
  372. {
  373. if (!musicplaying || lastplayed != Memory.MusicIndex)
  374. {
  375. PlayMusic();
  376. }
  377. else
  378. {
  379. StopMusic();
  380. }
  381. }
  382. private static Ffcc ffccMusic = null; // testing using class to play music instead of Naudio / Nvorbis
  383. private static int _currentSoundChannel;
  384. public static void PlayMusic()
  385. {
  386. string ext = "";
  387. bool bFakeLinux = false; //set to force linux behaviour on windows; To delete after Linux music playable
  388. if (Memory.dicMusic.Count > 0 && Memory.dicMusic[Memory.MusicIndex].Count > 0)
  389. {
  390. ext = Path.GetExtension(Memory.dicMusic[Memory.MusicIndex][0]).ToLower();
  391. }
  392. else
  393. return;
  394. string pt = Memory.dicMusic[Memory.MusicIndex][0];
  395. StopMusic();
  396. switch (ext)
  397. {
  398. case ".ogg":
  399. //ffccMusic = new Ffcc(@"c:\eyes_on_me.wav", AVMediaType.AVMEDIA_TYPE_AUDIO, Ffcc.FfccMode.STATE_MACH);
  400. if (ffccMusic != null)
  401. ffccMusic.Dispose();
  402. ffccMusic = new Ffcc(pt, AVMediaType.AVMEDIA_TYPE_AUDIO, Ffcc.FfccMode.STATE_MACH);
  403. ffccMusic.PlayInTask(.5f);
  404. break;
  405. case ".sgt":
  406. if(Extended.IsLinux || bFakeLinux)
  407. {
  408. ReadSegmentFileManually(pt);
  409. break;
  410. }
  411. if (!Extended.IsLinux)
  412. {
  413. #if _WINDOWS && !_X64
  414. if (cdm == null)
  415. {
  416. cdm = new CDirectMusic();
  417. cdm.Initialize();
  418. loader = new CDLSLoader();
  419. loader.Initialize();
  420. loader.LoadSegment(pt, out segment);
  421. ccollection = new CCollection();
  422. string pathDLS = Path.Combine(Memory.FF8DIRdata, "Music/dmusic_backup/FF8.dls");
  423. if (!File.Exists(pathDLS))
  424. {
  425. pathDLS = Path.Combine(Memory.FF8DIRdata, "Music/dmusic/FF8.dls");
  426. }
  427. loader.LoadDLS(pathDLS, out ccollection);
  428. uint dwInstrumentIndex = 0;
  429. while (ccollection.EnumInstrument(++dwInstrumentIndex, out INSTRUMENTINFO iInfo) == S_OK)
  430. {
  431. Debug.WriteLine(iInfo.szInstName);
  432. }
  433. instruments = new CInstrument[dwInstrumentIndex];
  434. path = new CAPathPerformance();
  435. path.Initialize(cdm, null, null, DMUS_APATH.DYNAMIC_3D, 128);
  436. cport = new CPortPerformance();
  437. cport.Initialize(cdm, null, null);
  438. outport = new COutputPort();
  439. outport.Initialize(cdm);
  440. uint dwPortCount = 0;
  441. INFOPORT infoport;
  442. do
  443. {
  444. outport.GetPortInfo(++dwPortCount, out infoport);
  445. }
  446. while ((infoport.dwFlags & DMUS_PC.SOFTWARESYNTH) == 0);
  447. outport.SetPortParams(0, 0, 0, DirectMidi.SET.REVERB | DirectMidi.SET.CHORUS, 44100);
  448. outport.ActivatePort(infoport);
  449. cport.AddPort(outport, 0, 1);
  450. for (int i = 0; i < dwInstrumentIndex; i++)
  451. {
  452. ccollection.GetInstrument(out instruments[i], i);
  453. outport.DownloadInstrument(instruments[i]);
  454. }
  455. segment.Download(cport);
  456. cport.PlaySegment(segment);
  457. }
  458. else
  459. {
  460. cport.Stop(segment);
  461. segment.Dispose();
  462. //segment.ConnectToDLS
  463. loader.LoadSegment(pt, out segment);
  464. segment.Download(cport);
  465. cport.PlaySegment(segment);
  466. cdm.Dispose();
  467. }
  468. //GCHandle.Alloc(cdm, GCHandleType.Pinned);
  469. //GCHandle.Alloc(loader, GCHandleType.Pinned);
  470. //GCHandle.Alloc(segment, GCHandleType.Pinned);
  471. //GCHandle.Alloc(path, GCHandleType.Pinned);
  472. //GCHandle.Alloc(cport, GCHandleType.Pinned);
  473. //GCHandle.Alloc(outport, GCHandleType.Pinned);
  474. //GCHandle.Alloc(infoport, GCHandleType.Pinned);
  475. #endif
  476. }
  477. break;
  478. }
  479. musicplaying = true;
  480. lastplayed = Memory.MusicIndex;
  481. }
  482. public static void KillAudio()
  483. {
  484. //if (Sound != null && !Sound.IsDisposed)
  485. //{
  486. // Sound.Dispose();
  487. //}
  488. for (int i = 0; i < MaxSoundChannels; i++)
  489. {
  490. if (SoundChannels[i] != null && !SoundChannels[i].isDisposed)
  491. {
  492. SoundChannels[i].Dispose();
  493. SoundChannels[i] = null;
  494. }
  495. }
  496. try
  497. {
  498. if (Extended.IsLinux)
  499. {
  500. #if _WINDOWS && !_X64
  501. cport.StopAll();
  502. cport.Dispose();
  503. ccollection.Dispose();
  504. loader.Dispose();
  505. outport.Dispose();
  506. path.Dispose();
  507. cdm.Dispose();
  508. #endif
  509. }
  510. }
  511. catch
  512. {
  513. }
  514. }
  515. public static void StopMusic()
  516. {
  517. musicplaying = false;
  518. if (ffccMusic != null)
  519. {
  520. ffccMusic.Dispose();
  521. ffccMusic = null;
  522. }
  523. #if _WINDOWS && !_X64
  524. try
  525. {
  526. if (!Extended.IsLinux)
  527. {
  528. cport.StopAll();
  529. }
  530. }
  531. catch { }
  532. #endif
  533. }
  534. //MUSIC_TIME=LONG->int32; REFERENCE_TIME=LONGLONG->long
  535. [StructLayout(LayoutKind.Sequential, Pack =1, Size =24)]
  536. struct DMUS_IO_SEGMENT_HEADER
  537. {
  538. public uint dwRepeats;
  539. public int mtLength;
  540. public int mtPlayStart;
  541. public int mtLoopStart;
  542. public int mtLoopEnd;
  543. public uint dwResolution;
  544. }
  545. [StructLayout(LayoutKind.Sequential, Pack =1, Size =8)]
  546. struct DMUS_IO_VERSION
  547. {
  548. uint dwVersionMS;
  549. uint dwVersionLS;
  550. }
  551. [StructLayout(LayoutKind.Sequential, Pack =1, Size =32)]
  552. struct DMUS_IO_TRACK_HEADER
  553. {
  554. [MarshalAs(UnmanagedType.ByValArray, SizeConst =16)]
  555. byte[] guidClassID;
  556. uint dwPosition;
  557. uint dwGroup;
  558. [MarshalAs(UnmanagedType.ByValArray, SizeConst =4)]
  559. char[] _ckid;
  560. [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
  561. char[] _fccType;
  562. public string ckid { get => new string(_ckid); }
  563. public string fccType { get => new string(_fccType); }
  564. }
  565. static DMUS_IO_SEGMENT_HEADER segh = new DMUS_IO_SEGMENT_HEADER();
  566. static DMUS_IO_VERSION vers = new DMUS_IO_VERSION();
  567. static List<DMUS_IO_TRACK_HEADER> trkh;
  568. /// <summary>
  569. /// [LINUX]: This method manually reads DirectMusic Segment files
  570. /// </summary>
  571. /// <param name="pt"></param>
  572. private static void ReadSegmentFileManually(string pt)
  573. {
  574. using (FileStream fs = new FileStream(pt, FileMode.Open, FileAccess.Read))
  575. using (BinaryReader br = new BinaryReader(fs))
  576. {
  577. if(ReadFourCc(br) != "RIFF")
  578. {
  579. Console.WriteLine($"init_debugger_Audio::ReadSegmentFileManually: NOT RIFF!");
  580. return;
  581. }
  582. fs.Seek(4, SeekOrigin.Current);
  583. if(ReadFourCc(br) != "DMSG")
  584. {
  585. Console.WriteLine($"init_debugger_Audio::ReadSegmentFileManually: Broken structure. Expected DMSG!");
  586. return;
  587. }
  588. ReadSegmentForm(fs, br);
  589. }
  590. }
  591. private static void ReadSegmentForm(FileStream fs, BinaryReader br)
  592. {
  593. string fourCc;
  594. trkh = new List<DMUS_IO_TRACK_HEADER>();
  595. if ((fourCc = ReadFourCc(br)) != "segh")
  596. { Console.WriteLine($"init_debugger_Audio::ReadSegmentForm: Broken structure. Expected segh, got={fourCc}");return;}
  597. uint chunkSize = br.ReadUInt32();
  598. if (chunkSize != Marshal.SizeOf(segh))
  599. { Console.WriteLine($"init_debugger_Audio::ReadSegmentForm: chunkSize={chunkSize} is different than DMUS_IO_SEGMENT_HEADER sizeof={Marshal.SizeOf(segh)}");return;}
  600. segh = Extended.ByteArrayToStructure<DMUS_IO_SEGMENT_HEADER>(br.ReadBytes((int)chunkSize));
  601. if((fourCc = ReadFourCc(br)) != "guid")
  602. {Console.WriteLine($"init_debugger_Audio::ReadSegmentForm: expected guid, got={fourCc}");return;}
  603. byte[] guid = br.ReadBytes(br.ReadInt32());
  604. if ((fourCc = ReadFourCc(br)) != "LIST")
  605. { Console.WriteLine($"init_debugger_Audio::ReadSegmentForm: expected LIST, got={fourCc}");return;}
  606. //let's skip segment data for now, looks like it's not needed, it's not even oficially a part of segh
  607. fs.Seek(br.ReadUInt32(), SeekOrigin.Current);
  608. if ((fourCc = ReadFourCc(br)) != "vers")
  609. { Console.WriteLine($"init_debugger_Audio::ReadSegmentForm: expected vers, got={fourCc}"); return;}
  610. if ((chunkSize = br.ReadUInt32()) != Marshal.SizeOf(vers))
  611. { Console.WriteLine($"init_debugger_Audio::ReadSegmentForm: vers expected sizeof={Marshal.SizeOf(vers)}, got={chunkSize}");return;}
  612. vers = Extended.ByteArrayToStructure<DMUS_IO_VERSION>(br.ReadBytes((int)chunkSize));
  613. if ((fourCc = ReadFourCc(br)) != "LIST")
  614. { Console.WriteLine($"init_debugger_Audio::ReadSegmentForm: expected LIST, got={fourCc}");return;}
  615. //this list should now contain metadata like name, authors and etc. It's completely useless in this project scope
  616. fs.Seek(br.ReadUInt32(), SeekOrigin.Current); //therefore let's just skip whole UNFO and etc.
  617. if ((fourCc = ReadFourCc(br)) != "LIST")
  618. { Console.WriteLine($"init_debugger_Audio::ReadSegmentForm: expected LIST, got={fourCc}"); return; }
  619. chunkSize = br.ReadUInt32();
  620. if ((fourCc = ReadFourCc(br)) != "trkl")
  621. { Console.WriteLine($"init_debugger_Audio::ReadSegmentForm: expected trkl, got={fourCc}"); return; }
  622. //at this point we are free to read the file up to the end by reading all available DMTK RIFFs;
  623. uint eof = (uint)fs.Position + chunkSize-4;
  624. while(fs.Position < eof)
  625. {
  626. if ((fourCc = ReadFourCc(br)) != "RIFF")
  627. { Console.WriteLine($"init_debugger_Audio::ReadSegmentForm: expected RIFF, got={fourCc}"); return; }
  628. chunkSize = br.ReadUInt32();
  629. long skipTell = fs.Position;
  630. Console.WriteLine($"RIFF entry: {ReadFourCc(br)}/{ReadFourCc(br)}");
  631. trkh.Add(Extended.ByteArrayToStructure<DMUS_IO_TRACK_HEADER>(br.ReadBytes((int)br.ReadUInt32())));
  632. //TODO HERE
  633. //this seek below is to ensure that no critical behaviour happens and every RIFF header is read correctly
  634. fs.Seek(skipTell+chunkSize, SeekOrigin.Begin);
  635. }
  636. }
  637. private static string ReadFourCc(BinaryReader br) => new string(br.ReadChars(4));
  638. }
  639. }