示例#1
0
        // 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();
            }
        }
示例#2
0
        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);
        }