// If the meter is already detected, normalize it to 100 BPM public static void Normalize(Model midi, bool prolongSustainedNotes = false) { var beatLength = 600; var events = midi.Events().OrderBy(k => k.AbsoluteRealTime).GetEnumerator(); var normalizedTime = TimeSpan.Zero; if (!events.MoveNext()) { throw new Exception("no events"); } var e = events.Current; var beatsCopy = midi.EventsOfType <BeatEvent>().OrderBy(b => b.AbsoluteRealTime).Select(b => new BeatEvent { AbsoluteRealTime = b.AbsoluteRealTime, Length = b.Length }); foreach (var beat in beatsCopy) { while (e != null && e.AbsoluteRealTime < beat.AbsoluteRealTime + beat.Length) { var delta = (e.AbsoluteRealTime - beat.AbsoluteRealTime).TotalMilliseconds * beatLength / beat.Length.TotalMilliseconds; e.AbsoluteRealTime = normalizedTime + TimeSpan.FromMilliseconds(delta); if (!events.MoveNext()) { break; } e = events.Current; } normalizedTime += TimeSpan.FromMilliseconds(beatLength); } foreach (var beat in midi.EventsOfType <BeatEvent>()) { beat.Length = TimeSpan.FromMilliseconds(beatLength); } events.Dispose(); TimeCalculator.CreateNoteLengths(midi); var collector = new VolumeChangeCollector(midi); collector.DetermineVolumes(); if (prolongSustainedNotes) { var sustainer = new Sustainer(midi); sustainer.ProlongSustainedNotes(); } }
public static Model Parse(string filename, bool computeNoteLenghts = true, bool computePitchBends = true, bool computeRealVolumes = true, bool determineInstruments = false, bool normalizeMetre = false, bool prolongSustainedNotes = false, bool showBeats = false, bool analyzeKeys = false, bool analyzeChords = false, bool playChords = false, bool discretizeBends = false, Tone?transposeTo = null) { if (playChords) { analyzeChords = true; } if (analyzeChords) { analyzeKeys = true; } if (discretizeBends) { computePitchBends = true; } if (transposeTo != null) { analyzeKeys = true; } var midi = new Model(); using (var reader = new MidiBigEndianReader(File.Open(filename, FileMode.Open))) { ParseHeaderChunk(reader, midi); foreach (var track in midi.Tracks) { ParseTrackChunk(reader, track); } if (computeNoteLenghts || normalizeMetre || showBeats) { TimeCalculator.ComputeRealTimes(midi); TimeCalculator.CreateNoteLengths(midi); } midi.Length = midi.EventsOfType <EndOfTrack>().Max(e => e.AbsoluteRealTime); if (computeRealVolumes || normalizeMetre || showBeats) { var collector = new VolumeChangeCollector(midi); collector.DetermineVolumes(); } if (prolongSustainedNotes || normalizeMetre || showBeats) { var sustainer = new Sustainer(midi); sustainer.ProlongSustainedNotes(); } if (normalizeMetre) { Normalizer.CalculateMetre(midi); Normalizer.Normalize(midi, prolongSustainedNotes); } else if (showBeats) { Normalizer.CalculateMetre(midi); Normalizer.AddBeats(midi, prolongSustainedNotes); } if (computePitchBends) { PitchBendCalculator.JoinPitchBends(midi); PitchBendCalculator.DeterminePitchRanges(midi); if (discretizeBends) { PitchBendCalculator.DiscretizeBends(midi); } } if (determineInstruments) { var collector = new InstrumentChangeCollector(midi); collector.DetermineInstruments(); } if (analyzeKeys) { if (!normalizeMetre && !showBeats) { Normalizer.CalculateMetre(midi); } if (midi.EventsOfType <KeySignature>().Any(k => k.Key.Tone != Tone.C || k.Key.Scale != Scale.Major)) { midi.Key = midi.EventsOfType <KeySignature>().First().Key; midi.IsKeyFoundByMidiItself = true; } else { MLKeyFinder.DetectKey(midi); midi.IsKeyFoundByMidiItself = false; } } if (analyzeChords) { var analyzer = new ChordAnalyzer(midi); analyzer.Analyze(); if (playChords) { analyzer.AddChordNotesToModel(); } } if (transposeTo != null) { Transposer.Transpose(midi, (Tone)transposeTo); } ChannelPlayabilityChecker.Check(midi); } return(midi); }