public void setMidiData(MidiEventCollection m, MidiSelection e)
        {
            // Get a temporary filename for the MIDI file.
            // We do this because we don't want to save to the
            // user's folders unless they request it.
            String temp = getTemporaryMidiFileName();

            if (e == MidiSelection.HARMONY_ONLY)
            {
                // Store the incoming MIDI data, but strip out
                // track 0
                m.RemoveTrack(0);
                midiData[(int)e] = m;
            }
            else
            {
                // Store the incoming MIDI data
                midiData[(int)e] = m;
            }



            // Export the temp copy...
            // NOTE: this is how we save MIDI files...
            m.PrepareForExport();
            MidiFile.Export(temp, m);

            // And update the filename so we remember where the
            // MIDI temp file is...
            fileNames[(int)e] = temp;

            return;
        }
Пример #2
0
 private static void RemoveTracks(MidiEventCollection midi, IEnumerable <int> trackNumbersToRemove)
 {
     // Remove in reverse order so the number of the remaining tracks to remove
     // aren't adjusted by the removals as we go
     foreach (var t in trackNumbersToRemove.OrderByDescending(i => i))
     {
         midi.RemoveTrack(t);
     }
 }
Пример #3
0
        private bool RemoveTrackIfEmpty(MidiEventCollection midi, int trackNumber)
        {
            // If a track only has an EndTrack (and optionally a name) then it is "empty"
            if (midi[trackNumber].All(e => e.IsSequenceTrackName() || MidiEvent.IsEndTrack(e)))
            {
                midi.RemoveTrack(trackNumber);
                return(true);
            }

            return(false);
        }
Пример #4
0
        public void ConsolidateTracks(MidiEventCollection midi)
        {
            // find all of the names
            var nameCounts = new Dictionary <string, int>();

            for (var t = 0; t < midi.Tracks; t++)
            {
                var names = midi[t].
                            OfType <TextEvent>().
                            Where(e => e.MetaEventType == MetaEventType.SequenceTrackName).
                            ToList();

                if (names.Count > 1)
                {
                    var detail = string.Join(", ", names.Select(n => $"'{n.Text}'"));
                    throw new InvalidOperationException($"Multiple names {detail} on the same track.");
                }

                var name = names.FirstOrDefault()?.Text ?? "";

                int count;
                nameCounts.TryGetValue(name, out count);
                nameCounts[name] = count + 1;
            }

            /* For all of the names that appear on more than one track
             * find all the other tracks that have this name and consolidate them.
             * We iterate multiple times because the track numbers will change every
             * time tracks are consolidated. */
            foreach (var kvp in nameCounts.Where(kvp => kvp.Value > 1))
            {
                var name = kvp.Key;
                var list = new List <MidiEvent>();

                // iterate in reverse so track numbers don't change mid iteration
                for (var t = midi.Tracks - 1; t >= 0; t--)
                {
                    if (!midi[t].OfType <TextEvent>().Any(e => e.IsSequenceTrackName() && e.Text == name))
                    {
                        continue;
                    }

                    var events = midi[t].Where(e => !MidiEvent.IsEndTrack(e) && !e.IsSequenceTrackName());

                    list.AddRange(events);
                    midi.RemoveTrack(t);
                }

                midi.AddNamedTrack(name, list.OrderBy(e => e.AbsoluteTime));
            }
        }
Пример #5
0
        public void ProcessTimeSignatures(MidiEventCollection midi)
        {
            // This is way easier if these have already been consolidated
            ConsolidateTimeTracks(midi);

            var timeSigTrackNo = midi.FindTrackNumberByName(TrackName.InputTimeSig.ToString());

            if (timeSigTrackNo == -1)
            {
                AddInfo($"No '{TrackName.InputTimeSig}' track");
                return;
            }

            var timeEvents = midi[midi.FindTrackNumberByName(TrackName.TempoMap.ToString())];

            var inputTimeSignatureEvents = midi[timeSigTrackNo].OfType <NoteOnEvent>();
            var groups = inputTimeSignatureEvents.GroupBy(e => e.AbsoluteTime);

            var error = false;

            foreach (var pair in groups)
            {
                var time = pair.Key;
                // The higher velocity value is the numerator (top)
                // And the lower velocity value is the denominator (bottom)
                var sorted = pair.OrderByDescending(e => e.Velocity).ToArray();
                if (sorted.Length != 2)
                {
                    error = true;
                    var detail = string.Join(", ", sorted.Select(e => $"<{e.NoteName} ({e.NoteNumber}), Velocity: {e.Velocity}>"));
                    AddError($"Incorrect number of time signature notes at {GetBarInfo(midi, time)}: {detail}");
                    continue;
                }

                if (sorted[0].Velocity == sorted[1].Velocity)
                {
                    error = true;
                    var detail = string.Join(", ", sorted.Select(e => $"<{e.NoteName} ({e.NoteNumber}), Velocity: {e.Velocity}>"));
                    AddError($"Multiple notes with the same velocity at {GetBarInfo(midi, time)}: {detail}");
                    continue;
                }

                var numerator = sorted[0].NoteNumber;

                int denominator;
                if (!TryConvertToDenominator(sorted[1].NoteNumber, out denominator))
                {
                    error = true;
                    AddError($"Invalid denominator note '{sorted[1].NoteNumber}' at {time}");
                    continue;
                }

                var timeSigEvent         = new TimeSignatureEvent(time, numerator, denominator, TicksInClick, NumberOfThirtySecondNotesInQuarterNote);
                var existingTimeSigEvent = timeEvents.OfType <TimeSignatureEvent>().SingleOrDefault(e => e.AbsoluteTime == time);
                if (existingTimeSigEvent != null)
                {
                    timeEvents.Remove(existingTimeSigEvent);
                }

                timeEvents.Add(timeSigEvent);
            }

            if (error)
            {
                throw new InvalidOperationException("Invalid time signature input");
            }

            // Clean up input track
            midi.RemoveTrack(timeSigTrackNo);

            UpdateTrackEnd(timeEvents, timeEvents.OrderBy(e => e.AbsoluteTime).Last().AbsoluteTime);

            // TODO: If there is no TimeSignatureEvent or TempoEvent at 0, wig out
        }