示例#1
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);
        }
示例#2
0
        /// <summary>
        /// Calculates the meter and saves it in BeatEvents
        /// </summary>
        /// <param name="midi"></param>
        public static void CalculateMetre(Model midi)
        {
            var offset = CalculateMeterFitnessMetric(midi);

            //use beats that are already in the midi file
            if (midi.GoodnessOfMetreFit > 0.4)
            {
                midi.IsNormalizedByMidiItself = true;
                CalculateImplicitMetre();
            }

            // else detect the meter by the detector
            else
            {
                midi.IsNormalizedByMidiItself = false;
                PadNotesToZero(midi);

                var metre = Analyze(midi).Select(TimeSpan.FromMilliseconds).ToList();
                for (var i = metre.Sum(t => t.TotalMilliseconds); i <= midi.Length.TotalMilliseconds; i += metre.Last().TotalMilliseconds)
                {
                    metre.Add(metre.Last());
                }

                CreateBeatEvents(metre);

                var beatStrengthAnalyzer = new BeatStrengthAnalyzer(midi);
                beatStrengthAnalyzer.Analyze();
            }

            var firstBeatTime = midi.EventsOfType <BeatEvent>().Min(b => b.AbsoluteRealTime);

            if (firstBeatTime != TimeSpan.Zero)
            {
                var beatEvent = new BeatEvent {
                    AbsoluteRealTime = TimeSpan.Zero, Level = 2, Length = firstBeatTime
                };
                midi.Tracks[0].MetaEvents.Add(beatEvent);
            }

            if (!midi.IsNormalizedByMidiItself)
            {
                midi.GoodnessOfMetreFit = (float)CalculateMeterFitnessOfBeatEvents(midi);
            }


            void CalculateImplicitMetre()
            {
                var baseTick = GetTicksPerBeat(midi);

                var end                 = midi.EventsOfType <EndOfTrack>().Max(e => e.AbsoluteTime);
                var timeSignatures      = new Queue <TimeSignature>(midi.EventsOfType <TimeSignature>().OrderBy(e => e.AbsoluteTime));
                var actualTimeSignature = new TimeSignature {
                    AbsoluteTime = 0, Numerator = 4, Denominator = 4
                };
                var tick       = baseTick * 4 / actualTimeSignature.Denominator;
                var barCounter = 0;

                if (offset > 0)
                {
                    midi.Tracks[0].MetaEvents.Add(new BeatEvent {
                        AbsoluteTime = 0, Level = 2
                    });
                }

                for (var time = offset; time <= end; time += tick)
                {
                    if (timeSignatures.Count > 0 && timeSignatures.Peek().AbsoluteTime <= time)
                    {
                        actualTimeSignature = timeSignatures.Dequeue();
                        barCounter          = 0;
                        tick = baseTick * 4 / actualTimeSignature.Denominator;
                    }

                    var level = 2;
                    if (barCounter % actualTimeSignature.Numerator == 0)
                    {
                        level = 0;
                    }
                    else if ((actualTimeSignature.Numerator == 4 && barCounter % actualTimeSignature.Numerator == 2) ||
                             (actualTimeSignature.Numerator == 6 && barCounter % actualTimeSignature.Numerator == 3))
                    {
                        level = 1;
                    }

                    var beat = new BeatEvent {
                        AbsoluteTime = time, Level = (byte)level
                    };
                    midi.Tracks[0].MetaEvents.Add(beat);

                    barCounter++;
                }

                TimeCalculator.ComputeRealTimes(midi);
                CalculateBeatLengths();

                var averageLength = midi.EventsOfType <BeatEvent>().Average(b => b.Length.TotalMilliseconds);

                while (averageLength > 1000)
                {
                    var beats = midi.EventsOfType <BeatEvent>().ToArray();
                    foreach (var beat in beats)
                    {
                        midi.Tracks[0].MetaEvents.Add(new BeatEvent {
                            AbsoluteRealTime = beat.AbsoluteRealTime + beat.Length.Divide(2), Level = 2
                        });
                    }
                    CalculateBeatLengths();
                    averageLength = averageLength / 2;
                }
            }

            void CalculateBeatLengths()
            {
                var beatEvents = midi.EventsOfType <BeatEvent>().OrderBy(b => b.AbsoluteRealTime).ToArray();

                for (var i = 0; i < beatEvents.Length - 1; i++)
                {
                    beatEvents[i].Length = beatEvents[i + 1].AbsoluteRealTime - beatEvents[i].AbsoluteRealTime;
                }
                beatEvents[beatEvents.Length - 1].Length = beatEvents[beatEvents.Length - 2].Length;
            }

            void CreateBeatEvents(IEnumerable <TimeSpan> metre)
            {
                var time = TimeSpan.Zero;

                foreach (var beat in metre)
                {
                    var beatEvent = new BeatEvent {
                        AbsoluteRealTime = time, Level = 0, Length = beat
                    };
                    midi.Tracks[0].MetaEvents.Add(beatEvent);
                    time += beat;
                }
            }
        }