From f1dbc26dc66776f4d870dc8a865b6bfe7b17ea2e Mon Sep 17 00:00:00 2001 From: Kaydax Date: Fri, 22 Jan 2021 12:06:35 -0500 Subject: [PATCH 1/8] Convert project to .net 5 --- Monad.FLParser.csproj | 73 ++++++++++++-------------------------- Properties/AssemblyInfo.cs | 36 ------------------- 2 files changed, 22 insertions(+), 87 deletions(-) delete mode 100644 Properties/AssemblyInfo.cs diff --git a/Monad.FLParser.csproj b/Monad.FLParser.csproj index 6909094..679de23 100644 --- a/Monad.FLParser.csproj +++ b/Monad.FLParser.csproj @@ -1,59 +1,30 @@ - - - + + - Debug - AnyCPU - {CE83037E-41AA-4C72-BE2E-1DF90583AD17} Library - Properties - Monad.FLParser - Monad.FLParser - v4.5.2 - 512 + net5.0 + AnyCPU;x64 - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 + + + true - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 + + + true + + + true + + + + true + + - - - - - - - - - - - - - - - - - - - - - - - - + + + - \ No newline at end of file diff --git a/Properties/AssemblyInfo.cs b/Properties/AssemblyInfo.cs deleted file mode 100644 index b52e19c..0000000 --- a/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("Monad.FLParser")] -[assembly: AssemblyDescription("An FL Studio project file parser for .NET")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("MONAD Demogroup")] -[assembly: AssemblyProduct("FLParser")] -[assembly: AssemblyCopyright("Copyright © MONAD 2017")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("ce83037e-41aa-4c72-be2e-1df90583ad17")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("0.1.*")] -[assembly: AssemblyFileVersion("1.0.0.0")] From 9c4bc55fbe19b980d436cfe79396c76f182e1a59 Mon Sep 17 00:00:00 2001 From: Kaydax Date: Mon, 25 Jan 2021 20:15:30 -0500 Subject: [PATCH 2/8] Make project use net standard 2.0 --- Monad.FLParser.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Monad.FLParser.csproj b/Monad.FLParser.csproj index 679de23..83a13ae 100644 --- a/Monad.FLParser.csproj +++ b/Monad.FLParser.csproj @@ -2,7 +2,7 @@ Library - net5.0 + netstandard2.0 AnyCPU;x64 From 0bcaf21cea3f2fe3454757a8851cd5c1e278416b Mon Sep 17 00:00:00 2001 From: Kaydax Date: Fri, 29 Jan 2021 01:07:01 -0500 Subject: [PATCH 3/8] Add a bunch of stuff that makes me die inside --- AutomationKeyframe.cs | 1 + Enums.cs | 34 ++++++++++++++++++++++ GeneratorData.cs | 3 ++ ProjectParser.cs | 66 ++++++++++++++++++++++++++++++++++--------- 4 files changed, 91 insertions(+), 13 deletions(-) diff --git a/AutomationKeyframe.cs b/AutomationKeyframe.cs index 28e4b5c..9ff9c2a 100644 --- a/AutomationKeyframe.cs +++ b/AutomationKeyframe.cs @@ -5,5 +5,6 @@ public class AutomationKeyframe public int Position { get; set; } = 0; public double Value { get; set; } = 0; public float Tension { get; set; } = 0; + public byte Mode { get; set; } = 0; } } diff --git a/Enums.cs b/Enums.cs index 45dd681..7a81eb8 100644 --- a/Enums.cs +++ b/Enums.cs @@ -129,6 +129,40 @@ public enum PluginType Vst = 8 } + /* + * Modes: + * 0 - Single Curve + * 1 - Double Curve + * 2 - Hold + * 3 - Stairs + * 4 - Smooth Stairs + * 5 - Pulse + * 6 - Wave + * 7 - Single Curve 2 + * 8 - Double Curve 2 + * 9 - Half Sine + * 10 - Smooth + * 11 - Single Curve 3 + * 12 - Double Curve 3 + */ + + public enum AutomationMode + { + SingleCurve = 0, + DoubleCurve = 1, + Hold = 2, + Stairs = 3, + SmoothStairs = 4, + Pulse = 5, + Wave = 6, + SingleCurve2 = 7, + DoubleCurve2 = 8, + HalfSine = 9, + Smooth = 10, + SingleCurve3 = 11, + DoubleCurve3 = 12 + } + /*public enum FilterType { LowPass = 0, diff --git a/GeneratorData.cs b/GeneratorData.cs index cfb533d..927c7bb 100644 --- a/GeneratorData.cs +++ b/GeneratorData.cs @@ -8,6 +8,9 @@ public class GeneratorData : IChannelData public double Volume { get; set; } = 100; public double Panning { get; set; } = 0; public uint BaseNote { get; set; } = 57; + public byte Echo { get; set; } = 0; + public uint EchoFeed { get; set; } = 0; + public uint EchoTime { get; set; } = 0; public int Insert { get; set; } = -1; public int LayerParent { get; set; } = -1; diff --git a/ProjectParser.cs b/ProjectParser.cs index ef574d6..6954b81 100644 --- a/ProjectParser.cs +++ b/ProjectParser.cs @@ -76,8 +76,8 @@ private void ParseFldt(BinaryReader reader) len = reader.ReadInt32(); // sanity check - if (len < 0 || len > 0x10000000) - throw new FlParseException($"Invalid chunk length: {len}", reader.BaseStream.Position); + //if (len < 0 || len > 0x10000000) + // throw new FlParseException($"Invalid chunk length: {len}", reader.BaseStream.Position); } while (id != "FLdt"); } @@ -250,6 +250,14 @@ private void ParseTextEvent(Enums.Event eventId, BinaryReader reader) case Enums.Event.TextInsertName: _curInsert.Name = unicodeString; break; + case Enums.Event.TextDelay: + if(genData != null) + { + genData.Echo = dataBytes[12]; + genData.EchoFeed = (uint)((dataBytes[1] << 8) | dataBytes[0]); + genData.EchoTime = (uint)((dataBytes[17] << 8) | dataBytes[16]); + } + break; } } @@ -286,6 +294,7 @@ private void ParseDataEvent(Enums.Event eventId, BinaryReader reader) case Enums.Event.DataChanParams: { if (genData == null) break; + //Console.WriteLine(reader.BaseStream.Position); var unknown1 = reader.ReadBytes(40); genData.ArpDir = (Enums.ArpDirection)reader.ReadInt32(); genData.ArpRange = reader.ReadInt32(); @@ -418,12 +427,24 @@ private void ParseDataEvent(Enums.Event eventId, BinaryReader reader) var unknown2 = reader.ReadUInt32(); var unknown3 = reader.ReadByte(); var param = reader.ReadUInt16(); - var paramDestination = reader.ReadInt16(); + var paramDestination = reader.ReadUInt16(); var unknown4 = reader.ReadUInt64(); var channel = _project.Channels[automationChannel]; - if ((paramDestination & 0x2000) == 0) // Automation on channel + if(paramDestination > _project.Channels.Count) + { + //Console.WriteLine("Tempo Automation Track found, but is currently not supported. Please use SAFC to merge the tempo back"); + //break; + channel.Data = new AutomationData // automation on insert slot + { + Parameter = param & 0x7fff + //InsertId = (paramDestination & 0x0FF0) >> 6, // seems to be out by one + //SlotId = paramDestination & 0x003F + }; + } + + if ((paramDestination & 0x2000) == 0 && paramDestination < _project.Channels.Count) // Automation on channel { channel.Data = new AutomationData { @@ -452,7 +473,7 @@ private void ParseDataEvent(Enums.Event eventId, BinaryReader reader) var length = reader.ReadInt32(); var track = reader.ReadInt32(); if (_versionMajor == 20) - track = 501 - track; + track = 499 - track; else track = 198 - track; var unknown1 = reader.ReadUInt16(); @@ -481,15 +502,28 @@ private void ParseDataEvent(Enums.Event eventId, BinaryReader reader) var startOffset = reader.ReadInt32(); var endOffset = reader.ReadInt32(); - _project.Tracks[track].Items.Add(new PatternPlaylistItem + if((patternId - patternBase - 1) > _project.Patterns.Count) { + Console.WriteLine("Pattern found on track " + (track) + ", but it seems to be empty. Skipping..."); + break; + } + + try + { + _project.Tracks[track].Items.Add(new PatternPlaylistItem + { Position = startTime, Length = length, StartOffset = startOffset, EndOffset = endOffset, Pattern = _project.Patterns[patternId - patternBase - 1], Muted = muted - }); + }); + } catch(Exception e) + { + Console.WriteLine("Pattern found on track " + (track) + ", but it seems to be empty. Skipping..."); + break; + } } } break; @@ -508,12 +542,15 @@ private void ParseDataEvent(Enums.Event eventId, BinaryReader reader) for (var i = 0; i < keyCount; i++) { + reader.ReadBytes(3); var startPos = reader.BaseStream.Position; - var keyPos = reader.ReadDouble(); - var keyVal = reader.ReadDouble(); - var keyTension = reader.ReadSingle(); - var unknown7 = reader.ReadUInt32(); // seems linked to tension? + var keyPos = reader.ReadUInt32(); //This is a UInt32 + reader.ReadUInt32(); //Skip 4 bytes + var keyVal = reader.ReadUInt32(); //This is a UInt32 + reader.ReadByte(); //Skip a byte, since it's useless + var keyTension = reader.ReadSingle(); // Tension is a single + var mode = reader.ReadByte(); // Seems to be the mode of the keyframe var endPos = reader.BaseStream.Position; reader.BaseStream.Position = startPos; @@ -524,8 +561,10 @@ private void ParseDataEvent(Enums.Event eventId, BinaryReader reader) { Position = (int)(keyPos * _project.Ppq), Tension = keyTension, - Value = keyVal + Value = keyVal, + Mode = mode }; + reader.ReadBytes(3); } // remaining data is unknown @@ -563,7 +602,7 @@ private Plugin ParsePluginChunk(byte[] chunk) if (pluginType != Enums.PluginType.Vst) { - return null; + return null; } while (reader.BaseStream.Position < reader.BaseStream.Length) @@ -591,6 +630,7 @@ private Plugin ParsePluginChunk(byte[] chunk) } } + //Console.WriteLine(reader.BaseStream.Position); return plugin; } } From d533217336e3c6d45790a6a5e1bf881140718c45 Mon Sep 17 00:00:00 2001 From: demberto <65948403+demberto@users.noreply.github.com> Date: Mon, 1 Feb 2021 19:36:09 +0530 Subject: [PATCH 4/8] Update README.md `Mode` should be `Enums.AutomationMode` actually --- README.md | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index d0d2e85..0b06a34 100644 --- a/README.md +++ b/README.md @@ -127,6 +127,7 @@ Represents an individual keyframe in an automation track. Has the following prop int Position; // keyframe position in pulses double Value; // keyframe value float Tension; // keyframe tension +byte Mode; // keyframe mode ``` #### `class Track` @@ -264,6 +265,24 @@ Flags for inserts to specify their states. Values are: - `Lock = 1 << 11` - insert is locked - `Solo = 1 << 12` - insert is solo'd (all other inserts will be muted) +### `enum AutomationMode` + +Automation ketframe modes. Values are: + + - `SingleCurve = 1` + - `SingleCurve = 2` + - `Hold = 2` + - `Stairs = 3` + - `SmoothStairs = 4` + - `Pulse = 5` + - `Wave = 6` + - `SingleCurve2 = 7` + - `DoubleCurve2 = 8` + - `HalfSine = 9` + - `Smooth = 10` + - `SingleCurve3 = 11` + - `DoubleCurve3 = 12` + ## license -Licensed under the GPL3 license. See the LICENSE file for more information. \ No newline at end of file +Licensed under the GPL3 license. See the LICENSE file for more information. From c08dfffc8ae3c117860ba88ce6b360d01a6a87dd Mon Sep 17 00:00:00 2001 From: Kaydax Date: Tue, 9 Feb 2021 11:15:33 -0500 Subject: [PATCH 5/8] Support Pattern Note Color Mapping --- Note.cs | 1 + ProjectParser.cs | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/Note.cs b/Note.cs index 9dfbe08..318c29d 100644 --- a/Note.cs +++ b/Note.cs @@ -3,6 +3,7 @@ public class Note { public int Position { get; set; } + public byte Color { get; set; } public int Length { get; set; } public byte Key { get; set; } public ushort FinePitch { get; set; } diff --git a/ProjectParser.cs b/ProjectParser.cs index 6954b81..8384272 100644 --- a/ProjectParser.cs +++ b/ProjectParser.cs @@ -324,7 +324,8 @@ private void ParseDataEvent(Enums.Event eventId, BinaryReader reader) var unknown3 = reader.ReadInt16(); var unknown4 = reader.ReadByte(); var finePitch = reader.ReadUInt16(); - var release = reader.ReadUInt16(); + var release = reader.ReadByte(); //Its actually a byte, next byte after is note channel + var color = reader.ReadByte(); //Used for map note color to midi channel var pan = reader.ReadByte(); var velocity = reader.ReadByte(); var x1 = reader.ReadByte(); @@ -335,6 +336,7 @@ private void ParseDataEvent(Enums.Event eventId, BinaryReader reader) _curPattern.Notes[channel].Add(new Note { Position = pos, + Color = color, Length = length, Key = key, FinePitch = finePitch, From 3ff798370b709a1ba451ac4d5c6402f3a5f990b6 Mon Sep 17 00:00:00 2001 From: Kaydax Date: Tue, 9 Feb 2021 13:19:08 -0500 Subject: [PATCH 6/8] Add muted to IPlaylistItem --- IPlaylistItem.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/IPlaylistItem.cs b/IPlaylistItem.cs index e46b531..fbb5b0c 100644 --- a/IPlaylistItem.cs +++ b/IPlaylistItem.cs @@ -5,6 +5,7 @@ public interface IPlaylistItem int Position { get; set; } int Length { get; set; } int StartOffset { get; set; } + bool Muted { get; set; } int EndOffset { get; set; } } } From 49267c7cf40129de8e8ff6ea8bbbba3ce7985233 Mon Sep 17 00:00:00 2001 From: Kaydax Date: Sat, 13 Feb 2021 13:26:26 -0500 Subject: [PATCH 7/8] For some reason we ever took into account to change the maxtracks to 499 when its actually using version 20 or higher... --- Project.cs | 20 +++++++++++++------- ProjectParser.cs | 4 ++++ 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/Project.cs b/Project.cs index 67ac34f..e13017f 100644 --- a/Project.cs +++ b/Project.cs @@ -6,7 +6,7 @@ namespace Monad.FLParser public class Project { public const int MaxInsertCount = 127; - public const int MaxTrackCount = 199; + //public const int MaxTrackCount = 499; //No longer used public int MainVolume { get; set; } = 300; public int MainPitch { get; set; } = 0; @@ -19,24 +19,20 @@ public class Project public string VersionString { get; set; } = string.Empty; public int Version { get; set; } = 0x100; public List Channels { get; set; } = new List(); - public Track[] Tracks { get; set; } = new Track[MaxTrackCount]; + public Track[] Tracks { get; set; } public List Patterns = new List(); public Insert[] Inserts { get; set; } = new Insert[MaxInsertCount]; public bool PlayTruncatedNotes { get; set; } = false; public Project() { - for (var i = 0; i < MaxTrackCount; i++) - { - Tracks[i] = new Track(); - } - for (var i = 0; i < MaxInsertCount; i++) { Inserts[i] = new Insert { Id = i, Name = $"Insert {i}" }; } Inserts[0].Name = "Master"; + InitTracks(199); } public static Project Load(string path, bool verbose) @@ -60,5 +56,15 @@ public static Project Load(BinaryReader reader, bool verbose) var parser = new ProjectParser(verbose); return parser.Parse(reader); } + + internal void InitTracks(int count) + { + Tracks = new Track[count]; + + for(var i = 0; i < Tracks.Length; i++) + { + Tracks[i] = new Track(); + } + } } } diff --git a/ProjectParser.cs b/ProjectParser.cs index 8384272..c250caa 100644 --- a/ProjectParser.cs +++ b/ProjectParser.cs @@ -243,6 +243,10 @@ private void ParseTextEvent(Enums.Event eventId, BinaryReader reader) _project.Version = (int.Parse(numbers[0]) << 8) + (int.Parse(numbers[1]) << 4) + (int.Parse(numbers[2]) << 0); + + var trackCount = _versionMajor <= 12 ? 199 : 499; + if(_project.Tracks.Length != trackCount) + _project.InitTracks(trackCount); break; case Enums.Event.GeneratorName: if (genData != null) genData.GeneratorName = unicodeString; From 2f48809bbf8f31c4ecf93051f5f1fa86a84b5468 Mon Sep 17 00:00:00 2001 From: Kaydax Date: Sat, 20 Feb 2021 05:23:52 -0500 Subject: [PATCH 8/8] Fixed tracks to be 500 instead of 499 --- ProjectParser.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ProjectParser.cs b/ProjectParser.cs index c250caa..667131a 100644 --- a/ProjectParser.cs +++ b/ProjectParser.cs @@ -244,7 +244,7 @@ private void ParseTextEvent(Enums.Event eventId, BinaryReader reader) (int.Parse(numbers[1]) << 4) + (int.Parse(numbers[2]) << 0); - var trackCount = _versionMajor <= 12 ? 199 : 499; + var trackCount = _versionMajor <= 12 ? 199 : 500; if(_project.Tracks.Length != trackCount) _project.InitTracks(trackCount); break; @@ -478,10 +478,10 @@ private void ParseDataEvent(Enums.Event eventId, BinaryReader reader) var patternId = reader.ReadUInt16(); var length = reader.ReadInt32(); var track = reader.ReadInt32(); - if (_versionMajor == 20) - track = 499 - track; + if(_versionMajor == 20) + track = 499 - track; else - track = 198 - track; + track = 198 - track; var unknown1 = reader.ReadUInt16(); var itemFlags = reader.ReadUInt16(); var unknown3 = reader.ReadUInt32();