Пример #1
0
        /// <summary>
        /// Create percussion sounds for the detected meter
        /// </summary>
        /// <param name="midi"></param>
        /// <param name="prolongSustainedNotes"></param>
        /// <param name="volume"></param>
        public static void AddBeats(Model midi, bool prolongSustainedNotes = false, int volume = 127)
        {
            var channel    = midi.Tracks[0].Channels[Channel.PercussionChannelNumber];
            var beatEvents = midi.EventsOfType <BeatEvent>().OrderBy(b => b.AbsoluteRealTime);

            foreach (var beat in beatEvents)
            {
                var length = TimeSpan.FromMilliseconds(beat.Length.TotalMilliseconds * 0.25);

                var note = new NoteOn
                {
                    ChannelNumber    = Channel.PercussionChannelNumber,
                    NoteNumber       = beat.Level == 0 ? (byte)36 : (byte)44,
                    Volume           = beat.Level == 2 ? (byte)(0.75 * volume) : (byte)volume,
                    AbsoluteRealTime = beat.AbsoluteRealTime,
                    AbsoluteTime     = beat.AbsoluteTime,
                    RealTimeLength   = length,
                    End = beat.AbsoluteRealTime + length
                };
                channel.Events.Add(note);
            }


            var collector = new VolumeChangeCollector(midi);

            collector.DetermineVolumes();

            if (prolongSustainedNotes)
            {
                var sustainer = new Sustainer(midi);
                sustainer.ProlongSustainedNotes();
            }
        }
Пример #2
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();
            }
        }
Пример #3
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);
        }