diff --git a/ChartTools/Instruments/Instrument.cs b/ChartTools/Instruments/Instrument.cs index 14e123d0..c572b286 100644 --- a/ChartTools/Instruments/Instrument.cs +++ b/ChartTools/Instruments/Instrument.cs @@ -48,7 +48,7 @@ public InstrumentType InstrumentType /// /// Set of special phrases applied to all difficulties /// - public List SpecialPhrases { get; set; } = new(); + public List SpecialPhrases { get; set; } = []; /// public sbyte? GetDifficulty(InstrumentDifficultySet difficulties) => difficulties.GetDifficulty(InstrumentIdentity); diff --git a/source - Copie/ChartTools.shproj b/source - Copie/ChartTools.shproj deleted file mode 100644 index 16c16c88..00000000 --- a/source - Copie/ChartTools.shproj +++ /dev/null @@ -1,81 +0,0 @@ - - - - 54924bc3-4a10-45ad-af3c-f17494e403e1 - 14.0 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/source - Copie/Chords/DrumsChord.cs b/source - Copie/Chords/DrumsChord.cs deleted file mode 100644 index 0e2464ac..00000000 --- a/source - Copie/Chords/DrumsChord.cs +++ /dev/null @@ -1,59 +0,0 @@ -using ChartTools.IO.Chart; -using ChartTools.IO.Chart.Entries; -using ChartTools.IO.Configuration.Sessions; - -namespace ChartTools; - -/// -/// Set of notes played simultaneously by drums -/// -public class DrumsChord : LaneChord -{ - public override bool OpenExclusivity => false; - - internal override DrumsChordModifiers DefaultModifiers => DrumsChordModifiers.None; - internal override bool ChartSupportedModifiers => true; - - public DrumsChord() : base() { } - - /// - public DrumsChord(uint position) : base(position) { } - /// - /// Notes to add - public DrumsChord(uint position, params DrumsNote[] notes) : base(position) - { - if (notes is null) - throw new ArgumentNullException(nameof(notes)); - - foreach (DrumsNote note in notes) - Notes.Add(note); - } - /// - public DrumsChord(uint position, params DrumsLane[] notes) : base(position) - { - if (notes is null) - throw new ArgumentNullException(nameof(notes)); - - foreach (DrumsLane note in notes) - Notes.Add(new DrumsNote(note)); - } - - protected override IReadOnlyCollection GetNotes() => Notes; - - internal override IEnumerable GetChartNoteData() - { - foreach (DrumsNote note in Notes) - { - yield return ChartFormatting.NoteEntry(Position, note.Lane == DrumsLane.DoubleKick ? (byte)32 : note.Index, note.Sustain); - - if (note.IsCymbal) - yield return ChartFormatting.NoteEntry(Position, (byte)(note.Lane + 64), 0); - } - } - - internal override IEnumerable GetChartModifierData(LaneChord? previous, WritingSession session) - { - if (Modifiers.HasFlag(DrumsChordModifiers.Flam)) - yield return ChartFormatting.NoteEntry(Position, 109, 0); - } -} diff --git a/source - Copie/Chords/GHLChord.cs b/source - Copie/Chords/GHLChord.cs deleted file mode 100644 index b714e630..00000000 --- a/source - Copie/Chords/GHLChord.cs +++ /dev/null @@ -1,62 +0,0 @@ -using ChartTools.IO.Chart; -using ChartTools.IO.Chart.Entries; -using ChartTools.IO.Configuration.Sessions; - -namespace ChartTools; - -/// -/// Set of notes played simultaneously by a Guitar Hero Live instrument -/// -public class GHLChord : LaneChord, GHLLane, GHLChordModifiers> -{ - public override bool OpenExclusivity => true; - - internal override GHLChordModifiers DefaultModifiers => GHLChordModifiers.None; - internal override bool ChartSupportedModifiers => !Modifiers.HasFlag(GHLChordModifiers.ExplicitHopo); - - public GHLChord() : base() { } - /// - public GHLChord(uint position) : base(position) { } - /// - /// Notes to add - public GHLChord(uint position, params LaneNote[] notes) : base(position) - { - if (notes is null) - throw new ArgumentNullException(nameof(notes)); - - foreach (var note in notes) - Notes.Add(note); - } - /// - public GHLChord(uint position, params GHLLane[] notes) : base(position) - { - if (notes is null) - throw new ArgumentNullException(nameof(notes)); - - foreach (GHLLane note in notes) - Notes.Add(new LaneNote(note)); - } - - protected override IReadOnlyCollection GetNotes() => Notes; - - internal override IEnumerable GetChartNoteData() => Notes.Select(note => ChartFormatting.NoteEntry(Position, note.Lane switch - { - GHLLane.Open => 7, - GHLLane.Black1 => 3, - GHLLane.Black2 => 4, - GHLLane.Black3 => 8, - GHLLane.White1 => 0, - GHLLane.White2 => 1, - GHLLane.White3 => 2, - }, note.Sustain)); - - internal override IEnumerable GetChartModifierData(LaneChord? previous, WritingSession session) - { - var isInvert = Modifiers.HasFlag(GHLChordModifiers.HopoInvert); - - if (Modifiers.HasFlag(GHLChordModifiers.ExplicitHopo) && (previous is null || previous.Position <= session.Formatting!.TrueHopoFrequency) != isInvert || isInvert) - yield return ChartFormatting.NoteEntry(Position, 5, 0); - if (Modifiers.HasFlag(GHLChordModifiers.Tap)) - yield return ChartFormatting.NoteEntry(Position, 6, 0); - } -} diff --git a/source - Copie/Chords/IChord.cs b/source - Copie/Chords/IChord.cs deleted file mode 100644 index 1fccc55f..00000000 --- a/source - Copie/Chords/IChord.cs +++ /dev/null @@ -1,15 +0,0 @@ -namespace ChartTools; - -/// -/// Set of notes tied together. -/// -/// Depending on the chord type, notes will be on the same position or in sequence. -public interface IChord : ITrackObject -{ - /// - /// Read-only set of the notes in the chord. - /// - public IReadOnlyCollection Notes { get; } - - public INote CreateNote(byte index, uint length = 0); -} diff --git a/source - Copie/Chords/LaneChord.cs b/source - Copie/Chords/LaneChord.cs deleted file mode 100644 index 4f7492a6..00000000 --- a/source - Copie/Chords/LaneChord.cs +++ /dev/null @@ -1,28 +0,0 @@ -using ChartTools.IO.Chart.Entries; -using ChartTools.IO.Configuration.Sessions; - -namespace ChartTools; - -public abstract class LaneChord : TrackObjectBase, IChord -{ - public IReadOnlyCollection Notes => GetNotes(); - IReadOnlyCollection IChord.Notes => GetNotes(); - - /// - /// Defines if open notes can be mixed with other notes for this chord type. indicated open notes cannot be mixed. - /// - public abstract bool OpenExclusivity { get; } - - internal abstract bool ChartSupportedModifiers { get; } - - public LaneChord() : base() { } - public LaneChord(uint position) : base(position) { } - - public abstract LaneNote CreateNote(byte index, uint sustain = 0); - INote IChord.CreateNote(byte index, uint sustain) => CreateNote(index, sustain); - - protected abstract IReadOnlyCollection GetNotes(); - - internal abstract IEnumerable GetChartNoteData(); - internal abstract IEnumerable GetChartModifierData(LaneChord? previous, WritingSession session); -} diff --git a/source - Copie/Chords/LaneChordGeneric.cs b/source - Copie/Chords/LaneChordGeneric.cs deleted file mode 100644 index 43bf7d44..00000000 --- a/source - Copie/Chords/LaneChordGeneric.cs +++ /dev/null @@ -1,32 +0,0 @@ -using System.Runtime.CompilerServices; - -namespace ChartTools; - -public abstract class LaneChord : LaneChord, IChord - where TNote : LaneNote, new() - where TLane : struct, Enum - where TModifiers : struct, Enum -{ - /// - /// Notes in the chord - /// - public new LaneNoteCollection Notes { get; } - - public TModifiers Modifiers { get; set; } - internal abstract TModifiers DefaultModifiers { get; } - - public LaneChord() : base() => Notes = new(OpenExclusivity); - public LaneChord(uint position) : base(position) => Notes = new(OpenExclusivity); - - public override LaneNote CreateNote(byte index, uint sustain = 0) - { - var note = new TNote() - { - Lane = Unsafe.As(ref index), - Sustain = sustain - }; - - Notes.Add(note); - return note; - } -} diff --git a/source - Copie/Chords/Phrase.cs b/source - Copie/Chords/Phrase.cs deleted file mode 100644 index 92050139..00000000 --- a/source - Copie/Chords/Phrase.cs +++ /dev/null @@ -1,89 +0,0 @@ -using ChartTools.Events; - -namespace ChartTools.Lyrics; - -public class Phrase : TrackObjectBase, IChord, ILongTrackObject -{ - public List Syllables { get; } = new(); - IReadOnlyCollection IChord.Notes => Syllables; - - /// - /// End of the phrase as defined by - /// - public uint EndPosition => Position + Length; - - public uint Length => LengthOverride ?? SyllableEndOffset; - uint ILongObject.Length - { - get => Length; - set => LengthOverride = value; - } - - public uint? LengthOverride - { - get => _lengthOverride; - set - { - if (value is not null && value < SyllableEndOffset) - throw new ArgumentException("Length must be large enough to fit all syllables.", nameof(value)); - - _lengthOverride = value; - } - } - private uint? _lengthOverride; - - /// - /// Offset of the first syllable - /// - public uint SyllableStartOffset => Syllables.Count == 0 ? 0 : Syllables.Select(s => s.PositionOffset).Min(); - /// - /// Offset of the end of the last syllable - /// - public uint SyllableEndOffset => Syllables.Count == 0 ? 0 : Syllables.Select(s => s.EndPositionOffset).Max(); - /// - /// Start position of the first syllable - /// - public uint SyllableStartPosition => SyllableStartOffset + Position; - /// - /// End position of the last syllable - /// - public uint SyllableEndPosition => SyllableEndOffset + Position; - - /// - /// Gets the raw text of all syllables as a single string with spaces between syllables - /// - public string RawText => BuildText(n => n.RawText); - public string DisplayedText => BuildText(n => n.DisplayedText); - - public Phrase(uint position) : base(position) { } - - public IEnumerable ToGlobalEvents() - { - yield return new(Position, EventTypeHelper.Global.PhraseStart); - - foreach (var syllable in Syllables) - yield return new(Position + syllable.PositionOffset, EventTypeHelper.Global.Lyric, syllable.RawText); - } - - private string BuildText(Func textSelector) => string.Concat(Syllables.Select(n => n.IsWordEnd ? textSelector(n) + ' ' : textSelector(n))); - - INote IChord.CreateNote(byte index, uint length) - { - var syllable = new Syllable(0, (VocalPitchValue)index) { Length = length }; - Syllables.Add(syllable); - return syllable; - } -} - -/// -/// Provides additional methods to -/// -public static class PhraseExtensions -{ - /// - /// Converts a set of to a set of making up the phrases. - /// - /// Phrases to convert into global events - /// Global events making up the phrases - public static IEnumerable ToGlobalEvents(this IEnumerable source) => source.SelectMany(p => p.ToGlobalEvents()); -} diff --git a/source - Copie/Chords/StandardChord.cs b/source - Copie/Chords/StandardChord.cs deleted file mode 100644 index 065d1ebd..00000000 --- a/source - Copie/Chords/StandardChord.cs +++ /dev/null @@ -1,53 +0,0 @@ -using ChartTools.IO.Chart; -using ChartTools.IO.Chart.Entries; -using ChartTools.IO.Configuration.Sessions; - -namespace ChartTools; - -/// -/// Set of notes played simultaneously by a standard five-fret instrument -/// -public class StandardChord : LaneChord, StandardLane, StandardChordModifiers> -{ - public override bool OpenExclusivity => true; - - internal override StandardChordModifiers DefaultModifiers => StandardChordModifiers.None; - internal override bool ChartSupportedModifiers => !Modifiers.HasFlag(StandardChordModifiers.ExplicitHopo); - - public StandardChord() : base() { } - /// - public StandardChord(uint position) : base(position) { } - /// - /// Notes to add - public StandardChord(uint position, params LaneNote[] notes) : this(position) - { - if (notes is null) - throw new ArgumentNullException(nameof(notes)); - - foreach (var note in notes) - Notes.Add(note); - } - /// - public StandardChord(uint position, params StandardLane[] notes) : this(position) - { - if (notes is null) - throw new ArgumentNullException(nameof(notes)); - - foreach (StandardLane note in notes) - Notes.Add(new LaneNote(note)); - } - - protected override IReadOnlyCollection GetNotes() => Notes; - - internal override IEnumerable GetChartNoteData() => Notes.Select(note => ChartFormatting.NoteEntry(Position, note.Lane == StandardLane.Open ? (byte)7 : (byte)(note.Lane - 1), note.Sustain)); - - internal override IEnumerable GetChartModifierData(LaneChord? previous, WritingSession session) - { - bool isInvert = Modifiers.HasFlag(StandardChordModifiers.HopoInvert); - - if (Modifiers.HasFlag(StandardChordModifiers.ExplicitHopo) && (previous is null || previous.Position <= session.Formatting!.TrueHopoFrequency) != isInvert || isInvert) - yield return ChartFormatting.NoteEntry(Position, 5, 0); - if (Modifiers.HasFlag(StandardChordModifiers.Tap)) - yield return ChartFormatting.NoteEntry(Position, 6, 0); - } -} diff --git a/source - Copie/Enums.cs b/source - Copie/Enums.cs deleted file mode 100644 index bcfb062e..00000000 --- a/source - Copie/Enums.cs +++ /dev/null @@ -1,457 +0,0 @@ -namespace ChartTools -{ - /// - /// Difficulty levels - /// - public enum Difficulty : byte - { - /// - /// Easy difficulty - /// - Easy, - /// - /// Medium difficulty - /// - Medium, - /// - /// Hard difficulty - /// - Hard, - /// - /// Expert difficulty - /// - Expert - } - /// - /// Modifier that affects the way the chord can be played - /// - [Flags] - public enum DrumsChordModifiers : byte - { - /// - None, - /// - /// *Unsupported* - /// - Accent, - /// - /// *Unsupported* - /// - Ghost, - Flam = 4 - } - /// - /// Drums pads and pedals for a - /// - public enum DrumsLane : byte - { - /// - /// Kick note, shown as a purple line - /// - Kick, - /// - /// Red pad - /// - Red, - /// - /// Yellow pad - /// - Yellow, - /// - /// Blue pad - /// - Blue, - /// - /// Green when playing with four pads, orange when playing with five pads - /// - Green4Lane_Orange5Lane, - /// - /// Green when playing with five pad, otherwise converted to - /// - Green5Lane, - /// - /// that only appears when playing with multiple pedals - /// - /// In Clone Hero, double kicks are enabled with the "2x Kick" modifier and are not limited to a single difficulty. - DoubleKick - } - public enum FileType : byte { Chart, Ini, MIDI } - /// - /// Modifier that affects how a can be played - /// - [Flags] - public enum GHLChordModifiers : byte - { - /// - None = 0, - /// - ExplicitHopo = 1, - /// - HopoInvert = 2, - /// - Tap = 4 - } - /// - /// Guitar Hero Live instruments - /// - /// Casting to will match the instrument. - public enum GHLInstrumentIdentity : byte { Guitar = 1, Bass } - /// - /// Frets for a GHL note - /// - public enum GHLLane : byte { Open, Black1, Black2, Black3, White1, White2, White3 } - - /// - /// Origins of an instrument - /// - public enum MidiInstrumentOrigin : byte - { - NA, - Unknown, - GuitarHero1, - GuitarHero2 = 4, - GuitarHero2Uncertain = Unknown | GuitarHero2, - RockBand = 6, - RockBandUncertain = Unknown | RockBand, - } - - /// - /// All instruments - /// - public enum InstrumentIdentity : byte { Drums, GHLGuitar, GHLBass, LeadGuitar, RhythmGuitar, CoopGuitar, Bass, Keys, Vocals } - public enum InstrumentType : byte { Drums, GHL, Standard, Vocals } - - /// - /// Modifier that affects how a can be played - /// - /// - [Flags] - public enum StandardChordModifiers : byte - { - /// - /// No modifier - /// - None = 0, - /// - /// The Hopo state is not relative to the previous chord. - /// - ExplicitHopo = 1, - /// - /// Forced Hopo if is set, otherwise inverts the natural state relative to the previous chord - /// - HopoInvert = 2, - ForcedHopo = ExplicitHopo | HopoInvert, - ForcedStrum = ExplicitHopo, - /// - /// The chord can be played without strumming - /// - Tap = 4, - Big = 8 - } - /// - /// Standard five-fret instruments - /// - /// - public enum StandardInstrumentIdentity : byte { LeadGuitar = 3, RhythmGuitar, CoopGuitar, Bass, Keys } - /// - /// Frets for a standard note - /// - public enum StandardLane : byte { Open, Green, Red, Yellow, Blue, Orange } - /// - /// Types of - /// - public enum TrackSpecialPhraseType : byte - { - /// - /// The is not a recognized phrase type - /// - Unknown, - /// - /// Grants star power if all notes are hit - /// - StarPowerGain, - /// - /// Allows the activation of star power - /// - StarPowerActivation, - Player1FaceOff, - Player2FaceOff, - Trill, - Tremolo, - DrumsRoll = 65, - DrumsDoubleRoll = 66 - } - /// - /// Types of - /// - public enum InstrumentSpecialPhraseType : byte - { - Unknown, - BigRockEnding - } -} - -namespace ChartTools.Lyrics -{ - /// - /// Pitch values for - /// - public enum VocalPitchValue : byte - { - /// - /// No pitch - /// - None = 0, - /// - /// Second C (lowest pitch) - /// - C2 = 0x20 | VocalsKey.C, - /// - /// Second C# - /// - CSharp2 = 0x20 | VocalsKey.CSharp, - /// - /// Second D - /// - D2 = 0x20 | VocalsKey.D, - /// - /// Second E-flat - /// - Eb2 = 0x20 | VocalsKey.Eb, - /// - /// Second E - /// - E2 = 0x20 | VocalsKey.E, - /// - /// Second F - /// - F2 = 0x20 | VocalsKey.F, - /// - /// Second F# - /// - FSharp2 = 0x20 | VocalsKey.FSharp, - /// - /// Second G - /// - G2 = 0x20 | VocalsKey.G, - /// - /// Second G# - /// - GSharp2 = 0x20 | VocalsKey.GSharp, - /// - /// Second A - /// - A2 = 0x20 | VocalsKey.A, - /// - /// Second B-flat - /// - Bb2 = 0x20 | VocalsKey.Bb, - /// - /// Second B - /// - B2 = 0x20 | VocalsKey.B, - /// - /// Third C - /// - C3 = 0x30 | VocalsKey.C, - /// - /// Third C# - /// - CSharp3 = 0x30 | VocalsKey.CSharp, - /// - /// Third D - /// - D3 = 0x30 | VocalsKey.D, - /// - /// Third E-flat - /// - Eb3 = 0x30 | VocalsKey.Eb, - /// - /// Third E - /// - E3 = 0x30 | VocalsKey.E, - /// - /// Third F - /// - F3 = 0x30 | VocalsKey.F, - /// - /// Third F# - /// - FSharp3 = 0x30 | VocalsKey.FSharp, - /// - /// Third G - /// - G3 = 0x30 | VocalsKey.G, - /// - /// Third G# - /// - GSharp3 = 0x30 | VocalsKey.GSharp, - /// - /// Third A - /// - A3 = 0x30 | VocalsKey.A, - /// - /// Third B-flat - /// - Bb3 = 0x30 | VocalsKey.Bb, - /// - /// Third B - /// - B3 = 0x30 | VocalsKey.B, - /// - /// Third C - /// - C4 = 0x40 | VocalsKey.C, - /// - /// Fourth C# - /// - CSharp4 = 0x40 | VocalsKey.CSharp, - /// - /// Fourth D - /// - D4 = 0x40 | VocalsKey.D, - /// - /// Fourth E-flat - /// - Eb4 = 0x40 | VocalsKey.Eb, - /// - /// Fourth E - /// - E4 = 0x40 | VocalsKey.E, - /// - /// Fourth F - /// - F4 = 0x40 | VocalsKey.F, - /// - /// Fourth F# - /// - FSharp4 = 0x40 | VocalsKey.FSharp, - /// - /// Fourth G - /// - G4 = 0x40 | VocalsKey.G, - /// - /// Fourth G# - /// - GSharp4 = 0x40 | VocalsKey.GSharp, - /// - /// Fourth A - /// - A4 = 0x40 | VocalsKey.A, - /// - /// Fourth B-flat - /// - Bb4 = 0x40 | VocalsKey.Bb, - /// - /// Fourth B - /// - B4 = 0x40 | VocalsKey.B, - /// - /// Fifth - /// - C5 = 0x50 | VocalsKey.C, - /// - /// Fifth C# - /// - CSharp5 = 0x50 | VocalsKey.CSharp, - /// - /// Fifth D - /// - D5 = 0x50 | VocalsKey.D, - /// - /// Fifth E-flat - /// - Eb5 = 0x50 | VocalsKey.Eb, - /// - /// Fifth E - /// - E5 = 0x50 | VocalsKey.E, - /// - /// Fifth F - /// - F5 = 0x50 | VocalsKey.F, - /// - /// Fifth F# - /// - FSharp5 = 0x50 | VocalsKey.FSharp, - /// - /// Fifth G - /// - G5 = 0x50 | VocalsKey.G, - /// - /// Fifth G# - /// - GSharp5 = 0x50 | VocalsKey.GSharp, - /// - /// Fifth A - /// - A5 = 0x50 | VocalsKey.A, - /// - /// Fifth B-flat - /// - Bb5 = 0x50 | VocalsKey.Bb, - /// - /// Fifth B - /// - B5 = 0x50 | VocalsKey.B, - /// - /// Sixth C (highest pitch) - /// - C6 = 0x60 | VocalsKey.C - } - - /// - /// Keys making up without the octave - /// - public enum VocalsKey : byte - { - /// - /// C key (Do) - /// - C, - /// - /// C# key - /// - CSharp, - /// - /// D key (Ré) - /// - D, - /// - /// E-flat key - /// - Eb, - /// - /// E key (Mi) - /// - E, - /// - /// F key (Fa) - /// - F, - /// - /// F# key - /// - FSharp, - /// - /// G key (Sol) - /// - G, - /// - /// G# key - /// - GSharp, - /// - /// A key (La) - /// - A, - /// - /// B-flat key - /// - Bb, - /// - /// B key (Si) - /// - B - } -} diff --git a/source - Copie/Events/Event.cs b/source - Copie/Events/Event.cs deleted file mode 100644 index 9d52c990..00000000 --- a/source - Copie/Events/Event.cs +++ /dev/null @@ -1,65 +0,0 @@ -namespace ChartTools.Events; - -/// -/// Marker that defines an occurrence at a given point in a song. -/// -public abstract class Event : TrackObjectBase -{ - private string _eventType = "Default"; - /// - /// Type of event as it is written in the file - /// - public string EventType - { - get => _eventType; - set - { - if (string.IsNullOrEmpty(value)) - throw new FormatException("Event type is empty"); - - if (value.Contains(' ')) - throw new FormatException("Event types cannot contain spaces"); - - _eventType = value; - } - } - - private string? _argument = null; - /// - /// Additional data to modify the outcome of the event - /// - /// A lack of argument is represented as an empty string. - public string? Argument - { - get => _argument; - set => _argument = value ?? string.Empty; - } - - public string EventData - { - get => Argument is null ? EventType : string.Join(' ', EventType, Argument); - set - { - var split = value.Split(' ', 2, StringSplitOptions.None); - - EventType = split[0]; - Argument = split.Length > 1 ? split[1] : string.Empty; - } - } - - public bool? ToggleState => EventType.EndsWith(EventTypeHelper.Common.ToggleOn) ? true : (EventType.EndsWith(EventTypeHelper.Common.ToggleOff) ? false : null); - - /// - /// - public Event(uint position, string data) : base(position) => EventData = data; - /// - /// - /// - public Event(uint position, string type, string? argument) : base(position) - { - EventType = type; - Argument = argument; - } - - public override string ToString() => EventData; -} diff --git a/source - Copie/Events/EventArgumentHelper.cs b/source - Copie/Events/EventArgumentHelper.cs deleted file mode 100644 index f2f98c83..00000000 --- a/source - Copie/Events/EventArgumentHelper.cs +++ /dev/null @@ -1,19 +0,0 @@ -namespace ChartTools.Events; - -public class EventArgumentHelper -{ - public static class Global - { - public static class Lighting - { - public const string - Blackout = "(blackout)", - Chase = "(chase)", - Color1 = "(color1)", - Color2 = "(color2)", - Flare = "(flare)", - Strobe = "(strobe)", - Sweep = "(sweep)"; - } - } -} diff --git a/source - Copie/Events/EventExtensions.cs b/source - Copie/Events/EventExtensions.cs deleted file mode 100644 index bc3d014c..00000000 --- a/source - Copie/Events/EventExtensions.cs +++ /dev/null @@ -1,57 +0,0 @@ -using ChartTools.Extensions.Collections; -using ChartTools.IO; -using ChartTools.IO.Chart; -using ChartTools.Lyrics; - -namespace ChartTools.Events; - -/// -/// Provides additional methods for events. -/// -public static class EventExtensions -{ - public static void ToFile(this IEnumerable events, string path) => ExtensionHandler.Write(path, events, (".chart", (path, events) => ChartFile.ReplaceGlobalEvents(path, events))); - public static async Task ToFileAsync(this IEnumerable events, string path, CancellationToken cancellationToken) => await ExtensionHandler.WriteAsync(path, events, (".chart", (path, events) => ChartFile.ReplaceGlobalEventsAsync(path, events, cancellationToken))); - - /// - /// Gets the lyrics from an enumerable of - /// - /// Enumerable of - public static IEnumerable GetLyrics(this IEnumerable globalEvents) - { - Phrase? phrase = null; - - foreach (GlobalEvent globalEvent in globalEvents.OrderBy(e => e.Position)) - switch (globalEvent.EventType) - { - // Change active phrase - case EventTypeHelper.Global.PhraseStart: - if (phrase is not null) - yield return phrase; - - phrase = new Phrase(globalEvent.Position); - break; - // Add syllable to the active phrase using the event argument - case EventTypeHelper.Global.Lyric: - phrase?.Syllables.Add(new(globalEvent.Position - phrase.Position, VocalPitchValue.None) { RawText = globalEvent.Argument ?? string.Empty }); - break; - // Set length of active phrase - case EventTypeHelper.Global.PhraseEnd: - if (phrase is not null) - phrase.LengthOverride = globalEvent.Position - phrase.Position; - break; - } - - if (phrase is not null) - yield return phrase; - } - /// - /// Gets a set of where phrase and lyric events are replaced with the events making up a set of . - /// - /// Enumerable of - public static IEnumerable SetLyrics(this IEnumerable events, IEnumerable lyrics) - { - foreach (GlobalEvent globalEvent in new OrderedAlternatingEnumerable(i => i.Position, events.Where(e => !e.IsLyricEvent), lyrics.SelectMany(p => p.ToGlobalEvents()))) - yield return globalEvent; - } -} diff --git a/source - Copie/Events/EventTypeHeaderHelper.cs b/source - Copie/Events/EventTypeHeaderHelper.cs deleted file mode 100644 index ff3c9175..00000000 --- a/source - Copie/Events/EventTypeHeaderHelper.cs +++ /dev/null @@ -1,26 +0,0 @@ -namespace ChartTools.Events; - -public static class EventTypeHeaderHelper -{ - public static class Global - { - public const string - BassistMovement = "bass_", - Crowd = "crowd_", - DrummerMovement = "drum_", - GuitaristMovement = "gtr_", - GuitaristSolo = "solo_", - GuitaristWail = "wail_", - KeyboardMovement = "keys_", - Phrase = "phrase_", - SingerMovement = "sing_", - Sync = "sync_"; - } - - public static class Local - { - public const string - GHL6 = "ghl_6", - OwFace = "ow_face_"; - } -} diff --git a/source - Copie/Events/EventTypeHelper.cs b/source - Copie/Events/EventTypeHelper.cs deleted file mode 100644 index cdc033a1..00000000 --- a/source - Copie/Events/EventTypeHelper.cs +++ /dev/null @@ -1,66 +0,0 @@ -namespace ChartTools.Events; - -public static class EventTypeHelper -{ - public static class Common - { - public const string ToggleOn = "on"; - public const string ToggleOff = "off"; - } - - public static class Global - { - public const string - BandJump = "band_jump", - BassistIdle = EventTypeHeaderHelper.Global.BassistMovement + Common.ToggleOff, - BassistMove = EventTypeHeaderHelper.Global.BassistMovement + Common.ToggleOn, - DrummerIdle = EventTypeHeaderHelper.Global.DrummerMovement + Common.ToggleOff, - DrummerAll = EventTypeHeaderHelper.Global.DrummerMovement + "allbeat", - DrummerDouble = EventTypeHeaderHelper.Global.DrummerMovement + "double", - DrummerHalf = EventTypeHeaderHelper.Global.DrummerMovement + "half", - DrummerMove = EventTypeHeaderHelper.Global.DrummerMovement + Common.ToggleOn, - Chorus = "chorus", - CrowdLightersFast = EventTypeHeaderHelper.Global.Crowd + "lighters_fast", - CrowdLightersOff = EventTypeHeaderHelper.Global.Crowd + "lighters_off", - CrowdLightersSlow = EventTypeHeaderHelper.Global.Crowd + "lighters_slow", - CrowdHalfTempo = EventTypeHeaderHelper.Global.Crowd + "half_tempo", - CrowdNormalTempo = EventTypeHeaderHelper.Global.Crowd + "normal_tempo", - CrowdDoubleTempo = EventTypeHeaderHelper.Global.Crowd + "double_tempo", - End = "end", - GuitaristIdle = EventTypeHeaderHelper.Global.GuitaristMovement + Common.ToggleOff, - GuitaristMove = EventTypeHeaderHelper.Global.GuitaristMovement + Common.ToggleOn, - GuitaristSoloOn = EventTypeHeaderHelper.Global.GuitaristSolo + Common.ToggleOn, - GuitaristSoloOff = EventTypeHeaderHelper.Global.GuitaristSolo + Common.ToggleOff, - GuitaristWailOn = EventTypeHeaderHelper.Global.GuitaristWail + Common.ToggleOn, - GuitaristWailOff = EventTypeHeaderHelper.Global.GuitaristWail + Common.ToggleOff, - HalfTempo = "half_tempo", - Idle = "idle", - KeyboardIdle = EventTypeHeaderHelper.Global.SingerMovement + Common.ToggleOff, - KeyboardMove = EventTypeHeaderHelper.Global.SingerMovement + Common.ToggleOn, - Lighting = "lighting", - Lyric = "lyric", - MusicStart = "music_start", - NotrmalTempo = "normal_tempo", - Play = "play", - PhraseStart = EventTypeHeaderHelper.Global.Phrase + "start", - PhraseEnd = EventTypeHeaderHelper.Global.Phrase + "end", - RB2CHSection = "section", - RB3Section = "prc_", - SingerIdle = EventTypeHeaderHelper.Global.SingerMovement + Common.ToggleOff, - SingerMove= EventTypeHeaderHelper.Global.SingerMovement + Common.ToggleOn, - SyncHeadBang = EventTypeHeaderHelper.Global.Sync + "head_bang", - SyncWag = EventTypeHeaderHelper.Global.Sync + "wag", - Verse = "verse"; - } - - public static class Local - { - public const string - GHL6 = EventTypeHeaderHelper.Local.GHL6, - GHL6Forced = EventTypeHeaderHelper.Local.GHL6 + "_forced", - OwFaceOn = EventTypeHeaderHelper.Local.OwFace + Common.ToggleOn, - OwFaceOff = EventTypeHeaderHelper.Local.OwFace + Common.ToggleOff, - Solo = "solo", - SoloEnd = "soloend"; - } -} diff --git a/source - Copie/Events/GlobalEvent.cs b/source - Copie/Events/GlobalEvent.cs deleted file mode 100644 index fb102f75..00000000 --- a/source - Copie/Events/GlobalEvent.cs +++ /dev/null @@ -1,39 +0,0 @@ -using ChartTools.IO; -using ChartTools.IO.Chart; - -namespace ChartTools.Events; - -/// -/// Event common to all instruments -/// -public class GlobalEvent : Event -{ - public bool IsBassistMovementEvent => EventType.StartsWith(EventTypeHeaderHelper.Global.BassistMovement); - public bool IsCrowdEvent => EventType.StartsWith(EventTypeHeaderHelper.Global.Crowd); - public bool IsDrummerMovementEvent => EventType.StartsWith(EventTypeHeaderHelper.Global.DrummerMovement); - public bool IsGuitaristMovementEvent => EventType.StartsWith(EventTypeHeaderHelper.Global.GuitaristMovement) || EventType.StartsWith(EventTypeHeaderHelper.Global.GuitaristSolo); - public bool IsGuitaristSoloEvent => EventType.StartsWith(EventTypeHeaderHelper.Global.GuitaristSolo); - public bool IsKeyboardMovementEvent => EventType.StartsWith(EventTypeHeaderHelper.Global.KeyboardMovement); - public bool IsLyricEvent => IsPhraseEvent || EventType == EventTypeHelper.Global.Lyric; - public bool IsPhraseEvent => EventType.StartsWith(EventTypeHeaderHelper.Global.Phrase); - public bool IsSectionEvent => EventType is EventTypeHelper.Global.RB2CHSection or EventTypeHelper.Global.RB3Section; - public bool IsSyncEvent => EventType.StartsWith(EventTypeHeaderHelper.Global.Sync); - public bool IsWailEvent => EventType.StartsWith(EventTypeHeaderHelper.Global.GuitaristWail); - - /// - public GlobalEvent(uint position, string data) : base(position, data) { } - /// - public GlobalEvent(uint position, string type, string? argument = null) : base(position, type, argument) { } - - /// - /// Reads global events from a file. - /// - /// Path of the file - public static IEnumerable FromFile(string path) => ExtensionHandler.Read>(path, (".chart", ChartFile.ReadGlobalEvents)); - /// - /// Reads global events from a file asynchronously using multitasking. - /// - /// - /// Token to request cancellation - public static async Task> FromFileAsync(string path, CancellationToken cancellationToken) => await ExtensionHandler.ReadAsync>(path, (".chart", path => ChartFile.ReadGlobalEventsAsync(path, cancellationToken))); -} diff --git a/source - Copie/Events/LocalEvent.cs b/source - Copie/Events/LocalEvent.cs deleted file mode 100644 index 0b85e316..00000000 --- a/source - Copie/Events/LocalEvent.cs +++ /dev/null @@ -1,16 +0,0 @@ -namespace ChartTools.Events; - -/// -/// Event specific to an instrument and difficulty -/// -public class LocalEvent : Event -{ - public bool IsSoloEvent => EventType is EventTypeHelper.Local.Solo or EventTypeHelper.Local.SoloEnd; - public bool IsOwFaceEvent => EventType.StartsWith(EventTypeHeaderHelper.Local.OwFace); - - /// - public LocalEvent(uint position, string data) : base(position, data) { } - /// - public LocalEvent(uint position, string type, string? argument = null) : base(position, type, argument) { } - -} diff --git a/source - Copie/Exceptions/DesynchronizedAnchorException.cs b/source - Copie/Exceptions/DesynchronizedAnchorException.cs deleted file mode 100644 index 9e7d5cb1..00000000 --- a/source - Copie/Exceptions/DesynchronizedAnchorException.cs +++ /dev/null @@ -1,12 +0,0 @@ -namespace ChartTools; - -/// -/// Exception thrown when an invalid operation is performed on a desynchronized anchored . -/// -public class DesynchronizedAnchorException : Exception -{ - public TimeSpan Anchor { get; } - - public DesynchronizedAnchorException(TimeSpan anchor) : this(anchor, $"Invalid operation performed with desynchronized anchored tempo at {anchor}.") { } - public DesynchronizedAnchorException(TimeSpan anchor, string message) : base(message) => Anchor = anchor; -} diff --git a/source - Copie/Exceptions/UndefinedEnumException.cs b/source - Copie/Exceptions/UndefinedEnumException.cs deleted file mode 100644 index 36575ba3..00000000 --- a/source - Copie/Exceptions/UndefinedEnumException.cs +++ /dev/null @@ -1,16 +0,0 @@ -namespace ChartTools; - -/// -/// Exception thrown when using an value that is not defined -/// -public class UndefinedEnumException : ArgumentException -{ - /// - /// Value used - /// - public Enum Value { get; } - - public UndefinedEnumException(Enum value) : base($"{value.GetType().Name} \"{value}\" is not defined.") => Value = value; - - -} diff --git a/source - Copie/Exceptions/Validator.cs b/source - Copie/Exceptions/Validator.cs deleted file mode 100644 index da33f26a..00000000 --- a/source - Copie/Exceptions/Validator.cs +++ /dev/null @@ -1,14 +0,0 @@ -namespace ChartTools; - -internal static class Validator -{ - /// - /// Validates that an value is defined. - /// - /// - public static void ValidateEnum(Enum value) - { - if (!Enum.IsDefined(value.GetType(), value)) - throw new UndefinedEnumException(value); - } -} diff --git a/source - Copie/Extensions/Collections/Alternating/Ordered/OrderedAlternatingEnumerable.cs b/source - Copie/Extensions/Collections/Alternating/Ordered/OrderedAlternatingEnumerable.cs deleted file mode 100644 index 83b1764c..00000000 --- a/source - Copie/Extensions/Collections/Alternating/Ordered/OrderedAlternatingEnumerable.cs +++ /dev/null @@ -1,47 +0,0 @@ -using ChartTools.Extensions.Linq; - -using System.Collections; - -namespace ChartTools.Extensions.Collections; - -/// -/// Enumerable where items are pulled from a set of enumerables in order using a key -/// -/// Type of the enumerated items -/// Type of the key used to determine the order -public class OrderedAlternatingEnumerable : IEnumerable where TKey : IComparable -{ - /// - /// Enumerables to alternate between - /// - private IEnumerable[] Enumerables { get; } - /// - /// Method that retrieves the key from an item - /// - private Func KeyGetter { get; } - - /// - /// Creates an instance of . - /// - /// Method that retrieves the key from an item - /// Enumerables to alternate between - /// - /// - public OrderedAlternatingEnumerable(Func keyGetter, params IEnumerable?[] enumerables) - { - if (keyGetter is null) - throw new ArgumentNullException(nameof(keyGetter)); - if (enumerables is null) - throw new ArgumentNullException(nameof(enumerables)); - if (enumerables.Length == 0) - throw new ArgumentException("No enumerables provided."); - - KeyGetter = keyGetter; - Enumerables = enumerables.NonNull().ToArray(); - } - - /// - public IEnumerator GetEnumerator() => new OrderedAlternatingEnumerator(KeyGetter, Enumerables.Select(e => e.GetEnumerator()).ToArray()); - /// - IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); -} diff --git a/source - Copie/Extensions/Collections/Alternating/Ordered/OrderedAlternatingEnumerator.cs b/source - Copie/Extensions/Collections/Alternating/Ordered/OrderedAlternatingEnumerator.cs deleted file mode 100644 index 898bef34..00000000 --- a/source - Copie/Extensions/Collections/Alternating/Ordered/OrderedAlternatingEnumerator.cs +++ /dev/null @@ -1,118 +0,0 @@ -using System.Collections; - -using ChartTools.Extensions.Linq; - -namespace ChartTools.Extensions.Collections; - -/// -/// Enumerator that yields items from a set of enumerators in order using a key -/// -/// Type of the enumerated items -/// Type of the key used to determine the order -internal class OrderedAlternatingEnumerator : IInitializable, IEnumerator where TKey : IComparable -{ - private IEnumerator[] Enumerators { get; } - /// - /// Method that retrieves the key from an item - /// - private Func KeyGetter { get; } - /// - public bool Initialized { get; private set; } - - /// Currently alternated item following a call - public T Current { get; private set; } - /// - object? IEnumerator.Current => Current; - - /// - /// for indexes where MoveNext previously returned - /// - readonly bool[] endsReached; - - /// - /// Creates a new instance of . - /// - /// Method that retrieves the key from an item - /// Enumerators to alternate between - /// - /// - public OrderedAlternatingEnumerator(Func keyGetter, params IEnumerator[] enumerators) - { - if (keyGetter is null) - throw new ArgumentNullException(nameof(keyGetter)); - if (enumerators is null) - throw new ArgumentNullException(nameof(enumerators)); - if (enumerators.Length == 0) - throw new ArgumentException("No enumerators provided."); - - Enumerators = enumerators.NonNull().ToArray(); - KeyGetter = keyGetter; - endsReached = new bool[Enumerators.Length]; - } - ~OrderedAlternatingEnumerator() => Dispose(false); - - /// - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - public virtual void Dispose(bool disposing) - { - foreach (IEnumerator enumerator in Enumerators) - enumerator.Dispose(); - } - - /// - public bool MoveNext() - { - // Index of the enumerators with items left - LinkedList usableEnumerators = new(); - - Initialize(); - - for (int i = 0; i < Enumerators.Length; i++) - if (!endsReached[i]) - usableEnumerators.AddLast(i); - - if (usableEnumerators.Count == 0) - return false; - - // Get the index of the enumerators whose current item yields the smallest key - int minIndex = usableEnumerators.MinBy(i => KeyGetter(Enumerators[i].Current)); - - // Get the enumerator of this index and set its current item as Current - IEnumerator minEnumerator = Enumerators[minIndex]; - Current = minEnumerator.Current; - - // Mark the enumerator as having reached its end if the next item can't be pulled - if (!minEnumerator.MoveNext()) - endsReached[minIndex] = true; - - return true; - } - - /// - public bool Initialize() - { - if (Initialized) - return false; - - for (int i = 0; i < Enumerators.Length; i++) - endsReached[i] = !Enumerators[i].MoveNext(); - - return Initialized = true; - } - - /// - public void Reset() - { - foreach (IEnumerator enumerator in Enumerators) - enumerator.Reset(); - - for (int i = 0; i < endsReached.Length; i++) - endsReached[i] = false; - - Initialized = false; - } -} diff --git a/source - Copie/Extensions/Collections/Alternating/Serial/SerialAlternatingEnumerable.cs b/source - Copie/Extensions/Collections/Alternating/Serial/SerialAlternatingEnumerable.cs deleted file mode 100644 index 476f3f6c..00000000 --- a/source - Copie/Extensions/Collections/Alternating/Serial/SerialAlternatingEnumerable.cs +++ /dev/null @@ -1,36 +0,0 @@ -using ChartTools.Extensions.Linq; - -using System.Collections; - -namespace ChartTools.Extensions.Collections; - -/// -/// Enumerable where items are yielded by alternating from a set of enumerables -/// -/// Type of the enumerated items -public class SerialAlternatingEnumerable : IEnumerable -{ - /// - protected IEnumerable[] Enumerables { get; } - - /// - /// Creates an instance of - /// - /// Enumerables to pull items from - /// - /// - public SerialAlternatingEnumerable(params IEnumerable?[] enumerables) - { - if (enumerables is null) - throw new ArgumentNullException(nameof(enumerables)); - if (enumerables.Length == 0) - throw new ArgumentException("No enumerables provided."); - - Enumerables = enumerables.NonNull().ToArray(); - } - - /// - public IEnumerator GetEnumerator() => new SerialAlternatingEnumerator(Enumerables.Select(e => e.GetEnumerator()).ToArray())!; - /// - IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); -} diff --git a/source - Copie/Extensions/Collections/Alternating/Serial/SerialAlternatingEnumerator.cs b/source - Copie/Extensions/Collections/Alternating/Serial/SerialAlternatingEnumerator.cs deleted file mode 100644 index e2a0fa73..00000000 --- a/source - Copie/Extensions/Collections/Alternating/Serial/SerialAlternatingEnumerator.cs +++ /dev/null @@ -1,93 +0,0 @@ -using System.Collections; - -using ChartTools.Extensions.Linq; - -namespace ChartTools.Extensions.Collections; - -/// -/// Enumerator that yields items by alternating through a set of enumerators -/// -/// Type of the enumerated items -internal class SerialAlternatingEnumerator : IEnumerator -{ - /// - /// Enumerators to alternate between - /// - private IEnumerator[] Enumerators { get; } - /// - /// Position of the next enumerator to pull from - /// - private int index; - - /// - /// Item to use in the iteration - /// - public T? Current { get; private set; } - /// - object? IEnumerator.Current => Current; - - /// - /// Creates an instance of - /// - /// Enumerators to alternate between - /// - /// - public SerialAlternatingEnumerator(params IEnumerator[] enumerators) - { - if (enumerators is null) - throw new ArgumentNullException(nameof(enumerators)); - if (enumerators.Length == 0) - throw new ArgumentException("No enumerators provided."); - - Enumerators = enumerators.NonNull().ToArray(); - } - - /// - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - public virtual void Dispose(bool disposing) - { - foreach (IEnumerator enumerator in Enumerators) - enumerator.Dispose(); - } - ~SerialAlternatingEnumerator() => Dispose(false); - - /// - public bool MoveNext() - { - int startingIndex = index; - return SearchEnumerator(); - - bool SearchEnumerator() - { - IEnumerator enumerator = Enumerators[index]; - - if (enumerator.MoveNext()) - { - Current = enumerator.Current; - - // Move to the next enumerator - if (++index == Enumerators.Length) - index = 0; - - return true; - } - - // End if looped back around to the first enumerator checked, else check the next enumerator - return index != startingIndex && SearchEnumerator(); - } - } - - /// - public void Reset() - { - // Reset every enumerator - foreach (IEnumerator enumerator in Enumerators) - enumerator.Reset(); - - index = 0; - } -} diff --git a/source - Copie/Extensions/Collections/Delayed/DelayedEnumerable.cs b/source - Copie/Extensions/Collections/Delayed/DelayedEnumerable.cs deleted file mode 100644 index 57550b50..00000000 --- a/source - Copie/Extensions/Collections/Delayed/DelayedEnumerable.cs +++ /dev/null @@ -1,31 +0,0 @@ -using System.Collections; - -namespace ChartTools.Extensions.Collections; - -public class DelayedEnumerable : IEnumerable, IDisposable -{ - private readonly DelayedEnumerator enumerator; - private readonly DelayedEnumerableSource source; - - /// - /// if there are more items to be received - /// - public bool AwaitingItems => source.AwaitingItems; - - internal DelayedEnumerable(DelayedEnumerableSource source) - { - this.source = source; - enumerator = new(source); - } - - public IEnumerable EnumerateSynchronously() - { - while (AwaitingItems); - return source.Buffer; - } - - public IEnumerator GetEnumerator() => enumerator; - IEnumerator IEnumerable.GetEnumerator() => enumerator; - - public void Dispose() => enumerator.Dispose(); -} diff --git a/source - Copie/Extensions/Collections/Delayed/DelayedEnumerableSource.cs b/source - Copie/Extensions/Collections/Delayed/DelayedEnumerableSource.cs deleted file mode 100644 index 14eb2763..00000000 --- a/source - Copie/Extensions/Collections/Delayed/DelayedEnumerableSource.cs +++ /dev/null @@ -1,37 +0,0 @@ -using System.Collections.Concurrent; - -namespace ChartTools.Extensions.Collections; - -public class DelayedEnumerableSource : IDisposable -{ - private bool disposed; - - public ConcurrentQueue Buffer { get; } = new(); - public DelayedEnumerable Enumerable { get; } - public bool AwaitingItems { get; private set; } = true; - - public DelayedEnumerableSource() => Enumerable = new(this); - - public void Add(T item) => Buffer.Enqueue(item); - public void EndAwait() => AwaitingItems = false; - - protected virtual void Dispose(bool disposing) - { - if (!disposed) - { - if (disposing) - AwaitingItems = false; - - Enumerable.Dispose(); - disposed = true; - } - } - - ~DelayedEnumerableSource() => Dispose(false); - - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } -} diff --git a/source - Copie/Extensions/Collections/Delayed/DelayedEnumerator.cs b/source - Copie/Extensions/Collections/Delayed/DelayedEnumerator.cs deleted file mode 100644 index 793313d6..00000000 --- a/source - Copie/Extensions/Collections/Delayed/DelayedEnumerator.cs +++ /dev/null @@ -1,37 +0,0 @@ -using System.Collections; - -namespace ChartTools.Extensions.Collections; - -internal class DelayedEnumerator : IEnumerator -{ - public T Current { get; private set; } - object? IEnumerator.Current => Current; - public bool AwaitingItems => source.AwaitingItems; - - private readonly DelayedEnumerableSource source; - - internal DelayedEnumerator(DelayedEnumerableSource source) => this.source = source; - - private bool WaitForItems() - { - while (source.Buffer.IsEmpty) - if (!AwaitingItems && source.Buffer.IsEmpty) - return false; - - return true; - } - public bool MoveNext() - { - if (!WaitForItems()) - return false; - - source.Buffer.TryDequeue(out T? item); - Current = item!; - - return true; - } - - public void Dispose() => GC.SuppressFinalize(this); - - public void Reset() => throw new InvalidOperationException(); -} diff --git a/source - Copie/Extensions/Collections/EagerEnumerable.cs b/source - Copie/Extensions/Collections/EagerEnumerable.cs deleted file mode 100644 index 73d428e1..00000000 --- a/source - Copie/Extensions/Collections/EagerEnumerable.cs +++ /dev/null @@ -1,23 +0,0 @@ -using System.Collections; - -namespace ChartTools.Internal.Collections; - -internal class EagerEnumerable : IEnumerable -{ - private IEnumerable? items; - private readonly Task> source; - - public EagerEnumerable(Task> source) => this.source = source; - - public IEnumerator GetEnumerator() - { - if (items is null) - { - source.Wait(); - items = source.Result; - } - - return items.GetEnumerator(); - } - IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); -} diff --git a/source - Copie/Extensions/Collections/IInitializable.cs b/source - Copie/Extensions/Collections/IInitializable.cs deleted file mode 100644 index 37a67eb0..00000000 --- a/source - Copie/Extensions/Collections/IInitializable.cs +++ /dev/null @@ -1,17 +0,0 @@ -namespace ChartTools.Extensions.Collections; - -/// -/// Defines an object that can be initialized -/// -public interface IInitializable -{ - /// - /// Has already been initialized - /// - public bool Initialized { get; } - /// - /// Does required initialization if not already done. - /// - /// if the object was not initialized prior to calling. - public bool Initialize(); -} diff --git a/source - Copie/Extensions/EnumCache.cs b/source - Copie/Extensions/EnumCache.cs deleted file mode 100644 index 52ee9d34..00000000 --- a/source - Copie/Extensions/EnumCache.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace ChartTools.Extensions; - -internal static class EnumCache where T : struct, Enum -{ - public static T[] Values => _values ??= Enum.GetValues().ToArray(); - private static T[]? _values; - - public static void Clear() => _values = null; -} diff --git a/source - Copie/Extensions/EqualityComparison.cs b/source - Copie/Extensions/EqualityComparison.cs deleted file mode 100644 index b99e1def..00000000 --- a/source - Copie/Extensions/EqualityComparison.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace ChartTools.Extensions; - -/// -/// equivalent to the delegate -/// -public delegate bool EqualityComparison(T a, T b); diff --git a/source - Copie/Extensions/FuncEqualityComparer.cs b/source - Copie/Extensions/FuncEqualityComparer.cs deleted file mode 100644 index 214df323..00000000 --- a/source - Copie/Extensions/FuncEqualityComparer.cs +++ /dev/null @@ -1,27 +0,0 @@ -namespace ChartTools.Extensions; - -/// -/// Delegate-based -/// -public class FuncEqualityComparer : IEqualityComparer -{ - /// - /// Method used to compare two objects - /// - public EqualityComparison Comparison { get; } - - /// - /// Creates a new instance. - /// - /// Method used to compare two objects - public FuncEqualityComparer(EqualityComparison comparison) - { - if (comparison is null) - throw new ArgumentNullException(nameof(comparison), "The comparison is null"); - - Comparison = comparison; - } - - public bool Equals(T? x, T? y) => Comparison(x, y); - public int GetHashCode(T obj) => obj!.GetHashCode(); -} diff --git a/source - Copie/Extensions/IInitializable.cs b/source - Copie/Extensions/IInitializable.cs deleted file mode 100644 index 4997f2db..00000000 --- a/source - Copie/Extensions/IInitializable.cs +++ /dev/null @@ -1,17 +0,0 @@ -namespace ChartTools.Extensions; - -/// -/// Defines an object that can be initialized -/// -public interface IInitializable -{ - /// - /// Has already been initialized - /// - public bool Initialized { get; } - /// - /// Does required initialization if not already done. - /// - /// if the object was not initialized prior to calling. - public bool Initialize(); -} diff --git a/source - Copie/Extensions/Linq/CollectionExtensions.cs b/source - Copie/Extensions/Linq/CollectionExtensions.cs deleted file mode 100644 index ca9c0eda..00000000 --- a/source - Copie/Extensions/Linq/CollectionExtensions.cs +++ /dev/null @@ -1,42 +0,0 @@ -namespace ChartTools.Extensions.Linq; - -public static class CollectionExtensions -{ - public static int BinarySearchIndex(this IList source, TKey target, Func keySelector, out bool exactMatch) where TKey : notnull, IComparable - { - int left = 0, right = source.Count - 1, middle, index = 0; - - while (left <= right) - { - middle = (left + right) / 2; - - switch (keySelector(source[middle]).CompareTo(target)) - { - case -1: - index = left = middle + 1; - break; - case 0: - exactMatch = true; - return middle; - case 1: - index = right = middle - 1; - break; - } - } - - exactMatch = false; - return index; - } - public static int BinarySearchIndex(this IList source, T target, out bool exactMatch) where T : notnull, IComparable => BinarySearchIndex(source, target, t => t, out exactMatch); - - /// - /// Removes all items in a that meet a condition - /// - /// Collection to remove items from - /// Function that determines which items to remove - public static void RemoveWhere(this ICollection source, Predicate predicate) - { - foreach (T item in source.Where(i => predicate(i))) - source.Remove(item); - } -} diff --git a/source - Copie/Extensions/Linq/EnumerableExtensions.cs b/source - Copie/Extensions/Linq/EnumerableExtensions.cs deleted file mode 100644 index 6b260a8a..00000000 --- a/source - Copie/Extensions/Linq/EnumerableExtensions.cs +++ /dev/null @@ -1,378 +0,0 @@ -using ChartTools.Extensions.Collections; - -using System.Collections; -using System.Runtime.CompilerServices; - -namespace ChartTools.Extensions.Linq; - -public static class EnumerableExtensions -{ - /// - /// Checks that all booleans in a collection are . - /// - /// Source of booleans - /// if all booleans are or the collection is empty - public static bool All(this IEnumerable source) - { - foreach (bool b in source) - if (!b) - return false; - - return true; - } - - /// - /// Checks if any boolean in a collection is . - /// - /// Source of booleans - public static bool Any(this IEnumerable source) - { - foreach (bool b in source) - if (b) - return true; - - return false; - } - - #region First - /// - /// if no items meeting the condition were found - public static T? FirstOrDefault(this IEnumerable source, Predicate predicate, T? defaultValue, out bool returnedDefault) - { - if (predicate is null) - throw new ArgumentNullException(nameof(predicate)); - - foreach (T item in source) - if (predicate(item)) - { - returnedDefault = false; - return item; - } - - returnedDefault = true; - return defaultValue; - } - /// - /// Tries to get the first item that meet a condition from en enumerable. - /// - /// Method that returns if a given item meets the condition - /// Found item - /// if an item was found - public static bool TryGetFirst(this IEnumerable source, Predicate predicate, out T item) - { - if (predicate is null) - throw new ArgumentNullException(nameof(predicate)); - - foreach (T t in source) - if (predicate(t)) - { - item = t; - return true; - } - - item = default!; - return false; - } - /// - /// Tries to get the first element of a collection. - /// - /// Source of items - /// Found item - /// if an item was found - public static bool TryGetFirst(this IEnumerable source, out T result) - { - using var enumerator = source.GetEnumerator(); - var success = enumerator.MoveNext(); - - result = success ? enumerator.Current : default!; - return success; - } - /// - /// Tries to get the first item of a given type in a collection. - /// - /// Source of items - /// Found item - /// if an item was found - public static bool TryGetFirstOfType(this IEnumerable source, out TResult result) => source.OfType().TryGetFirst(out result); - #endregion - - /// - /// Excludes items. - /// - public static IEnumerable NonNull(this IEnumerable source) => source.Where(t => t is not null)!; - public static IEnumerable NonNull(this IEnumerable source) where T : struct - { - foreach (var item in source) - if (item.HasValue) - yield return item.Value; - } - - #region Replace - /// - /// Replaces items that meet a condition with another item. - /// - /// The IEnumerable<out T> to replace the items of - /// A function that determines if an item must be replaced - /// The item to replace items with - public static IEnumerable Replace(this IEnumerable source, Predicate predicate, T replacement) - { - if (predicate is null) - throw new ArgumentNullException(nameof(predicate)); - - foreach (T item in source) - yield return predicate(item) ? replacement : item; - } - - /// - /// Replaces a section with other items. - /// - /// Items that match startReplace or endReplace are not included in the returned items. - /// Items to replace a section in - public static IEnumerable ReplaceSection(this IEnumerable source, SectionReplacement replacement) - { - if (replacement.StartReplace is null) - throw new NullReferenceException(nameof(replacement.StartReplace)); - if (replacement.EndReplace is null) - throw new NullReferenceException(nameof(replacement.EndReplace)); - - IEnumerator itemsEnumerator = source.GetEnumerator(); - - // Initialize the enumerator - if (!itemsEnumerator.MoveNext()) - { - // Return the replacement - if (replacement.AddIfMissing) - foreach (T item in replacement.Replacement) - yield return item; - - yield break; - } - - // Return original until startReplace - while (!replacement.StartReplace(itemsEnumerator.Current)) - { - yield return itemsEnumerator.Current; - - if (!itemsEnumerator.MoveNext()) - { - // Return the replacement - if (replacement.AddIfMissing) - foreach (T item in replacement.Replacement) - yield return item; - yield break; - } - } - - // Return replacement - foreach (T item in replacement.Replacement) - yield return item; - - // Find the end of the section to replace - do - if (!itemsEnumerator.MoveNext()) - yield break; - while (replacement.EndReplace(itemsEnumerator.Current)); - - // Return the rest - while (itemsEnumerator.MoveNext()) - yield return itemsEnumerator.Current; - } - - /// - /// Replaces multiple sections of items. - /// - /// Items that match startReplace or endReplace are not included in the returned items. - /// Items to replace sections in - public static IEnumerable ReplaceSections(this IEnumerable source, IEnumerable> replacements) - { - if (replacements is null || !replacements.Any()) - { - foreach (T item in source) - yield return item; - yield break; - } - - List> replacementList = replacements.ToList(); - using IEnumerator itemsEnumerator = source.GetEnumerator(); - - if (!itemsEnumerator.MoveNext()) - { - foreach (var item in AddMissing()) - yield return item; - - yield break; - } - - do - { - // Find a matching replacement start - if (replacementList.TryGetFirst(r => r.StartReplace(itemsEnumerator.Current), out var replacement)) - { - // Move to the end of the section to replace - do - if (!itemsEnumerator.MoveNext()) - { - foreach (var item in AddMissing()) - yield return item; - yield break; - } - while (!replacement.EndReplace(itemsEnumerator.Current)); - - // Return the replacement - foreach (T item in replacement.Replacement) - yield return item; - - replacementList.Remove(replacement); - } - else - { - yield return itemsEnumerator.Current; - - if (!itemsEnumerator.MoveNext()) - { - foreach (var item in AddMissing()) - yield return item; - yield break; - } - } - } - // Continue until all replacements are applied - while (replacementList.Count > 0); - - // Return the rest of the items - while (itemsEnumerator.MoveNext()) - yield return itemsEnumerator.Current; - - IEnumerable AddMissing() - { - // Return remaining replacements - foreach (var replacement in replacementList.Where(r => r.AddIfMissing)) - // Return the replacement - foreach (T item in replacement.Replacement) - yield return item; - } - } - /// - /// Removes a section of items. - /// - /// Items that match startRemove or endRemove - /// Source items to remove a section of - /// Function that determines the start of the section to replace - /// Function that determines the end of the section to replace - public static IEnumerable RemoveSection(this IEnumerable source, Predicate startRemove, Predicate endRemove) - { - IEnumerator itemsEnumerator = source.GetEnumerator(); - - // Initialize the enumerator - if (!itemsEnumerator.MoveNext()) - yield break; - - // Move to the start of items to remove - while (!startRemove(itemsEnumerator.Current)) - if (!itemsEnumerator.MoveNext()) - yield break; - - // Skip items to remove - do - if (!itemsEnumerator.MoveNext()) - yield break; - while (!endRemove(itemsEnumerator.Current)); - - // Return the rest - while (itemsEnumerator.MoveNext()) - yield return itemsEnumerator.Current; - } - #endregion - - /// - /// Loops through a set of objects and returns a set of tuples containing the current object and the previous one. - /// - /// Items to loop through - /// Value of the previous item in the first call of the action - public static IEnumerable<(T? previous, T current)> RelativeLoop(this IEnumerable source, T? firstPrevious = default) - { - var previousItem = firstPrevious; - - foreach (var item in source) - { - yield return (previousItem, item); - previousItem = item; - } - } - public static IEnumerable<(T previous, T current)> RelativeLoopSkipFirst(this IEnumerable source) - { - using var enumerator = source.GetEnumerator(); - - if (enumerator.MoveNext()) - yield break; - - var previous = enumerator.Current; - - while (enumerator.MoveNext()) - yield return (previous, enumerator.Current); - } - - #region Unique - /// - /// Returns distinct elements of a sequence using a method to determine the equality of elements - /// - /// Method that determines if two elements are the same - public static IEnumerable Distinct(this IEnumerable source, EqualityComparison comparison) => source.Distinct(new FuncEqualityComparer(comparison)); - public static bool Unique(this IEnumerable source) => UniqueFromDistinct(source.Distinct()); - public static bool UniqueBy(this IEnumerable source, Func selector) => UniqueFromDistinct(source.DistinctBy(selector)); - private static bool UniqueFromDistinct(IEnumerable distinct) => !distinct.Skip(1).Any(); - #endregion - - #region MinMax - /// - /// Finds the items for which a function returns the smallest or greatest value based on a comparison. - /// - /// Items to find the minimum or maximum of - /// Function that gets the key to use in the comparison from an item - /// Function that returns if the second item defeats the first - private static IEnumerable ManyMinMaxBy(this IEnumerable source, Func selector, Func comparison) where TKey : IComparable - { - TKey minMaxKey; - - using (IEnumerator enumerator = source.GetEnumerator()) - { - if (!enumerator.MoveNext()) - throw new ArgumentException("The enumerable has no items.", nameof(source)); - - minMaxKey = selector(enumerator.Current); - - while (enumerator.MoveNext()) - { - TKey key = selector(enumerator.Current); - - if (comparison(key, minMaxKey)) - minMaxKey = key; - } - } - return source.Where(t => selector(t).CompareTo(minMaxKey) == 0); - } - /// - /// Finds the items for which a function returns the smallest value. - /// - /// Items to find the minimum or maximum of - /// Function that gets the key to use in the comparison from an item - public static IEnumerable ManyMinBy(this IEnumerable source, Func selector) where TKey : IComparable => ManyMinMaxBy(source, selector, (key, mmkey) => key.CompareTo(mmkey) < 0); - /// - /// Finds the items for which a function returns the greatest value. - /// - /// Items to find the minimum or maximum of - /// Function that gets the key to use in the comparison from an item - public static IEnumerable ManyMaxBy(this IEnumerable source, Func selector) where TKey : IComparable => ManyMinMaxBy(source, selector, (key, mmkey) => key.CompareTo(mmkey) > 0); - #endregion - - public static async IAsyncEnumerable ToAsyncEnumerable(this IEnumerable source) - { - foreach (var item in source) - yield return await Task.FromResult(item); - } - - #region Collections - public static IEnumerable Alternate(this IEnumerable> source) => new SerialAlternatingEnumerable(source.ToArray()); - public static IEnumerable AlternateBy(this IEnumerable> source, Func selector) where TKey : IComparable => new OrderedAlternatingEnumerable(selector, source.ToArray()); - #endregion -} diff --git a/source - Copie/Extensions/Linq/SectionReplacement.cs b/source - Copie/Extensions/Linq/SectionReplacement.cs deleted file mode 100644 index ed2b35b4..00000000 --- a/source - Copie/Extensions/Linq/SectionReplacement.cs +++ /dev/null @@ -1,11 +0,0 @@ -namespace ChartTools.Extensions.Linq -{ - /// - /// Replacement for a section of items in a collection - /// - /// Items to replace with - /// Method that defines if a source marks the start of the section to replace - /// Method that defines if a source item marks the end of the section to replace - /// The replacement should be appended to the collection if the section to replace is not found - public readonly record struct SectionReplacement(IEnumerable Replacement, Predicate StartReplace, Predicate EndReplace, bool AddIfMissing); -} diff --git a/source - Copie/Extensions/StringExtensions.cs b/source - Copie/Extensions/StringExtensions.cs deleted file mode 100644 index 09b1edf9..00000000 --- a/source - Copie/Extensions/StringExtensions.cs +++ /dev/null @@ -1,22 +0,0 @@ -namespace ChartTools.Extensions; - -/// -/// Provides additional methods to string -/// -internal static class StringExtensions -{ - /// - public static string VerbalEnumerate(this IEnumerable items, string lastItemPreceder) => VerbalEnumerate(lastItemPreceder, items.ToArray()); - /// - /// Enumerates items with commas and a set word preceding the last item. - /// - /// Word to place before the last item - /// - public static string VerbalEnumerate(string lastItemPreceder, params string[] items) => items is null ? throw new ArgumentNullException(nameof(items)) : items.Length switch - { - 0 => string.Empty, // "" - 1 => items[0], // "Item1" - 2 => $"{items[0]} {lastItemPreceder} {items[1]}", // "Item1 lastItemPreceder Item2" - _ => $"{string.Join(", ", items, items.Length - 1)} {lastItemPreceder} {items[^0]}" // "Item1, Item2 lastItemPreceder Item3" - }; -} diff --git a/source - Copie/GlobalSuppressions.cs b/source - Copie/GlobalSuppressions.cs deleted file mode 100644 index bf762268..00000000 --- a/source - Copie/GlobalSuppressions.cs +++ /dev/null @@ -1,8 +0,0 @@ -// This file is used by Code Analysis to maintain SuppressMessage -// attributes that are applied to this project. -// Project-level suppressions either have no target or are given -// a specific target and scoped to a namespace, type, member, etc. - -using System.Diagnostics.CodeAnalysis; - -[assembly: SuppressMessage("Minor Code Smell", "S101:Types should be named in PascalCase", Justification = "GHL is an accronym", Scope = "type", Target = "~T:ChartTools.GHLChord")] diff --git a/source - Copie/IEmptyVerifiable.cs b/source - Copie/IEmptyVerifiable.cs deleted file mode 100644 index a77c5ecd..00000000 --- a/source - Copie/IEmptyVerifiable.cs +++ /dev/null @@ -1,12 +0,0 @@ -namespace ChartTools; - -/// -/// Adds support for a property defining if an object is empty -/// -public interface IEmptyVerifiable -{ - /// - /// if containing no data - /// - public bool IsEmpty { get; } -} diff --git a/source - Copie/ILongObject.cs b/source - Copie/ILongObject.cs deleted file mode 100644 index 8edfa160..00000000 --- a/source - Copie/ILongObject.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace ChartTools; - -public interface ILongObject : IReadOnlyLongObject -{ - /// - public new uint Length { get; set; } - - uint IReadOnlyLongObject.Length => Length; -} diff --git a/source - Copie/IO/Anchor.cs b/source - Copie/IO/Anchor.cs deleted file mode 100644 index 4f5eaaf2..00000000 --- a/source - Copie/IO/Anchor.cs +++ /dev/null @@ -1,13 +0,0 @@ -namespace ChartTools.IO; - -internal readonly struct Anchor : IReadOnlyTrackObject -{ - public uint Position { get; } - public TimeSpan Value { get; } - - public Anchor(uint position, TimeSpan value) - { - Position = position; - Value = value; - } -} diff --git a/source - Copie/IO/Appliables/IInstrumentAppliable.cs b/source - Copie/IO/Appliables/IInstrumentAppliable.cs deleted file mode 100644 index ea00b2c2..00000000 --- a/source - Copie/IO/Appliables/IInstrumentAppliable.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace ChartTools.IO; - -internal interface IInstrumentAppliable where TChord : IChord -{ - public void ApplyToInstrument(Instrument instrument); -} diff --git a/source - Copie/IO/Appliables/ISongAppliable.cs b/source - Copie/IO/Appliables/ISongAppliable.cs deleted file mode 100644 index 645fd2be..00000000 --- a/source - Copie/IO/Appliables/ISongAppliable.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace ChartTools.IO; - -internal interface ISongAppliable -{ - public void ApplyToSong(Song song); -} diff --git a/source - Copie/IO/Chart/ChartFile.cs b/source - Copie/IO/Chart/ChartFile.cs deleted file mode 100644 index 87790eb9..00000000 --- a/source - Copie/IO/Chart/ChartFile.cs +++ /dev/null @@ -1,707 +0,0 @@ -using ChartTools.Events; -using ChartTools.Extensions; -using ChartTools.Extensions.Linq; -using ChartTools.IO.Chart.Parsing; -using ChartTools.IO.Chart.Serializing; -using ChartTools.IO.Configuration; -using ChartTools.IO.Configuration.Sessions; -using ChartTools.IO.Formatting; -using ChartTools.Lyrics; - -namespace ChartTools.IO.Chart; - -/// -/// Provides methods for reading and writing chart files -/// -public static class ChartFile -{ - /// - /// Default configuration to use for reading when the provided configuration is - /// - public static ReadingConfiguration DefaultReadConfig { get; set; } = new() - { - DuplicateTrackObjectPolicy = DuplicateTrackObjectPolicy.ThrowException, - SoloNoStarPowerPolicy = SoloNoStarPowerPolicy.Convert - }; - /// - /// Default configuration to use for writing when the provided configuration is - /// - public static WritingConfiguration DefaultWriteConfig { get; set; } = new() - { - SoloNoStarPowerPolicy = SoloNoStarPowerPolicy.Convert, - EventSource = TrackObjectSource.Merge, - StarPowerSource = TrackObjectSource.Merge, - UnsupportedModifierPolicy = UnsupportedModifierPolicy.ThrowException - }; - - #region Reading - #region Song - /// - /// Creates a for parsing a section based on the header. - /// - /// - private static ChartParser GetSongParser(string header, ReadingSession session) - { - switch (header) - { - case ChartFormatting.MetadataHeader: - return new MetadataParser(); - case ChartFormatting.GlobalEventHeader: - return new GlobalEventParser(session); - case ChartFormatting.SyncTrackHeader: - return new SyncTrackParser(session); - default: - if (drumsTrackHeaders.TryGetValue(header, out Difficulty diff)) - return new DrumsTrackParser(diff, session, header); - else if (ghlTrackHeaders.TryGetValue(header, out (Difficulty, GHLInstrumentIdentity) ghlTuple)) - return new GHLTrackParser(ghlTuple.Item1, ghlTuple.Item2, session, header); - else if (standardTrackHeaders.TryGetValue(header, out (Difficulty, StandardInstrumentIdentity) standardTuple)) - return new StandardTrackParser(standardTuple.Item1, standardTuple.Item2, session, header); - else - { - return session.Configuration.UnknownSectionPolicy == UnknownSectionPolicy.ThrowException - ? throw new Exception($"Unknown section with header \"{header}\". Consider using {UnknownSectionPolicy.Store} to avoid this error.") - : new UnknownSectionParser(session, header); - } - } - } - - /// - /// Combines the results from the parsers of a into a . - /// - /// Reader to get the parsers from - private static Song CreateSongFromReader(ChartFileReader reader) - { - Song song = new(); - - foreach (var parser in reader.Parsers) - parser.ApplyToSong(song); - - return song; - } - - /// - /// - /// - public static Song ReadSong(string path, ReadingConfiguration? config = default, FormattingRules? formatting = default) - { - var session = new ReadingSession(config ?? DefaultReadConfig, formatting ?? new()); - var reader = new ChartFileReader(path, header => GetSongParser(header, session)); - - reader.Read(); - return CreateSongFromReader(reader); - } - - /// - /// - /// - /// - public static async Task ReadSongAsync(string path, ReadingConfiguration? config = default, FormattingRules? formatting = default, CancellationToken cancellationToken = default) - { - var session = new ReadingSession(config ?? DefaultReadConfig, formatting ?? new()); - var reader = new ChartFileReader(path, header => GetSongParser(header, session)); - - await reader.ReadAsync(cancellationToken); - return CreateSongFromReader(reader); - } - #endregion - #region Instruments - /// - /// Combines the results from the parsers in a into an instrument. - /// - private static TInst? CreateInstrumentFromReader(ChartFileReader reader) where TInst : Instrument, new() where TChord : IChord, new() - { - TInst? output = null; - - foreach (var parser in reader.Parsers) - (output ??= new()).SetTrack(((TrackParser)parser).Result!); - - return output; - } - - /// - /// Reads an instrument from a chart file. - /// - /// Instance of containing all data about the given instrument - /// if the file contains no data for the given instrument - /// - /// Path of the file to read - /// Instrument to read - /// - /// - /// - /// - public static Instrument? ReadInstrument(string path, InstrumentIdentity instrument, ReadingConfiguration? config = default, FormattingRules? formatting = default) - { - if (instrument == InstrumentIdentity.Drums) - return ReadDrums(path, config, formatting); - if (Enum.IsDefined((GHLInstrumentIdentity)instrument)) - return ReadInstrument(path, (GHLInstrumentIdentity)instrument, config, formatting); - return Enum.IsDefined((StandardInstrumentIdentity)instrument) - ? ReadInstrument(path, (StandardInstrumentIdentity)instrument, config, formatting) - : throw new UndefinedEnumException(instrument); - } - public static async Task ReadInstrumentAsync(string path, InstrumentIdentity instrument, ReadingConfiguration? config = default, FormattingRules? formatting = default, CancellationToken cancellationToken = default) - { - if (instrument == InstrumentIdentity.Drums) - return await ReadDrumsAsync(path, config, formatting, cancellationToken); - if (Enum.IsDefined((GHLInstrumentIdentity)instrument)) - return await ReadInstrumentAsync(path, (GHLInstrumentIdentity)instrument, config, formatting, cancellationToken); - return Enum.IsDefined((StandardInstrumentIdentity)instrument) - ? await ReadInstrumentAsync(path, (StandardInstrumentIdentity)instrument, config, formatting, cancellationToken) - : throw new UndefinedEnumException(instrument); - } - #region Vocals - /// - /// Reads vocals from the global events in a chart file. - /// - /// Instance of where TChord is containing lyric and timing data - /// if the file contains no drums data - /// - /// Path of the file to read - public static Vocals? ReadVocals(string path) => BuildVocals(ReadGlobalEvents(path)); - public static async Task ReadVocalsAsync(string path, CancellationToken cancellationToken = default) => BuildVocals(await ReadGlobalEventsAsync(path, cancellationToken)); - private static Vocals? BuildVocals(List events) - { - var lyrics = events.GetLyrics().ToArray(); - - if (lyrics.Length == 0) - return null; - - var instument = new Vocals(); - - foreach (var diff in EnumCache.Values) - { - var track = instument.CreateTrack(diff); - track.Chords.AddRange(lyrics); - } - - return instument; - } - #endregion - #region Drums - private static DrumsTrackParser? GetAnyDrumsTrackParser(string header, ReadingSession session) => drumsTrackHeaders.TryGetValue(header, out Difficulty difficulty) - ? new(difficulty, session, header) - : null; - /// - /// Reads drums from a chart file. - /// - /// Instance of where TChord is containing all drums data - /// if the file contains no drums data - /// - /// Path of the file to read - /// - /// - public static Drums? ReadDrums(string path, ReadingConfiguration? config = default, FormattingRules? formatting = default) - { - var session = new ReadingSession(config ?? DefaultReadConfig, formatting ?? new()); - var reader = new ChartFileReader(path, header => GetAnyDrumsTrackParser(header, session)); - - reader.Read(); - return CreateInstrumentFromReader(reader); - } - public static async Task ReadDrumsAsync(string path, ReadingConfiguration? config = default, FormattingRules? formatting = default, CancellationToken cancellationToken = default) - { - var session = new ReadingSession(config ?? DefaultReadConfig, formatting ?? new()); - var reader = new ChartFileReader(path, header => GetAnyDrumsTrackParser(header, session)); - - await reader.ReadAsync(cancellationToken); - return CreateInstrumentFromReader(reader); - } - #endregion - #region GHL - private static GHLTrackParser? GetAnyGHLTrackParser(string header, GHLInstrumentIdentity instrument, ReadingSession session) => ghlTrackHeaders.TryGetValue(header, out (Difficulty, GHLInstrumentIdentity) tuple) && tuple.Item2 == instrument - ? new(tuple.Item1, tuple.Item2, session, header) - : null; - /// - /// Reads a Guitar Hero Live instrument from a chart file. - /// - /// Instance of where TChord is containing all data about the given instrument - /// if the file has no data for the given instrument - /// - /// Path of the file to read - /// - public static GHLInstrument? ReadInstrument(string path, GHLInstrumentIdentity instrument, ReadingConfiguration? config = default, FormattingRules? formatting = default) - { - Validator.ValidateEnum(instrument); - - var session = new ReadingSession(config ?? DefaultReadConfig, formatting ?? new()); - var reader = new ChartFileReader(path, header => GetAnyGHLTrackParser(header, instrument, session)); - - reader.Read(); - return CreateInstrumentFromReader(reader); - } - public static async Task ReadInstrumentAsync(string path, GHLInstrumentIdentity instrument, ReadingConfiguration? config = default, FormattingRules? formatting = default, CancellationToken cancellationToken = default) - { - Validator.ValidateEnum(instrument); - - var session = new ReadingSession(config ?? DefaultReadConfig, formatting ?? new()); - var reader = new ChartFileReader(path, header => GetAnyGHLTrackParser(header, instrument, session)); - - await reader.ReadAsync(cancellationToken); - return CreateInstrumentFromReader(reader); - } - #endregion - #region Standard - private static StandardTrackParser? GetAnyStandardTrackParser(string header, StandardInstrumentIdentity instrument, ReadingSession session) => standardTrackHeaders.TryGetValue(header, out (Difficulty, StandardInstrumentIdentity) tuple) && tuple.Item2 == instrument - ? new(tuple.Item1, tuple.Item2, session, header) - : null; - /// - /// - /// - /// - public static StandardInstrument? ReadInstrument(string path, StandardInstrumentIdentity instrument, ReadingConfiguration? config = default, FormattingRules? formatting = default) - { - Validator.ValidateEnum(instrument); - - var session = new ReadingSession(config ?? DefaultReadConfig, formatting ?? new()); - var reader = new ChartFileReader(path, header => GetAnyStandardTrackParser(header, instrument, session)); - - reader.Read(); - return CreateInstrumentFromReader(reader); - } - /// - /// - /// - /// - /// - public static async Task ReadInstrumentAsync(string path, StandardInstrumentIdentity instrument, ReadingConfiguration? config = default, FormattingRules? formatting = default, CancellationToken cancellationToken = default) - { - Validator.ValidateEnum(instrument); - - var session = new ReadingSession(config ?? DefaultReadConfig, formatting ?? new()); - var reader = new ChartFileReader(path, header => GetAnyStandardTrackParser(header, instrument, session)); - - await reader.ReadAsync(cancellationToken); - return CreateInstrumentFromReader(reader); - } - #endregion - #endregion - #region Tracks - /// - /// - /// - /// - /// - public static Track ReadTrack(string path, InstrumentIdentity instrument, Difficulty difficulty, ReadingConfiguration? config = default, FormattingRules? formatting = default) - { - if (instrument == InstrumentIdentity.Drums) - return ReadDrumsTrack(path, difficulty, config, formatting); - if (Enum.IsDefined((GHLInstrumentIdentity)instrument)) - return ReadTrack(path, (GHLInstrumentIdentity)instrument, difficulty, config, formatting); - if (Enum.IsDefined((StandardInstrumentIdentity)instrument)) - return ReadTrack(path, (StandardInstrumentIdentity)instrument, difficulty, config, formatting); - - throw new UndefinedEnumException(instrument); - } - /// - /// - /// - /// - /// - /// - public static async Task ReadTrackAsync(string path, InstrumentIdentity instrument, Difficulty difficulty, ReadingConfiguration? config = default, FormattingRules? formatting = default, CancellationToken cancellationToken = default) - { - if (instrument == InstrumentIdentity.Drums) - return await ReadDrumsTrackAsync(path, difficulty, config, formatting, cancellationToken); - if (Enum.IsDefined((GHLInstrumentIdentity)instrument)) - return await ReadTrackAsync(path, (GHLInstrumentIdentity)instrument, difficulty, config, formatting, cancellationToken); - if (Enum.IsDefined((StandardInstrumentIdentity)instrument)) - return await ReadTrackAsync(path, (StandardInstrumentIdentity)instrument, difficulty, config, formatting, cancellationToken); - - throw new UndefinedEnumException(instrument); - } - #region Drums - /// - /// Creates a is the header matches the requested standard track, otherwise . - /// - /// Header of the part - /// Header to compare against - /// Difficulty identity to provide the parser - /// Session to provide the parser - private static DrumsTrackParser? GetDrumsTrackParser(string header, string seekedHeader, Difficulty difficulty, ReadingSession session) => header == seekedHeader ? new(difficulty, session, header) : null; - /// - /// Headers for drums tracks - /// - private static readonly Dictionary drumsTrackHeaders = EnumCache.Values.ToDictionary(diff => ChartFormatting.Header(ChartFormatting.DrumsHeaderName, diff)); - /// - /// - /// - /// - public static Track ReadDrumsTrack(string path, Difficulty difficulty, ReadingConfiguration? config = default, FormattingRules? formatting = default) - { - Validator.ValidateEnum(difficulty); - - var seekedHeader = ChartFormatting.Header(InstrumentIdentity.Drums, difficulty); - var session = new ReadingSession(config ?? DefaultReadConfig, formatting ?? new()); - var reader = new ChartFileReader(path, header => GetDrumsTrackParser(header, seekedHeader, difficulty, session)); - - reader.Read(); - return reader.Parsers.TryGetFirstOfType(out DrumsTrackParser? parser) ? parser!.Result! : new(); - } - /// - /// - /// - /// - /// - public static async Task> ReadDrumsTrackAsync(string path, Difficulty difficulty, ReadingConfiguration? config = default, FormattingRules? formatting = default, CancellationToken cancellationToken = default) - { - Validator.ValidateEnum(difficulty); - - var seekedHeader = ChartFormatting.Header(ChartFormatting.DrumsHeaderName, difficulty); - var session = new ReadingSession(config ?? DefaultReadConfig, formatting ?? new()); - var reader = new ChartFileReader(path, header => GetDrumsTrackParser(header, seekedHeader, difficulty, session)); - - await reader.ReadAsync(cancellationToken); - return reader.Parsers.TryGetFirstOfType(out DrumsTrackParser? parser) ? parser!.Result! : new(); - } - #endregion - #region GHL - /// - /// Creates a is the header matches the requested standard track, otherwise . - /// - /// Header of the part - /// Header to compare against - /// Instrument identity to provide the parser - /// Difficulty identity to provide the parser - /// Session to provide the parser - private static GHLTrackParser? GetGHLTrackParser(string header, string seekedHeader, GHLInstrumentIdentity instrument, Difficulty difficulty, ReadingSession session) => header == seekedHeader ? new(difficulty, instrument, session, header) : null; - /// - /// Headers for GHL tracks - /// - private static readonly Dictionary ghlTrackHeaders = GetTrackCombinations(Enum.GetValues()).ToDictionary(tuple => ChartFormatting.Header(tuple.instrument, tuple.difficulty)); - /// - /// - /// - /// - /// - public static Track ReadTrack(string path, GHLInstrumentIdentity instrument, Difficulty difficulty, ReadingConfiguration? config = default, FormattingRules? formatting = default) - { - Validator.ValidateEnum(instrument); - Validator.ValidateEnum(difficulty); - - var seekedHeader = ChartFormatting.Header(instrument, difficulty); - var session = new ReadingSession(config ?? DefaultReadConfig, formatting ?? new()); - var reader = new ChartFileReader(path, header => GetGHLTrackParser(header, seekedHeader, instrument, difficulty, session)); - - reader.Read(); - return reader.Parsers.TryGetFirstOfType(out GHLTrackParser? parser) ? parser!.Result : new(); - } - /// - /// - /// - /// - /// - /// - public static async Task> ReadTrackAsync(string path, GHLInstrumentIdentity instrument, Difficulty difficulty, ReadingConfiguration? config, FormattingRules? formatting = default, CancellationToken cancellationToken = default) - { - Validator.ValidateEnum(instrument); - Validator.ValidateEnum(difficulty); - - var seekedHeader = ChartFormatting.Header(instrument, difficulty); - var session = new ReadingSession(config ?? DefaultReadConfig, formatting ?? new()); - var reader = new ChartFileReader(path, header => GetGHLTrackParser(header, seekedHeader, instrument, difficulty, session)); - - await reader.ReadAsync(cancellationToken); - return reader.Parsers.TryGetFirstOfType(out GHLTrackParser? parser) ? parser!.Result : new(); - } - #endregion - #region Standard - /// - /// Creates a is the header matches the requested standard track, otherwise . - /// - /// Header of the part - /// Header to compare against - /// Instrument identity to provide the parser - /// Difficulty identity to provide the parser - /// Session to provide the parser - private static StandardTrackParser? GetStandardTrackParser(string header, string seekedHeader, StandardInstrumentIdentity instrument, Difficulty difficulty, ReadingSession session) => header == seekedHeader ? new(difficulty, instrument, session, header) : null; - - /// - /// Headers for standard tracks - /// - private static readonly Dictionary standardTrackHeaders = GetTrackCombinations(Enum.GetValues()).ToDictionary(tuple => ChartFormatting.Header((InstrumentIdentity)tuple.instrument, tuple.difficulty)); - - /// - /// - /// - /// - /// - public static Track ReadTrack(string path, StandardInstrumentIdentity instrument, Difficulty difficulty, ReadingConfiguration? config = default, FormattingRules? formatting = default) - { - Validator.ValidateEnum(instrument); - Validator.ValidateEnum(difficulty); - - var seekedHeader = ChartFormatting.Header(instrument, difficulty); - var session = new ReadingSession(config ?? DefaultReadConfig, formatting ?? new()); - var reader = new ChartFileReader(path, header => GetStandardTrackParser(header, seekedHeader, instrument, difficulty, session)); - - reader.Read(); - return reader.Parsers.TryGetFirstOfType(out StandardTrackParser? parser) ? parser!.Result! : new(); - } - /// - /// - /// - /// - /// - /// - /// - public static async Task> ReadTrackAsync(string path, StandardInstrumentIdentity instrument, Difficulty difficulty, ReadingConfiguration? config = default, FormattingRules? formatting = default, CancellationToken cancellationToken = default) - { - Validator.ValidateEnum(instrument); - Validator.ValidateEnum(difficulty); - - var seekedHeader = ChartFormatting.Header(instrument, difficulty); - var session = new ReadingSession(config ?? DefaultReadConfig, formatting ?? new()); - var reader = new ChartFileReader(path, header => GetStandardTrackParser(header, seekedHeader, instrument, difficulty, session)); - - await reader.ReadAsync(cancellationToken); - return reader.Parsers.TryGetFirstOfType(out StandardTrackParser? parser) ? parser!.Result! : new(); - } - #endregion - #endregion - #region Metadata - private static MetadataParser? GetMetadataParser(string header) => header == ChartFormatting.MetadataHeader ? new() : null; - /// - /// Reads metadata from a chart file. - /// - /// Path of the file to read - public static Metadata ReadMetadata(string path) - { - var reader = new ChartFileReader(path, header => GetMetadataParser(header)); - reader.Read(); - return reader.Parsers.TryGetFirstOfType(out MetadataParser? parser) ? parser!.Result : new(); - } - #endregion - #region Global events - /// - /// Creates a if the header matches the sync track header, otherwise . - /// - private static GlobalEventParser? GetGlobalEventParser(string header) => header == ChartFormatting.GlobalEventHeader ? new(null!) : null; - - /// - /// - public static List ReadGlobalEvents(string path) - { - var reader = new ChartFileReader(path, GetGlobalEventParser); - reader.Read(); - return reader.Parsers.TryGetFirstOfType(out GlobalEventParser? parser) ? parser!.Result! : new(); - } - /// - /// - /// - /// - public static async Task> ReadGlobalEventsAsync(string path, CancellationToken cancellationToken = default) - { - var reader = new ChartFileReader(path, GetGlobalEventParser); - await reader.ReadAsync(cancellationToken); - return reader.Parsers.TryGetFirstOfType(out GlobalEventParser? parser) ? parser!.Result! : new(); - } - - /// - /// Reads lyrics from a chart file. - /// - /// Enumerable of containing the lyrics from the file - /// Path of the file to read - /// - public static IEnumerable ReadLyrics(string path) => ReadGlobalEvents(path).GetLyrics(); - /// - /// Reads lyrics from a chart file asynchronously using multitasking. - /// - /// - /// Token to request cancellation - public static async Task> ReadLyricsAsync(string path, CancellationToken cancellationToken = default) => (await ReadGlobalEventsAsync(path, cancellationToken)).GetLyrics(); - #endregion - #region Sync track - /// - /// Creates a if the header matches the sync track header, otherwise . - /// - private static SyncTrackParser? GetSyncTrackParser(string header, ReadingSession session) => header == ChartFormatting.SyncTrackHeader ? new(session) : null; - - /// - /// - /// - public static SyncTrack ReadSyncTrack(string path, ReadingConfiguration? config, FormattingRules? formatting = default) - { - config ??= DefaultReadConfig; - - var reader = new ChartFileReader(path, (header) => GetSyncTrackParser(header, new(config ?? DefaultReadConfig, formatting ?? new()))); - reader.Read(); - return reader.Parsers.TryGetFirstOfType(out SyncTrackParser? syncTrackParser) ? syncTrackParser!.Result! : new(); - } - /// - /// - /// - /// - public static async Task ReadSyncTrackAsync(string path, ReadingConfiguration? config = default, CancellationToken cancellationToken = default) - { - config ??= DefaultReadConfig; - - var reader = new ChartFileReader(path, (header) => GetSyncTrackParser(header, new(config ?? DefaultReadConfig, null))); - await reader.ReadAsync(cancellationToken); - return reader.Parsers.TryGetFirstOfType(out SyncTrackParser? syncTrackParser) ? syncTrackParser!.Result! : new(); - } - #endregion - #endregion - - #region Writing - /// - /// Writes a song to a chart file. - /// - /// Path of the file to write - /// Song to write - public static void WriteSong(string path, Song song, WritingConfiguration? config = default) - { - var writer = GetSongWriter(path, song, new(config ?? DefaultWriteConfig, song.Metadata.Formatting)); - writer.Write(); - } - public static async Task WriteSongAsync(string path, Song song, WritingConfiguration? config = default, CancellationToken cancellationToken = default) - { - var writer = GetSongWriter(path, song, new(config ?? DefaultWriteConfig, song.Metadata.Formatting)); - await writer.WriteAsync(cancellationToken); - } - private static ChartFileWriter GetSongWriter(string path, Song song, WritingSession session) - { - var instruments = song.Instruments.NonNull().ToArray(); - var serializers = new List>(instruments.Length + 2); - var removedHeaders = new List(); - - serializers.Add(new MetadataSerializer(song.Metadata)); - - if (!song.SyncTrack.IsEmpty) - serializers.Add(new SyncTrackSerializer(song.SyncTrack, session)); - else - removedHeaders.Add(ChartFormatting.SyncTrackHeader); - - if (song.GlobalEvents.Count > 0) - serializers.Add(new GlobalEventSerializer(song.GlobalEvents, session)); - else - removedHeaders.Add(ChartFormatting.GlobalEventHeader); - - var difficulties = EnumCache.Values; - - // Remove headers for null instruments - removedHeaders.AddRange((from identity in Enum.GetValues() - where instruments.Any(instrument => instrument.InstrumentIdentity == identity) - let instrumentName = ChartFormatting.InstrumentHeaderNames[identity] - let headers = from diff in difficulties - select ChartFormatting.Header(identity, diff) - select headers).SelectMany(h => h)); - - foreach (var instrument in instruments) - { - var instrumentName = ChartFormatting.InstrumentHeaderNames[instrument.InstrumentIdentity]; - var tracks = instrument.GetExistingTracks().ToArray(); - - serializers.AddRange(tracks.Select(t => new TrackSerializer(t, session))); - removedHeaders.AddRange(difficulties.Where(diff => !tracks.Any(t => t.Difficulty == diff)).Select(diff => ChartFormatting.Header(instrumentName, diff))); - } - - if (song.UnknownChartSections is not null) - serializers.AddRange(song.UnknownChartSections.Select(s => new UnknownSectionSerializer(s.Header, s, session))); - - return new(path, removedHeaders, serializers.ToArray()); - } - - /// - /// Replaces an instrument in a file. - /// - /// Path of the file to write - public static void ReplaceInstrument(string path, Instrument instrument, WritingConfiguration? config = default, FormattingRules? formatting = default) - { - var writer = GetInstrumentWriter(path, instrument, new(config ?? DefaultWriteConfig, formatting ?? new())); - writer.Write(); - } - public static async Task ReplaceInstrumentAsync(string path, Instrument instrument, WritingConfiguration? config = default, FormattingRules? formatting = default, CancellationToken cancellationToken = default) - { - var writer = GetInstrumentWriter(path, instrument, new(config ?? DefaultWriteConfig, formatting ?? new())); - await writer.WriteAsync(cancellationToken); - } - private static ChartFileWriter GetInstrumentWriter(string path, Instrument instrument, WritingSession session) - { - if (!Enum.IsDefined(instrument.InstrumentIdentity)) - throw new ArgumentException("Instrument cannot be written because its identity is unknown.", nameof(instrument)); - - var instrumentName = ChartFormatting.InstrumentHeaderNames[instrument.InstrumentIdentity]; - var tracks = instrument.GetExistingTracks().ToArray(); - - return new(path, - EnumCache.Values.Where(d => !tracks.Any(t => t.Difficulty == d)).Select(d => ChartFormatting.Header(instrumentName, d)), - tracks.Select(t => new TrackSerializer(t, session)).ToArray()); - } - - public static void ReplaceTrack(string path, Track track, WritingConfiguration? config = default, FormattingRules? formatting = default) - { - var writer = GetTrackWriter(path, track, new(config ?? DefaultWriteConfig, formatting ?? new())); - writer.Write(); - } - public static async Task ReplaceTrackAsync(string path, Track track, WritingConfiguration? config = default, FormattingRules? formatting = default, CancellationToken cancellationToken = default) - { - var writer = GetTrackWriter(path, track, new(config ?? DefaultWriteConfig, formatting ?? new())); - await writer.WriteAsync(cancellationToken); - } - private static ChartFileWriter GetTrackWriter(string path, Track track, WritingSession session) - { - if (track.ParentInstrument is null) - throw new ArgumentNullException(nameof(track), "Cannot write track because it does not belong to an instrument."); - if (!Enum.IsDefined(track.ParentInstrument.InstrumentIdentity)) - throw new ArgumentException("Cannot write track because the instrument it belongs to is unknown.", nameof(track)); - - return new(path, null, new TrackSerializer(track, session)); - } - - /// - /// Replaces the metadata in a file. - /// - /// Path of the file to read - /// Metadata to write - public static void ReplaceMetadata(string path, Metadata metadata) - { - var writer = GetMetadataWriter(path, metadata); - writer.Write(); - } - private static ChartFileWriter GetMetadataWriter(string path, Metadata metadata) => new(path, null, new MetadataSerializer(metadata)); - - /// - /// Replaces the global events in a file. - /// - /// Path of the file to write - /// Events to use as a replacement - public static void ReplaceGlobalEvents(string path, IEnumerable events) - { - var writer = GetGlobalEventWriter(path, events, new(DefaultWriteConfig, null)); - writer.Write(); - } - public static async Task ReplaceGlobalEventsAsync(string path, IEnumerable events, CancellationToken cancellationToken = default) - { - var writer = GetGlobalEventWriter(path, events, new(DefaultWriteConfig, null)); - await writer.WriteAsync(cancellationToken); - } - private static ChartFileWriter GetGlobalEventWriter(string path, IEnumerable events, WritingSession session) => new(path, null, new GlobalEventSerializer(events, session)); - - /// - /// Replaces the sync track in a file. - /// - /// Path of the file to write - /// Sync track to write - /// - public static void ReplaceSyncTrack(string path, SyncTrack syncTrack, WritingConfiguration? config = default) - { - var writer = GetSyncTrackWriter(path, syncTrack, new(config ?? DefaultWriteConfig, null)); - writer.Write(); - } - /// - public static async Task ReplaceSyncTrackAsync(string path, SyncTrack syncTrack, WritingConfiguration? config = default, CancellationToken cancellationToken = default) - { - var writer = GetSyncTrackWriter(path, syncTrack, new(config ?? DefaultWriteConfig, null)); - await writer.WriteAsync(cancellationToken); - } - private static ChartFileWriter GetSyncTrackWriter(string path, SyncTrack syncTrack, WritingSession session) => new(path, null, new SyncTrackSerializer(syncTrack, session)); - #endregion - - /// - /// Gets all the combinations of instruments and difficulties. - /// - /// Enum containing the instruments - private static IEnumerable<(Difficulty difficulty, TInstEnum instrument)> GetTrackCombinations(IEnumerable instruments) => from difficulty in EnumCache.Values from instrument in instruments select (difficulty, instrument); -} diff --git a/source - Copie/IO/Chart/ChartFileReader.cs b/source - Copie/IO/Chart/ChartFileReader.cs deleted file mode 100644 index d27b3e66..00000000 --- a/source - Copie/IO/Chart/ChartFileReader.cs +++ /dev/null @@ -1,17 +0,0 @@ -using ChartTools.IO.Chart.Parsing; - -namespace ChartTools.IO.Chart; - -/// -/// Reader of text file that sends read lines to subscribers of its events. -/// -internal class ChartFileReader : TextFileReader -{ - public override IEnumerable Parsers => base.Parsers.Cast(); - public override bool DefinedSectionEnd => true; - - public ChartFileReader(string path, Func parserGetter) : base(path, parserGetter) { } - - protected override bool IsSectionStart(string line) => line == "{"; - protected override bool IsSectionEnd(string line) => ChartFormatting.IsSectionEnd(line); -} diff --git a/source - Copie/IO/Chart/ChartFileWriter.cs b/source - Copie/IO/Chart/ChartFileWriter.cs deleted file mode 100644 index c92a8396..00000000 --- a/source - Copie/IO/Chart/ChartFileWriter.cs +++ /dev/null @@ -1,11 +0,0 @@ -namespace ChartTools.IO.Chart; - -internal class ChartFileWriter : TextFileWriter -{ - protected override string? PreSerializerContent => "{"; - protected override string? PostSerializerContent => "}"; - - public ChartFileWriter(string path, IEnumerable? removedHeaders, params Serializer[] serializers) : base(path, removedHeaders, serializers) { } - - protected override bool EndReplace(string line) => line.StartsWith('['); -} diff --git a/source - Copie/IO/Chart/ChartFormatting.cs b/source - Copie/IO/Chart/ChartFormatting.cs deleted file mode 100644 index a7dceaf2..00000000 --- a/source - Copie/IO/Chart/ChartFormatting.cs +++ /dev/null @@ -1,78 +0,0 @@ -using ChartTools.IO.Chart.Entries; - -namespace ChartTools.IO.Chart; - -internal static class ChartFormatting -{ - public const string DrumsHeaderName = "Drums", - MetadataHeader = "[Song]", - SyncTrackHeader = "[SyncTrack]", - GlobalEventHeader = "[Events]", - Title = "Name", - Artist = "Artist", - Charter = "Charter", - Album = "Album", - Year = "Year", - AudioOffset = "Offset", - Resolution = "Resolution", - Difficulty = "Difficulty", - PreviewStart = "PreviewStart", - PreviewEnd = "PreviewEnd", - Genre = "Genre", - MediaType = "MediaType", - MusicStream = "MusicStream", - GuitarStream = "GuitarStream", - BassStream = "BassStream", - RhythmStream = "RhythmStream", - KeysStream = "KeysStream", - DrumStream = "DrumStream", - Drum2Stream = "Drum2Stream", - Drum3Stream = "Drum3Stream", - Drum4Stream = "Drum4Stream", - VocalStream = "VocalStream", - CrowdStream = "CrowdStream"; - - /// - /// Part names of without the difficulty - /// - public static readonly Dictionary InstrumentHeaderNames = new() - { - { InstrumentIdentity.Drums, DrumsHeaderName }, - { InstrumentIdentity.GHLGuitar, "GHLGuitar" }, - { InstrumentIdentity.GHLBass, "GHLBass" }, - { InstrumentIdentity.LeadGuitar, "Single" }, - { InstrumentIdentity.RhythmGuitar, "DoubleRhythm" }, - { InstrumentIdentity.CoopGuitar, "DoubleGuitar" }, - { InstrumentIdentity.Bass, "DoubleBass" }, - { InstrumentIdentity.Keys, "Keyboard" } - }; - - public static string Header(Enum instrument, Difficulty difficulty) => Header((InstrumentIdentity)instrument, difficulty); - public static string Header(InstrumentIdentity instrument, Difficulty difficulty) => Header(InstrumentHeaderNames[instrument], difficulty); - public static string Header(string instrumentName, Difficulty difficulty) => Header(difficulty.ToString() + instrumentName); - public static string Header(string name) => $"[{name}]"; - - public static string Line(string header, string? value) => value is null ? string.Empty : $" {header} = {value}"; - - /// - /// Gets the written data for a note. - /// - /// Position of the parent - /// Value of - /// Value of - public static TrackObjectEntry NoteEntry(uint position, byte index, uint sustain) => new(position, "N", $"{index} {sustain}"); - - /// - /// Gets the written value of a float. - /// - /// Value to get the written equivalent of - public static string Float(float value) => ((int)(value * 1000)).ToString().Replace(".", "").Replace(",", ""); - - public static bool IsSectionEnd(string line) => line == "}"; - - /// - /// Splits the data of an entry. - /// - /// Data portion of a - internal static string[] SplitData(string data) => data.Split(' ', 2, StringSplitOptions.RemoveEmptyEntries); -} diff --git a/source - Copie/IO/Chart/ChartSectionSet.cs b/source - Copie/IO/Chart/ChartSectionSet.cs deleted file mode 100644 index fc8358ed..00000000 --- a/source - Copie/IO/Chart/ChartSectionSet.cs +++ /dev/null @@ -1,37 +0,0 @@ -using ChartTools.Extensions; -using ChartTools.IO.Sections; - -namespace ChartTools.IO.Chart; - -public class ChartSection : SectionSet -{ - public static readonly ReservedSectionHeaderSet DefaultReservedHeaders; - public override ReservedSectionHeaderSet ReservedHeaders => DefaultReservedHeaders; - - static ChartSection() - { - var headers = new List - { - new(ChartFormatting.MetadataHeader, nameof(Song.Metadata)), - new(ChartFormatting.SyncTrackHeader, nameof(Song.SyncTrack)), - new(ChartFormatting.GlobalEventHeader, nameof(Song.GlobalEvents)) - }; - - var instrumentSources = new Dictionary() - { - { ChartFormatting.InstrumentHeaderNames[InstrumentIdentity.LeadGuitar], nameof(Song.Instruments.LeadGuitar) }, - { ChartFormatting.InstrumentHeaderNames[InstrumentIdentity.RhythmGuitar], nameof(Song.Instruments.RhythmGuitar) }, - { ChartFormatting.InstrumentHeaderNames[InstrumentIdentity.CoopGuitar], nameof(Song.Instruments.CoopGuitar) }, - { ChartFormatting.InstrumentHeaderNames[InstrumentIdentity.Bass], nameof(Song.Instruments.Bass) }, - { ChartFormatting.InstrumentHeaderNames[InstrumentIdentity.Keys], nameof(Song.Instruments.Keys) }, - { ChartFormatting.InstrumentHeaderNames[InstrumentIdentity.GHLGuitar], nameof(Song.Instruments.GHLGuitar) }, - { ChartFormatting.InstrumentHeaderNames[InstrumentIdentity.GHLBass], nameof(Song.Instruments.GHLBass) }, - { ChartFormatting.InstrumentHeaderNames[InstrumentIdentity.Drums], nameof(Song.Instruments.Drums) } - }; - - headers.AddRange(instrumentSources.SelectMany(pair => from diff in EnumCache.Values select new ReservedSectionHeader(ChartFormatting.Header(pair.Value, diff), $"{pair.Value}.{diff}"))); - - DefaultReservedHeaders = new(headers); - } - public ChartSection() : base() { } -} diff --git a/source - Copie/IO/Chart/Entries/NoteData.cs b/source - Copie/IO/Chart/Entries/NoteData.cs deleted file mode 100644 index 2d2d0c72..00000000 --- a/source - Copie/IO/Chart/Entries/NoteData.cs +++ /dev/null @@ -1,32 +0,0 @@ -namespace ChartTools.IO.Chart.Entries; - -/// -/// Line of chart data representing a -/// -internal readonly ref struct NoteData -{ - /// - /// Value of - /// - internal byte Index { get; } - /// - /// Value of - /// - internal uint SustainLength { get; } - - /// - /// Creates an instance of . - /// - /// Data section of the line in the file - /// - internal NoteData(string data) - { - string[] split = data.Split(' ', 2, StringSplitOptions.RemoveEmptyEntries); - - if (split.Length < 2) - throw new EntryException(); - - Index = ValueParser.ParseByte(split[0], "note index"); - SustainLength = ValueParser.ParseUint(split[1], "sustain length"); - } -} diff --git a/source - Copie/IO/Chart/Entries/TrackObjectEntry.cs b/source - Copie/IO/Chart/Entries/TrackObjectEntry.cs deleted file mode 100644 index 3559f700..00000000 --- a/source - Copie/IO/Chart/Entries/TrackObjectEntry.cs +++ /dev/null @@ -1,51 +0,0 @@ -namespace ChartTools.IO.Chart.Entries; - -/// -/// Line of chart file data representing a -/// -internal readonly struct TrackObjectEntry : IReadOnlyTrackObject -{ - /// - /// Value of - /// - public uint Position { get; } - /// - /// Type code of - /// - public string Type { get; } - /// - /// Additional data - /// - public string Data { get; } - - /// - /// Creates an instance of see. - /// - /// Line in the file - /// - public TrackObjectEntry(string line) - { - TextEntry entry = new(line); - - if (entry.Value is null) - throw new LineException(line, new FormatException("Line has no object data.")); - - string[] split = entry.Value.Split(' ', 2, StringSplitOptions.RemoveEmptyEntries); - - if (split.Length < 2) - throw new LineException(line, new EntryException()); - - Type = split[0]; - Data = split[1]; - - Position = ValueParser.ParseUint(entry.Key, "position"); - } - public TrackObjectEntry(uint position, string type, string data) - { - Position = position; - Type = type; - Data = data; - } - - public override string ToString() => ChartFormatting.Line(Position.ToString(), $"{Type} {Data}"); -} diff --git a/source - Copie/IO/Chart/Parsing/ChartParser.cs b/source - Copie/IO/Chart/Parsing/ChartParser.cs deleted file mode 100644 index a5d73d7b..00000000 --- a/source - Copie/IO/Chart/Parsing/ChartParser.cs +++ /dev/null @@ -1,11 +0,0 @@ -using ChartTools.IO.Configuration.Sessions; -using ChartTools.IO.Parsing; - -namespace ChartTools.IO.Chart.Parsing; - -internal abstract class ChartParser : TextParser, ISongAppliable -{ - protected ChartParser(ReadingSession session, string header) : base(session, header) { } - - public abstract void ApplyToSong(Song song); -} diff --git a/source - Copie/IO/Chart/Parsing/DrumsTrackParser.cs b/source - Copie/IO/Chart/Parsing/DrumsTrackParser.cs deleted file mode 100644 index 86651e44..00000000 --- a/source - Copie/IO/Chart/Parsing/DrumsTrackParser.cs +++ /dev/null @@ -1,50 +0,0 @@ -using ChartTools.Extensions.Linq; -using ChartTools.IO.Chart.Entries; -using ChartTools.IO.Configuration.Sessions; - -namespace ChartTools.IO.Chart.Parsing; - -internal class DrumsTrackParser : TrackParser -{ - public DrumsTrackParser(Difficulty difficulty, ReadingSession session, string header) : base(difficulty, session, header) { } - - public override void ApplyToSong(Song song) - { - song.Instruments.Drums ??= new(); - ApplyToInstrument(song.Instruments.Drums); - } - - protected override void HandleNoteEntry(DrumsChord chord, NoteData data) - { - switch (data.Index) - { - // Note - case < 5: - AddNote(new DrumsNote((DrumsLane)data.Index) { Sustain = data.SustainLength }); - break; - // Double kick - case 32: - AddNote(new DrumsNote(DrumsLane.DoubleKick)); - break; - // Cymbal - case > 65 and < 69: - // NoteIndex of the note to set as cymbal - byte seekedIndex = (byte)(data.Index - 64); - - if (chord.Notes.TryGetFirst(n => n.Index == seekedIndex, out DrumsNote note)) - { - if (session.DuplicateTrackObjectProcedure(chord.Position, "drums note cymbal marker", () => note.IsCymbal)) - note.IsCymbal = true; - } - else - AddNote(new DrumsNote((DrumsLane)seekedIndex) { IsCymbal = true, Sustain = data.SustainLength }); - break; - case 109: - AddModifier(DrumsChordModifiers.Flam); - break; - } - - void AddNote(DrumsNote note) => HandleAddNote(note, () => chord.Notes.Add(note)); - void AddModifier(DrumsChordModifiers modifier) => HandleAddModifier(chord.Modifiers, modifier, () => chord.Modifiers |= modifier); - } -} diff --git a/source - Copie/IO/Chart/Parsing/GHLTrackParser.cs b/source - Copie/IO/Chart/Parsing/GHLTrackParser.cs deleted file mode 100644 index b2a1244d..00000000 --- a/source - Copie/IO/Chart/Parsing/GHLTrackParser.cs +++ /dev/null @@ -1,49 +0,0 @@ -using ChartTools.IO.Chart.Entries; -using ChartTools.IO.Configuration.Sessions; - -namespace ChartTools.IO.Chart.Parsing; - -internal class GHLTrackParser : VariableInstrumentTrackParser -{ - public GHLTrackParser(Difficulty difficulty, GHLInstrumentIdentity instrument, ReadingSession session, string header) : base(difficulty, instrument, session, header) { } - - public override void ApplyToSong(Song song) - { - var inst = song.Instruments.Get(Instrument); - - if (inst is null) - song.Instruments.Set(inst = new(Instrument)); - - ApplyToInstrument(inst); - } - - protected override void HandleNoteEntry(GHLChord chord, NoteData data) - { - switch (data.Index) - { - // White notes - case < 3: - AddNote(new LaneNote((GHLLane)(data.Index + 4)) { Sustain = data.SustainLength }); - break; - // Black 1 and 2 - case < 5: - AddNote(new LaneNote((GHLLane)(data.Index - 2)) { Sustain = data.SustainLength }); - break; - case 5: - AddModifier(GHLChordModifiers.HopoInvert); - return; - case 6: - AddModifier(GHLChordModifiers.Tap); - return; - case 7: - AddNote(new LaneNote(GHLLane.Open) { Sustain = data.SustainLength }); - break; - case 8: - AddNote(new LaneNote(GHLLane.Black3) { Sustain = data.SustainLength }); - break; - } - - void AddNote(LaneNote note) => HandleAddNote(note, () => chord.Notes.Add(note)); - void AddModifier(GHLChordModifiers modifier) => HandleAddModifier(chord.Modifiers, modifier, () => chord.Modifiers |= modifier); - } -} diff --git a/source - Copie/IO/Chart/Parsing/GlobalEventParser.cs b/source - Copie/IO/Chart/Parsing/GlobalEventParser.cs deleted file mode 100644 index 15e8cddf..00000000 --- a/source - Copie/IO/Chart/Parsing/GlobalEventParser.cs +++ /dev/null @@ -1,21 +0,0 @@ -using ChartTools.Events; -using ChartTools.IO.Chart.Entries; -using ChartTools.IO.Configuration.Sessions; - -namespace ChartTools.IO.Chart.Parsing; - -internal class GlobalEventParser : ChartParser -{ - public override List Result => GetResult(result); - private readonly List result = new(); - - public GlobalEventParser(ReadingSession session) : base(session, ChartFormatting.GlobalEventHeader) { } - - protected override void HandleItem(string line) - { - TrackObjectEntry entry = new(line); - result.Add(new(entry.Position, entry.Data.Trim('"'))); - } - - public override void ApplyToSong(Song song) => song.GlobalEvents = Result; -} diff --git a/source - Copie/IO/Chart/Parsing/MetadataParser.cs b/source - Copie/IO/Chart/Parsing/MetadataParser.cs deleted file mode 100644 index f42c7883..00000000 --- a/source - Copie/IO/Chart/Parsing/MetadataParser.cs +++ /dev/null @@ -1,90 +0,0 @@ -namespace ChartTools.IO.Chart.Parsing; - -internal class MetadataParser : ChartParser -{ - public override Metadata Result => GetResult(result); - private readonly Metadata result = new(); - - public MetadataParser(Metadata? existing = null) : base(null!, ChartFormatting.MetadataHeader) => result = existing ?? new(); - - protected override void HandleItem(string line) - { - TextEntry entry = new(line); - var value = entry.Value?.Trim('"'); - - switch (entry.Key) - { - case ChartFormatting.Title: - result.Title = value; - break; - case ChartFormatting.Artist: - result.Artist = value; - break; - case ChartFormatting.Charter: - result.Charter.Name = value; - break; - case ChartFormatting.Album: - result.Album = value; - break; - case ChartFormatting.Year: - result.Year = ValueParser.ParseUshort(value?.TrimStart(','), "year"); - break; - case ChartFormatting.AudioOffset: - result.AudioOffset = TimeSpan.FromMilliseconds(ValueParser.ParseFloat(value, "audio offset") * 1000); - break; - case ChartFormatting.Difficulty: - result.Difficulty = ValueParser.ParseSbyte(value, "difficulty"); - break; - case ChartFormatting.PreviewStart: - result.PreviewStart = ValueParser.ParseUint(value, "preview start"); - break; - case ChartFormatting.PreviewEnd: - result.PreviewEnd = ValueParser.ParseUint(value, "preview end"); - break; - case ChartFormatting.Genre: - result.Genre = value; - break; - case ChartFormatting.MediaType: - result.MediaType = value; - break; - case ChartFormatting.MusicStream: - result.Streams.Music = value; - break; - case ChartFormatting.GuitarStream: - result.Streams.Guitar = value; - break; - case ChartFormatting.BassStream: - result.Streams.Bass = value; - break; - case ChartFormatting.RhythmStream: - result.Streams.Rhythm = value; - break; - case ChartFormatting.KeysStream: - result.Streams.Keys = value; - break; - case ChartFormatting.DrumStream: - result.Streams.Drum = value; - break; - case ChartFormatting.Drum2Stream: - result.Streams.Drum2 = value; - break; - case ChartFormatting.Drum3Stream: - result.Streams.Drum3 = value; - break; - case ChartFormatting.Drum4Stream: - result.Streams.Drum4 = value; - break; - case ChartFormatting.VocalStream: - result.Streams.Vocals = value; - break; - case ChartFormatting.CrowdStream: - result.Streams.Crowd = value; - break; - default: - result.UnidentifiedData.Add(new() { Key = entry.Key, Value = entry.Value, Origin = FileType.Chart }); - break; - } - } - - public override void ApplyToSong(Song song) => song.Metadata = Result; -} diff --git a/source - Copie/IO/Chart/Parsing/StandardTrackParser.cs b/source - Copie/IO/Chart/Parsing/StandardTrackParser.cs deleted file mode 100644 index dde1e28f..00000000 --- a/source - Copie/IO/Chart/Parsing/StandardTrackParser.cs +++ /dev/null @@ -1,42 +0,0 @@ -using ChartTools.IO.Chart.Entries; -using ChartTools.IO.Configuration.Sessions; - -namespace ChartTools.IO.Chart.Parsing; - -internal class StandardTrackParser : VariableInstrumentTrackParser -{ - public StandardTrackParser(Difficulty difficulty, StandardInstrumentIdentity instrument, ReadingSession session, string header) : base(difficulty, instrument, session, header) { } - - public override void ApplyToSong(Song song) - { - var inst = song.Instruments.Get(Instrument); - - if (inst is null) - song.Instruments.Set(inst = new(Instrument)); - - ApplyToInstrument(inst); - } - - protected override void HandleNoteEntry(StandardChord chord, NoteData data) - { - switch (data.Index) - { - // Colored note - case < 5: - AddNote(new((StandardLane)(data.Index + 1)) { Sustain = data.SustainLength }); - break; - case 5: - AddModifier(StandardChordModifiers.HopoInvert); - return; - case 6: - AddModifier(StandardChordModifiers.Tap); - return; - case 7: - AddNote(new(StandardLane.Open) { Sustain = data.SustainLength }); - break; - } - - void AddNote(LaneNote note) => HandleAddNote(note, () => chord.Notes.Add(note)); - void AddModifier(StandardChordModifiers modifier) => HandleAddModifier(chord.Modifiers, modifier, () => chord.Modifiers |= modifier); - } -} diff --git a/source - Copie/IO/Chart/Parsing/SyncTrackParser.cs b/source - Copie/IO/Chart/Parsing/SyncTrackParser.cs deleted file mode 100644 index 586b632a..00000000 --- a/source - Copie/IO/Chart/Parsing/SyncTrackParser.cs +++ /dev/null @@ -1,104 +0,0 @@ -using ChartTools.Extensions.Linq; -using ChartTools.IO.Chart.Entries; -using ChartTools.IO.Configuration.Sessions; - -namespace ChartTools.IO.Chart.Parsing; - -internal class SyncTrackParser : ChartParser -{ - public override SyncTrack Result => GetResult(result); - private readonly SyncTrack result = new(); - - private readonly List tempos = new(), orderedTempos = new(); - private readonly List orderedAnchors = new(); - private readonly List orderedSignatures = new(); - - public SyncTrackParser(ReadingSession session) : base(session, ChartFormatting.SyncTrackHeader) { } - - protected override void HandleItem(string line) - { - TrackObjectEntry entry = new(line); - - switch (entry.Type) - { - case "TS": // Time signature - if (CheckDuplicate(orderedSignatures, "time signature", out int newIndex)) - break; - - string[] split = ChartFormatting.SplitData(entry.Data); - - var numerator = ValueParser.ParseByte(split[0], "numerator"); - byte denominator = 4; - - // Denominator is only written if not equal to 4 - if (split.Length >= 2) - denominator = (byte)Math.Pow(2, ValueParser.ParseByte(split[1], "denominator")); - - var signature = new TimeSignature(entry.Position, numerator, denominator); - - result.TimeSignatures.Add(signature); - orderedSignatures.Insert(newIndex, signature); - break; - case "B": // Tempo - if (CheckDuplicate(orderedTempos, "tempo marker", out newIndex)) - break; - - // Floats are written by rounding to the 3rd decimal and removing the decimal point - var value = ValueParser.ParseFloat(entry.Data, "value") / 1000; - var tempo = new Tempo(entry.Position, value); - - tempos.Add(tempo); - orderedTempos.Add(tempo); - break; - case "A": // Anchor - if (CheckDuplicate(orderedAnchors, "tempo anchor", out newIndex)) - break; - - // Floats are written by rounding to the 3rd decimal and removing the decimal point - var anchor = TimeSpan.FromSeconds(ValueParser.ParseFloat(entry.Data, "anchor") / 1000); - - orderedAnchors.Insert(newIndex, new(entry.Position, anchor)); - break; - } - - bool CheckDuplicate(IList existing, string objectType, out int newIndex) where T : IReadOnlyTrackObject - { - var index = 0; - var result = !session.DuplicateTrackObjectProcedure(entry.Position, objectType, () => - { - index = existing.BinarySearchIndex(entry.Position, t => t.Position, out bool exactMatch); - - return exactMatch; - }); - - newIndex = index; - - return result; - } - } - - protected override void FinaliseParse() - { - foreach (var anchor in orderedAnchors) - { - // Find the marker matching the position in case it was already added through a mention of value - var markerIndex = orderedTempos.BinarySearchIndex(anchor.Position, t => t.Position, out bool markerFound); - - if (markerFound) - { - orderedTempos[markerIndex].Anchor = anchor.Value; - orderedTempos.RemoveAt(markerIndex); - } - else if (session.TempolessAnchorProcedure(anchor)) - result.Tempo.Add(new(anchor.Position, 0) { Anchor = anchor.Value }); - } - - base.FinaliseParse(); - } - - public override void ApplyToSong(Song song) - { - song.SyncTrack = Result; - song.SyncTrack.Tempo.AddRange(tempos); - } -} diff --git a/source - Copie/IO/Chart/Parsing/TrackParser.cs b/source - Copie/IO/Chart/Parsing/TrackParser.cs deleted file mode 100644 index 501eba98..00000000 --- a/source - Copie/IO/Chart/Parsing/TrackParser.cs +++ /dev/null @@ -1,114 +0,0 @@ -using ChartTools.IO.Chart.Entries; -using ChartTools.IO.Configuration; -using ChartTools.IO.Configuration.Sessions; -using ChartTools.Extensions.Linq; -using ChartTools.Tools; - -namespace ChartTools.IO.Chart.Parsing; - -internal abstract class TrackParser : ChartParser, IInstrumentAppliable where TChord : IChord, new() -{ - public Difficulty Difficulty { get; } - - public override Track Result => GetResult(result); - private readonly Track result; - - private TChord? chord; - private bool newChord = true; - private readonly List orderedChords = new(); - - public TrackParser(Difficulty difficulty, ReadingSession session, string header) : base(session, header) - { - Difficulty = difficulty; - result = new() { Difficulty = difficulty }; - } - - protected override void HandleItem(string line) - { - TrackObjectEntry entry = new(line); - - switch (entry.Type) - { - // Local event - case "E": - result.LocalEvents.Add(new(entry.Position, entry.Data)); - break; - // Note or chord modifier - case "N": - var newIndex = 0; - - // Find the parent chord or create it - if (chord is null) - { - chord = new() { Position = entry.Position }; - newIndex = orderedChords.Count; - } - else if (entry.Position == chord.Position) - newChord = false; - else - { - newIndex = orderedChords.BinarySearchIndex(entry.Position, c => c.Position, out bool exactMatch); - - if (newChord = !exactMatch) - chord = new() { Position = entry.Position }; - } - - HandleNoteEntry(chord!, new(entry.Data)); - - if (newChord) - { - result.Chords.Add(chord!); - orderedChords.Insert(newIndex, chord!); - } - - break; - // Star power - case "S": - var split = ChartFormatting.SplitData(entry.Data); - - var typeCode = ValueParser.ParseByte(split[0], "type code"); - var length = ValueParser.ParseUint(split[1], "length"); - - result.SpecialPhrases.Add(new(entry.Position, typeCode, length)); - break; - } - - if (session!.Configuration.SoloNoStarPowerPolicy == SoloNoStarPowerPolicy.Convert) - result.SpecialPhrases.AddRange(result.SoloToStarPower(true)); - } - - protected abstract void HandleNoteEntry(TChord chord, NoteData data); - protected void HandleAddNote(INote note, Action add) - { - if (session.DuplicateTrackObjectProcedure(chord!.Position, "note", () => chord!.Notes.Any(n => n.Index == note.Index))) - add(); - } - protected void HandleAddModifier(Enum existingModifier, Enum modifier, Action add) - { - if (session.DuplicateTrackObjectProcedure(chord!.Position, "chord modifier", () => existingModifier.HasFlag(modifier))) - add(); - } - - protected override void FinaliseParse() - { - ApplyOverlappingSpecialPhrasePolicy(result.SpecialPhrases, session!.Configuration.OverlappingStarPowerPolicy); - base.FinaliseParse(); - } - - public void ApplyToInstrument(Instrument instrument) => instrument.SetTrack(Result); - - private static void ApplyOverlappingSpecialPhrasePolicy(IEnumerable specialPhrases, OverlappingSpecialPhrasePolicy policy) - { - switch (policy) - { - case OverlappingSpecialPhrasePolicy.Cut: - specialPhrases.CutLengths(); - break; - case OverlappingSpecialPhrasePolicy.ThrowException: - foreach ((var previous, var current) in specialPhrases.RelativeLoopSkipFirst()) - if (Optimizer.LengthNeedsCut(previous, current)) - throw new Exception($"Overlapping star power phrases at position {current!.Position}. Consider using {nameof(OverlappingSpecialPhrasePolicy.Cut)} to avoid this error."); - break; - } - } -} diff --git a/source - Copie/IO/Chart/Parsing/UnknownSectionParser.cs b/source - Copie/IO/Chart/Parsing/UnknownSectionParser.cs deleted file mode 100644 index 69d75eb1..00000000 --- a/source - Copie/IO/Chart/Parsing/UnknownSectionParser.cs +++ /dev/null @@ -1,14 +0,0 @@ -using ChartTools.IO.Configuration.Sessions; -using ChartTools.IO.Sections; - -namespace ChartTools.IO.Chart.Parsing; - -internal class UnknownSectionParser : ChartParser -{ - public override Section Result => GetResult(result); - private readonly Section result; - public UnknownSectionParser(ReadingSession session, string header) : base(session, header) => result = new(header); - - public override void ApplyToSong(Song song) => (song.UnknownChartSections ??= new()).Add(Result); - protected override void HandleItem(string item) => result.Add(item); -} diff --git a/source - Copie/IO/Chart/Parsing/VariableInstrumentTrackParser.cs b/source - Copie/IO/Chart/Parsing/VariableInstrumentTrackParser.cs deleted file mode 100644 index b3f81d16..00000000 --- a/source - Copie/IO/Chart/Parsing/VariableInstrumentTrackParser.cs +++ /dev/null @@ -1,9 +0,0 @@ -using ChartTools.IO.Configuration.Sessions; - -namespace ChartTools.IO.Chart.Parsing; - -internal abstract class VariableInstrumentTrackParser : TrackParser where TChord : IChord, new() where TInstEnum : Enum -{ - public TInstEnum Instrument { get; } - public VariableInstrumentTrackParser(Difficulty difficulty, TInstEnum instrument, ReadingSession session, string header) : base(difficulty, session, header) => Instrument = instrument; -} diff --git a/source - Copie/IO/Chart/Providers/ChordProvider.cs b/source - Copie/IO/Chart/Providers/ChordProvider.cs deleted file mode 100644 index c93ccd96..00000000 --- a/source - Copie/IO/Chart/Providers/ChordProvider.cs +++ /dev/null @@ -1,31 +0,0 @@ -using ChartTools.IO.Chart.Entries; -using ChartTools.IO.Configuration.Sessions; -using ChartTools.Extensions.Linq; - -namespace ChartTools.IO.Chart.Providers; - -internal class ChordProvider: ISerializerDataProvider -{ - public IEnumerable ProvideFor(IEnumerable source, WritingSession session) - { - List orderedPositions = new(); - LaneChord? previousChord = null; - - foreach (var chord in source) - { - if (session.DuplicateTrackObjectProcedure(chord.Position, "chord", () => - { - var index = orderedPositions.BinarySearchIndex(chord.Position, out bool exactMatch); - - if (!exactMatch) - orderedPositions.Insert(index, chord.Position); - - return exactMatch; - })) - foreach (var entry in (chord.ChartSupportedModifiers ? chord.GetChartModifierData(previousChord, session) : session.GetChordEntries(previousChord, chord)).Concat(chord.GetChartNoteData())) - yield return entry; - - previousChord = chord; - } - } -} diff --git a/source - Copie/IO/Chart/Providers/EventProvider.cs b/source - Copie/IO/Chart/Providers/EventProvider.cs deleted file mode 100644 index 84bfe2cf..00000000 --- a/source - Copie/IO/Chart/Providers/EventProvider.cs +++ /dev/null @@ -1,10 +0,0 @@ -using ChartTools.Events; -using ChartTools.IO.Chart.Entries; -using ChartTools.IO.Configuration.Sessions; - -namespace ChartTools.IO.Chart.Providers; - -internal class EventProvider : ISerializerDataProvider -{ - public IEnumerable ProvideFor(IEnumerable source, WritingSession session) => source.Select(e => new TrackObjectEntry(e.Position, "E", $"\"{e.EventData}\"")); -} diff --git a/source - Copie/IO/Chart/Providers/SpecialPhraseProvider.cs b/source - Copie/IO/Chart/Providers/SpecialPhraseProvider.cs deleted file mode 100644 index d90ed4be..00000000 --- a/source - Copie/IO/Chart/Providers/SpecialPhraseProvider.cs +++ /dev/null @@ -1,9 +0,0 @@ -using ChartTools.IO.Chart.Entries; -using ChartTools.IO.Configuration.Sessions; - -namespace ChartTools.IO.Chart.Providers; - -internal class SpeicalPhraseProvider : ISerializerDataProvider -{ - public IEnumerable ProvideFor(IEnumerable source, WritingSession session) => source.Select(sp => new TrackObjectEntry(sp.Position, "S", $"{sp.TypeCode} {sp.Length}")); -} diff --git a/source - Copie/IO/Chart/Providers/SyncTrackProvider.cs b/source - Copie/IO/Chart/Providers/SyncTrackProvider.cs deleted file mode 100644 index c4085448..00000000 --- a/source - Copie/IO/Chart/Providers/SyncTrackProvider.cs +++ /dev/null @@ -1,34 +0,0 @@ -using ChartTools.IO.Chart.Entries; -using ChartTools.IO.Configuration.Sessions; -using ChartTools.Extensions.Linq; - -namespace ChartTools.IO.Chart.Providers; - -internal abstract class SyncTrackProvider : ISerializerDataProvider where T : TrackObjectBase -{ - protected abstract string ObjectType { get; } - - public IEnumerable ProvideFor(IEnumerable source, WritingSession session) - { - List orderedPositions = new(); - - foreach (var item in source) - { - if (session.DuplicateTrackObjectProcedure(item.Position, ObjectType, () => - { - var index = orderedPositions.BinarySearchIndex(item.Position, out bool exactMatch); - - if (!exactMatch) - orderedPositions.Insert(index, item.Position); - - return exactMatch; - })) - foreach (var entry in GetEntries(item)) - yield return entry; - - orderedPositions.Add(item.Position); - } - } - - protected abstract IEnumerable GetEntries(T item); -} diff --git a/source - Copie/IO/Chart/Providers/TempoProvider.cs b/source - Copie/IO/Chart/Providers/TempoProvider.cs deleted file mode 100644 index 45599de3..00000000 --- a/source - Copie/IO/Chart/Providers/TempoProvider.cs +++ /dev/null @@ -1,17 +0,0 @@ -using ChartTools.IO.Chart.Entries; - -namespace ChartTools.IO.Chart.Providers; - -internal class TempoProvider : SyncTrackProvider -{ - protected override string ObjectType => "tempo marker"; - - protected override IEnumerable GetEntries(Tempo item) - { - if (item.Anchor is not null) - yield return item.PositionSynced - ? new(item.Position, "A", ChartFormatting.Float((float)item.Anchor.Value.TotalSeconds)) - : throw new DesynchronizedAnchorException(item.Anchor.Value, $"Cannot write desynchronized anchored tempo at {item.Anchor}."); - yield return new(item.Position, "B", ChartFormatting.Float(item.Value)); - } -} diff --git a/source - Copie/IO/Chart/Providers/TimeSignatureProvider.cs b/source - Copie/IO/Chart/Providers/TimeSignatureProvider.cs deleted file mode 100644 index 047fb200..00000000 --- a/source - Copie/IO/Chart/Providers/TimeSignatureProvider.cs +++ /dev/null @@ -1,19 +0,0 @@ -using ChartTools.IO.Chart.Entries; - -namespace ChartTools.IO.Chart.Providers; - -internal class TimeSignatureProvider : SyncTrackProvider -{ - protected override string ObjectType => "time signature"; - - protected override IEnumerable GetEntries(TimeSignature item) - { - byte writtenDenominator = (byte)Math.Log2(item.Denominator); - string data = item.Numerator.ToString(); - - if (writtenDenominator == 1) - data += ' ' + writtenDenominator.ToString(); - - yield return new(item.Position, "TS", data); - } -} diff --git a/source - Copie/IO/Chart/Serializing/ChartKeySerializableAttribute.cs b/source - Copie/IO/Chart/Serializing/ChartKeySerializableAttribute.cs deleted file mode 100644 index 41382f6f..00000000 --- a/source - Copie/IO/Chart/Serializing/ChartKeySerializableAttribute.cs +++ /dev/null @@ -1,16 +0,0 @@ -namespace ChartTools.IO.Chart.Serializing; - -public class ChartKeySerializableAttribute : KeySerializableAttribute -{ - public override FileType Format => FileType.Chart; - - public ChartKeySerializableAttribute(string key) : base(key) { } - - protected override string GetValueString(object propValue) - { - var propString = propValue.ToString()!; - return propValue is string ? $"\"{propString}\"" : propString; - } - - public static IEnumerable<(string key, string value)> GetSerializable(object source) => GetSerializable(source); -} diff --git a/source - Copie/IO/Chart/Serializing/GlobalEventSerializer.cs b/source - Copie/IO/Chart/Serializing/GlobalEventSerializer.cs deleted file mode 100644 index 8fb46f54..00000000 --- a/source - Copie/IO/Chart/Serializing/GlobalEventSerializer.cs +++ /dev/null @@ -1,13 +0,0 @@ -using ChartTools.Events; -using ChartTools.IO.Chart.Entries; -using ChartTools.IO.Chart.Providers; -using ChartTools.IO.Configuration.Sessions; - -namespace ChartTools.IO.Chart.Serializing; - -internal class GlobalEventSerializer : TrackObjectGroupSerializer> -{ - public GlobalEventSerializer(IEnumerable content, WritingSession session) : base(ChartFormatting.GlobalEventHeader, content, session) { } - - protected override IEnumerable[] LaunchProviders() => new IEnumerable[] { new EventProvider().ProvideFor(Content, session!) }; -} diff --git a/source - Copie/IO/Chart/Serializing/MetadataSerializer.cs b/source - Copie/IO/Chart/Serializing/MetadataSerializer.cs deleted file mode 100644 index 47b15cd5..00000000 --- a/source - Copie/IO/Chart/Serializing/MetadataSerializer.cs +++ /dev/null @@ -1,27 +0,0 @@ -namespace ChartTools.IO.Chart.Serializing; - -internal class MetadataSerializer : Serializer -{ - public MetadataSerializer(Metadata content) : base(ChartFormatting.MetadataHeader, content, new(ChartFile.DefaultWriteConfig, content.Formatting)) { } - - public override IEnumerable Serialize() - { - if (Content is null) - yield break; - - var props = ChartKeySerializableAttribute.GetSerializable(Content) - .Concat(ChartKeySerializableAttribute.GetSerializable(Content.Formatting)) - .Concat(ChartKeySerializableAttribute.GetSerializable(Content.Charter) - .Concat(ChartKeySerializableAttribute.GetSerializable(Content.InstrumentDifficulties)) - .Concat(ChartKeySerializableAttribute.GetSerializable(Content.Streams))); - - foreach ((var key, var value) in props) - yield return ChartFormatting.Line(key, value); - - if (Content.Year is not null) - yield return ChartFormatting.Line("Year", $"\", {Content.Year}\""); - - foreach (var data in Content.UnidentifiedData.Where(d => d.Origin == FileType.Chart)) - yield return ChartFormatting.Line(data.Key, data.Value); - } -} diff --git a/source - Copie/IO/Chart/Serializing/SyncTrackSerializer.cs b/source - Copie/IO/Chart/Serializing/SyncTrackSerializer.cs deleted file mode 100644 index d644afc9..00000000 --- a/source - Copie/IO/Chart/Serializing/SyncTrackSerializer.cs +++ /dev/null @@ -1,12 +0,0 @@ -using ChartTools.IO.Chart.Entries; -using ChartTools.IO.Chart.Providers; -using ChartTools.IO.Configuration.Sessions; - -namespace ChartTools.IO.Chart.Serializing; - -internal class SyncTrackSerializer : TrackObjectGroupSerializer -{ - public SyncTrackSerializer(SyncTrack content, WritingSession session) : base(ChartFormatting.SyncTrackHeader, content, session) { } - - protected override IEnumerable[] LaunchProviders() => new IEnumerable[] { new TempoProvider().ProvideFor(Content.Tempo, session), new TimeSignatureProvider().ProvideFor(Content.TimeSignatures, session) }; -} diff --git a/source - Copie/IO/Chart/Serializing/TrackObjectGroupSerializer.cs b/source - Copie/IO/Chart/Serializing/TrackObjectGroupSerializer.cs deleted file mode 100644 index 1ec492c0..00000000 --- a/source - Copie/IO/Chart/Serializing/TrackObjectGroupSerializer.cs +++ /dev/null @@ -1,12 +0,0 @@ -using ChartTools.Extensions.Collections; -using ChartTools.IO.Chart.Entries; -using ChartTools.IO.Configuration.Sessions; - -namespace ChartTools.IO.Chart.Serializing; - -internal abstract class TrackObjectGroupSerializer : GroupSerializer -{ - public TrackObjectGroupSerializer(string header, T content, WritingSession session) : base(header, content, session) { } - - protected override IEnumerable CombineProviderResults(IEnumerable[] results) => new OrderedAlternatingEnumerable(entry => entry.Position, results).Select(entry => entry.ToString()); -} diff --git a/source - Copie/IO/Chart/Serializing/TrackSerializer.cs b/source - Copie/IO/Chart/Serializing/TrackSerializer.cs deleted file mode 100644 index 4e0a7ddd..00000000 --- a/source - Copie/IO/Chart/Serializing/TrackSerializer.cs +++ /dev/null @@ -1,73 +0,0 @@ -using ChartTools.Events; -using ChartTools.Extensions.Collections; -using ChartTools.Extensions.Linq; -using ChartTools.IO.Chart.Entries; -using ChartTools.IO.Chart.Providers; -using ChartTools.IO.Configuration; -using ChartTools.IO.Configuration.Sessions; -using ChartTools.Tools; - -namespace ChartTools.IO.Chart.Serializing; - -internal class TrackSerializer : TrackObjectGroupSerializer -{ - public TrackSerializer(Track content, WritingSession session) : base(ChartFormatting.Header(content.ParentInstrument!.InstrumentIdentity, content.Difficulty), content, session) { } - - public override IEnumerable Serialize() => new OrderedAlternatingEnumerable(entry => entry.Position, LaunchProviders()).Select(entry => entry.ToString()); - - protected override IEnumerable[] LaunchProviders() - { - ApplyOverlappingSpecialPhrasePolicy(Content.SpecialPhrases, session.Configuration.OverlappingStarPowerPolicy); - - // Convert solo and soloend events into star power - if (session.Configuration.SoloNoStarPowerPolicy == SoloNoStarPowerPolicy.Convert && Content.SpecialPhrases.Count == 0 && Content.LocalEvents is not null) - { - TrackSpecialPhrase? starPower = null; - - foreach (var e in Content.LocalEvents) - switch (e.EventType) - { - case EventTypeHelper.Local.Solo: - if (starPower is not null) - { - starPower.Length = e.Position - starPower.Position; - Content.SpecialPhrases.Add(starPower); - } - - starPower = new(e.Position, TrackSpecialPhraseType.StarPowerGain); - break; - case EventTypeHelper.Local.SoloEnd when starPower is not null: - - starPower.Length = e.Position - starPower.Position; - Content.SpecialPhrases.Add(starPower); - - starPower = null; - break; - } - - Content.LocalEvents.RemoveWhere(e => e.IsSoloEvent); - } - - return new IEnumerable[] - { - new ChordProvider().ProvideFor(Content.Chords.Cast(), session), - new SpeicalPhraseProvider().ProvideFor(Content.SpecialPhrases, session!), - Content.LocalEvents is null ? Enumerable.Empty() : new EventProvider().ProvideFor(Content.LocalEvents!, session!) - }; - } - - private static void ApplyOverlappingSpecialPhrasePolicy(IEnumerable specialPhrases, OverlappingSpecialPhrasePolicy policy) - { - switch (policy) - { - case OverlappingSpecialPhrasePolicy.Cut: - specialPhrases.CutLengths(); - break; - case OverlappingSpecialPhrasePolicy.ThrowException: - foreach ((var previous, var current) in specialPhrases.RelativeLoopSkipFirst()) - if (Optimizer.LengthNeedsCut(previous, current)) - throw new Exception($"Overlapping star power phrases at position {current!.Position}."); - break; - } - } -} diff --git a/source - Copie/IO/Chart/Serializing/UnknownSectionSerializer.cs b/source - Copie/IO/Chart/Serializing/UnknownSectionSerializer.cs deleted file mode 100644 index 582fcf7a..00000000 --- a/source - Copie/IO/Chart/Serializing/UnknownSectionSerializer.cs +++ /dev/null @@ -1,11 +0,0 @@ -using ChartTools.IO.Configuration.Sessions; -using ChartTools.IO.Sections; - -namespace ChartTools.IO.Chart.Serializing; - -internal class UnknownSectionSerializer : Serializer, string> -{ - public UnknownSectionSerializer(string header, Section content, WritingSession session) : base(header, content, session) { } - - public override IEnumerable Serialize() => Content; -} diff --git a/source - Copie/IO/Configuration/CommonConfiguration.cs b/source - Copie/IO/Configuration/CommonConfiguration.cs deleted file mode 100644 index d1239f83..00000000 --- a/source - Copie/IO/Configuration/CommonConfiguration.cs +++ /dev/null @@ -1,17 +0,0 @@ -namespace ChartTools.IO.Configuration; - -/// -/// Configuration object to direct the reading or writing of a file -/// -/// If , the default configuration for the file format will be used. -public record CommonConfiguration -{ - /// - public DuplicateTrackObjectPolicy DuplicateTrackObjectPolicy { get; init; } - /// - public OverlappingSpecialPhrasePolicy OverlappingStarPowerPolicy { get; init; } - /// - public SnappedNotesPolicy SnappedNotesPolicy { get; init; } - /// - public SoloNoStarPowerPolicy SoloNoStarPowerPolicy { get; init; } -} diff --git a/source - Copie/IO/Configuration/ConfigurationExceptions.cs b/source - Copie/IO/Configuration/ConfigurationExceptions.cs deleted file mode 100644 index 261e2ffb..00000000 --- a/source - Copie/IO/Configuration/ConfigurationExceptions.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace ChartTools.IO.Configuration; - -internal static class ConfigurationExceptions -{ - public static ArgumentException UnsupportedPolicy(Enum policy) => new("Policy is not supported.", $"{policy}"); -} diff --git a/source - Copie/IO/Configuration/Enums.cs b/source - Copie/IO/Configuration/Enums.cs deleted file mode 100644 index 80a9ed80..00000000 --- a/source - Copie/IO/Configuration/Enums.cs +++ /dev/null @@ -1,242 +0,0 @@ -using ChartTools.Events; -using Melanchall.DryWetMidi.Core; - -namespace ChartTools.IO.Configuration; - -/// -/// Defines how duplicate track objects are handled. -/// -public enum DuplicateTrackObjectPolicy : byte -{ - /// - /// Throw an exception with the position. - /// - ThrowException, - /// - /// Include only the first object - /// - IncludeFirst, - /// - /// Include all objects. - /// - IncludeAll, -} -/// -/// Define where lyrics are obtained when writing a format that defines lyrics as events. -/// -public enum LyricEventSource : byte -{ - /// - /// Obtain lyrics from . - /// - GlobalEvents, - /// - /// Obtain lyrics from the instrument. - /// - Vocals -} -public enum MisalignedBigRockMarkersPolicy : byte -{ - ThrowException, - IgnoreAll, - IncludeFirst, - Combine -} -public enum MissingBigRockMarkerPolicy : byte -{ - ThrowException, - IgnoreAll, - IgnoreMissing -} -/// -/// Defines how overlapping star power phrases should be handled. -/// -public enum OverlappingSpecialPhrasePolicy : byte -{ - /// - /// Throw an exception. - /// - ThrowException, - /// - /// Ignore the overlapping phrase. - /// - Ignore, - /// - /// Cut the length of the first phrase to the start of the next one. - /// - Cut, -} -/// -/// Defines how a tempo anchor with no parent marker is handled. -/// -public enum TempolessAnchorPolicy -{ - /// - /// Throw an exception. - /// - ThrowException, - /// - /// Ignore the anchor. - /// - Ignore, - /// - /// Create a tempo marker with the anchor. - /// - Create -} -/// -/// Defines how notes within ticks of each other are handled during a Midi operation. -/// -public enum SnappedNotesPolicy : byte -{ - /// - /// Throw an exception. - /// - ThrowException, - /// - /// Combine the notes as a single chord at the position of the earlier note. - /// - Snap, - /// - /// Leave each note as its own chord. - /// - Ignore -} -/// -/// Defines how or events are handled when there are no star power phrases. -/// -/// is always used when star power phrases are present. -public enum SoloNoStarPowerPolicy : byte -{ - /// - /// Store the events under . - /// - StoreAsEvents, - /// - /// Convert the space between the and event to a star power phrase. - /// - Convert -} -/// -/// Difficulty of the to serve as a source of for track objects for which the target format requires these objects to be the same across all difficulties. -/// -/// Can be cast from . -public enum TrackObjectSource : byte -{ - /// - /// Use the objects from the track. - /// - Easy, - /// - /// Use the objects from the track. - /// - Medium, - /// - /// Use the objects from the track. - /// - Hard, - /// - /// Use the objects from the track. - /// - Expert, - /// - /// Combine the unique track objects from all the tracks in the instrument. - /// - Merge, -} -/// -/// Defines how lead guitar and bass and handled when the Midi mapping is uncertain. -/// -public enum UncertainGuitarBassFormatPolicy : byte -{ - /// - /// Throw an exception. - /// - ThrowException, - /// - /// Use the format that was defaulted to when reading. - /// - /// Policy is invalid when reading. - UseReadingDefault, - /// - /// Default to the Guitar Hero 2 format. - /// - UseGuitarHero2, - /// - /// Default to the Rock Band format. - /// - UseRockBand -} -/// -/// Defines how unknown sections or Midi chunks are handled. -/// -public enum UnknownSectionPolicy : byte -{ - /// - /// Throw an exception with the section or chunk header. - /// - ThrowException, - /// - /// Store the raw data to be included when writing. - /// - Store -} -/// -/// Defines chord modifiers not supported by the target format are handled. -/// -public enum UnsupportedModifierPolicy : byte -{ - /// - /// Throw an exception with the modifier index. - /// - ThrowException, - /// - /// Convert the modifier to one supported by the format. - /// - /// Will throw an exception if the modifier cannot be converted. - Convert, - /// - /// Ignore the modifier. - /// - IgnoreModifier, - /// - /// Ignore the chord containing the modifier. - /// - IgnoreChord, -} -/// -/// Defines how track object defined with a with no matching are handled when reading Midi. -/// -public enum UnopenedTrackObjectPolicy : byte -{ - /// - /// Throw an exception with the event position and index. - /// - ThrowException, - /// - /// Create a track object at the position of the closing event and a length of 0. - /// - Create, - /// - /// Ignore the event. - /// - Ignore -} -/// -/// Defines how track object defined with a with no matching are handled when reading Midi. -/// -public enum UnclosedTrackObjectPolicy : byte -{ - /// - /// Throw an exception with the event position and index. - /// - ThrowException, - /// - /// Include the track object with a length going up to the next track object opening of the same index. - /// - Include, - /// - /// Ignore the event and track object. - /// - Ignore -} diff --git a/source - Copie/IO/Configuration/ReadingConfiguration.cs b/source - Copie/IO/Configuration/ReadingConfiguration.cs deleted file mode 100644 index 35194948..00000000 --- a/source - Copie/IO/Configuration/ReadingConfiguration.cs +++ /dev/null @@ -1,25 +0,0 @@ -using Melanchall.DryWetMidi.Core; - -namespace ChartTools.IO.Configuration; - -/// -/// Configuration object to direct the reading of a file -/// -/// -public record ReadingConfiguration : CommonConfiguration -{ - public bool IgnoreInvalidMidiEventType { get; set; } - public MisalignedBigRockMarkersPolicy MisalignedBigRockMarkersPolicy { get; set; } - public MissingBigRockMarkerPolicy MissingBigRockMarkerPolicy { get; set; } - public UnopenedTrackObjectPolicy UnopenedTrackObjectPolicy { get; set; } - public UnclosedTrackObjectPolicy UnclosedTracjObjectPolicy { get; set; } - public UnknownSectionPolicy UnknownSectionPolicy { get; set; } - public TempolessAnchorPolicy TempolessAnchorPolicy { get; set; } - public UncertainGuitarBassFormatPolicy UncertainGuitarBassFormatPolicy { get; set; } - - /// - /// Configuration object to customize how DryWetMidi reads Midi file before being parsed - /// - /// Setting to will use default settings - public ReadingSettings? MidiFirstPassReadingSettings { get; set; } -} diff --git a/source - Copie/IO/Configuration/Sessions/ReadingSession.cs b/source - Copie/IO/Configuration/Sessions/ReadingSession.cs deleted file mode 100644 index fa64c2d6..00000000 --- a/source - Copie/IO/Configuration/Sessions/ReadingSession.cs +++ /dev/null @@ -1,22 +0,0 @@ -using ChartTools.IO.Formatting; - -namespace ChartTools.IO.Configuration.Sessions; - -internal class ReadingSession : Session -{ - public delegate bool TempolessAnchorHandler(Anchor anchor); - - public override ReadingConfiguration Configuration { get; } - public TempolessAnchorHandler TempolessAnchorProcedure { get; private set; } - public ReadingSession(ReadingConfiguration config, FormattingRules? formatting) : base(formatting) - { - Configuration = config; - TempolessAnchorProcedure = anchor => (TempolessAnchorProcedure = Configuration.TempolessAnchorPolicy switch - { - TempolessAnchorPolicy.ThrowException => anchor => throw new Exception($"Tempo anchor at position {anchor.Position} does not have a parent tempo marker."), - TempolessAnchorPolicy.Ignore => anchor => false, - TempolessAnchorPolicy.Create => anchor => true, - _ => throw ConfigurationExceptions.UnsupportedPolicy(Configuration.TempolessAnchorPolicy) - })(anchor); - } -} diff --git a/source - Copie/IO/Configuration/Sessions/Session.cs b/source - Copie/IO/Configuration/Sessions/Session.cs deleted file mode 100644 index 2b214884..00000000 --- a/source - Copie/IO/Configuration/Sessions/Session.cs +++ /dev/null @@ -1,35 +0,0 @@ -using ChartTools.IO.Formatting; - -namespace ChartTools.IO.Configuration.Sessions; - -internal abstract class Session -{ - public delegate bool DuplicateTrackObjectHandler(uint position, string objectType, Func checkDuplciate); - public delegate bool SnappedNotesHandler(uint origin, uint position); - - public DuplicateTrackObjectHandler DuplicateTrackObjectProcedure { get; private set; } - public SnappedNotesHandler SnappedNotesProcedure { get; private set; } - public virtual CommonConfiguration Configuration { get; } = new(); - public FormattingRules? Formatting { get; set; } - - public Session(FormattingRules? formatting) - { - Formatting = formatting; - - DuplicateTrackObjectProcedure = (position, objectType, checkDuplicate) => (DuplicateTrackObjectProcedure = Configuration.DuplicateTrackObjectPolicy switch - { - DuplicateTrackObjectPolicy.ThrowException => (position, objectType, checkDuplicate) => checkDuplicate() - ? throw new Exception($"Duplicate {objectType} on position {position}.") : true, - DuplicateTrackObjectPolicy.IncludeAll => (_, _, _) => true, - DuplicateTrackObjectPolicy.IncludeFirst => (_, _, checkDuplicate) => !checkDuplicate(), - _ => throw ConfigurationExceptions.UnsupportedPolicy(Configuration.DuplicateTrackObjectPolicy) - })(position, objectType, checkDuplicate); - SnappedNotesProcedure = (origin, position) => (SnappedNotesProcedure = Configuration.SnappedNotesPolicy switch - { - SnappedNotesPolicy.ThrowException => (origin, position) => throw new Exception($"Note at position {position} is within snapping distance from chord at position {origin}"), - SnappedNotesPolicy.Snap => (_, _) => true, - SnappedNotesPolicy.Ignore => (_, _) => false, - _ => throw ConfigurationExceptions.UnsupportedPolicy(Configuration.SnappedNotesPolicy) - })(origin, position); - } -} diff --git a/source - Copie/IO/Configuration/Sessions/WritingSession.cs b/source - Copie/IO/Configuration/Sessions/WritingSession.cs deleted file mode 100644 index 9ed4d2be..00000000 --- a/source - Copie/IO/Configuration/Sessions/WritingSession.cs +++ /dev/null @@ -1,25 +0,0 @@ -using ChartTools.IO.Formatting; -using ChartTools.IO.Chart.Entries; - -namespace ChartTools.IO.Configuration.Sessions; - -internal class WritingSession : Session -{ - public delegate IEnumerable ChordEntriesGetter(LaneChord? previous, LaneChord current); - - public override WritingConfiguration Configuration { get; } - public ChordEntriesGetter GetChordEntries { get; private set; } - - public WritingSession(WritingConfiguration config, FormattingRules? formatting) : base(formatting) - { - Configuration = config; - GetChordEntries = (previous, chord) => (GetChordEntries = Configuration.UnsupportedModifierPolicy switch - { - UnsupportedModifierPolicy.IgnoreChord => (_, _) => Enumerable.Empty(), - UnsupportedModifierPolicy.ThrowException => (_, chord) => throw new Exception($"Chord at position {chord.Position} as an unsupported modifier for the chart format."), - UnsupportedModifierPolicy.IgnoreModifier => (_, chord) => chord.GetChartNoteData(), - UnsupportedModifierPolicy.Convert => (previous, chord) => chord.GetChartModifierData(previous, this), - _ => throw ConfigurationExceptions.UnsupportedPolicy(Configuration.UnsupportedModifierPolicy) - })(previous, chord); - } -} diff --git a/source - Copie/IO/Configuration/WritingConfiguration.cs b/source - Copie/IO/Configuration/WritingConfiguration.cs deleted file mode 100644 index 6e816269..00000000 --- a/source - Copie/IO/Configuration/WritingConfiguration.cs +++ /dev/null @@ -1,12 +0,0 @@ -namespace ChartTools.IO.Configuration; - -public record WritingConfiguration : CommonConfiguration -{ - /// - /// Defines which difficulty to get local events from - /// - public TrackObjectSource EventSource { get; init; } - public TrackObjectSource StarPowerSource { get; init; } - /// - public UnsupportedModifierPolicy UnsupportedModifierPolicy { get; init; } -} diff --git a/source - Copie/IO/DirectoryHandler.cs b/source - Copie/IO/DirectoryHandler.cs deleted file mode 100644 index ac7fe117..00000000 --- a/source - Copie/IO/DirectoryHandler.cs +++ /dev/null @@ -1,36 +0,0 @@ -using ChartTools.IO.Formatting; -using ChartTools.IO.Ini; - -namespace ChartTools.IO; - -public record DirectoryResult(T Result, Metadata Metadata); - -internal static class DirectoryHandler -{ - public static DirectoryResult FromDirectory(string directory, Func read) - { - var iniPath = directory + @"\song.ini"; - var chartPath = directory + @"\notes.chart"; - var iniMetadata = File.Exists(iniPath) ? IniFile.ReadMetadata(iniPath) : new(); - - T? value = default; - - if (File.Exists(chartPath)) - value = read(chartPath, iniMetadata.Formatting); - - return new(value, iniMetadata); - } - public static async Task> FromDirectoryAsync(string directory, Func> read, CancellationToken cancellationToken) - { - var iniPath = directory + @"\song.ini"; - var chartPath = directory + @"\notes.chart"; - var iniMetadata = File.Exists(iniPath) ? await IniFile.ReadMetadataAsync(iniPath, null, cancellationToken) : new(); - - T? value = default; - - if (File.Exists(chartPath)) - value = await read(chartPath, iniMetadata.Formatting); - - return new(value, iniMetadata); - } -} diff --git a/source - Copie/IO/Exceptions/EntryException.cs b/source - Copie/IO/Exceptions/EntryException.cs deleted file mode 100644 index a6e0f528..00000000 --- a/source - Copie/IO/Exceptions/EntryException.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace ChartTools.IO; - -public class EntryException : FormatException -{ - public EntryException() : base("Cannot divide line into entry elements.") { } -} diff --git a/source - Copie/IO/Exceptions/LineException.cs b/source - Copie/IO/Exceptions/LineException.cs deleted file mode 100644 index b26878e1..00000000 --- a/source - Copie/IO/Exceptions/LineException.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace ChartTools.IO; - -public class LineException : FormatException -{ - public string Line { get; } - public LineException(string line, Exception innerException) : base($"Line \"{line}\" {innerException.Message}", innerException) => Line = line; -} diff --git a/source - Copie/IO/Exceptions/ParseException.cs b/source - Copie/IO/Exceptions/ParseException.cs deleted file mode 100644 index 13fc8c0a..00000000 --- a/source - Copie/IO/Exceptions/ParseException.cs +++ /dev/null @@ -1,15 +0,0 @@ -namespace ChartTools.IO; - -public class ParseException : FormatException -{ - public string? Object { get; } - public string Target { get; } - public Type Type { get; } - - public ParseException(string? obj, string target, Type type) : base($"Cannot convert {target} \"{obj}\" to {type.Name}") - { - Object = obj; - Target = target; - Type = type; - } -} diff --git a/source - Copie/IO/Exceptions/SectionException.cs b/source - Copie/IO/Exceptions/SectionException.cs deleted file mode 100644 index ae32e9ee..00000000 --- a/source - Copie/IO/Exceptions/SectionException.cs +++ /dev/null @@ -1,11 +0,0 @@ -namespace ChartTools.IO; - -public class SectionException : Exception -{ - public string Header { get; } - - public SectionException(string header, Exception innerException) : base($"Section \"{header}\" {innerException.Message}") => Header = header; - - public static SectionException EarlyEnd(string header) => new(header, new InvalidDataException("Section did not end within the provided lines")); - public static SectionException MissingRequired(string header) => new(header, new InvalidDataException("Required section could not be found.")); -} diff --git a/source - Copie/IO/ExtensionHandler.cs b/source - Copie/IO/ExtensionHandler.cs deleted file mode 100644 index 5aa1685f..00000000 --- a/source - Copie/IO/ExtensionHandler.cs +++ /dev/null @@ -1,114 +0,0 @@ -using ChartTools.Extensions; - -namespace ChartTools.IO; - -/// -/// Read method that returns no value. -/// -/// File path -public delegate void VoidRead(string path); -/// -/// Read method that generates an object of the target type -/// -/// File path -public delegate T Read(string path); -/// -/// Asynchronous read method that generates an object of the target type -/// -/// Output type -/// File path -public delegate Task AsyncRead(string path); -/// -/// Write method hat takes an object of a target type -/// -/// Target type -/// File path -/// Object to write -public delegate void Write(string path, T content); -/// -/// Write method hat takes an object of a target type -/// -/// Target type -/// File path -/// Object to write -public delegate Task AsyncWrite(string path, T content); - -/// -/// Provides methods for reading and writing files based on the extension -/// -internal static class ExtensionHandler -{ - #region Reading - /// - /// Reads a file using the method that matches the extension. - /// - /// Path of the file to read - /// Array of tuples representing the supported extensions - public static void Read(string path, params (string extension, VoidRead readMetod)[] readers) - { - string extension = Path.GetExtension(path); - (string extension, VoidRead readMethod) reader = readers.FirstOrDefault(r => r.extension == extension); - - if (reader == default) - throw GetException(extension, readers.Select(r => r.extension)); - - reader.readMethod(path); - } - /// - /// Reads a file using the method that matches the extension and generates an output object. - /// - /// Type of the generated object - /// File path - /// set of tuples containing the supported extensions and the matching read method - public static T Read(string path, params (string extension, Read readMethod)[] readers) - { - string extension = Path.GetExtension(path); - (string extension, Read readMethod) reader = readers.FirstOrDefault(r => r.extension == extension); - - return reader == default ? throw GetException(extension, readers.Select(r => r.extension)) : reader.readMethod(path); - } - public static async Task ReadAsync(string path, params (string extension, AsyncRead readMethod)[] readers) - { - string extension = Path.GetExtension(path); - (string extension, AsyncRead readMethod) reader = readers.FirstOrDefault(r => r.extension == extension); - - return reader == default ? throw GetException(extension, readers.Select(r => r.extension)) : await reader.readMethod(path); - } - #endregion - - #region Writing - /// - /// Writes an object to a file using the method that matches the extension. - /// - /// Path of the file to write - /// Item to write - /// Array of tupples representing the supported extensions - /// - public static void Write(string path, T content, params (string extension, Write writeMethod)[] writers) - { - string extension = Path.GetExtension(path); - (string extension, Write writeMethod) writer = writers.FirstOrDefault(w => w.extension == extension); - - if (writer == default) - throw GetException(extension, writers.Select(w => w.extension)); - - writer.writeMethod(path, content); - } - public static async Task WriteAsync(string path, T content, params (string extension, AsyncWrite writeMethod)[] writers) - { - string extension = Path.GetExtension(path); - (string extension, AsyncWrite writeMethod) writer = writers.FirstOrDefault(w => w.extension == extension); - - if (writer == default) - throw GetException(extension, writers.Select(w => w.extension)); - - await writer.writeMethod(path, content); - } - #endregion - - /// - /// Gets the exception to throw if the extension has no method that handles it. - /// - /// Instance of to throw - private static Exception GetException(string extension, IEnumerable supportedExtensions) => new ArgumentException($"\"{extension}\" is not a supported extension. File must be {supportedExtensions.VerbalEnumerate("or")}."); -} diff --git a/source - Copie/IO/FileReader.cs b/source - Copie/IO/FileReader.cs deleted file mode 100644 index c327592e..00000000 --- a/source - Copie/IO/FileReader.cs +++ /dev/null @@ -1,79 +0,0 @@ -using ChartTools.Extensions.Collections; - -namespace ChartTools.IO; - -internal abstract class FileReader : IDisposable -{ - public string Path { get; } - public bool IsReading { get; protected set; } - public abstract IEnumerable> Parsers { get; } - - public FileReader(string path) => Path = path; - - public abstract void Read(); - public abstract Task ReadAsync(CancellationToken cancellationToken); - - protected void CheckBusy() - { - if (IsReading) - throw new InvalidOperationException("Cannot start read operation while the reader is busy."); - } - - public abstract void Dispose(); -} - -internal abstract class FileReader : FileReader where TParser : FileParser -{ - public record ParserContentGroup(TParser Parser, DelayedEnumerableSource Source); - - public override IEnumerable Parsers => parserGroups.Select(g => g.Parser); - - protected readonly List parserGroups = new(); - protected readonly List parseTasks = new(); - protected readonly Func parserGetter; - - public FileReader(string path, Func parserGetter) : base(path) => this.parserGetter = parserGetter; - - public override void Read() - { - CheckBusy(); - IsReading = true; - - ReadBase(false, CancellationToken.None); - - foreach (var group in parserGroups) - group.Parser.Parse(group.Source.Enumerable.EnumerateSynchronously()); - - IsReading = false; - } - public override async Task ReadAsync(CancellationToken cancellationToken) - { - CheckBusy(); - IsReading = true; - - ReadBase(true, cancellationToken); - await Task.WhenAll(parseTasks); - - IsReading = false; - } - - protected abstract void ReadBase(bool read, CancellationToken cancellationToken); - - public void Reset() - { - parseTasks.Clear(); - parserGroups.Clear(); - } - - public override async void Dispose() - { - foreach (var group in parserGroups) - group.Source.Dispose(); - - foreach (var task in parseTasks) - { - await task; - task.Dispose(); - } - } -} diff --git a/source - Copie/IO/Formatting/FormattingEnums.cs b/source - Copie/IO/Formatting/FormattingEnums.cs deleted file mode 100644 index ce0c64e5..00000000 --- a/source - Copie/IO/Formatting/FormattingEnums.cs +++ /dev/null @@ -1,5 +0,0 @@ -namespace ChartTools.IO.Formatting; - -[Flags] public enum AlbumTrackKey : byte { AlbumTrack, Track } -[Flags] public enum CharterKey : byte { Charter, Frets } -public enum HopoFrequencyStep : byte { TwentyFourth, Sixteenth, Twelveth, Eight, Sixth, Fourth } diff --git a/source - Copie/IO/Formatting/FormattingRules.cs b/source - Copie/IO/Formatting/FormattingRules.cs deleted file mode 100644 index 13a72529..00000000 --- a/source - Copie/IO/Formatting/FormattingRules.cs +++ /dev/null @@ -1,113 +0,0 @@ -using ChartTools.IO.Chart; -using ChartTools.IO.Chart.Serializing; -using ChartTools.IO.Ini; - -namespace ChartTools.IO.Formatting; - -/// -/// Rules defined in song.ini that affect how the song data file is read and written -/// -/// Property summaries provided by Nathan Hurst. -public class FormattingRules -{ - public AlbumTrackKey AlbumTrackKey { get; set; } - public CharterKey CharterKey { get; set; } - - /// - /// Number of values per beat - /// - [ChartKeySerializable(ChartFormatting.Resolution)] - public uint? Resolution { get; set; } - public uint TrueResolution => Resolution ?? 480; - - /// - /// Overrides the default sustain cutoff threshold with the specified number of ticks. - /// - [IniKeySerializable(IniFormatting.SustainCutoff)] - public uint? SustainCutoff { get; set; } - - #region Hopo frequency - /// - /// Overrides the natural HOPO threshold with the specified number of ticks. - /// - [IniKeySerializable(IniFormatting.HopoFrequency)] - public uint? HopoFrequency { get; set; } - /// - /// (FoFiX) Overrides the natural HOPO threshold using numbers from 0 to 5. - /// - [IniKeySerializable(IniFormatting.HopoFrequencyStep)] - public HopoFrequencyStep? HopoFrequencyStep { get; set; } - /// - /// (FoFiX) Overrides the natural HOPO threshold to be a 1/8th step. - /// - [IniKeySerializable(IniFormatting.ForceEightHopoFrequency)] - public bool? ForceEightHopoFrequency { get; set; } - - public uint? TrueHopoFrequency - { - get - { - if (HopoFrequency is not null) - return HopoFrequency.Value; - - if (HopoFrequencyStep is not null) - return TrueResolution / (uint)(HopoFrequencyStep.Value switch - { - Formatting.HopoFrequencyStep.Fourth => 4, - Formatting.HopoFrequencyStep.Eight => 8, - Formatting.HopoFrequencyStep.Twelveth => 12, - Formatting.HopoFrequencyStep.Sixteenth => 16, - _ => throw new System.Exception($"{HopoFrequencyStep} is not a valid hopo frequency step.") - }); - - return ForceEightHopoFrequency is true ? TrueResolution / 8 : null; - } - } - #endregion - - #region Star power - /// - /// Overrides the Star Power phrase MIDI note for .mid charts. - /// - [IniKeySerializable(IniFormatting.MultiplierNote)] - public byte? MultiplierNote { get; set; } - /// - /// (PhaseShift) Overrides the Star Power phrase MIDI note for .mid charts. - /// - [IniKeySerializable(IniFormatting.StarPowerNote)] - public byte? StarPowerNote { get; set; } - public byte? TrueStarPowerNote => StarPowerNote ?? MultiplierNote; - #endregion - - #region SysEx - /// - /// (PhaseShift) Indicates if the chart uses SysEx events for sliders/tap notes. - /// - [IniKeySerializable(IniFormatting.SysExSliders)] - public bool? SysExSliders { get; set; } - - /// - /// (PhaseShift) Indicates if the chart uses SysEx events for Drums Real hi-hat pedal control. - /// - [IniKeySerializable(IniFormatting.SysExHighHat)] - public bool? SysExHighHat { get; set; } - - /// - /// (PhaseShift) Indicates if the chart uses SysEx events for Drums Real rimshot hits. - /// - [IniKeySerializable(IniFormatting.Rimshot)] - public bool? SysExRimshot { get; set; } - - /// - /// (PhaseShift) Indicates if the chart uses SysEx events for open notes. - /// - [IniKeySerializable(IniFormatting.SysExOpenBass)] - public bool? SysExOpenBass { get; set; } - - /// - /// (PhaseShift) Indicates if the chart uses SysEx events for Pro Guitar/Bass slide directions. - /// - [IniKeySerializable(IniFormatting.SysExProSlide)] - public bool? SysexProSlide { get; set; } - #endregion -} \ No newline at end of file diff --git a/source - Copie/IO/ISerializerDataProvider.cs b/source - Copie/IO/ISerializerDataProvider.cs deleted file mode 100644 index 5e6fb5f0..00000000 --- a/source - Copie/IO/ISerializerDataProvider.cs +++ /dev/null @@ -1,8 +0,0 @@ -using ChartTools.IO.Configuration.Sessions; - -namespace ChartTools.IO; - -internal interface ISerializerDataProvider -{ - public IEnumerable ProvideFor(IEnumerable source, WritingSession session); -} diff --git a/source - Copie/IO/Ini/IniFile.cs b/source - Copie/IO/Ini/IniFile.cs deleted file mode 100644 index fd960875..00000000 --- a/source - Copie/IO/Ini/IniFile.cs +++ /dev/null @@ -1,47 +0,0 @@ -using ChartTools.Extensions.Linq; -using ChartTools.IO.Formatting; -using ChartTools.IO.Configuration; - -namespace ChartTools.IO.Ini; - -/// -/// Provides methods for reading and writing ini files -/// -public static class IniFile -{ - /// - /// - /// A new instance of if is , otherwise the same reference. - public static Metadata ReadMetadata(string path, Metadata? existing = null) - { - var reader = new IniFileReader(path, header => header.Equals(IniFormatting.Header, StringComparison.OrdinalIgnoreCase) ? new(existing) : null); - reader.Read(); - - return reader.Parsers.TryGetFirst(out var parser) - ? parser!.Result - : throw SectionException.MissingRequired(IniFormatting.Header); - } - /// - /// - /// A new instance of if is , otherwise the same reference. - public static async Task ReadMetadataAsync(string path, Metadata? existing = null, CancellationToken cancellationToken = default) - { - var reader = new IniFileReader(path, header => header.Equals(IniFormatting.Header, StringComparison.OrdinalIgnoreCase) ? new(existing) : null); - await reader.ReadAsync(cancellationToken); - - return reader.Parsers.TryGetFirst(out var parser) - ? parser!.Result - : throw SectionException.MissingRequired(IniFormatting.Header); - } - - /// - /// Writes the metadata in a file. - /// - /// Path of the file to read - /// Metadata to write - public static void WriteMetadata(string path, Metadata metadata) - { - var writer = new IniFileWriter(path, new IniSerializer(metadata)); - writer.Write(); - } -} diff --git a/source - Copie/IO/Ini/IniFileReader.cs b/source - Copie/IO/Ini/IniFileReader.cs deleted file mode 100644 index 9638629b..00000000 --- a/source - Copie/IO/Ini/IniFileReader.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace ChartTools.IO.Ini; - -internal class IniFileReader : TextFileReader -{ - public override IEnumerable Parsers => base.Parsers.Cast(); - - public IniFileReader(string path, Func parserGetter) : base(path, parserGetter) { } - - protected override bool IsSectionStart(string line) => !line.StartsWith('['); -} diff --git a/source - Copie/IO/Ini/IniFileWriter.cs b/source - Copie/IO/Ini/IniFileWriter.cs deleted file mode 100644 index 2fc5775a..00000000 --- a/source - Copie/IO/Ini/IniFileWriter.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace ChartTools.IO.Ini; - -internal class IniFileWriter : TextFileWriter -{ - public IniFileWriter(string path, params Serializer[] serializers) : base(path, Enumerable.Empty(), serializers) { } - - protected override bool EndReplace(string line) => line.StartsWith('['); -} diff --git a/source - Copie/IO/Ini/IniFormatting.cs b/source - Copie/IO/Ini/IniFormatting.cs deleted file mode 100644 index 079989ab..00000000 --- a/source - Copie/IO/Ini/IniFormatting.cs +++ /dev/null @@ -1,47 +0,0 @@ -namespace ChartTools.IO.Ini; - -public static class IniFormatting -{ - public const string - Header = "[song]", - Title = "name", - Artist = "artist", - Album = "album", - AlbumTrack = "album_track", - Track = "track", - Playlist = "playlist", - SubPlaylist = "sub_playlist", - PlaylistTrack = "playlis_track", - Genre = "genre", - Year = "year", - Charter = "charter", - Frets = "frets", - Icon = "icon", - PreviewStart = "preview_start_time", - PreviewEnd = "preview_end_time", - AudioOffset = "delay", - VideoOffset = "video_start_time", - Length = "song_length", - LoadingText = "loading_text", - Difficulty = "diff_band", - Modchart = "modchart", - SustainCutoff = "sustain_cutoff_threshold", - HopoFrequency = "hopo_frequency", - HopoFrequencyStep = "hopofreq", - ForceEightHopoFrequency = "eighthnote_hopo", - MultiplierNote = "multiplier_note", - StarPowerNote = "star_power_note", - SysExSliders = "sysex_slider", - SysExHighHat = "sysex_high_hat_ctrl", - Rimshot = "sysex_rimshot", - SysExOpenBass = "sysex_open_bass", - SysExProSlide = "sysex_pro_slide", - GuitarDifficulty = "diff_guitar", - BassDifficulty = "diff_bass", - DrumsDifficulty = "diff_drums", - KeysDifficulty = "diff_keys", - GHLGuitarDifficulty = "diff_guitarghl", - GHLBassDifficulty = "diff_bassghl"; - - public static string Line(string key, string value) => $"{key} = {value}"; -} diff --git a/source - Copie/IO/Ini/IniKeySerializableAttribute.cs b/source - Copie/IO/Ini/IniKeySerializableAttribute.cs deleted file mode 100644 index db9e88f8..00000000 --- a/source - Copie/IO/Ini/IniKeySerializableAttribute.cs +++ /dev/null @@ -1,13 +0,0 @@ -namespace ChartTools.IO.Ini -{ - public class IniKeySerializableAttribute : KeySerializableAttribute - { - public override FileType Format => FileType.Ini; - - public IniKeySerializableAttribute(string key) : base(key) { } - - protected override string GetValueString(object propValue) => propValue.ToString()!; - - public static IEnumerable<(string key, string value)> GetSerializable(object source) => GetSerializable(source); - } -} diff --git a/source - Copie/IO/Ini/IniParser.cs b/source - Copie/IO/Ini/IniParser.cs deleted file mode 100644 index b11f766a..00000000 --- a/source - Copie/IO/Ini/IniParser.cs +++ /dev/null @@ -1,141 +0,0 @@ -using ChartTools.IO.Formatting; -using ChartTools.IO.Parsing; -using ChartTools.Tools; - -namespace ChartTools.IO.Ini; - -internal class IniParser : TextParser, ISongAppliable -{ - public override Metadata Result => GetResult(result); - private readonly Metadata result; - - public IniParser(Metadata? existing = null) : base(null!, IniFormatting.Header) => result = existing ?? new(); - - protected override void HandleItem(string item) - { - var entry = new TextEntry(item); - - if (entry.Value is null) - return; - - switch (entry.Key) - { - case IniFormatting.Title: - result.Title = entry.Value; - break; - case IniFormatting.Artist: - result.Artist = entry.Value; - break; - case IniFormatting.Album: - result.Album = entry.Value; - break; - case IniFormatting.AlbumTrack: - ParseAlbumTrack(); - result.Formatting.AlbumTrackKey |= AlbumTrackKey.AlbumTrack; - break; - case IniFormatting.Track: - ParseAlbumTrack(); - result.Formatting.AlbumTrackKey |= AlbumTrackKey.Track; - break; - case IniFormatting.Playlist: - result.Playlist = entry.Value; - break; - case IniFormatting.SubPlaylist: - result.SubPlaylist = entry.Value; - break; - case IniFormatting.PlaylistTrack: - result.PlaylistTrack = ValueParser.ParseUshort(entry.Value, "playlist track"); - break; - case IniFormatting.Year: - result.Year = ValueParser.ParseUshort(entry.Value, "year"); - break; - case IniFormatting.Genre: - result.Genre = entry.Value; - break; - case IniFormatting.Charter: - ParseCharter(); - result.Formatting.CharterKey |= CharterKey.Charter; - break; - case IniFormatting.Frets: - ParseCharter(); - result.Formatting.CharterKey |= CharterKey.Frets; - break; - case IniFormatting.Icon: - result.Charter.Icon = entry.Value; - break; - case IniFormatting.PreviewStart: - result.PreviewStart = entry.Value.StartsWith('-') ? null : ValueParser.ParseUint(entry.Value, "preview start"); - break; - case IniFormatting.PreviewEnd: - result.PreviewEnd = entry.Value.StartsWith('-') ? null : ValueParser.ParseUint(entry.Value, "preview end"); - break; - case IniFormatting.AudioOffset: - result.AudioOffset = TimeSpan.FromMilliseconds(ValueParser.ParseInt(entry.Value, "audio offset")); - break; - case IniFormatting.VideoOffset: - result.VideoOffset = TimeSpan.FromMilliseconds(ValueParser.ParseInt(entry.Value, "video offset")); - break; - case IniFormatting.Length: - result.Length = ValueParser.ParseUint(entry.Value, "song length"); - break; - case IniFormatting.Difficulty: - result.Difficulty = ValueParser.ParseSbyte(entry.Value, "difficulty"); - break; - case IniFormatting.LoadingText: - result.LoadingText = entry.Value; - break; - case IniFormatting.Modchart: - result.IsModchart = ValueParser.ParseInt(entry.Value, "modchart") == 1; - break; - case IniFormatting.GuitarDifficulty: - result.InstrumentDifficulties.Guitar = ValueParser.ParseSbyte(entry.Value, "guitar difficulty"); - break; - case IniFormatting.BassDifficulty: - result.InstrumentDifficulties.Bass = ValueParser.ParseSbyte(entry.Value, "bass difficulty"); - break; - case IniFormatting.DrumsDifficulty: - result.InstrumentDifficulties.Drums = ValueParser.ParseSbyte(entry.Value, "drums difficulty"); - break; - case IniFormatting.KeysDifficulty: - result.InstrumentDifficulties.Keys = ValueParser.ParseSbyte(entry.Value, "keys difficulty"); - break; - case IniFormatting.GHLGuitarDifficulty: - result.InstrumentDifficulties.GHLGuitar = ValueParser.ParseSbyte(entry.Value, "GHL guitar difficulty"); - break; - case IniFormatting.GHLBassDifficulty: - result.InstrumentDifficulties.GHLBass = ValueParser.ParseSbyte(entry.Value, "GHL bass difficulty"); - break; - case IniFormatting.SustainCutoff: - result.Formatting.SustainCutoff = ValueParser.ParseUint(entry.Value, "sustain cutoff"); - break; - case IniFormatting.HopoFrequency: - result.Formatting.HopoFrequency = ValueParser.ParseUint(entry.Value, "hopo frequency"); - break; - case IniFormatting.HopoFrequencyStep: - result.Formatting.HopoFrequencyStep = (HopoFrequencyStep)ValueParser.ParseByte(entry.Value, "hopo frequency step"); - break; - case IniFormatting.ForceEightHopoFrequency: - result.Formatting.ForceEightHopoFrequency = ValueParser.ParseBool(entry.Value, "force eight hopo frequency"); - break; - default: - if (entry.Value is not null) - result.UnidentifiedData.Add(new() { Key = entry.Key, Value = entry.Value, Origin = FileType.Ini }); - break; - } - - void ParseAlbumTrack() => ValueParser.ParseUshort(entry.Value, "album track"); - void ParseCharter() - { - result.Charter ??= new(); - result.Charter.Name = entry.Value; - } - } - - public void ApplyToSong(Song song) - { - if (song.Metadata is null) - song.Metadata = Result; - else - PropertyMerger.Merge(song.Metadata, false, true, Result); - } -} diff --git a/source - Copie/IO/Ini/IniSerializer.cs b/source - Copie/IO/Ini/IniSerializer.cs deleted file mode 100644 index fd1334f0..00000000 --- a/source - Copie/IO/Ini/IniSerializer.cs +++ /dev/null @@ -1,34 +0,0 @@ -using ChartTools.IO.Formatting; - -namespace ChartTools.IO.Ini; - -internal class IniSerializer : Serializer -{ - public IniSerializer(Metadata content) : base(IniFormatting.Header, content, null!) { } - - public override IEnumerable Serialize() - { - if (Content is null) - yield break; - - var props = IniKeySerializableAttribute.GetSerializable(Content) - .Concat(IniKeySerializableAttribute.GetSerializable(Content.Formatting)) - .Concat(IniKeySerializableAttribute.GetSerializable(Content.Charter) - .Concat(IniKeySerializableAttribute.GetSerializable(Content.InstrumentDifficulties))); - - foreach ((var key, var value) in props) - yield return IniFormatting.Line(key, value.ToString()); - - foreach (var data in Content.UnidentifiedData) - yield return IniFormatting.Line(data.Key, data.Value); - - if (Content.AlbumTrack is not null) - { - if (Content.Formatting.AlbumTrackKey.HasFlag(AlbumTrackKey.Track)) - yield return IniFormatting.Line(IniFormatting.Track, Content.AlbumTrack.ToString()!); - - if (Content.Formatting.AlbumTrackKey.HasFlag(AlbumTrackKey.AlbumTrack)) - yield return IniFormatting.Line(IniFormatting.AlbumTrack, Content.AlbumTrack.ToString()!); - } - } -} diff --git a/source - Copie/IO/Parsers/FileParser.cs b/source - Copie/IO/Parsers/FileParser.cs deleted file mode 100644 index 84fe1c8e..00000000 --- a/source - Copie/IO/Parsers/FileParser.cs +++ /dev/null @@ -1,54 +0,0 @@ -using ChartTools.IO.Configuration.Sessions; - -namespace ChartTools.IO; - -internal abstract class FileParser -{ - public bool ResultReady { get; private set; } - public abstract object? Result { get; } - protected ReadingSession session; - - public FileParser(ReadingSession session) => this.session = session; - - public async Task StartAsyncParse(IEnumerable items) - { - await Task.Run(() => ParseBase(items)); - -#if CRASH_SOURCE - FinaliseParse(); -#else - try { FinaliseParse(); } - catch (Exception e) { throw GetFinalizeException(e); } -#endif - } - public void Parse(IEnumerable items) - { - ParseBase(items); - -#if CRASH_SOURCE - FinaliseParse(); -#else - try { FinaliseParse(); } - catch (Exception e) { throw GetFinalizeException(e); } -#endif - } - private void ParseBase(IEnumerable items) - { - foreach (var item in items) -#if CRASH_SOURCE - HandleItem(item); -#else - try { HandleItem(item); } - catch (Exception e) { throw GetHandleException(item, e); } -#endif - } - - protected abstract void HandleItem(T item); - - protected virtual void FinaliseParse() => ResultReady = true; - - protected TResult GetResult(TResult result) => ResultReady ? result : throw new Exception("Result is not ready."); - - protected abstract Exception GetHandleException(T item, Exception innerException); - protected abstract Exception GetFinalizeException(Exception innerException); -} diff --git a/source - Copie/IO/Parsers/SectionParser.cs b/source - Copie/IO/Parsers/SectionParser.cs deleted file mode 100644 index 6efa526b..00000000 --- a/source - Copie/IO/Parsers/SectionParser.cs +++ /dev/null @@ -1,14 +0,0 @@ -using ChartTools.IO.Configuration.Sessions; - -namespace ChartTools.IO.Parsing; - -internal abstract class SectionParser : FileParser -{ - public string Header { get; } - - public SectionParser(ReadingSession session, string header) : base(session) => Header = header; - - protected override Exception GetHandleException(T item, Exception innerException) => new SectionException(Header, GetHandleInnerException(item, innerException)); - protected abstract Exception GetHandleInnerException(T item, Exception innerException); - protected override Exception GetFinalizeException(Exception innerException) => new SectionException(Header, innerException); -} diff --git a/source - Copie/IO/Parsers/TextParser.cs b/source - Copie/IO/Parsers/TextParser.cs deleted file mode 100644 index cc872d09..00000000 --- a/source - Copie/IO/Parsers/TextParser.cs +++ /dev/null @@ -1,10 +0,0 @@ -using ChartTools.IO.Configuration.Sessions; - -namespace ChartTools.IO.Parsing; - -internal abstract class TextParser : SectionParser -{ - protected TextParser(ReadingSession session, string header) : base(session, header) { } - - protected override Exception GetHandleInnerException(string item, Exception innerException) => new LineException(item, innerException); -} diff --git a/source - Copie/IO/Sections/ReservedSectionHeader.cs b/source - Copie/IO/Sections/ReservedSectionHeader.cs deleted file mode 100644 index 0b0ba104..00000000 --- a/source - Copie/IO/Sections/ReservedSectionHeader.cs +++ /dev/null @@ -1,13 +0,0 @@ -namespace ChartTools.IO.Sections; - -public readonly struct ReservedSectionHeader -{ - public string Header { get; } - public string DataSource { get; } - - public ReservedSectionHeader(string header, string dataSource) - { - Header = header; - DataSource = dataSource; - } -} diff --git a/source - Copie/IO/Sections/ReservedSectionHeaderSet.cs b/source - Copie/IO/Sections/ReservedSectionHeaderSet.cs deleted file mode 100644 index a7629318..00000000 --- a/source - Copie/IO/Sections/ReservedSectionHeaderSet.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System.Collections; - -namespace ChartTools.IO.Sections; - -public class ReservedSectionHeaderSet : IEnumerable -{ - private readonly IEnumerable _headers; - - public ReservedSectionHeaderSet(IEnumerable headers) => _headers = headers; - - public IEnumerator GetEnumerator() => _headers.GetEnumerator(); - IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); -} diff --git a/source - Copie/IO/Sections/Section.cs b/source - Copie/IO/Sections/Section.cs deleted file mode 100644 index ead0d0ec..00000000 --- a/source - Copie/IO/Sections/Section.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace ChartTools.IO.Sections; - -public class Section : List -{ - public string Header { get; } - public Section(string header) => Header = header; -} diff --git a/source - Copie/IO/Sections/SectionSet.cs b/source - Copie/IO/Sections/SectionSet.cs deleted file mode 100644 index 59e9bd2a..00000000 --- a/source - Copie/IO/Sections/SectionSet.cs +++ /dev/null @@ -1,56 +0,0 @@ -using System.Collections; - -namespace ChartTools.IO.Sections; - -public abstract class SectionSet : IList> -{ - private readonly List> _sections = new(); - public abstract ReservedSectionHeaderSet ReservedHeaders { get; } - - #region IList - public int Count => _sections.Count; - public bool IsReadOnly => false; - - public Section this[int index] - { - get => _sections[index]; - set - { - CheckHeader(value.Header); - _sections[index] = value; - } - } - - public int IndexOf(Section item) => _sections.IndexOf(item); - public void Insert(int index, Section item) - { - CheckHeader(item.Header); - _sections.Insert(index, item); - } - public void RemoveAt(int index) => _sections.RemoveAt(index); - public void Add(Section item) - { - CheckHeader(item.Header); - _sections.Add(item); - } - public void Clear() => _sections.Clear(); - public bool Contains(Section item) => _sections.Contains(item); - public void CopyTo(Section[] array, int arrayIndex) => _sections.CopyTo(array, arrayIndex); - public bool Remove(Section item) => _sections.Remove(item); - public IEnumerator> GetEnumerator() => _sections.GetEnumerator(); - IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); - #endregion - - public Section? Get(string header) - { - CheckHeader(header); - return _sections.FirstOrDefault(s => s.Header == header); - } - - private void CheckHeader(string header) - { - foreach (var reserved in ReservedHeaders) - if (reserved.Header == header) - throw new Exception($"Header {header} is already modeled under {reserved.DataSource}"); - } -} diff --git a/source - Copie/IO/Serializers/GroupSerializer.cs b/source - Copie/IO/Serializers/GroupSerializer.cs deleted file mode 100644 index 649fbab4..00000000 --- a/source - Copie/IO/Serializers/GroupSerializer.cs +++ /dev/null @@ -1,13 +0,0 @@ -using ChartTools.IO.Configuration.Sessions; - -namespace ChartTools.IO; - -internal abstract class GroupSerializer : Serializer -{ - public GroupSerializer(string header, TContent content, WritingSession session) : base(header, content, session) { } - - protected abstract IEnumerable[] LaunchProviders(); - protected abstract IEnumerable CombineProviderResults(IEnumerable[] results); - - public override IEnumerable Serialize() => CombineProviderResults(LaunchProviders()); -} diff --git a/source - Copie/IO/Serializers/KeySerializable.cs b/source - Copie/IO/Serializers/KeySerializable.cs deleted file mode 100644 index b575abaa..00000000 --- a/source - Copie/IO/Serializers/KeySerializable.cs +++ /dev/null @@ -1,24 +0,0 @@ -using System.Reflection; - -namespace ChartTools.IO; - -public abstract class KeySerializableAttribute : Attribute -{ - public abstract FileType Format { get; } - public string Key { get; } - - public KeySerializableAttribute(string key) => Key = key; - - /// - /// Generates groups of non-null property values and their serialization keys. - /// - /// Object containing the properties - protected static IEnumerable<(string key, string value)> GetSerializable(object source) where TAttribute : KeySerializableAttribute => from prop in source.GetType().GetProperties() - let att = prop.GetCustomAttribute() - where att is not null - let value = prop.GetValue(source) - where value is not null - select (att.Key, att.GetValueString(value)); - - protected abstract string GetValueString(object propValue); -} diff --git a/source - Copie/IO/Serializers/Serializer.cs b/source - Copie/IO/Serializers/Serializer.cs deleted file mode 100644 index 051c91bf..00000000 --- a/source - Copie/IO/Serializers/Serializer.cs +++ /dev/null @@ -1,26 +0,0 @@ -using ChartTools.IO.Configuration.Sessions; - -namespace ChartTools.IO; - -internal abstract class Serializer -{ - protected WritingSession session; - - public string Header { get; } - - public Serializer(string header, WritingSession session) - { - Header = header; - this.session = session; - } - - public abstract IEnumerable Serialize(); - public async Task> SerializeAsync() => await Task.Run(() => Serialize().ToArray()); -} - -internal abstract class Serializer : Serializer -{ - public TContent Content { get; } - - public Serializer(string header, TContent content, WritingSession session) : base(header, session) => Content = content; -} diff --git a/source - Copie/IO/TextEntry.cs b/source - Copie/IO/TextEntry.cs deleted file mode 100644 index 12e87ffd..00000000 --- a/source - Copie/IO/TextEntry.cs +++ /dev/null @@ -1,33 +0,0 @@ -namespace ChartTools.IO -{ - /// - /// Line of text file data - /// - internal readonly struct TextEntry - { - /// - /// Text before the equal sign - /// - public string Key { get; } - /// - /// Text after the equal sign - /// - public string? Value { get; } - - public TextEntry(string key, string value) - { - Key = key; - Value = value; - } - public TextEntry(string line) - { - string[] split = line.Split('=', 2, StringSplitOptions.RemoveEmptyEntries); - - if (split.Length < 1) - throw new EntryException(); - - Key = split[0].Trim(); - Value = split.Length < 2 ? null : split[1].Trim(); - } - } -} diff --git a/source - Copie/IO/TextFileReader.cs b/source - Copie/IO/TextFileReader.cs deleted file mode 100644 index e75f3659..00000000 --- a/source - Copie/IO/TextFileReader.cs +++ /dev/null @@ -1,93 +0,0 @@ -using ChartTools.Extensions.Collections; -using ChartTools.IO.Parsing; - -namespace ChartTools.IO; - -internal abstract class TextFileReader : FileReader -{ - public virtual bool DefinedSectionEnd { get; } = false; - - public TextFileReader(string path, Func parserGetter) : base(path, parserGetter) { } - - protected override void ReadBase(bool async, CancellationToken cancellationToken) - { - ParserContentGroup? currentGroup = null; - using var enumerator = File.ReadLines(Path).Where(s => !string.IsNullOrEmpty(s)).Select(s => s.Trim()).GetEnumerator(); - - while (enumerator.MoveNext()) - { - // Find part - while (!enumerator.Current.StartsWith('[')) - if (enumerator.MoveNext()) - return; - - if (async && cancellationToken.IsCancellationRequested) - { - Dispose(); - return; - } - - var header = enumerator.Current; - var parser = parserGetter(header); - - if (parser is not null) - { - var source = new DelayedEnumerableSource(); - - parserGroups.Add(currentGroup = new(parser, source)); - - if (async) - { - if (cancellationToken.IsCancellationRequested) - { - Dispose(); - return; - } - - parseTasks.Add(parser.StartAsyncParse(source.Enumerable)); - } - } - - // Move to the start of the entries - do - if (!AdvanceSection()) - { - Finish(); - return; - } - while (!IsSectionStart(enumerator.Current)); - - AdvanceSection(); - - // Read until end - while (!IsSectionEnd(enumerator.Current)) - { - currentGroup?.Source.Add(enumerator.Current); - - if (!AdvanceSection()) - { - Finish(); - return; - } - } - - Finish(); - - void Finish() - { - if (cancellationToken.IsCancellationRequested) - { - Dispose(); - return; - } - - currentGroup?.Source.EndAwait(); - } - - bool AdvanceSection() => enumerator.MoveNext() || (DefinedSectionEnd ? throw SectionException.EarlyEnd(header) : false); - } - } - - protected abstract bool IsSectionStart(string line); - protected virtual bool IsSectionEnd(string line) => false; -} diff --git a/source - Copie/IO/TextFileWriter.cs b/source - Copie/IO/TextFileWriter.cs deleted file mode 100644 index d262d66b..00000000 --- a/source - Copie/IO/TextFileWriter.cs +++ /dev/null @@ -1,66 +0,0 @@ -using ChartTools.Extensions.Linq; -using ChartTools.Internal.Collections; - -namespace ChartTools.IO; - -internal abstract class TextFileWriter -{ - public string Path { get; } - protected virtual string? PreSerializerContent => null; - protected virtual string? PostSerializerContent => null; - - private readonly List> serializers; - private readonly string tempPath = System.IO.Path.GetTempFileName(); - private readonly IEnumerable? removedHeaders; - - public TextFileWriter(string path, IEnumerable? removedHeaders, params Serializer[] serializers) - { - Path = path; - this.serializers = serializers.ToList(); - this.removedHeaders = removedHeaders; - } - - private IEnumerable> AddRemoveReplacements(IEnumerable> replacements) => removedHeaders is null ? replacements : replacements.Concat(removedHeaders.Select(header => new SectionReplacement(Enumerable.Empty(), line => line == header, EndReplace, false))); - - private IEnumerable Wrap(string header, IEnumerable lines) - { - yield return header; - - if (PreSerializerContent is not null) - yield return PreSerializerContent; - - foreach (var line in lines) - yield return line; - - if (PostSerializerContent is not null) - yield return PostSerializerContent; - } - - public void Write() - { - using (var writer = new StreamWriter(tempPath)) - foreach (var line in GetLines(serializer => serializer.Serialize())) - writer.WriteLine(line); - - File.Copy(tempPath, Path, true); - File.Delete(tempPath); - } - public async Task WriteAsync(CancellationToken cancellationToken) - { - using (var writer = new StreamWriter(tempPath)) - foreach (var line in GetLines(serializer => new EagerEnumerable(serializer.SerializeAsync()))) - await writer.WriteLineAsync(line); - - if (cancellationToken.IsCancellationRequested) - File.Delete(tempPath); - else - File.Move(tempPath, Path, true); - } - - private IEnumerable GetLines(Func, IEnumerable> getSerializerLines) => File.Exists(Path) - ? File.ReadLines(Path) - .ReplaceSections(AddRemoveReplacements(serializers.Select(serializer => new SectionReplacement(Wrap(serializer.Header, getSerializerLines(serializer)), line => line == serializer.Header, EndReplace, true)))) - : serializers.SelectMany(serializer => Wrap(serializer.Header, serializer.Serialize())); - - protected abstract bool EndReplace(string line); -} diff --git a/source - Copie/IO/ValueParser.cs b/source - Copie/IO/ValueParser.cs deleted file mode 100644 index 0b983c4e..00000000 --- a/source - Copie/IO/ValueParser.cs +++ /dev/null @@ -1,16 +0,0 @@ -namespace ChartTools.IO; - -internal static class ValueParser -{ - public delegate bool TryParse(string? input, out T result); - public static T Parse(string? value, string target, TryParse tryParse) where T : struct => tryParse(value, out T result) ? result : throw new ParseException(value, target, typeof(T)); - - public static bool ParseBool(string? value, string target) => Parse(value, target, bool.TryParse); - public static byte ParseByte(string? value, string target) => Parse(value, target, byte.TryParse); - public static sbyte ParseSbyte(string? value, string target) => Parse(value, target, sbyte.TryParse); - public static short ParseShort(string? value, string target) => Parse(value, target, short.TryParse); - public static ushort ParseUshort(string? value, string target) => Parse(value, target, ushort.TryParse); - public static int ParseInt(string? value, string target) => Parse(value, target, int.TryParse); - public static uint ParseUint(string? value, string target) => Parse(value, target, uint.TryParse); - public static float ParseFloat(string? value, string target) => Parse(value, target, float.TryParse); -} diff --git a/source - Copie/IReadOnlyLongObject.cs b/source - Copie/IReadOnlyLongObject.cs deleted file mode 100644 index 2e62a2b8..00000000 --- a/source - Copie/IReadOnlyLongObject.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace ChartTools; - -public interface IReadOnlyLongObject -{ - /// - /// Length of the object in ticks - /// - public uint Length { get; } -} diff --git a/source - Copie/Instruments/Drums.cs b/source - Copie/Instruments/Drums.cs deleted file mode 100644 index 9d17c83f..00000000 --- a/source - Copie/Instruments/Drums.cs +++ /dev/null @@ -1,25 +0,0 @@ -using ChartTools.IO; -using ChartTools.IO.Chart; -using ChartTools.IO.Configuration; -using ChartTools.IO.Formatting; - -namespace ChartTools; - -public record Drums : Instrument -{ - protected override InstrumentIdentity GetIdentity() => InstrumentIdentity.Drums; - - #region File reading - [Obsolete($"Use {nameof(ChartFile.ReadDrums)}.")] - public static Drums? FromFile(string path, ReadingConfiguration? config = default, FormattingRules? formatting = default) => ExtensionHandler.Read(path, (".chart", path => ChartFile.ReadDrums(path, config, formatting))); - - [Obsolete($"Use {nameof(ChartFile.ReadDrumsAsync)}.")] - public static async Task FromFileAsync(string path, ReadingConfiguration? config = default, FormattingRules? formatting = default, CancellationToken cancellationToken = default) => await ExtensionHandler.ReadAsync(path, (".chart", path => ChartFile.ReadDrumsAsync(path, config, formatting, cancellationToken))); - - [Obsolete($"Use {nameof(ChartFile.ReadDrums)} with {nameof(Metadata.Formatting)}.")] - public static DirectoryResult FromDirectory(string directory, ReadingConfiguration? config = default) => DirectoryHandler.FromDirectory(directory, (path, formatting) => FromFile(path, config, formatting)); - - [Obsolete($"Use {nameof(ChartFile.ReadDrumsAsync)} with {nameof(Metadata.Formatting)}.")] - public static Task> FromDirectoryAsync(string directory, ReadingConfiguration? config = default, CancellationToken cancellationToken = default) => DirectoryHandler.FromDirectoryAsync(directory, async (path, formatting) => await FromFileAsync(path, config, formatting, cancellationToken), cancellationToken); - #endregion -} diff --git a/source - Copie/Instruments/GHLInstrument.cs b/source - Copie/Instruments/GHLInstrument.cs deleted file mode 100644 index 567f847f..00000000 --- a/source - Copie/Instruments/GHLInstrument.cs +++ /dev/null @@ -1,30 +0,0 @@ -using ChartTools.IO; -using ChartTools.IO.Chart; -using ChartTools.IO.Configuration; -using ChartTools.IO.Formatting; - -namespace ChartTools; - -public record GHLInstrument : Instrument -{ - public new GHLInstrumentIdentity InstrumentIdentity { get; init; } - - public GHLInstrument() { } - public GHLInstrument(GHLInstrumentIdentity identity) => InstrumentIdentity = identity; - - protected override InstrumentIdentity GetIdentity() => (InstrumentIdentity)InstrumentIdentity; - - #region File reading - [Obsolete($"Use {nameof(ChartFile.ReadInstrument)}.")] - public static GHLInstrument? FromFile(string path, GHLInstrumentIdentity instrument, ReadingConfiguration? config = default, FormattingRules? formatting = default) => ExtensionHandler.Read(path, (".chart", path => ChartFile.ReadInstrument(path, instrument, config, formatting))); - - [Obsolete($"Use {nameof(ChartFile.ReadInstrumentAsync)}.")] - public static async Task FromFileAsync(string path, GHLInstrumentIdentity instrument, ReadingConfiguration? config = default, FormattingRules? formatting = default, CancellationToken cancellationToken = default) => await ExtensionHandler.ReadAsync(path, (".chart", path => ChartFile.ReadInstrumentAsync(path, instrument, config, formatting, cancellationToken))); - - [Obsolete($"Use {nameof(ChartFile.ReadInstrument)} with {nameof(Metadata.Formatting)}.")] - public static DirectoryResult FromDirectory(string directory, GHLInstrumentIdentity instrument, ReadingConfiguration? config = default) => DirectoryHandler.FromDirectory(directory, (path, formatting) => FromFile(path, instrument, config, formatting)); - - [Obsolete($"Use {nameof(ChartFile.ReadInstrumentAsync)} with {nameof(Metadata.Formatting)}.")] - public static Task> FromDirectoryAsync(string directory, GHLInstrumentIdentity instrument, ReadingConfiguration? config = default, CancellationToken cancellationToken = default) => DirectoryHandler.FromDirectoryAsync(directory, async (path, formatting) => await FromFileAsync(path, instrument, config, formatting, cancellationToken), cancellationToken); - #endregion -} diff --git a/source - Copie/Instruments/Instrument.cs b/source - Copie/Instruments/Instrument.cs deleted file mode 100644 index 14e123d0..00000000 --- a/source - Copie/Instruments/Instrument.cs +++ /dev/null @@ -1,156 +0,0 @@ -using ChartTools.Extensions.Linq; -using ChartTools.IO; -using ChartTools.IO.Chart; -using ChartTools.IO.Configuration; -using ChartTools.IO.Formatting; - -using DiffEnum = ChartTools.Difficulty; - -namespace ChartTools; - -/// -/// Base class for instruments -/// -public abstract record Instrument : IEmptyVerifiable -{ - /// - public bool IsEmpty => GetExistingTracks().All(t => t.IsEmpty); - - /// - /// Identity of the instrument the object belongs to - /// - public InstrumentIdentity InstrumentIdentity => GetIdentity(); - - /// - /// Type of instrument - /// - public InstrumentType InstrumentType - { - get - { - if (_instrumentType is not null) - return _instrumentType.Value; - - _instrumentType = InstrumentIdentity switch - { - InstrumentIdentity.Drums => InstrumentType.Drums, - InstrumentIdentity.LeadGuitar or InstrumentIdentity.RhythmGuitar or InstrumentIdentity.Bass or InstrumentIdentity.CoopGuitar or InstrumentIdentity.GHLBass or InstrumentIdentity.Keys => InstrumentType.Standard, - InstrumentIdentity.GHLGuitar or InstrumentIdentity.GHLBass => InstrumentType.GHL, - InstrumentIdentity.Vocals => InstrumentType.Vocals, - _ => throw new InvalidDataException($"Instrument identity {InstrumentIdentity} does not belong to an instrument type.") - }; - - return _instrumentType.Value; - } - } - private InstrumentType? _instrumentType; - - /// - /// Set of special phrases applied to all difficulties - /// - public List SpecialPhrases { get; set; } = new(); - - /// - public sbyte? GetDifficulty(InstrumentDifficultySet difficulties) => difficulties.GetDifficulty(InstrumentIdentity); - /// - public void SetDifficulty(InstrumentDifficultySet difficulties, sbyte? difficulty) => difficulties.SetDifficulty(InstrumentIdentity, difficulty); - - /// - /// Easy track - /// - public Track? Easy => GetEasy(); - /// - /// Medium track - /// - public Track? Medium => GetMedium(); - /// - /// Hard track - /// - public Track? Hard => GetHard(); - /// - /// Expert track - /// - public Track? Expert => GetExpert(); - - /// - /// Gets the track matching a difficulty. - /// - public abstract Track? GetTrack(DiffEnum difficulty); - - protected abstract Track? GetEasy(); - protected abstract Track? GetMedium(); - protected abstract Track? GetHard(); - protected abstract Track? GetExpert(); - - /// - /// Creates a track - /// - /// Difficulty of the track - public abstract Track CreateTrack(DiffEnum difficulty); - /// - /// Removes a track. - /// - /// Difficulty of the target track - public abstract bool RemoveTrack(DiffEnum difficulty); - - /// - /// Creates an array containing all tracks. - /// - public virtual Track?[] GetTracks() => new Track?[] { Easy, Medium, Hard, Expert }; - /// - /// Creates an array containing all tracks with data. - /// - public virtual IEnumerable GetExistingTracks() => GetTracks().NonNull().Where(t => !t.IsEmpty); - - protected abstract InstrumentIdentity GetIdentity(); - - /// - /// Gives all tracks the same local events. - /// - public void ShareLocalEvents(TrackObjectSource source) => ShareEventsStarPower(source, track => track.LocalEvents); - /// - /// Gives all tracks the same star power - /// - public void ShareStarPower(TrackObjectSource source) => ShareEventsStarPower(source, track => track.SpecialPhrases); - private void ShareEventsStarPower(TrackObjectSource source, Func> collectionGetter) where T : TrackObjectBase - { - var collections = GetExistingTracks().Select(track => collectionGetter(track)).ToArray(); - - var objects = (source switch - { - TrackObjectSource.Easy => collections[0], - TrackObjectSource.Medium => collections[1], - TrackObjectSource.Hard => collections[2], - TrackObjectSource.Expert => collections[3], - TrackObjectSource.Merge => collections.SelectMany(col => col).Distinct(), - _ => throw new UndefinedEnumException(source) - }).ToArray(); - - foreach (var collection in collections) - { - collection.Clear(); - collection.AddRange(objects); - } - } - - #region IO - #region Reading - [Obsolete($"Use {nameof(ChartFile.ReadInstrument)}.")] - public static Instrument? FromFile(string path, InstrumentIdentity instrument, ReadingConfiguration? config = default, FormattingRules? formatting = default) => ExtensionHandler.Read(path, (".chart", path => ChartFile.ReadInstrument(path, instrument, config, formatting))); - [Obsolete($"Use {nameof(ChartFile.ReadInstrumentAsync)}.")] - public static async Task FromFileAsync(string path, InstrumentIdentity instrument, ReadingConfiguration? config = default, FormattingRules? formatting = default, CancellationToken cancellationToken = default) => await ExtensionHandler.ReadAsync(path, (".chart", path => ChartFile.ReadInstrumentAsync(path, instrument, config, formatting, cancellationToken))); - - [Obsolete($"Use {nameof(ChartFile.ReadInstrument)} with {nameof(Metadata.Formatting)}.")] - public static DirectoryResult FromDirectory(string directory, InstrumentIdentity instrument, ReadingConfiguration? config = default) => DirectoryHandler.FromDirectory(directory, (path, formatting) => FromFile(path, instrument, config, formatting)); - [Obsolete($"Use {nameof(ChartFile.ReadInstrumentAsync)} with {nameof(Metadata.Formatting)}.")] - public static Task> FromDirectoryAsync(string directory, InstrumentIdentity instrument, ReadingConfiguration? config = default, CancellationToken cancellationToken = default) => DirectoryHandler.FromDirectoryAsync(directory, async (path, formatting) => await FromFileAsync(path, instrument, config, formatting, cancellationToken), cancellationToken); - #endregion - - [Obsolete($"Use {nameof(ChartFile.ReplaceInstrument)}.")] - public void ToFile(string path, WritingConfiguration? config = default, FormattingRules? formatting = default) => ExtensionHandler.Write(path, this, (".chart", (path, inst) => ChartFile.ReplaceInstrument(path, inst, config, formatting))); - [Obsolete($"Use {nameof(ChartFile.ReplaceInstrumentAsync)}.")] - public async Task ToFileAsync(string path, WritingConfiguration? config = default, FormattingRules? formatting = default, CancellationToken cancellationToken = default) => await ExtensionHandler.WriteAsync(path, this, (".chart", (path, inst) => ChartFile.ReplaceInstrumentAsync(path, inst, config, formatting, cancellationToken))); - #endregion - - public override string ToString() => InstrumentIdentity.ToString(); -} diff --git a/source - Copie/Instruments/InstrumentGeneric.cs b/source - Copie/Instruments/InstrumentGeneric.cs deleted file mode 100644 index cd6c3088..00000000 --- a/source - Copie/Instruments/InstrumentGeneric.cs +++ /dev/null @@ -1,121 +0,0 @@ -namespace ChartTools; - -/// -/// Set of tracks common to an instrument -/// -public abstract record Instrument : Instrument where TChord : IChord -{ - /// - /// Easy track - /// - public new Track? Easy - { - get => _easy; - set => _easy = value is null ? null : value with { Difficulty = Difficulty.Easy, ParentInstrument = this }; - } - private Track? _easy; - - /// - /// Medium track - /// - public new Track? Medium - { - get => _medium; - set => _medium = value is null ? null : value with { Difficulty = Difficulty.Medium, ParentInstrument = this }; - } - private Track? _medium; - - /// - /// Hard track - /// - public new Track? Hard - { - get => _hard; - set => _hard = value is null ? null : value with { Difficulty = Difficulty.Hard, ParentInstrument = this }; - } - private Track? _hard; - - /// - /// Expert track - /// - public new Track? Expert - { - get => _expert; - set => _expert = value is null ? null : value with { Difficulty = Difficulty.Expert, ParentInstrument = this }; - } - private Track? _expert; - - /// - /// Gets the that matches a - /// - public override Track? GetTrack(Difficulty difficulty) => difficulty switch - { - Difficulty.Easy => Easy, - Difficulty.Medium => Medium, - Difficulty.Hard => Hard, - ChartTools.Difficulty.Expert => Expert, - _ => throw new UndefinedEnumException(difficulty) - }; - - /// - public override Track CreateTrack(Difficulty difficulty) => difficulty switch - { - Difficulty.Easy => Easy = new(), - Difficulty.Medium => Medium = new(), - Difficulty.Hard => Hard = new(), - Difficulty.Expert => Expert = new(), - _ => throw new UndefinedEnumException(difficulty) - }; - /// - public override bool RemoveTrack(Difficulty difficulty) - { - bool found; - - switch (difficulty) - { - case Difficulty.Easy: - found = _easy is not null; - _easy = null; - return found; - case Difficulty.Medium: - found = _medium is not null; - _medium = null; - return found; - case Difficulty.Hard: - found = _hard is not null; - _hard = null; - return found; - case Difficulty.Expert: - found = _expert is not null; - _expert = null; - return found; - default: - throw new UndefinedEnumException(difficulty); - } - } - - protected override Track? GetEasy() => Easy; - protected override Track? GetMedium() => Medium; - protected override Track? GetHard() => Hard; - protected override Track? GetExpert() => Expert; - - public override Track?[] GetTracks() => new Track?[] { Easy, Medium, Hard, Expert }; - public override IEnumerable> GetExistingTracks() => base.GetExistingTracks().Cast>(); - - /// - /// Sets a track for a given . - /// - /// Track instance assigned to the instrument. Changed made to the passed reference will not be reflected in the instrument. - /// - /// - public Track SetTrack(Track track) => track is null - ? throw new ArgumentNullException(nameof(track)) - : track.Difficulty switch - { - Difficulty.Easy => _easy = track with { ParentInstrument = this }, - Difficulty.Medium => _medium = track with { ParentInstrument = this }, - Difficulty.Hard => _hard = track with { ParentInstrument = this }, - Difficulty.Expert => _expert = track with { ParentInstrument = this }, - _ => throw new UndefinedEnumException(track.Difficulty) - }; -} diff --git a/source - Copie/Instruments/InstrumentSet.cs b/source - Copie/Instruments/InstrumentSet.cs deleted file mode 100644 index 361b57d7..00000000 --- a/source - Copie/Instruments/InstrumentSet.cs +++ /dev/null @@ -1,163 +0,0 @@ -using ChartTools.Extensions.Linq; - -using System.Collections; - -namespace ChartTools; - -/// -/// Set of all instruments -/// -public class InstrumentSet : IEnumerable -{ - /// - /// Set of drums tracks - /// - public Drums? Drums { get; set; } - /// - /// Set of Guitar Hero Live guitar tracks - /// - public GHLInstrument? GHLGuitar - { - get => _ghlGuitar; - set => _ghlGuitar = value is null ? value : value with { InstrumentIdentity = GHLInstrumentIdentity.Guitar }; - } - private GHLInstrument? _ghlGuitar; - /// - /// Set of Guitar Hero Live bass tracks - /// - public GHLInstrument? GHLBass - { - get => _ghlBass; - set => _ghlBass = value is null ? value : value with { InstrumentIdentity = GHLInstrumentIdentity.Bass }; - } - private GHLInstrument? _ghlBass; - /// - /// Set of lead guitar tracks - /// - public StandardInstrument? LeadGuitar - { - get => _leadGuitar; - set => _leadGuitar = value is null ? value : value with { InstrumentIdentity = StandardInstrumentIdentity.LeadGuitar }; - } - private StandardInstrument? _leadGuitar; - /// - /// Set of rhythm guitar tracks - /// - public StandardInstrument? RhythmGuitar - { - get => _rhythmGuitar; - set => _rhythmGuitar = value is null ? value : value with { InstrumentIdentity = StandardInstrumentIdentity.RhythmGuitar }; - } - private StandardInstrument? _rhythmGuitar; - /// - /// Set of coop guitar tracks - /// - public StandardInstrument? CoopGuitar - { - get => _coopGuitar; - set => _coopGuitar = value is null ? value : value with { InstrumentIdentity = StandardInstrumentIdentity.CoopGuitar }; - } - private StandardInstrument? _coopGuitar; - /// - /// Set of bass tracks - /// - public StandardInstrument? Bass - { - get => _bass; - set => _bass = value is null ? value : value with { InstrumentIdentity = StandardInstrumentIdentity.Bass }; - } - private StandardInstrument? _bass; - /// - /// Set of keyboard tracks - /// - public StandardInstrument? Keys - { - get => _keys; - set => _keys = value is null ? value : value with { InstrumentIdentity = StandardInstrumentIdentity.Keys }; - } - private StandardInstrument? _keys; - public Vocals? Vocals { get; set; } - - /// - /// Gets property value for an from a value. - /// - /// Instance of from the - /// Instrument to get - public Instrument? Get(InstrumentIdentity instrument) => instrument switch - { - InstrumentIdentity.Drums => Drums, - InstrumentIdentity.GHLGuitar => GHLGuitar, - InstrumentIdentity.GHLBass => GHLBass, - InstrumentIdentity.LeadGuitar => LeadGuitar, - InstrumentIdentity.RhythmGuitar => RhythmGuitar, - InstrumentIdentity.CoopGuitar => CoopGuitar, - InstrumentIdentity.Bass => Bass, - InstrumentIdentity.Keys => Keys, - InstrumentIdentity.Vocals => Vocals, - _ => throw new UndefinedEnumException(instrument) - }; - /// - /// Gets property value for an from a value. - /// - /// /// Instrument to get - /// Instance of where TChord is from the . - public GHLInstrument? Get(GHLInstrumentIdentity instrument) - { - Validator.ValidateEnum(instrument); - return Get((InstrumentIdentity)instrument) as GHLInstrument; - } - /// - /// Gets property value for an from a value. - /// - /// Instrument to get - /// Instance of where TChord is from the . - public StandardInstrument? Get(StandardInstrumentIdentity instrument) - { - Validator.ValidateEnum(instrument); - return Get((InstrumentIdentity)instrument) as StandardInstrument; - } - - public IEnumerable Existing() => this.NonNull().Where(instrument => !instrument.IsEmpty); - - public void Set(StandardInstrument instrument) - { - switch (instrument.InstrumentIdentity) - { - case StandardInstrumentIdentity.LeadGuitar: - _leadGuitar = instrument; - break; - case StandardInstrumentIdentity.RhythmGuitar: - _rhythmGuitar = instrument; - break; - case StandardInstrumentIdentity.CoopGuitar: - _coopGuitar = instrument; - break; - case StandardInstrumentIdentity.Bass: - _bass = instrument; - break; - case StandardInstrumentIdentity.Keys: - _keys = instrument; - break; - default: - throw new UndefinedEnumException(instrument.InstrumentIdentity); - } - } - public void Set(GHLInstrument instrument) - { - switch (instrument.InstrumentIdentity) - { - case GHLInstrumentIdentity.Guitar: - GHLGuitar = instrument; - break; - case GHLInstrumentIdentity.Bass: - GHLBass = instrument; - break; - default: - throw new UndefinedEnumException(instrument.InstrumentIdentity); - } - } - - public IEnumerator GetEnumerator() => new Instrument?[] { Drums, GHLGuitar, GHLBass, LeadGuitar, RhythmGuitar, CoopGuitar, Bass, Keys }.NonNull().GetEnumerator(); - - IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); -} diff --git a/source - Copie/Instruments/StandardInstrument.cs b/source - Copie/Instruments/StandardInstrument.cs deleted file mode 100644 index b1fe9681..00000000 --- a/source - Copie/Instruments/StandardInstrument.cs +++ /dev/null @@ -1,51 +0,0 @@ -using ChartTools.IO; -using ChartTools.IO.Chart; -using ChartTools.IO.Configuration; -using ChartTools.IO.Formatting; - -namespace ChartTools; - -public record StandardInstrument : Instrument -{ - public new StandardInstrumentIdentity InstrumentIdentity { get; init; } - - - /// - /// Format of lead guitar and bass. Not applicable to other instruments. - /// - public MidiInstrumentOrigin MidiOrigin - { - get => midiOrigin; - set - { - if (value is MidiInstrumentOrigin.GuitarHero1 && InstrumentIdentity is not StandardInstrumentIdentity.LeadGuitar) - throw new ArgumentException($"{InstrumentIdentity} is not supported by Guitar Hero 1.", nameof(value)); - - midiOrigin = value; - } - } - private MidiInstrumentOrigin midiOrigin; - - public StandardInstrument() { } - public StandardInstrument(StandardInstrumentIdentity identity) => InstrumentIdentity = identity; - - protected override InstrumentIdentity GetIdentity() => (InstrumentIdentity)InstrumentIdentity; - - #region File reading - [Obsolete($"Use {nameof(ChartFile.ReadInstrument)}.")] - public static StandardInstrument? FromFile(string path, StandardInstrumentIdentity instrument, ReadingConfiguration? config = default, FormattingRules? formatting = default) - { - Validator.ValidateEnum(instrument); - return ExtensionHandler.Read(path, (".chart", path => ChartFile.ReadInstrument(path, instrument, config, formatting))); - } - - [Obsolete($"Use {nameof(ChartFile.ReadInstrumentAsync)}.")] - public static async Task FromFileAsync(string path, StandardInstrumentIdentity instrument, ReadingConfiguration? config = default, FormattingRules? formatting = default, CancellationToken cancellationToken = default) => await ExtensionHandler.ReadAsync(path, (".chart", path => ChartFile.ReadInstrumentAsync(path, instrument, config, formatting, cancellationToken))); - - [Obsolete($"Use {nameof(ChartFile.ReadInstrument)} with {nameof(Metadata.Formatting)}.")] - public static DirectoryResult FromDirectory(string directory, StandardInstrumentIdentity instrument, ReadingConfiguration? config = default) => DirectoryHandler.FromDirectory(directory, (path, formatting) => FromFile(path, instrument, config, formatting)); - - [Obsolete($"Use {nameof(ChartFile.ReadInstrumentAsync)} with {nameof(Metadata.Formatting)}.")] - public static Task> FromDirectoryAsync(string directory, StandardInstrumentIdentity instrument, ReadingConfiguration? config = default, CancellationToken cancellationToken = default) => DirectoryHandler.FromDirectoryAsync(directory, async (path, formatting) => await FromFileAsync(path, instrument, config, formatting, cancellationToken), cancellationToken); - #endregion -} diff --git a/source - Copie/Instruments/Vocals.cs b/source - Copie/Instruments/Vocals.cs deleted file mode 100644 index 780d7d63..00000000 --- a/source - Copie/Instruments/Vocals.cs +++ /dev/null @@ -1,20 +0,0 @@ -using ChartTools.IO; -using ChartTools.IO.Chart; -using ChartTools.IO.Configuration; -using ChartTools.IO.Formatting; -using ChartTools.Lyrics; - -namespace ChartTools; - -public record Vocals : Instrument -{ - protected override InstrumentIdentity GetIdentity() => InstrumentIdentity.Vocals; - - #region File reading - [Obsolete($"Use {nameof(ChartFile.ReadVocals)}.")] - public static Vocals? FromFile(string path, ReadingConfiguration? config = default, FormattingRules? formatting = default) => ExtensionHandler.Read(path, (".chart", path => ChartFile.ReadVocals(path))); - - [Obsolete($"Use {nameof(ChartFile.ReadVocalsAsync)}.")] - public static async Task FromFileAsync(string path, ReadingConfiguration? config = default, FormattingRules? formatting = default, CancellationToken cancellationToken = default) => await ExtensionHandler.ReadAsync(path, (".chart", path => ChartFile.ReadVocalsAsync(path))); - #endregion -} diff --git a/source - Copie/Metadata/Charter.cs b/source - Copie/Metadata/Charter.cs deleted file mode 100644 index f2d6105f..00000000 --- a/source - Copie/Metadata/Charter.cs +++ /dev/null @@ -1,25 +0,0 @@ -using ChartTools.IO.Chart; -using ChartTools.IO.Chart.Serializing; -using ChartTools.IO.Ini; - -namespace ChartTools; - -/// -/// Creator of the chart -/// -public class Charter -{ - /// - /// Name of the creator - /// - [ChartKeySerializable(ChartFormatting.Charter)] - public string? Name { get; set; } - - /// - /// Location of the image file to use as an icon in the Clone Hero song browser - /// - [IniKeySerializable(IniFormatting.Icon)] - public string? Icon { get; set; } - - public override string ToString() => Name ?? string.Empty; -} diff --git a/source - Copie/Metadata/InstrumentDifficultySet.cs b/source - Copie/Metadata/InstrumentDifficultySet.cs deleted file mode 100644 index 112c5670..00000000 --- a/source - Copie/Metadata/InstrumentDifficultySet.cs +++ /dev/null @@ -1,80 +0,0 @@ -using ChartTools.IO.Ini; - -using System.Reflection; - -namespace ChartTools; - -/// -/// Stores the estimated difficulties for instruments -/// -public class InstrumentDifficultySet -{ - /// - /// Difficulty of , and - /// - [IniKeySerializable(IniFormatting.GuitarDifficulty)] - public sbyte? Guitar { get; set; } - /// - /// Difficulty of - /// - [IniKeySerializable(IniFormatting.BassDifficulty)] - public sbyte? Bass { get; set; } - /// - /// Difficulty of - /// - [IniKeySerializable(IniFormatting.DrumsDifficulty)] - public sbyte? Drums { get; set; } - /// - /// Difficulty of - /// - [IniKeySerializable(IniFormatting.KeysDifficulty)] - public sbyte? Keys { get; set; } - /// - /// Difficulty of - /// - [IniKeySerializable(IniFormatting.GHLGuitarDifficulty)] - public sbyte? GHLGuitar { get; set; } - /// - /// Difficulty of - /// - [IniKeySerializable(IniFormatting.GHLBassDifficulty)] - public sbyte? GHLBass { get; set; } - - /// - /// Gets the difficulty for an . - /// - public sbyte? GetDifficulty(InstrumentIdentity identity) => GetDifficultyProperty(identity, out var info) ? (sbyte?)info!.GetValue(this) : null; - /// - /// Sets the difficulty for an . - /// - public void SetDifficulty(InstrumentIdentity identity, sbyte? difficulty) - { - if (GetDifficultyProperty(identity, out var info)) - info!.SetValue(this, difficulty); - } - - private bool GetDifficultyProperty(InstrumentIdentity identity, out PropertyInfo? info) - { - Validator.ValidateEnum(identity); - var propName = identity switch - { - InstrumentIdentity.LeadGuitar or InstrumentIdentity.CoopGuitar or InstrumentIdentity.RhythmGuitar => nameof(Guitar), - InstrumentIdentity.Bass => nameof(Bass), - InstrumentIdentity.Drums => nameof(Drums), - InstrumentIdentity.Keys => nameof(Keys), - InstrumentIdentity.GHLGuitar => nameof(GHLGuitar), - InstrumentIdentity.GHLBass => nameof(GHLBass), - _ => null - }; - - if (propName is null) - { - info = null; - return false; - } - - info = typeof(InstrumentDifficultySet).GetProperty(propName); - - return true; - } -} diff --git a/source - Copie/Metadata/Metadata.cs b/source - Copie/Metadata/Metadata.cs deleted file mode 100644 index cb9d63c9..00000000 --- a/source - Copie/Metadata/Metadata.cs +++ /dev/null @@ -1,225 +0,0 @@ -using ChartTools.Extensions; -using ChartTools.IO; -using ChartTools.IO.Chart; -using ChartTools.IO.Chart.Serializing; -using ChartTools.IO.Formatting; -using ChartTools.IO.Ini; - -namespace ChartTools; - -/// -/// Set of miscellaneous information about a -/// -public class Metadata -{ - #region Properties - /// - /// Title of the - /// - [ChartKeySerializable(ChartFormatting.Title)] - [IniKeySerializable(IniFormatting.Title)] - public string? Title { get; set; } - - /// - /// Artist or band behind the - /// - [ChartKeySerializable(ChartFormatting.Artist)] - [IniKeySerializable(IniFormatting.Artist)] - public string? Artist { get; set; } - - /// - /// Album featuring the - /// - [ChartKeySerializable(ChartFormatting.Album)] - [IniKeySerializable(IniFormatting.Album)] - public string? Album { get; set; } - - /// - /// Track number of the song within the album - /// - public ushort? AlbumTrack { get; set; } - - /// - /// Playlist that the song should show up in - /// - [IniKeySerializable(IniFormatting.Playlist)] - public string? Playlist { get; set; } - - /// - /// Sub-playlist that the song should show up in - /// - [IniKeySerializable(IniFormatting.SubPlaylist)] - public string? SubPlaylist { get; set; } - - /// - /// Track number of the song within the playlist/setlist - /// - [IniKeySerializable(IniFormatting.PlaylistTrack)] - public ushort? PlaylistTrack { get; set; } - - /// - /// Year of release - /// - [IniKeySerializable(IniFormatting.Year)] - public ushort? Year { get; set; } - - /// - /// Genre of the - /// - [ChartKeySerializable(ChartFormatting.Genre)] - [IniKeySerializable(IniFormatting.Genre)] - public string? Genre { get; set; } - - /// - /// Creator of the chart - /// - public Charter Charter - { - get => _charter; - set => _charter = value ?? throw new ArgumentNullException(nameof(value)); - } - private Charter _charter = new(); - - /// - /// Start time in milliseconds of the preview in the Clone Hero song browser - /// - [ChartKeySerializable(ChartFormatting.PreviewStart)] - [IniKeySerializable(IniFormatting.PreviewStart)] - public uint? PreviewStart { get; set; } - - /// - /// End time in milliseconds of the preview in the Clone Hero song browser - /// - [ChartKeySerializable(ChartFormatting.PreviewEnd)] - [IniKeySerializable(IniFormatting.PreviewEnd)] - public uint? PreviewEnd { get; set; } - - /// - /// Duration in milliseconds of the preview in the Clone Hero song browser - /// - public uint PreviewLength - { - get - { - if (PreviewEnd is null) - return 30000; - - return PreviewStart is null ? PreviewEnd.Value : PreviewEnd.Value - PreviewStart.Value; - } - } - - /// - /// Overall difficulty of the song - /// - [ChartKeySerializable(ChartFormatting.Difficulty)] - [IniKeySerializable(IniFormatting.Difficulty)] - public sbyte? Difficulty { get; set; } - /// - public InstrumentDifficultySet InstrumentDifficulties - { - get => _instrumentDifficulties; - set => _instrumentDifficulties = value ?? throw new ArgumentNullException(nameof(value)); - } - private InstrumentDifficultySet _instrumentDifficulties = new(); - /// - /// Type of media the audio track comes from - /// - [ChartKeySerializable(ChartFormatting.MediaType)] - public string? MediaType { get; set; } - - /// - /// Offset of the audio track. A higher value makes the audio start sooner. - /// - [ChartKeySerializable(ChartFormatting.AudioOffset)] - [IniKeySerializable(IniFormatting.AudioOffset)] - public TimeSpan? AudioOffset { get; set; } - - /// - /// Paths of audio files - /// - public StreamCollection Streams - { - get => _streams; - set => _streams = value ?? throw new ArgumentNullException(nameof(value)); - } - private StreamCollection _streams = new(); - - /// - /// Offset of the background video. A higher value makes the video start sooner. - /// - public TimeSpan? VideoOffset { get; set; } - - /// - /// Length of the song in milliseconds - /// - [IniKeySerializable(IniFormatting.Length)] - public uint? Length { get; set; } - - /// - /// Text to be displayed on the load screen - /// - [IniKeySerializable(IniFormatting.LoadingText)] - public string? LoadingText { get; set; } - - /// - /// The song is a modchart - /// - [IniKeySerializable(IniFormatting.Modchart)] - public bool IsModchart { get; set; } - - - private FormattingRules _formatting = new(); - /// - public FormattingRules Formatting - { - get => _formatting; - set => _formatting = value ?? throw new ArgumentNullException(nameof(value)); - } - - /// - /// Unrecognized metadata - /// - /// When writing, these will only be written if the target format matches the origin - public HashSet UnidentifiedData { get; } = new(new FuncEqualityComparer((a, b) => a.Key == b.Key)); - #endregion - - public void ReadFile(string path) => Read(path, this); - /// - /// Reads the metadata from a file. - /// - /// Path of the file to read - /// - /// - /// - /// - /// - public static Metadata FromFile(string path) => Read(path); - - private static Metadata Read(string path, Metadata? existing = null) => ExtensionHandler.Read(path, (".chart", ChartFile.ReadMetadata), (".ini", path => IniFile.ReadMetadata(path, existing))); - - /// - /// Reads the metadata from multiple files. - /// - /// Each file has less priority than the preceding. - /// Paths of the files to read - /// - /// - /// - /// - /// - public static Metadata? FromFiles(params string[] paths) - { - // No files provided - if (paths is null || paths.Length == 0) - throw new ArgumentException("No provided paths"); - - var data = FromFile(paths[0]); - - foreach (var path in paths[1..]) - data.ReadFile(path); - - return data; - } - - public void ToFile(string path) => ExtensionHandler.Write(path, this, (".ini", IniFile.WriteMetadata)); -} diff --git a/source - Copie/Metadata/StreamCollection.cs b/source - Copie/Metadata/StreamCollection.cs deleted file mode 100644 index d419fdbc..00000000 --- a/source - Copie/Metadata/StreamCollection.cs +++ /dev/null @@ -1,70 +0,0 @@ -using ChartTools.IO.Chart; -using ChartTools.IO.Chart.Serializing; - -namespace ChartTools; - -/// -/// Set of audio files to play and mute during gameplay -/// -/// Instrument audio may be muted when chords of the respective instrument are missed -public class StreamCollection -{ - /// - /// Location of the base audio file - /// - [ChartKeySerializable(ChartFormatting.MusicStream)] - public string? Music { get; set; } - /// - /// Location of the guitar audio file - /// - [ChartKeySerializable(ChartFormatting.GuitarStream)] - public string? Guitar { get; set; } - /// - /// Location of the bass audio - /// - [ChartKeySerializable(ChartFormatting.BassStream)] - public string? Bass { get; set; } - /// - /// Location of the rhythm guitar audio file - /// - [ChartKeySerializable(ChartFormatting.RhythmStream)] - public string? Rhythm { get; set; } - /// - /// Location of the keys audio file - /// - [ChartKeySerializable(ChartFormatting.KeysStream)] - public string? Keys { get; set; } - /// - /// Location of the drums' kicks audio file - /// - /// Can include all drums audio - [ChartKeySerializable(ChartFormatting.DrumStream)] - public string? Drum { get; set; } - /// - /// Location of the drums' snares audio file - /// - /// Can include all drums audio except kicks - [ChartKeySerializable(ChartFormatting.Drum2Stream)] - public string? Drum2 { get; set; } - /// - /// Location of the drum's toms audio file - /// - /// Can include toms and cymbals - [ChartKeySerializable(ChartFormatting.Drum3Stream)] - public string? Drum3 { get; set; } - /// - /// Location of the drum's cymbals audio file - /// - [ChartKeySerializable(ChartFormatting.Drum4Stream)] - public string? Drum4 { get; set; } - /// - /// Location of the vocals audio file - /// - [ChartKeySerializable(ChartFormatting.VocalStream)] - public string? Vocals { get; set; } - /// - /// Location of the crowd reaction audio file - /// - [ChartKeySerializable(ChartFormatting.CrowdStream)] - public string? Crowd { get; set; } -} diff --git a/source - Copie/Metadata/UnidentifiedMetadata.cs b/source - Copie/Metadata/UnidentifiedMetadata.cs deleted file mode 100644 index 2716e6ed..00000000 --- a/source - Copie/Metadata/UnidentifiedMetadata.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace ChartTools; - -public struct UnidentifiedMetadata -{ - public string Key { get; init; } - public string? Value { get; set; } - public FileType Origin { get; set; } -} diff --git a/source - Copie/Notes/DrumsNote.cs b/source - Copie/Notes/DrumsNote.cs deleted file mode 100644 index 8a0e5da2..00000000 --- a/source - Copie/Notes/DrumsNote.cs +++ /dev/null @@ -1,32 +0,0 @@ -namespace ChartTools; - -/// -/// Note played by drums -/// -public class DrumsNote : LaneNote -{ - private bool _isCymbal = false; - /// - /// if the cymbal must be hit instead of the pad on supported drum sets - /// - /// notes cannot be cymbal. - public bool IsCymbal - { - get => _isCymbal; - set - { - if ((Lane == DrumsLane.Red || Lane == DrumsLane.Green5Lane) && value) - throw new InvalidOperationException("Red and 5-lane green notes cannot be cymbal."); - - _isCymbal = value; - } - } - - public DrumsNote() : base() { } - public DrumsNote(DrumsLane lane) : base(lane) { } - - /// - /// Determines if the note is played by kicking - /// - public bool IsKick => Lane is DrumsLane.Kick or DrumsLane.DoubleKick; -} diff --git a/source - Copie/Notes/INote.cs b/source - Copie/Notes/INote.cs deleted file mode 100644 index 6934db0f..00000000 --- a/source - Copie/Notes/INote.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace ChartTools; - -public interface INote : ILongObject -{ - /// - /// Numerical value of the note identity - /// - public byte Index { get; } -} diff --git a/source - Copie/Notes/LaneNote.cs b/source - Copie/Notes/LaneNote.cs deleted file mode 100644 index e86be78c..00000000 --- a/source - Copie/Notes/LaneNote.cs +++ /dev/null @@ -1,16 +0,0 @@ -namespace ChartTools; - -public abstract class LaneNote : INote -{ - public abstract byte Index { get; } - - /// - /// Maximum length the note can be held for extra points - /// - public uint Sustain { get; set; } - uint ILongObject.Length - { - get => Sustain; - set => Sustain = value; - } -} diff --git a/source - Copie/Notes/LaneNoteCollection.cs b/source - Copie/Notes/LaneNoteCollection.cs deleted file mode 100644 index 305b972d..00000000 --- a/source - Copie/Notes/LaneNoteCollection.cs +++ /dev/null @@ -1,95 +0,0 @@ -using System.Collections; - -namespace ChartTools; - -public class LaneNoteCollection : ICollection, IReadOnlyList where TNote : LaneNote, new() where TLane : struct, Enum -{ - private readonly List _notes = new(); - - /// - /// If , trying to combine an open note with other notes will remove the current ones. - /// - public bool OpenExclusivity { get; } - public int Count => _notes.Count; - bool ICollection.IsReadOnly => false; - - public LaneNoteCollection(bool openExclusivity) => OpenExclusivity = openExclusivity; - - public void Add(TLane lane) => AddNonNull(new TNote() { Lane = lane }); - /// - /// Adds a note to the . - /// - /// Adding a note that already exists will overwrite the existing note. - /// If is , combining an open note with other notes will remove the current ones. - /// - /// Note to add - public void Add(TNote note) => AddNonNull(note ?? throw new ArgumentNullException(nameof(note))); - private void AddNonNull(TNote note) - { - if (OpenExclusivity && (note.Index == 0 || Count == 1 && this[0].Index == 0)) // An open note is present and needs to be removed - Clear(); - - _notes.Add(note); - } - - public void Clear() => _notes.Clear(); - - /// - /// Determines if any note matches the lane of a given note. - /// - /// - public bool Contains(TNote note) => note is null ? throw new ArgumentNullException(nameof(note)) : Contains(note.Lane); - /// - /// Determines if any note matches a given lane. - /// - public bool Contains(TLane lane) => _notes.Any(note => note.Lane.Equals(lane)); - /// - /// Determines if any note matches a given index. - /// - public bool Contains(byte index) => _notes.Any(note => note.Index == index); - - public void CopyTo(TNote[] array, int arrayIndex) => _notes.CopyTo(array, arrayIndex); - - /// - /// Removes the note that matches the lane of a given note. - /// - /// if a matching note was found. - public bool Remove(TNote note) => Remove(note.Lane); - /// - /// Removes the note that matches a given lane. - /// - /// if a matching note was found. - public bool Remove(TLane lane) => Remove(n => n.Lane.Equals(lane)); - /// - /// Removes the note that matches a given index. - /// - /// if a matching note was found. - public bool Remove(byte index) => Remove(n => n.Index == index); - private bool Remove(Predicate match) - { - var index = _notes.FindIndex(match); - - if (index is -1) - return false; - - _notes.RemoveAt(index); - return true; - } - - /// - /// Gets the note matching a given lane. - /// - /// Lane of the note - /// Note with the lane if present, otherwise . - public TNote? this[TLane lane] => _notes.FirstOrDefault(n => n.Lane.Equals(lane)); - /// - /// Gets the note at a given index based on order or addition. - /// - /// Index of the note in the collection, not to be confused with . - /// Note at the index - /// - public TNote this[int index] => _notes[index]; - - public IEnumerator GetEnumerator() => _notes.GetEnumerator(); - IEnumerator IEnumerable.GetEnumerator() => _notes.GetEnumerator(); -} diff --git a/source - Copie/Notes/LaneNoteGeneric.cs b/source - Copie/Notes/LaneNoteGeneric.cs deleted file mode 100644 index c973cd07..00000000 --- a/source - Copie/Notes/LaneNoteGeneric.cs +++ /dev/null @@ -1,24 +0,0 @@ -using System.Runtime.CompilerServices; - -namespace ChartTools; - -/// -/// Base class for notes -/// -public class LaneNote : LaneNote where TLane : struct, Enum -{ - public override byte Index => Unsafe.As(ref _lane); - public TLane Lane - { - get => _lane; - init => _lane = value; - } - private TLane _lane; - - public LaneNote() { } - public LaneNote(TLane lane, uint sustain = 0) - { - Lane = lane; - Sustain = sustain; - } -} diff --git a/source - Copie/Notes/Syllable.cs b/source - Copie/Notes/Syllable.cs deleted file mode 100644 index 07fc4100..00000000 --- a/source - Copie/Notes/Syllable.cs +++ /dev/null @@ -1,61 +0,0 @@ -namespace ChartTools.Lyrics; - -/// -/// Karaoke step of a -/// -public class Syllable : INote -{ - /// - /// Position offset from the - /// - public uint PositionOffset { get; set; } - /// - /// Position offset of the end from the - /// - public uint EndPositionOffset => PositionOffset + Length; - /// - /// Duration of the syllable in ticks - /// - public uint Length { get; set; } - - /// - /// Pitch to sing - /// - /// Although the octave is specified, some games only require the player to match the key.

