From 041963de4e0a220c6e72fe4d22ae4759e3d85155 Mon Sep 17 00:00:00 2001 From: Thomas Neumann Date: Fri, 17 Nov 2023 17:00:48 +0100 Subject: [PATCH] Can now show sample information from TFMX modules. --- Source/Agents/Players/Tfmx/TfmxWorker.cs | 186 +++++++++++++++++++++++ 1 file changed, 186 insertions(+) diff --git a/Source/Agents/Players/Tfmx/TfmxWorker.cs b/Source/Agents/Players/Tfmx/TfmxWorker.cs index 8631f185..b3e9b377 100644 --- a/Source/Agents/Players/Tfmx/TfmxWorker.cs +++ b/Source/Agents/Players/Tfmx/TfmxWorker.cs @@ -4,6 +4,7 @@ /* information. */ /******************************************************************************/ using System; +using System.Collections.Generic; using System.IO; using System.Linq; using System.Security.Cryptography; @@ -24,6 +25,19 @@ namespace Polycode.NostalgicPlayer.Agent.Player.Tfmx /// internal class TfmxWorker : ModulePlayerWithSubSongDurationAgentBase { + private class SampleRange : IComparable + { + public int Start; + public int End; + public int LoopStart; + public int LoopLength; + + public int CompareTo(SampleRange other) + { + return Start.CompareTo(other.Start); + } + } + private const int BufSize = 1024; private readonly ModuleType currentModuleType; @@ -68,6 +82,8 @@ internal class TfmxWorker : ModulePlayerWithSubSongDurationAgentBase private bool endReached; + private SampleInfo[] sampleInfo; + private const int InfoPositionLine = 3; private const int InfoTrackLine = 4; private const int InfoSpeedLine = 5; @@ -449,6 +465,8 @@ public override bool InitPlayer(out string errorMessage) numBytes = 0; bytesDone = 0; + ExtractSampleInfo(); + return true; } @@ -635,6 +653,16 @@ public override SubSongInfo SubSongs return new SubSongInfo(songCount, 0); } } + + + + /********************************************************************/ + /// + /// Returns all the samples available in the module. If none, null + /// is returned + /// + /********************************************************************/ + public override IEnumerable Samples => sampleInfo; #endregion #region ModulePlayerWithSubSongDurationAgentBase implementation @@ -2514,6 +2542,164 @@ private void SetupChannel(int chan) + /********************************************************************/ + /// + /// Extract the sample information by parsing the instrument macros + /// + /********************************************************************/ + private void ExtractSampleInfo() + { + List samples = new List(); + + for (int i = 0; i < numMacro; i++) + { + // Find the start of the macro + int macroOffset = BitConverter.ToInt32(musicData, macroStart + i * 4); + bool endOfMacro = false; + + SampleRange range = new SampleRange(); + + for (int step = 0; !endOfMacro; step += 4) + { + Uni x = new Uni((uint)ToInt32(macroOffset + step)); + byte b0 = x.b0; + x.b0 = 0; + + switch (b0) + { + // Stop + case 0x07: + case 0xff: + { + endOfMacro = true; + break; + } + + // SetBegin + case 0x02: + { + if (range.Start != 0) + { + AddSample(samples, range); + range = new SampleRange(); + } + + range.Start = (int)x.l; + break; + } + + // SetLen + case 0x03: + { + range.End = range.Start + x.w1 * 2; + break; + } + + // SampleLoop + case 0x18: + { + range.LoopStart = (int)(range.Start + x.l); + range.LoopLength = range.End - range.LoopStart; + break; + } + } + } + + AddSample(samples, range); + } + + sampleInfo = new SampleInfo[samples.Count]; + + if (samples.Count > 0) + { + for (int i = 0; i < samples.Count - 1; i++) + sampleInfo[i] = GetSampleInfo(samples[i], samples[i + 1]); + + sampleInfo[samples.Count - 1] = GetSampleInfo(samples[samples.Count - 1], null); + } + } + + + + /********************************************************************/ + /// + /// Add current range into the right position in the list + /// + /********************************************************************/ + private void AddSample(List list, SampleRange range) + { + if (range.End == 0) + return; + + int j; + + for (j = 0; j < list.Count; j++) + { + SampleRange storedRange = list[j]; + + if ((range.Start >= storedRange.Start) && (range.Start < storedRange.End)) + { + if (range.End > storedRange.End) + storedRange.End = range.End; + + j = -1; + break; + } + + if ((range.Start < storedRange.Start) && (range.End > storedRange.Start)) + { + storedRange.Start = range.Start; + + if (range.End > storedRange.End) + storedRange.End = range.End; + + j = -1; + break; + } + + if (range.Start < storedRange.Start) + break; + } + + if (j != -1) + list.Insert(j, range); + } + + + + /********************************************************************/ + /// + /// Return an initialized sample info object + /// + /********************************************************************/ + private SampleInfo GetSampleInfo(SampleRange current, SampleRange next) + { + int sampleLength = (next == null ? current.End : next.Start) - current.Start; + + SampleInfo info = new SampleInfo + { + Name = string.Empty, + Flags = SampleInfo.SampleFlag.None, + Type = SampleInfo.SampleType.Sample, + BitSize = SampleInfo.SampleSize._8Bit, + Panning = -1, + Volume = 256, + Sample = sampleData.AsSpan(current.Start, sampleLength).ToArray(),//XX + Length = (uint)sampleLength + }; + + if (current.LoopLength != 0) + { + info.Flags |= SampleInfo.SampleFlag.Loop; + info.LoopStart = (uint)(current.LoopStart - current.Start); + info.LoopLength = (uint)current.LoopLength; + } + + return info; + } + + + /********************************************************************/ /// /// Will update the module information with current song position