diff --git a/Midi files/Bach_Air_on_G_String_BWV1068.mid b/Midi files/Bach_Air_on_G_String_BWV1068.mid index e81a505..472b565 100644 Binary files a/Midi files/Bach_Air_on_G_String_BWV1068.mid and b/Midi files/Bach_Air_on_G_String_BWV1068.mid differ diff --git a/Midi files/Bach_invention_10_Gmajor.mid b/Midi files/Bach_invention_10_Gmajor.mid index 7e73dad..c12e781 100644 Binary files a/Midi files/Bach_invention_10_Gmajor.mid and b/Midi files/Bach_invention_10_Gmajor.mid differ diff --git a/Midi files/Bach_invention_4_Dminor.mid b/Midi files/Bach_invention_4_Dminor.mid index 1ba42e6..177077f 100644 Binary files a/Midi files/Bach_invention_4_Dminor.mid and b/Midi files/Bach_invention_4_Dminor.mid differ diff --git a/MusicCore.Tests/ChomskyAnalysisTest.cs b/MusicCore.Tests/ChomskyAnalysisTest.cs index 925c826..6a1a1a1 100644 --- a/MusicCore.Tests/ChomskyAnalysisTest.cs +++ b/MusicCore.Tests/ChomskyAnalysisTest.cs @@ -12,7 +12,7 @@ public class ChomskyAnalysisTest [DataTestMethod] public void Albinoni_Adagio(string filename) { - Test(filename); + Test(filename, int.MaxValue, new Fraction(1,8)); } [DataRow(@"Bach_invention_1_Cmajor.mid")] @@ -24,14 +24,14 @@ public void Albinoni_Adagio(string filename) [DataTestMethod] public void Bach_inventions(string filename) { - Test(filename); + Test(filename, int.MaxValue, new Fraction(1, 96)); } [DataRow(@"Bach_Air_on_G_String_BWV1068.mid")] - [DataTestMethod, Ignore] + [DataTestMethod] public void Bach_Air_on_G_String(string filename) { - Test(filename); + Test(filename, int.MaxValue, new Fraction(1, 24)); } [DataRow(@"Mozart_Symphony40_Allegro.mid")] @@ -41,9 +41,9 @@ public void Mozart_Symphony40_Allegro(string filename) Test(filename, 2); } - private void Test(string filename, int take = int.MaxValue) + private void Test(string filename, int take = int.MaxValue, Fraction? prec = null) { - var lists = MidiFileReader.Read(filename).GetVoices().Take(take).ToList(); + var lists = MidiFileReader.Read(filename, prec).GetVoices().Take(take).ToList(); // Save copy var copy = FlatCopy(lists); diff --git a/MusicCore/Fraction.cs b/MusicCore/Fraction.cs index b1fa841..3a1a72d 100644 --- a/MusicCore/Fraction.cs +++ b/MusicCore/Fraction.cs @@ -65,6 +65,11 @@ public static Fraction Min(Fraction a, Fraction b) return new Fraction(f.p * n, f.q); } + public static Fraction operator/(Fraction f1, Fraction f2) + { + return new Fraction(f1.p * f2.q, f1.q * f2.p); + } + #region Equals and GetHashCode public override bool Equals(object obj) { @@ -97,6 +102,11 @@ static public implicit operator Fraction(int n) return new Fraction(n, 1); } + public bool IsWhole() + { + return p % q == 0; + } + public override string ToString() { if (q == 1) diff --git a/MusicCore/MidiFileReader.cs b/MusicCore/MidiFileReader.cs index 3b63937..3c98572 100644 --- a/MusicCore/MidiFileReader.cs +++ b/MusicCore/MidiFileReader.cs @@ -1,14 +1,27 @@ -using System.Collections.Generic; -using NAudio.Midi; +using NAudio.Midi; +using System; namespace MusicCore { public static class MidiFileReader { - public static Composition Read(string filename) + private static void AddNote(MelodyPartList list, NoteWithDuration nwd, Fraction? prec = null, long absoluteTime = 0) + { + if (prec != null) + { + Fraction times = (nwd.Duration / prec.Value); + if (!times.IsWhole()) + throw new Exception($"Duration of Note {nwd} not divisible by {prec.Value} at absoluteTime={absoluteTime}"); + } + + list.Add(nwd); + } + + public static Composition Read(string filename, Fraction? prec = null) { MidiFile midi = new MidiFile(filename, true); Composition composition = new Composition(); + int quarterNoteInTicks = midi.DeltaTicksPerQuarterNote; for (int track = 0; track < midi.Tracks; track++) { @@ -20,14 +33,16 @@ public static Composition Read(string filename) if (noteonevent.OffEvent != null) { if (noteonevent.DeltaTime > 0) - list.Add(new NoteWithDuration(new Fraction(noteonevent.DeltaTime, 120))); + AddNote(list, new NoteWithDuration(new Fraction(noteonevent.DeltaTime, quarterNoteInTicks)), prec, noteonevent.AbsoluteTime); - list.Add( + AddNote( + list, new NoteWithDuration( noteonevent.NoteNumber, Alteration.Natural, - new Fraction(noteonevent.NoteLength, 120))); - + new Fraction(noteonevent.NoteLength, quarterNoteInTicks)), + prec, + noteonevent.AbsoluteTime); } } else