Example #1
0
        /// <summary>Write the track to the output stream.</summary>
        /// <param name="outputStream">The output stream to which the track should be written.</param>
        internal void Write(Stream outputStream)
        {
            Validate.NonNull("outputStream", outputStream);

            // Make sure we have an end of track marker if we need one
            if (!HasEndOfTrack && RequireEndOfTrack)
            {
                throw new InvalidOperationException("The track cannot be written until it has an end of track marker.");
            }

            using (MemoryStream memStream = new MemoryStream())
            {
                // Get the event data and write it out
                for (int i = 0; i < Events.Count; i++)
                {
                    Events[i].Write(memStream);
                }

                // Tack on the header and write the whole thing out to the main stream.
                MTrkChunkHeader header = new MTrkChunkHeader(memStream.ToArray());
                header.Write(outputStream);
            }
        }
        /// <summary>Trims a MIDI file to a specified length.</summary>
        /// <param name="sequence">The sequence to be copied and trimmed.</param>
        /// <param name="totalTime">The requested time length of the new MIDI sequence.</param>
        /// <returns>A MIDI sequence with only those events that fell before the requested time limit.</returns>
        public static MidiSequence Trim(this MidiSequence sequence, long totalTime)
        {
            Validate.NonNull("sequence", sequence);
            Validate.InRange("totalTime", totalTime, 0, long.MaxValue);

            // Create a new sequence to mimic the old
            MidiSequence newSequence = new MidiSequence(sequence.Format, sequence.Division);

            // Copy each track up to the specified time limit
            foreach (MidiTrack track in sequence)
            {
                // Create a new track in the new sequence to match the old track in the old sequence
                MidiTrack newTrack = newSequence.Tracks.AddNewTrack();

                // Convert all times in the old track to deltas
                track.Events.ConvertDeltasToTotals();

                // Copy over all events that fell before the specified time
                for (int i = 0; i < track.Events.Count && track.Events[i].DeltaTime < totalTime; i++)
                {
                    newTrack.Events.Add(track.Events[i].DeepClone());
                }

                // Convert all times back (on both new and old tracks; the new one inherited the totals)
                track.Events.ConvertTotalsToDeltas();
                newTrack.Events.ConvertTotalsToDeltas();

                // If the new track lacks an end of track, add one
                if (!newTrack.HasEndOfTrack)
                {
                    newTrack.Events.Add(new EndOfTrackMetaMidiEvent(0));
                }
            }

            // Return the new sequence
            return(newSequence);
        }
 /// <summary>Gets whether the sequence contains any lyric events.</summary>
 /// <param name="sequence">The sequence to examine.</param>
 /// <returns>true if the sequence contains any lyric events; otherwise, false.</returns>
 public static bool HasLyrics(this MidiSequence sequence)
 {
     Validate.NonNull("sequence", sequence);
     return(sequence.SelectMany(t => t.Events).Any(e => e is LyricTextMetaMidiEvent));
 }
        /// <summary>Converts the MIDI sequence into a new one with the desired format.</summary>
        /// <param name="sequence">The sequence to be converted.</param>
        /// <param name="format">The format to which we want to convert the sequence.</param>
        /// <param name="options">Options used when doing the conversion.</param>
        /// <returns>The new, converted sequence.</returns>
        public static MidiSequence Convert(this MidiSequence sequence, Format format, FormatConversionOption options)
        {
            Validate.NonNull("sequence", sequence);
            Validate.InRange("format", (int)format, (int)Format.Zero, (int)Format.Two);

            if (sequence.Format == format)
            {
                // If the desired format is the same as the original, just return a copy.
                // No transformation is necessary.
                sequence = new MidiSequence(sequence);
            }
            else if (format != Format.Zero || sequence.Tracks.Count == 1)
            {
                // If the desired format is is not 0 or there's only one track, just copy the sequence with a different format number.
                // If it's not zero, then multiple tracks are acceptable, so no transformation is necessary.
                // Or if there's only one track, then there's no possible transformation to be done.
                var newSequence = new MidiSequence(format, sequence.Division);
                foreach (MidiTrack t in sequence)
                {
                    newSequence.Tracks.Add(new MidiTrack(t));
                }
                sequence = newSequence;
            }
            else
            {
                // Now the harder cases, converting to format 0.  We need to combine all tracks into 1,
                // as format 0 requires that there only be a single track with all of the events for the song.
                sequence = new MidiSequence(sequence);

                // Iterate through all events in all tracks and change deltaTimes to actual times.
                // We'll then be able to sort based on time and change them back to deltas later.
                foreach (MidiTrack track in sequence)
                {
                    track.Events.ConvertDeltasToTotals();
                }

                // Add all events to new track (except for end of track markers!)
                int       trackNumber = 0;
                MidiTrack newTrack    = new MidiTrack();
                foreach (MidiTrack track in sequence)
                {
                    foreach (MidiEvent midiEvent in track.Events)
                    {
                        // If this event has a channel, and if we're storing tracks as channels, copy to it
                        if ((options & FormatConversionOption.CopyTrackToChannel) > 0 && trackNumber >= 0 && trackNumber <= 0xF)
                        {
                            var vme = midiEvent as VoiceMidiEvent;
                            if (vme != null)
                            {
                                vme.Channel = (byte)trackNumber;
                            }
                        }

                        // Add all events, except for end of track markers (we'll add our own)
                        if (!(midiEvent is EndOfTrackMetaMidiEvent))
                        {
                            newTrack.Events.Add(midiEvent);
                        }
                    }
                    trackNumber++;
                }

                // Sort the events by total time, then convert back to delta time,
                // and top things off with an end-of-track marker.
                newTrack.Events.Sort((x, y) => x.DeltaTime.CompareTo(y.DeltaTime));
                newTrack.Events.ConvertTotalsToDeltas();
                newTrack.Events.Add(new EndOfTrackMetaMidiEvent(0));

                // We now have all of the combined events in newTrack.  Clear out the sequence, replacing all the tracks
                // with this new one.
                sequence.Tracks.Clear();
                sequence.Tracks.Add(newTrack);
            }

            return(sequence);
        }