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