Chart files do not support pitches.
- public VocalsPitch Pitch { get; set; } = new(); - public byte Index => (byte)Pitch.Value; - - private string _rawText = string.Empty; - /// - /// Unformatted text data - /// - /// Setting to will set to an empty string. - public string RawText - { - get => _rawText; - set => _rawText = value is null ? string.Empty : value; - } - /// - /// Text formatted to its in-game appearance - /// - public string DisplayedText => RawText.Replace("-", "").Replace('=', '-').Trim('+', '#', '^', '*'); - /// - /// if is the last syllable or the only syllable of its word - /// - public bool IsWordEnd - { - get => RawText.Length == 0 || RawText[^1] is '§' or '_' or not '-' and not '='; - set - { - if (value) - { - if (!IsWordEnd) - RawText = RawText[..^1]; - } - else if (IsWordEnd) - RawText += '-'; - } - } - public Syllable(uint offset) => PositionOffset = offset; - public Syllable(uint offset, VocalsPitch pitch) : this(offset) => Pitch = pitch; -} diff --git a/source - Copie/Notes/VocalsPitch.cs b/source - Copie/Notes/VocalsPitch.cs deleted file mode 100644 index 5fc02652..00000000 --- a/source - Copie/Notes/VocalsPitch.cs +++ /dev/null @@ -1,72 +0,0 @@ -namespace ChartTools.Lyrics; - -/// -/// Wrapper type for with helper properties to get the pitch and key -/// -public readonly struct VocalsPitch : IEquatable, IEquatable -{ - /// - /// Pitch value - /// - public VocalPitchValue Value { get; } - /// - /// Key excluding the octave - /// - public VocalsKey Key => (VocalsKey)((int)Value & 0x0F); - /// - /// Octave number - /// - public byte Octave => (byte)(((int)Value & 0xF0) >> 4); - - /// - /// Creates a pitch from a raw pitch value. - /// - /// - public VocalsPitch(VocalPitchValue value) => Value = value; - - #region Equals - /// - /// Indicates if two pitches have the same value. - /// - /// Pitch to compare - public bool Equals(VocalsPitch other) => Value == other.Value; - /// - /// Indicates if a pitch has a value equal to a raw pitch value. - /// - /// Value to compare - public bool Equals(VocalPitchValue other) => Value == other; - /// - /// Indicates if an object is a raw pitch value or wrapper and the value is equal. - /// - /// Source of value - public override bool Equals(object? obj) => obj is VocalPitchValue value && Equals(value) || obj is VocalsPitch wrapper && Equals(wrapper); - #endregion - - #region Operators - /// - /// Converts a raw pitch value to a matching wrapper. - /// - /// Pitch value - public static implicit operator VocalsPitch(VocalPitchValue pitch) => new(pitch); - - /// - public static bool operator ==(VocalsPitch left, VocalsPitch right) => left.Equals(right); - /// - /// Indicates if two pitches don't have the same value. - /// - public static bool operator !=(VocalsPitch left, VocalsPitch right) => !(left == right); - /// - /// Indicates if the left pitch has a lower value than the right pitch according to music theory. - /// - public static bool operator <(VocalsPitch left, VocalsPitch right) => left.Value < right.Value; - /// - /// Indicates if the left pitch has a higher value than the right pitch according to music theory. - /// - public static bool operator >(VocalsPitch left, VocalsPitch right) => left.Value > right.Value; - #endregion - - /// - /// Returns the hash code for the pitch value. - /// - public override int GetHashCode() => (int)Value; -} diff --git a/source - Copie/Song.cs b/source - Copie/Song.cs deleted file mode 100644 index e428b6b4..00000000 --- a/source - Copie/Song.cs +++ /dev/null @@ -1,123 +0,0 @@ -using ChartTools.IO; -using ChartTools.IO.Chart; -using ChartTools.IO.Ini; -using ChartTools.Lyrics; - -using ChartTools.IO.Configuration; -using ChartTools.Events; -using ChartTools.Tools; -using ChartTools.IO.Formatting; - -namespace ChartTools; - -/// -/// Song playable in Clone Hero -/// -public class Song -{ - /// - /// Set of information about the song not unrelated to instruments, syncing or events - /// - public Metadata Metadata - { - get => _metadata; - set => _metadata = value ?? throw new ArgumentNullException(nameof(value)); - } - private Metadata _metadata = new(); - - /// - public FormattingRules Formatting - { - get => _formatting; - set => _formatting = value ?? throw new ArgumentNullException(nameof(value)); - } - private FormattingRules _formatting = new(); - - /// - public SyncTrack SyncTrack - { - get => _syncTrack; - set => _syncTrack = value ?? throw new ArgumentNullException(nameof(value)); - } - private SyncTrack _syncTrack = new(); - - /// - /// List of events common to all instruments - /// - public List GlobalEvents - { - get => _globalEvents; - set => _globalEvents = value ?? throw new ArgumentNullException(nameof(value)); - } - private List _globalEvents = new(); - - /// - public InstrumentSet Instruments - { - get => _instruments; - set => _instruments = value ?? throw new ArgumentNullException(nameof(value)); - } - private InstrumentSet _instruments = new(); - - public ChartSection? UnknownChartSections { get; set; } - - #region Reading - /// - /// Reads all elements of a from a file. - /// - /// Path of the file - /// - /// - public static Song FromFile(string path, ReadingConfiguration? config = default, FormattingRules? formatting = default) => ExtensionHandler.Read(path, (".chart", path => ChartFile.ReadSong(path, config, formatting)), (".ini", path => new Song { Metadata = IniFile.ReadMetadata(path) })); - /// - /// Reads all elements of a from a file asynchronously using multitasking. - /// - /// - /// /// - /// Token to request cancellation - public static async Task FromFileAsync(string path, ReadingConfiguration? config = default, FormattingRules? formatting = default, CancellationToken cancellationToken = default) => await ExtensionHandler.ReadAsync(path, (".chart", path => ChartFile.ReadSongAsync(path, config, formatting, cancellationToken))); - - public static Song FromDirectory(string directory, ReadingConfiguration? config = default) - { - (var song, var metadata) = DirectoryHandler.FromDirectory(directory, (path, formatting) => FromFile(path, config, formatting)); - song ??= new(); - - PropertyMerger.Merge(song.Metadata, true, true, metadata); - - return song; - } - public static async Task FromDirectoryAsync(string directory, ReadingConfiguration? config = default, CancellationToken cancellationToken = default) - { - (var song, var metadata) = await DirectoryHandler.FromDirectoryAsync(directory, async (path, formatting) => await FromFileAsync(path, config, formatting, cancellationToken), cancellationToken); - song ??= new(); - - PropertyMerger.Merge(song.Metadata, true, true, metadata); - - return song; - } - #endregion - - /// - /// Writes the to a file. - /// - /// - /// - /// - /// - /// - /// - /// - /// - public void ToFile(string path, WritingConfiguration? config = default) => ExtensionHandler.Write(path, this, (".chart", (path, song) => ChartFile.WriteSong(path, song, config))); - public async Task ToFileAsync(string path, WritingConfiguration? config = default, CancellationToken cancellationToken = default) => await ExtensionHandler.WriteAsync(path, this, (".chart", (path, song) => ChartFile.WriteSongAsync(path, song, config, cancellationToken))); - - /// - /// Retrieves the lyrics from the global events. - /// - public IEnumerable GetLyrics() => GlobalEvents is null ? Enumerable.Empty() : GlobalEvents.GetLyrics(); - /// - /// Replaces phrase and lyric events from with the ones making up a set of . - /// - /// Phrases to use as a replacement - public void SetLyrics(IEnumerable phrases) => GlobalEvents = (GlobalEvents ?? new()).SetLyrics(phrases).ToList(); -} diff --git a/source - Copie/Special/InstrumentSpecialPhrase.cs b/source - Copie/Special/InstrumentSpecialPhrase.cs deleted file mode 100644 index 7e052cb0..00000000 --- a/source - Copie/Special/InstrumentSpecialPhrase.cs +++ /dev/null @@ -1,37 +0,0 @@ -namespace ChartTools; - -/// -/// Phrase related to an instrument that triggers an in-game event. -/// -public class InstrumentSpecialPhrase : SpecialPhrase -{ - /// - /// Type of the phrase that drives the gameplay effect - /// - public InstrumentSpecialPhraseType Type - { - get - { - var typeEnum = (InstrumentSpecialPhraseType)TypeCode; - return Enum.IsDefined(typeEnum) ? typeEnum : InstrumentSpecialPhraseType.Unknown; - } - set => TypeCode = value == InstrumentSpecialPhraseType.Unknown ? throw new ArgumentException($"{InstrumentSpecialPhraseType.Unknown} is not a valid explicit value.", nameof(value)) : (byte)value; - } - - /// - /// Creates an instance of . - /// - /// Effect of the phrase - /// - public InstrumentSpecialPhrase(uint position, InstrumentSpecialPhraseType type, uint length = 0) : base(position, (byte)type, length) { } - /// - /// - /// - /// - public InstrumentSpecialPhrase(uint position, byte typeCode, uint length = 0) : base(position, typeCode, length) { } - - public override bool Equals(object? obj) => Equals(obj as TrackSpecialPhrase); - public bool Equals(TrackSpecialPhrase? other) => base.Equals(other); - - public override int GetHashCode() => base.GetHashCode(); -} diff --git a/source - Copie/Special/SpecialPhrase.cs b/source - Copie/Special/SpecialPhrase.cs deleted file mode 100644 index 1c7e9a5d..00000000 --- a/source - Copie/Special/SpecialPhrase.cs +++ /dev/null @@ -1,28 +0,0 @@ -namespace ChartTools; - -/// -/// Base class for phrases that define an in-game event with a duration such as star power. -/// -public abstract class SpecialPhrase : TrackObjectBase, ILongTrackObject -{ - /// - /// Numerical value of the phrase type - /// - public byte TypeCode { get; set; } - /// - /// Duration of the phrase in ticks - /// - public uint Length { get; set; } - - /// - /// Base constructor of special phrases. - /// - /// Position of the phrase - /// Effect of the phrase - /// Duration in ticks - public SpecialPhrase(uint position, byte typeCode, uint length = 0) : base(position) - { - TypeCode = typeCode; - Length = length; - } -} diff --git a/source - Copie/Special/TrackSpecialPhrase.cs b/source - Copie/Special/TrackSpecialPhrase.cs deleted file mode 100644 index 273535b1..00000000 --- a/source - Copie/Special/TrackSpecialPhrase.cs +++ /dev/null @@ -1,39 +0,0 @@ -namespace ChartTools; - -/// -/// Phrase related to a track that triggers an in-game event. -/// -public class TrackSpecialPhrase : SpecialPhrase -{ - /// - /// Type of the phrase that drives the gameplay effect - /// - public TrackSpecialPhraseType Type - { - get - { - var typeEnum = (TrackSpecialPhraseType)TypeCode; - return Enum.IsDefined(typeEnum) ? typeEnum : TrackSpecialPhraseType.Unknown; - } - set => TypeCode = value == TrackSpecialPhraseType.Unknown ? throw new ArgumentException($"{TrackSpecialPhraseType.Unknown} is not a valid explicit value.", nameof(value)) : (byte)value; - } - - public bool IsFaceOff => Type is TrackSpecialPhraseType.Player1FaceOff or TrackSpecialPhraseType.Player2FaceOff; - - /// - /// Creates an instance of . - /// - /// Effect of the phrase - /// - public TrackSpecialPhrase(uint position, TrackSpecialPhraseType type, uint length = 0) : base(position, (byte)type, length) { } - /// - /// - /// - /// - public TrackSpecialPhrase(uint position, byte typeCode, uint length = 0) : base(position, typeCode, length) { } - - public override bool Equals(object? obj) => Equals(obj as TrackSpecialPhrase); - public bool Equals(TrackSpecialPhrase? other) => base.Equals(other); - - public override int GetHashCode() => base.GetHashCode(); -} diff --git a/source - Copie/Sync/SyncTrack.cs b/source - Copie/Sync/SyncTrack.cs deleted file mode 100644 index a48712b0..00000000 --- a/source - Copie/Sync/SyncTrack.cs +++ /dev/null @@ -1,40 +0,0 @@ -using ChartTools.IO; -using ChartTools.IO.Chart; -using ChartTools.IO.Configuration; - -namespace ChartTools; - -/// -/// Set of markers that define the time signature and tempo -/// -public class SyncTrack : IEmptyVerifiable -{ - /// - public bool IsEmpty => Tempo.Count == 0 && TimeSignatures.Count == 0; - - /// - /// Tempo markers - /// - public TempoMap Tempo { get; } = new(); - /// - /// Time signature markers - /// - public List TimeSignatures { get; } = new(); - - /// - /// Reads a from a file. - /// - /// Path of the file - /// - public static SyncTrack FromFile(string path, ReadingConfiguration? config = default) => ExtensionHandler.Read(path, (".chart", path => ChartFile.ReadSyncTrack(path, config))); - /// - /// Reads a from a file asynchronously using multitasking. - /// - /// - /// Token to request cancellation - /// - /// - public static async Task FromFileAsync(string path, ReadingConfiguration? config = default, CancellationToken cancellationToken = default) => await ExtensionHandler.ReadAsync(path, (".chart", path => ChartFile.ReadSyncTrackAsync(path, config, cancellationToken))); - public void ToFile(string path, WritingConfiguration? config = default) => ExtensionHandler.Write(path, this, (".chart", (path, track) => ChartFile.ReplaceSyncTrack(path, track, config))); - public async Task ToFileAsync(string path, WritingConfiguration? config = default, CancellationToken cancellationToken = default) => await ExtensionHandler.WriteAsync(path, this, (".chart", (path, track) => ChartFile.ReplaceSyncTrackAsync(path, track, config, cancellationToken))); -} diff --git a/source - Copie/Sync/Tempo.cs b/source - Copie/Sync/Tempo.cs deleted file mode 100644 index e708d202..00000000 --- a/source - Copie/Sync/Tempo.cs +++ /dev/null @@ -1,86 +0,0 @@ -namespace ChartTools; - -/// -/// Marker that alters the tempo -/// -public class Tempo : TrackObjectBase -{ - /// - /// Parent map the marker is contained - /// - public TempoMap? Map - { - get => _map; - internal set - { - if (value is not null) - PositionSynced = false; - - _map = value; - } - } - private TempoMap? _map; - - /// - /// Only refer to the position if is . - public override uint Position - { - get => _position; - set - { - _position = value; - - if (Anchor is not null) - PositionSynced = false; - } - } - private uint _position; - - /// - /// New tempo in beats per minute - /// - public float Value { get; set; } - - /// - /// Locks the tempo to a specific real-time position independent of the sync track. - /// - public TimeSpan? Anchor - { - get => _anchor; - set - { - var valueNull = value is null; - - if (valueNull) - { - if (_anchor is not null) - Map?.RemoveAnchor(this); - } - else if (_anchor is null) - Map?.AddAnchor(this); - - _anchor = value; - PositionSynced = valueNull; - } - } - private TimeSpan? _anchor; - - /// - /// Indicates if the tick position is up to date with . - /// - /// if the marker has no anchor. - public bool PositionSynced { get; private set; } = true; - - /// - /// Creates an instance of . - /// - public Tempo(uint position, float value) : base(position) => Value = value; - public Tempo(TimeSpan anchor, float value) : this(0, value) => Anchor = anchor; - - internal void SyncPosition(uint position) - { - _position = position; - PositionSynced = true; - } - internal void DesyncPosition() => PositionSynced = false; -} diff --git a/source - Copie/Sync/TempoMap.cs b/source - Copie/Sync/TempoMap.cs deleted file mode 100644 index 59f0c05f..00000000 --- a/source - Copie/Sync/TempoMap.cs +++ /dev/null @@ -1,208 +0,0 @@ -using System.Collections; - -namespace ChartTools; - -/// -/// Set of tempo markers that handles synchronism of anchored tempos. -/// -public class TempoMap : IList -{ - private readonly List _items = new(); - private readonly List _anchors = new(); - - public Tempo this[int index] - { - get => _items[index]; - set => _items[index] = value; - } - public int Count => _items.Count; - bool ICollection.IsReadOnly => false; - /// - /// Indicates if all anchored markers are synchronized. - /// - public bool Synchronized { get; private set; } - - private void AddBase(Tempo item) - { - item.Map = this; - - if (item.Anchor is not null) - _anchors.Add(item); - } - public void Add(Tempo item) - { - if (item is null) - throw new ArgumentNullException(nameof(item)); - - _items.Add(item); - - AddBase(item); - Desync(); - } - public void AddRange(IEnumerable items) - { - foreach (var item in items) - { - _items.Add(item); - AddBase(item); - } - - Desync(); - } - public void Clear() => _items.Clear(); - public void Clear(bool detachMap) - { - if (detachMap) - foreach (var tempo in _items) - tempo.Map = null; - - _items.Clear(); - } - public bool Contains(Tempo item) => _items.Contains(item); - public void CopyTo(Tempo[] array, int arrayIndex) => _items.CopyTo(array, arrayIndex); - public int IndexOf(Tempo item) => _items.IndexOf(item); - public void Insert(int index, Tempo item) - { - _items.Insert(index, item); - - AddBase(item); - Desync(); - } - public void InsertRange(int index, IEnumerable items) - { - foreach (var item in items) - { - _items.Insert(index, item); - AddBase(item); - } - - Desync(); - } - public bool Remove(Tempo item) => Remove(item, false); - public bool Remove(Tempo item, bool detachMap) - { - if (detachMap) - item.Map = null; - - if (item.Anchor is not null) - _anchors.Remove(item); - - var found = _items.Remove(item); - Desync(); - return found; - } - public void RemoveAt(int index) - { - _items.RemoveAt(index); - - var item = _items[index]; - if (item.Anchor is not null) - _anchors.Remove(item); - - Desync(); - } - public void RemoveAt(int index, bool detachMap) - { - if (detachMap) - { - var tempo = _items[index]; - tempo.Map = null; - } - - _items.RemoveAt(index); - - var item = _items[index]; - if (item.Anchor is not null) - _anchors.Remove(item); - - Desync(); - } - - public IEnumerator GetEnumerator() => _items.GetEnumerator(); - IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); - - /// - /// Synchronizes anchored markers by calculating their tick position. - /// - /// - /// - /// - public void Synchronize(uint resolution, bool desyncedPreOrdered = false) - { - if (Synchronized) - return; - - List synced = new(); - List desynced = new(); - - // Split synced and desynced. Sync 0 anchors. - foreach (var tempo in _items) - { - if (tempo.PositionSynced) - synced.Add(tempo); - else if (tempo.Anchor!.Value == TimeSpan.Zero) - { - tempo.SyncPosition(0); - synced.Add(tempo); - } - else - desynced.Add(tempo); - } - - if (desynced.Count == 0) - return; - - using var syncedEnumerator = (desyncedPreOrdered ? (IEnumerable)synced : synced.OrderBy(t => t.Position)).GetEnumerator(); - - if (!syncedEnumerator.MoveNext() || syncedEnumerator.Current.Position != 0) - throw new Exception("A tempo marker at position or anchor zero is required to sync anchors."); - - using var desyncedEnumerator = desynced.OrderBy(t => t.Anchor).GetEnumerator(); - - syncedEnumerator.MoveNext(); - desyncedEnumerator.MoveNext(); - - var previous = syncedEnumerator.Current; - var previousMs = 0ul; - - while (syncedEnumerator.MoveNext()) - while (TryInsertDesynced(syncedEnumerator.Current)) - if (!desyncedEnumerator.MoveNext()) - return; - - while (desyncedEnumerator.MoveNext()) - SyncAnchor(); - return; - - bool TryInsertDesynced(Tempo next) - { - var deltaMs = previous.Value * 50 / 3 * ((next.Position - previous.Position) / resolution); - - if (desyncedEnumerator.Current.Anchor!.Value.TotalMilliseconds - previousMs <= deltaMs) - { - SyncAnchor(); - return true; - } - - previous = next; - return false; - } - void SyncAnchor() - { - var desynced = desyncedEnumerator.Current; - desynced.SyncPosition((uint)((desynced.Anchor!.Value.TotalMilliseconds - previousMs) * previous.Value * resolution / 240000)); - - previous = desynced; - } - } - internal void Desync() - { - foreach (var tempo in _anchors) - tempo.DesyncPosition(); - - Synchronized = false; - } - - internal void AddAnchor(Tempo item) => _anchors.Add(item); - internal void RemoveAnchor(Tempo item) => _anchors.Remove(item); -} diff --git a/source - Copie/Sync/TimeSignature.cs b/source - Copie/Sync/TimeSignature.cs deleted file mode 100644 index a5870cec..00000000 --- a/source - Copie/Sync/TimeSignature.cs +++ /dev/null @@ -1,28 +0,0 @@ -namespace ChartTools; - -/// -/// Marker that alters the time signature -/// -public class TimeSignature : TrackObjectBase -{ - /// - /// Value of a beat - /// - public byte Numerator { get; set; } - /// - /// Beats per measure - /// - public byte Denominator { get; set; } - - /// - /// Creates an instance of . - /// - /// Value of - /// Value of - /// Value of - public TimeSignature(uint position, byte numerator, byte denominator) : base(position) - { - Numerator = numerator; - Denominator = denominator; - } -} diff --git a/source - Copie/Tools/LengthMerger.cs b/source - Copie/Tools/LengthMerger.cs deleted file mode 100644 index e7fd610a..00000000 --- a/source - Copie/Tools/LengthMerger.cs +++ /dev/null @@ -1,16 +0,0 @@ -namespace ChartTools.Tools; - -public static class LengthMerger -{ - public static T MergeLengths(this IEnumerable objects, T? target = null) where T : class, ILongTrackObject - { - var start = objects.Min(o => o.Position); - var end = objects.Max(o => o.EndPosition); - target ??= objects.First(); - - target.Position = start; - target.Length = end - start; - - return target; - } -} diff --git a/source - Copie/Tools/Optimizer.cs b/source - Copie/Tools/Optimizer.cs deleted file mode 100644 index 8814e272..00000000 --- a/source - Copie/Tools/Optimizer.cs +++ /dev/null @@ -1,153 +0,0 @@ -using ChartTools.Extensions.Linq; -using ChartTools.IO.Formatting; - -using System.Data; - -namespace ChartTools.Tools; - -/// -/// Provides methods for simplifying songs -/// -public static class Optimizer -{ - internal static bool LengthNeedsCut(ILongTrackObject current, ILongTrackObject next) => current.Position + current.Length > next.Position; - - /// - /// Cuts short sustains that exceed the position of the next note preventing the sustain from continuing. - /// - /// Chords to cut the sustains of - /// Skip ordering of chords by position - public static void CutSustains(this IEnumerable chords, bool preOrdered = false) where T : LaneChord - { - var sustains = new Dictionary(); - - foreach (var chord in GetOrdered(chords, preOrdered)) - { - if (chord.Notes.Count == 0) - continue; - - using var noteEnumerator = chord.Notes.GetEnumerator(); - noteEnumerator.MoveNext(); - - var note = noteEnumerator.Current; - - if (chord.OpenExclusivity) - { - if (noteEnumerator.Current.Index == 0) // Open stops all sustains - foreach ((var position, var sustained) in sustains.Values) - { - if (position + sustained.Sustain > chord.Position) - sustained.Sustain = chord.Position; - - sustains.Remove(noteEnumerator.Current.Index); - } - else - RemoveSustain(0); // Non-opens stops open sustain - } - else - RemoveSustain(note.Index); - - AddSustain(); - - while (noteEnumerator.MoveNext()) - { - note = noteEnumerator.Current; - - RemoveSustain(note.Index); - AddSustain(); - } - - void AddSustain() - { - if (noteEnumerator.Current.Sustain > 0) - sustains[noteEnumerator.Current.Index] = (chord.Position, noteEnumerator.Current); - } - void RemoveSustain(byte index) - { - if (sustains.TryGetValue(index, out var sustained)) - { - sustained.Item2.Sustain = chord.Position; - sustains.Remove(index); - } - } - } - } - - /// - /// Cuts lengths of special phrases based on the numeric value of the type. - /// - /// Set of phrases - /// Skip ordering of phrases by position - /// Passed phrases ordered by position and grouped by type - /// - public static List[] CutSpecialLengths(IEnumerable phrases, bool preOrdered = false) where T : SpecialPhrase - { - if (typeof(T) == typeof(SpecialPhrase)) - throw new InvalidOperationException($"Collection must be of a type deriving from {nameof(SpecialPhrase)}."); - - var output = phrases.GroupBy(p => p.TypeCode).Select(g => g.ToList()).ToArray(); - - foreach (var grouping in output) - grouping.CutLengths(preOrdered); - - return output; - } - - /// - /// Cuts short long track objects that exceed the start of the next one. - /// - /// Set of long track objects - /// Skip ordering of objects by position - public static void CutLengths(this IEnumerable objects, bool preOrdered = false) where T : ILongTrackObject - { - foreach ((var current, var next) in GetOrdered(objects, preOrdered).RelativeLoopSkipFirst()) - if (LengthNeedsCut(current, next)) - next.Length = current.Position - current.Position; - } - - /// - /// Removes redundant tempo markers. - /// - /// Tempo markers without anchors. - /// Skip ordering of markers by position. - /// - /// If some markers may be anchored, use the overload with a resolution. - public static void RemoveUneeded(this ICollection markers, bool preOrdered = false) - { - if (markers.TryGetFirst(m => !m.PositionSynced, out var marker)) - throw new DesynchronizedAnchorException(marker.Anchor!.Value, $"Collection contains a desynchronized anchored tempo at {marker.Anchor}. Resolution needed to synchronize anchors."); - - foreach ((var previous, var current) in GetOrdered(markers, preOrdered).RelativeLoopSkipFirst()) - if (previous.Value == current.Value) - markers.Remove(current); - } - /// - /// Removes redundant tempo markers by syncing the position of anchored markers. - /// - /// Set of markers - /// Resolution from - /// Skip ordering of desynced markers by position - public static void RemoveUneeded(this TempoMap markers, uint resolution, bool desyncedPreOrdered = false) - { - markers.Synchronize(resolution, desyncedPreOrdered); - - foreach ((var previous, var current) in markers.OrderBy(m => m.Position).RelativeLoopSkipFirst()) - if (current.Value == previous!.Value) - markers.Remove(current); - } - - /// - /// Removes redundant time signature markers. - /// - /// Time signatures to remove the unneeded from - /// Skip ordering of markers by position - /// Passed markers, ordered by position. Same instance if is and is . - public static void RemoveUnneeded(this ICollection signatures, bool preOrdered = false) - { - foreach ((var previous, var current) in GetOrdered(signatures, preOrdered).RelativeLoopSkipFirst()) - if (previous.Numerator == current.Numerator && previous.Denominator == current.Denominator) - signatures.Remove(current); - } - - private static IEnumerable GetOrdered(IEnumerable items, bool preOredered) where T : ITrackObject => preOredered ? items : items.OrderBy(i => i.Position); -} diff --git a/source - Copie/Tools/Printer.cs b/source - Copie/Tools/Printer.cs deleted file mode 100644 index f43918dd..00000000 --- a/source - Copie/Tools/Printer.cs +++ /dev/null @@ -1,89 +0,0 @@ -namespace ChartTools.Tools; - -public static class Printer -{ - private readonly struct ConsoleContent - { - public string Content { get; } - public ConsoleColor Color { get; } - - public ConsoleContent(string content, ConsoleColor color) - { - Content = content; - Color = color; - } - } - - public static void PrintTrack(Track track) - { - var content = new List>(); - uint[] sustainEnds = new uint[6]; - ConsoleColor[] laneColors = new ConsoleColor[] - { - ConsoleColor.Green, - ConsoleColor.Red, - ConsoleColor.Yellow, - ConsoleColor.Blue, - ConsoleColor.DarkYellow - }; - - foreach (var chord in track.Chords.Where(c => c.Notes.Count > 0).OrderBy(t => t.Position)) - { - var open = chord.Notes[StandardLane.Open]; - var lineContent = new List(); - - if (open is not null) - { - lineContent.Add(new("-----", ConsoleColor.Magenta)); - - SetSustainEnd(open); - - for (int i = 1; i < sustainEnds.Length; i++) - sustainEnds[i] = chord.Position; - } - else - { - if (chord.Notes.Count == 0) - lineContent.Add(new(sustainEnds[0] >= chord.Position ? " | " : " ", ConsoleColor.Magenta)); - else - for (int i = 1; i < 6; i++) - { - var note = chord.Notes[(StandardLane)i]; - string text; - - if (note is null) - text = sustainEnds[i] >= chord.Position ? "|" : " "; - else - { - text = "O"; - SetSustainEnd(note); - } - - lineContent.Add(new(text, laneColors[i - 1])); - } - } - - content.Add(lineContent); - - void SetSustainEnd(LaneNote note) => sustainEnds[(int)note.Lane] = chord.Position + note.Sustain; - } - - PrintLines(content); - } - - private static void PrintLines(IEnumerable> content) - { - foreach (var line in content.Reverse()) - { - Console.WriteLine(); - - foreach (var ct in line) - { - Console.ForegroundColor = ct.Color; - Console.Write(ct.Content); - } - } - - Console.ResetColor(); - } -} diff --git a/source - Copie/Tools/PropertyMerger.cs b/source - Copie/Tools/PropertyMerger.cs deleted file mode 100644 index 2930013b..00000000 --- a/source - Copie/Tools/PropertyMerger.cs +++ /dev/null @@ -1,49 +0,0 @@ -using System.Reflection; -using ChartTools.Extensions.Linq; - -namespace ChartTools.Tools; - -/// -/// Provides methods to merge properties between two instances -/// -public static class PropertyMerger -{ - /// - /// Replaces the property values of an instance with the first non-null equivalent from other instances. - /// - /// If overwriteNonNull is , only replaces property values that are null in the original instance. - /// Item to assign the property values to - /// If , only replaces property values that are null in the original instance. - /// Items to pull new property values from in order of priority - public static void Merge(this T current, bool overwriteNonNull, bool deepMerge, params T[] newValues) - { - T? newValue = current; - var stringType = typeof(string); - var nullableType = typeof(Nullable); - - foreach (var prop in GetProperties(typeof(T))) - MergeValue(current, prop, GetValues(newValues.Cast(), prop)); - - void MergeValue(object? source, PropertyInfo prop, IEnumerable newValues) - { - var value = prop.GetValue(source); - - if (deepMerge && !prop.PropertyType.IsPrimitive && prop.PropertyType != stringType && Nullable.GetUnderlyingType(prop.PropertyType) is null) - { - if (value is not null) - foreach (var deepProp in GetProperties(prop.PropertyType)) - MergeValue(value, deepProp, GetValues(newValues, deepProp)); - } - else if (value is null || overwriteNonNull) - { - var newVal = newValues.FirstOrDefault(newVal => newVal is not null); - - if (newVal is not null) - prop.SetValue(source, newVal); - } - } - - IEnumerable GetProperties(Type type) => type.GetProperties().Where(i => i.CanWrite); - IEnumerable GetValues(IEnumerable sources, PropertyInfo prop) => sources.Select(s => prop.GetValue(s)).NonNull(); - } -} diff --git a/source - Copie/Tools/TempoRescaler.cs b/source - Copie/Tools/TempoRescaler.cs deleted file mode 100644 index 54ebef73..00000000 --- a/source - Copie/Tools/TempoRescaler.cs +++ /dev/null @@ -1,103 +0,0 @@ -namespace ChartTools.Tools; - -public static class TempoRescaler -{ - /// - /// Rescales the length a long object. - /// - /// Object to rescale - /// Positive number where 1 is the current scale. - public static void Rescale(this ILongObject obj, float scale) => obj.Length = (uint)(obj.Length * scale); - /// - /// Rescales the position of a track object - /// - /// Object to rescale - /// Positive number where 1 is the current scale. - public static void Rescale(this ITrackObject trackObject, float scale) => trackObject.Position = (uint)(trackObject.Position * scale); - /// - /// Rescales the position and length of a long track object - /// - /// Object to rescale - /// Positive number where 1 is the current scale. - public static void Rescale(this ILongTrackObject trackObject, float scale) - { - trackObject.Position = (uint)(trackObject.Position * scale); - trackObject.Length = (uint)(trackObject.Length * scale); - } - - /// - /// Rescales the position and value of a tempo marker. - /// - /// Marker to rescale - /// Positive number where 1 is the current scale. - public static void Rescale(this Tempo tempo, float scale) - { - tempo.Position = (uint)(tempo.Position * scale); - tempo.Value *= scale; - } - /// - /// Rescales the position of a chord and sustain of its notes. - /// - /// Chord to rescale - /// Positive number where 1 is the current scale. - public static void Rescale(this IChord chord, float scale) - { - chord.Position = (uint)(chord.Position * scale); - - foreach (var note in chord.Notes) - note.Rescale(scale); - } - /// - /// Rescales the chords in a track. - /// - /// Source of chords - /// Positive number where 1 is the current scale. - public static void Rescale(this Track track, float scale) - { - foreach (var chord in track.Chords) - Rescale(chord, scale); - - if (track.LocalEvents is not null) - foreach (var e in track.LocalEvents) - e.Rescale(scale); - } - /// - /// Rescales all tracks in an instrument. - /// - /// Source of the tracks - /// Positive number where 1 is the current scale. - public static void Rescale(this Instrument instrument, float scale) - { - foreach (var track in instrument.GetExistingTracks()) - track.Rescale(scale); - } - - /// - /// Rescales the tempo and time signatures in a song. - /// - /// Source of markers - /// Positive number where 1 is the current scale. - public static void Rescale(this SyncTrack syncTrack, float scale) - { - foreach (var tempo in syncTrack.Tempo) - tempo.Rescale(scale); - foreach (var signature in syncTrack.TimeSignatures) - signature.Rescale(scale); - } - /// - /// Rescales all instruments, tempo and time signatures. - /// - /// Source of objects - /// Positive number where 1 is the current scale. - public static void Rescale(this Song song, float scale) - { - foreach (var instrument in song.Instruments) - instrument.Rescale(scale); - - song.SyncTrack?.Rescale(scale); - - if (song.GlobalEvents is not null) - foreach (var e in song.GlobalEvents) - e.Rescale(scale); - } -} diff --git a/source - Copie/TrackObjects/ILongTrackObject.cs b/source - Copie/TrackObjects/ILongTrackObject.cs deleted file mode 100644 index 3e2464d0..00000000 --- a/source - Copie/TrackObjects/ILongTrackObject.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace ChartTools; - -public interface ILongTrackObject : ITrackObject, ILongObject -{ - /// - /// Tick number marking the end of the object - /// - public uint EndPosition => Position + Length; -} diff --git a/source - Copie/TrackObjects/IReadOnlyTrackObject.cs b/source - Copie/TrackObjects/IReadOnlyTrackObject.cs deleted file mode 100644 index 61ec6efc..00000000 --- a/source - Copie/TrackObjects/IReadOnlyTrackObject.cs +++ /dev/null @@ -1,15 +0,0 @@ -namespace ChartTools; - -/// -/// Object located on a track -/// -public interface IReadOnlyTrackObject : IEquatable -{ - /// - /// Tick number on the track. - /// - /// A tick represents a subdivision of a beat. The number of subdivisions per beat is stored in . - public uint Position { get; } - - bool IEquatable.Equals(IReadOnlyTrackObject? other) => other is not null && other.Position == Position; -} diff --git a/source - Copie/TrackObjects/ITrackObject.cs b/source - Copie/TrackObjects/ITrackObject.cs deleted file mode 100644 index 2598e676..00000000 --- a/source - Copie/TrackObjects/ITrackObject.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace ChartTools; - -/// -public interface ITrackObject : IReadOnlyTrackObject -{ - /// - public new uint Position { get; set; } - - uint IReadOnlyTrackObject.Position => Position; -} diff --git a/source - Copie/TrackObjects/TrackObjectBase.cs b/source - Copie/TrackObjects/TrackObjectBase.cs deleted file mode 100644 index a572237c..00000000 --- a/source - Copie/TrackObjects/TrackObjectBase.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace ChartTools; - -public abstract class TrackObjectBase : ITrackObject -{ - public virtual uint Position { get; set; } - - public TrackObjectBase() : this(0) { } - public TrackObjectBase(uint position) => Position = position; -} diff --git a/source - Copie/Tracks/Track.cs b/source - Copie/Tracks/Track.cs deleted file mode 100644 index 8210fec8..00000000 --- a/source - Copie/Tracks/Track.cs +++ /dev/null @@ -1,133 +0,0 @@ -using ChartTools.Events; -using ChartTools.IO; -using ChartTools.IO.Chart; -using ChartTools.IO.Configuration; -using ChartTools.IO.Formatting; - -namespace ChartTools; - -/// -/// Base class for tracks -/// -public abstract record Track : IEmptyVerifiable -{ - /// - public bool IsEmpty => Chords.Count == 0 && LocalEvents.Count == 0 && SpecialPhrases.Count == 0; - - /// - /// Difficulty of the track - /// - public Difficulty Difficulty { get; init; } - /// - /// Instrument containing the track - /// - public Instrument? ParentInstrument => GetInstrument(); - /// - /// Events specific to the - /// - public List LocalEvents { get; } = new(); - /// - /// Set of special phrases - /// - public List SpecialPhrases { get; } = new(); - - /// - /// Groups of notes of the same position - /// - public IReadOnlyList Chords => GetChords(); - - protected abstract IReadOnlyList GetChords(); - - internal IEnumerable SoloToStarPower(bool removeEvents) - { - if (LocalEvents is null) - yield break; - - foreach (LocalEvent e in LocalEvents.OrderBy(e => e.Position)) - { - TrackSpecialPhrase? phrase = null; - - switch (e.EventType) - { - case EventTypeHelper.Local.Solo: - phrase = new(e.Position, TrackSpecialPhraseType.StarPowerGain); - break; - case EventTypeHelper.Local.SoloEnd: - if (phrase is not null) - { - phrase.Length = e.Position - phrase.Position; - yield return phrase; - phrase = null; - } - break; - } - } - - if (removeEvents) - LocalEvents.RemoveAll(e => e.IsSoloEvent); - } - - protected abstract Instrument? GetInstrument(); - - #region File reading - #region Single file - [Obsolete($"Use {nameof(ChartFile.ReadTrack)}.")] - public static Track FromFile(string path, InstrumentIdentity instrument, Difficulty difficulty, ReadingConfiguration? config = default, FormattingRules? formatting = default) => ExtensionHandler.Read(path, (".chart", path => ChartFile.ReadTrack(path, instrument, difficulty, config, formatting))); - - [Obsolete($"Use {nameof(ChartFile.ReadTrackAsync)}.")] - public static async Task FromFileAsync(string path, InstrumentIdentity instrument, Difficulty difficulty, ReadingConfiguration? config = default, FormattingRules? formatting = default, CancellationToken cancellationToken = default) => await ExtensionHandler.ReadAsync(path, (".chart", path => ChartFile.ReadTrackAsync(path, instrument, difficulty, config, formatting, cancellationToken))); - - [Obsolete($"Use {nameof(ChartFile.ReadDrumsTrack)}.")] - public static Track FromFile(string path, Difficulty difficulty, ReadingConfiguration? config = default, FormattingRules? formatting = default) => ExtensionHandler.Read>(path, (".chart", path => ChartFile.ReadDrumsTrack(path, difficulty, config, formatting))); - - [Obsolete($"Use {nameof(ChartFile.ReadDrumsTrackAsync)}.")] - public static async Task> FromFileAsync(string path, Difficulty difficulty, ReadingConfiguration? config = default, FormattingRules? formatting = default, CancellationToken cancellationToken = default) => await ExtensionHandler.ReadAsync>(path, (".chart", path => ChartFile.ReadDrumsTrackAsync(path, difficulty, config, formatting, cancellationToken))); - - [Obsolete($"Use {nameof(ChartFile.ReadTrack)}.")] - public static Track FromFile(string path, GHLInstrumentIdentity instrument, Difficulty difficulty, ReadingConfiguration? config = default, FormattingRules? formatting = default) => ExtensionHandler.Read>(path, (".chart", path => ChartFile.ReadTrack(path, instrument, difficulty, config, formatting))); - - [Obsolete($"Use {nameof(ChartFile.ReadTrackAsync)}.")] - public static async Task> FromFileAsync(string path, GHLInstrumentIdentity instrument, Difficulty difficulty, ReadingConfiguration? config = default, FormattingRules? formatting = default, CancellationToken cancellationToken = default) => await ExtensionHandler.ReadAsync>(path, (".chart", path => ChartFile.ReadTrackAsync(path, instrument, difficulty, config, formatting, cancellationToken))); - - [Obsolete($"Use {nameof(ChartFile.ReadTrack)}.")] - public static Track FromFile(string path, StandardInstrumentIdentity instrument, Difficulty difficulty, ReadingConfiguration? config = default, FormattingRules? formatting = default) => ExtensionHandler.Read>(path, (".chart", path => ChartFile.ReadTrack(path, instrument, difficulty, config, formatting))); - - [Obsolete($"Use {nameof(ChartFile.ReadTrackAsync)}.")] - public static async Task> FromFileAsync(string path, StandardInstrumentIdentity instrument, Difficulty difficulty, ReadingConfiguration? config = default, FormattingRules? formatting = default, CancellationToken cancellationToken = default) => await ExtensionHandler.ReadAsync>(path, (".chart", path => ChartFile.ReadTrackAsync(path, instrument, difficulty, config, formatting, cancellationToken))); - #endregion - - #region Directory - [Obsolete($"Use {nameof(ChartFile.ReadTrack)} with {nameof(Metadata.Formatting)}.")] - public static DirectoryResult FromDirectory(string directory, InstrumentIdentity instrument, Difficulty difficulty, ReadingConfiguration? config = default) => DirectoryHandler.FromDirectory(directory, (path, formatting) => FromFile(path, instrument, difficulty, config, formatting)); - - [Obsolete($"Use {nameof(ChartFile.ReadTrackAsync)} with {nameof(Metadata.Formatting)}.")] - public static async Task> FromDirectoryAsync(string directory, InstrumentIdentity instrument, Difficulty difficulty, ReadingConfiguration? config = default, CancellationToken cancellationToken = default) => await DirectoryHandler.FromDirectoryAsync(directory, async (path, formatting) => await FromFileAsync(path, instrument, difficulty, config, formatting, cancellationToken), cancellationToken); - - [Obsolete($"Use {nameof(ChartFile.ReadDrumsTrack)} with {nameof(Metadata.Formatting)}.")] - public static DirectoryResult?> FromDirectory(string directory, Difficulty difficulty, ReadingConfiguration? config = default) => DirectoryHandler.FromDirectory(directory, (path, formatting) => FromFile(path, difficulty, config, formatting)); - - [Obsolete($"Use {nameof(ChartFile.ReadDrumsTrackAsync)} with {nameof(Metadata.Formatting)}.")] - public static async Task?>> FromDirectoryAsync(string directory, Difficulty difficulty, ReadingConfiguration? config = default, CancellationToken cancellationToken = default) => await DirectoryHandler.FromDirectoryAsync(directory, async (path, formatting) => await FromFileAsync(path, difficulty, config, formatting, cancellationToken), cancellationToken); - - [Obsolete($"Use {nameof(ChartFile.ReadTrack)} with {nameof(Metadata.Formatting)}.")] - public static DirectoryResult?> FromDirectory(string directory, GHLInstrumentIdentity instrument, Difficulty difficulty, ReadingConfiguration? config = default) => DirectoryHandler.FromDirectory(directory, (path, formatting) => FromFile(path, instrument, difficulty, config, formatting)); - - [Obsolete($"Use {nameof(ChartFile.ReadTrackAsync)} with {nameof(Metadata.Formatting)}.")] - public static async Task?>> FromDirectoryAsync(string directory, GHLInstrumentIdentity instrument, Difficulty difficulty, ReadingConfiguration? config = default, CancellationToken cancellationToken = default) => await DirectoryHandler.FromDirectoryAsync(directory, async (path, formatting) => await FromFileAsync(path, instrument, difficulty, config, formatting, cancellationToken), cancellationToken); - - [Obsolete($"Use {nameof(ChartFile.ReadTrack)} with {nameof(Metadata.Formatting)}.")] - public static DirectoryResult?> FromDirectory(string directory, StandardInstrumentIdentity instrument, Difficulty difficulty, ReadingConfiguration? config = default) => DirectoryHandler.FromDirectory(directory, (path, formatting) => FromFile(path, instrument, difficulty, config, formatting)); - - [Obsolete($"Use {nameof(ChartFile.ReadTrackAsync)} with {nameof(Metadata.Formatting)}.")] - public static async Task?>> FromDirectoryAsync(string directory, StandardInstrumentIdentity instrument, Difficulty difficulty, ReadingConfiguration? config = default, CancellationToken cancellationToken = default) => await DirectoryHandler.FromDirectoryAsync(directory, async (path, formatting) => await FromFileAsync(path, instrument, difficulty, config, formatting, cancellationToken), cancellationToken); - #endregion - #endregion - - [Obsolete($"Use {nameof(ChartFile.ReplaceTrack)}.")] - public void ToFile(string path, WritingConfiguration? config = default, FormattingRules? formatting = default) => ExtensionHandler.Write(path, this, (".chart", (path, track) => ChartFile.ReplaceTrack(path, track, config, formatting))); - - [Obsolete($"Use {nameof(ChartFile.ReplaceTrackAsync)}.")] - public async Task ToFileAsync(string path, WritingConfiguration? config = default,FormattingRules? formatting = default, CancellationToken cancellationToken = default) => await ExtensionHandler.WriteAsync(path, this, (".chart", (path, track) => ChartFile.ReplaceTrackAsync(path, track, config, formatting, cancellationToken))); - - public override string ToString() => Difficulty.ToString(); -} diff --git a/source - Copie/Tracks/TrackGeneric.cs b/source - Copie/Tracks/TrackGeneric.cs deleted file mode 100644 index 97c1b598..00000000 --- a/source - Copie/Tracks/TrackGeneric.cs +++ /dev/null @@ -1,26 +0,0 @@ -namespace ChartTools; - -/// -/// Set of chords for a instrument at a certain difficulty -/// -public record Track : Track where TChord : IChord -{ - /// - /// Chords making up the difficulty track. - /// - public new List Chords { get; } = new(); - /// - /// Instrument the track is held in. - /// - public new Instrument? ParentInstrument { get; init; } - - /// - /// Gets the chords as a read-only list of the base interface. - /// - /// - protected override IReadOnlyList GetChords() => (IReadOnlyList)Chords; - /// - /// Gets the parent instrument as an instance of the base type. - /// - protected override Instrument? GetInstrument() => ParentInstrument; -} diff --git a/source - Copie/Tracks/UniqueTrackObjectCollection.cs b/source - Copie/Tracks/UniqueTrackObjectCollection.cs deleted file mode 100644 index 5c73b2b9..00000000 --- a/source - Copie/Tracks/UniqueTrackObjectCollection.cs +++ /dev/null @@ -1,39 +0,0 @@ -using System.Collections; - -namespace ChartTools.Extensions.Collections; - -/// -/// Set of track objects where each one must have a different position -/// -public class UniqueTrackObjectCollection : ICollection where T : ITrackObject -{ - private readonly Dictionary items; - - public UniqueTrackObjectCollection(IEnumerable? items = null) => this.items = items is null ? new() : items.ToDictionary(i => i.Position); - - public int Count => items.Count; - bool ICollection.IsReadOnly => false; - - private void RemoveDuplicate(T item) - { - if (items.ContainsKey(item.Position)) - items.Remove(item.Position); - } - - public void Add(T item) - { - RemoveDuplicate(item); - items.Add(item.Position, item); - } - - public void Clear() => items.Clear(); - - public bool Contains(T item) => items.ContainsKey(item.Position); - - public void CopyTo(T[] array, int arrayIndex) => items.Values.CopyTo(array, arrayIndex); - - public bool Remove(T item) => items.Remove(item.Position); - - public IEnumerator GetEnumerator() => items.Values.GetEnumerator(); - IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); -} diff --git a/source - Copie/source.projitems b/source - Copie/source.projitems deleted file mode 100644 index f45ab8a1..00000000 --- a/source - Copie/source.projitems +++ /dev/null @@ -1,166 +0,0 @@ - - - - $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - true - 54924bc3-4a10-45ad-af3c-f17494e403e1 - - - ChartTools - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/source/ChartTools/ChartTools.csproj b/source/ChartTools/ChartTools.csproj deleted file mode 100644 index fa71b7ae..00000000 --- a/source/ChartTools/ChartTools.csproj +++ /dev/null @@ -1,9 +0,0 @@ - - - - net8.0 - enable - enable - - - diff --git a/source/ChartTools/Class1.cs b/source/ChartTools/Class1.cs deleted file mode 100644 index 45152ce6..00000000 --- a/source/ChartTools/Class1.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace ChartTools -{ - public class Class1 - { - - } -} diff --git a/source/ChartTools/obj/ChartTools.csproj.nuget.dgspec.json b/source/ChartTools/obj/ChartTools.csproj.nuget.dgspec.json deleted file mode 100644 index 7900ff52..00000000 --- a/source/ChartTools/obj/ChartTools.csproj.nuget.dgspec.json +++ /dev/null @@ -1,67 +0,0 @@ -{ - "format": 1, - "restore": { - "C:\\Users\\joujo\\OneDrive\\Documents\\GitHub\\charttools\\source\\ChartTools\\ChartTools.csproj": {} - }, - "projects": { - "C:\\Users\\joujo\\OneDrive\\Documents\\GitHub\\charttools\\source\\ChartTools\\ChartTools.csproj": { - "version": "1.0.0", - "restore": { - "projectUniqueName": "C:\\Users\\joujo\\OneDrive\\Documents\\GitHub\\charttools\\source\\ChartTools\\ChartTools.csproj", - "projectName": "ChartTools", - "projectPath": "C:\\Users\\joujo\\OneDrive\\Documents\\GitHub\\charttools\\source\\ChartTools\\ChartTools.csproj", - "packagesPath": "C:\\Users\\joujo\\.nuget\\packages\\", - "outputPath": "C:\\Users\\joujo\\OneDrive\\Documents\\GitHub\\charttools\\source\\ChartTools\\obj\\", - "projectStyle": "PackageReference", - "fallbackFolders": [ - "C:\\Program Files (x86)\\Microsoft Visual Studio\\Shared\\NuGetPackages" - ], - "configFilePaths": [ - "C:\\Users\\joujo\\AppData\\Roaming\\NuGet\\NuGet.Config", - "C:\\Program Files (x86)\\NuGet\\Config\\Microsoft.VisualStudio.FallbackLocation.config", - "C:\\Program Files (x86)\\NuGet\\Config\\Microsoft.VisualStudio.Offline.config" - ], - "originalTargetFrameworks": [ - "net8.0" - ], - "sources": { - "C:\\Program Files (x86)\\Microsoft SDKs\\NuGetPackages\\": {}, - "https://api.nuget.org/v3/index.json": {} - }, - "frameworks": { - "net8.0": { - "targetAlias": "net8.0", - "projectReferences": {} - } - }, - "warningProperties": { - "warnAsError": [ - "NU1605" - ] - } - }, - "frameworks": { - "net8.0": { - "targetAlias": "net8.0", - "imports": [ - "net461", - "net462", - "net47", - "net471", - "net472", - "net48", - "net481" - ], - "assetTargetFallback": true, - "warn": true, - "frameworkReferences": { - "Microsoft.NETCore.App": { - "privateAssets": "all" - } - }, - "runtimeIdentifierGraphPath": "C:\\Program Files\\dotnet\\sdk\\8.0.100/PortableRuntimeIdentifierGraph.json" - } - } - } - } -} \ No newline at end of file diff --git a/source/ChartTools/obj/ChartTools.csproj.nuget.g.props b/source/ChartTools/obj/ChartTools.csproj.nuget.g.props deleted file mode 100644 index 4b04bbd9..00000000 --- a/source/ChartTools/obj/ChartTools.csproj.nuget.g.props +++ /dev/null @@ -1,16 +0,0 @@ - - - - True - NuGet - $(MSBuildThisFileDirectory)project.assets.json - $(UserProfile)\.nuget\packages\ - C:\Users\joujo\.nuget\packages\;C:\Program Files (x86)\Microsoft Visual Studio\Shared\NuGetPackages - PackageReference - 6.8.0 - - - - - - \ No newline at end of file diff --git a/source/ChartTools/obj/ChartTools.csproj.nuget.g.targets b/source/ChartTools/obj/ChartTools.csproj.nuget.g.targets deleted file mode 100644 index 3dc06ef3..00000000 --- a/source/ChartTools/obj/ChartTools.csproj.nuget.g.targets +++ /dev/null @@ -1,2 +0,0 @@ - - \ No newline at end of file diff --git a/source/ChartTools/obj/Debug/net8.0/.NETCoreApp,Version=v8.0.AssemblyAttributes.cs b/source/ChartTools/obj/Debug/net8.0/.NETCoreApp,Version=v8.0.AssemblyAttributes.cs deleted file mode 100644 index 2217181c..00000000 --- a/source/ChartTools/obj/Debug/net8.0/.NETCoreApp,Version=v8.0.AssemblyAttributes.cs +++ /dev/null @@ -1,4 +0,0 @@ -// -using System; -using System.Reflection; -[assembly: global::System.Runtime.Versioning.TargetFrameworkAttribute(".NETCoreApp,Version=v8.0", FrameworkDisplayName = ".NET 8.0")] diff --git a/source/ChartTools/obj/Debug/net8.0/ChartTools.AssemblyInfo.cs b/source/ChartTools/obj/Debug/net8.0/ChartTools.AssemblyInfo.cs deleted file mode 100644 index b6abbcb1..00000000 --- a/source/ChartTools/obj/Debug/net8.0/ChartTools.AssemblyInfo.cs +++ /dev/null @@ -1,23 +0,0 @@ -//------------------------------------------------------------------------------ -// -// Ce code a été généré par un outil. -// Version du runtime :4.0.30319.42000 -// -// Les modifications apportées à ce fichier peuvent provoquer un comportement incorrect et seront perdues si -// le code est régénéré. -// -//------------------------------------------------------------------------------ - -using System; -using System.Reflection; - -[assembly: System.Reflection.AssemblyCompanyAttribute("ChartTools")] -[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")] -[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")] -[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0")] -[assembly: System.Reflection.AssemblyProductAttribute("ChartTools")] -[assembly: System.Reflection.AssemblyTitleAttribute("ChartTools")] -[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")] - -// Généré par la classe MSBuild WriteCodeFragment. - diff --git a/source/ChartTools/obj/Debug/net8.0/ChartTools.AssemblyInfoInputs.cache b/source/ChartTools/obj/Debug/net8.0/ChartTools.AssemblyInfoInputs.cache deleted file mode 100644 index 1392b3c9..00000000 --- a/source/ChartTools/obj/Debug/net8.0/ChartTools.AssemblyInfoInputs.cache +++ /dev/null @@ -1 +0,0 @@ -6376c159ad7a773a0301f1fd812ca5f03224f4d8b58bcf9fe09a803f035ce768 diff --git a/source/ChartTools/obj/Debug/net8.0/ChartTools.GeneratedMSBuildEditorConfig.editorconfig b/source/ChartTools/obj/Debug/net8.0/ChartTools.GeneratedMSBuildEditorConfig.editorconfig deleted file mode 100644 index 1a643956..00000000 --- a/source/ChartTools/obj/Debug/net8.0/ChartTools.GeneratedMSBuildEditorConfig.editorconfig +++ /dev/null @@ -1,13 +0,0 @@ -is_global = true -build_property.TargetFramework = net8.0 -build_property.TargetPlatformMinVersion = -build_property.UsingMicrosoftNETSdkWeb = -build_property.ProjectTypeGuids = -build_property.InvariantGlobalization = -build_property.PlatformNeutralAssembly = -build_property.EnforceExtendedAnalyzerRules = -build_property._SupportedPlatformList = Linux,macOS,Windows -build_property.RootNamespace = ChartTools -build_property.ProjectDir = C:\Users\joujo\OneDrive\Documents\GitHub\charttools\source\ChartTools\ -build_property.EnableComHosting = -build_property.EnableGeneratedComInterfaceComImportInterop = diff --git a/source/ChartTools/obj/Debug/net8.0/ChartTools.GlobalUsings.g.cs b/source/ChartTools/obj/Debug/net8.0/ChartTools.GlobalUsings.g.cs deleted file mode 100644 index 8578f3d0..00000000 --- a/source/ChartTools/obj/Debug/net8.0/ChartTools.GlobalUsings.g.cs +++ /dev/null @@ -1,8 +0,0 @@ -// -global using global::System; -global using global::System.Collections.Generic; -global using global::System.IO; -global using global::System.Linq; -global using global::System.Net.Http; -global using global::System.Threading; -global using global::System.Threading.Tasks; diff --git a/source/ChartTools/obj/Debug/net8.0/ChartTools.assets.cache b/source/ChartTools/obj/Debug/net8.0/ChartTools.assets.cache deleted file mode 100644 index f3b1f190..00000000 Binary files a/source/ChartTools/obj/Debug/net8.0/ChartTools.assets.cache and /dev/null differ diff --git a/source/ChartTools/obj/project.assets.json b/source/ChartTools/obj/project.assets.json deleted file mode 100644 index 79ece19e..00000000 --- a/source/ChartTools/obj/project.assets.json +++ /dev/null @@ -1,73 +0,0 @@ -{ - "version": 3, - "targets": { - "net8.0": {} - }, - "libraries": {}, - "projectFileDependencyGroups": { - "net8.0": [] - }, - "packageFolders": { - "C:\\Users\\joujo\\.nuget\\packages\\": {}, - "C:\\Program Files (x86)\\Microsoft Visual Studio\\Shared\\NuGetPackages": {} - }, - "project": { - "version": "1.0.0", - "restore": { - "projectUniqueName": "C:\\Users\\joujo\\OneDrive\\Documents\\GitHub\\charttools\\source\\ChartTools\\ChartTools.csproj", - "projectName": "ChartTools", - "projectPath": "C:\\Users\\joujo\\OneDrive\\Documents\\GitHub\\charttools\\source\\ChartTools\\ChartTools.csproj", - "packagesPath": "C:\\Users\\joujo\\.nuget\\packages\\", - "outputPath": "C:\\Users\\joujo\\OneDrive\\Documents\\GitHub\\charttools\\source\\ChartTools\\obj\\", - "projectStyle": "PackageReference", - "fallbackFolders": [ - "C:\\Program Files (x86)\\Microsoft Visual Studio\\Shared\\NuGetPackages" - ], - "configFilePaths": [ - "C:\\Users\\joujo\\AppData\\Roaming\\NuGet\\NuGet.Config", - "C:\\Program Files (x86)\\NuGet\\Config\\Microsoft.VisualStudio.FallbackLocation.config", - "C:\\Program Files (x86)\\NuGet\\Config\\Microsoft.VisualStudio.Offline.config" - ], - "originalTargetFrameworks": [ - "net8.0" - ], - "sources": { - "C:\\Program Files (x86)\\Microsoft SDKs\\NuGetPackages\\": {}, - "https://api.nuget.org/v3/index.json": {} - }, - "frameworks": { - "net8.0": { - "targetAlias": "net8.0", - "projectReferences": {} - } - }, - "warningProperties": { - "warnAsError": [ - "NU1605" - ] - } - }, - "frameworks": { - "net8.0": { - "targetAlias": "net8.0", - "imports": [ - "net461", - "net462", - "net47", - "net471", - "net472", - "net48", - "net481" - ], - "assetTargetFallback": true, - "warn": true, - "frameworkReferences": { - "Microsoft.NETCore.App": { - "privateAssets": "all" - } - }, - "runtimeIdentifierGraphPath": "C:\\Program Files\\dotnet\\sdk\\8.0.100/PortableRuntimeIdentifierGraph.json" - } - } - } -} \ No newline at end of file diff --git a/source/ChartTools/obj/project.nuget.cache b/source/ChartTools/obj/project.nuget.cache deleted file mode 100644 index 6751d6f6..00000000 --- a/source/ChartTools/obj/project.nuget.cache +++ /dev/null @@ -1,8 +0,0 @@ -{ - "version": 2, - "dgSpecHash": "aU9tXI4aevssEaT7LF4tiAi9WYx+F5+nl4iPJwoDllKtikOBB5NJiswBaEI+M73YQAWO+c8FhjaWwn3y0qQREA==", - "success": true, - "projectFilePath": "C:\\Users\\joujo\\OneDrive\\Documents\\GitHub\\charttools\\source\\ChartTools\\ChartTools.csproj", - "expectedPackageFiles": [], - "logs": [] -} \ No newline at end of file