/// <summary> /// Constructor (standard). /// </summary> /// <param name="TrackNumber">The defined track number for the new track. This number will be used to refer to the track when adding events.</param> /// <param name="TrackName">The human-readable track name for the new track.</param> public MIDITrack(int TrackNumber, String TrackName) { // create a list of bytes that represents the track's human-readable name. List <byte> trackHeader = new List <byte>(); // populate the local holder variables for the track's number and human-readable name. this.TrackNumber = TrackNumber; this.TrackName = TrackName; // instantiate the list of Events. Events = new List <List <byte> >(); // populate the header event with the standard MIDI track header. trackHeader.Add(0x00); trackHeader.Add(0xFF); trackHeader.Add(0x03); // Write out the length of the track's human-readable name (as a string of characters). This is // defined to be a variable length quantity. VariableLength.WriteVariableLength(trackHeader, (ulong)TrackName.Length); // Go through each character in the track's human-readable name. Write it out as an ASCII byte. for (int x = 0; x < TrackName.Length; x++) { trackHeader.Add((byte)TrackName[x]); } // add the track's name as an event. Events.Add(trackHeader); }
/// <summary> /// AddNoteEvent() provides a workhorse method for the AddNote() and AddNotes() methods. /// Specifically, the AddNoteEvent method translates the specific notes into MIDI-format event commands. /// </summary> /// <param name="onOff">A boolean representing whether the note is beginning (analagous to a musician pressing a key) or if it is ending (analagous to a musician releasing a key). True is ON (pressing a key), and false is OFF (releasing a key).</param> /// <param name="nChannel">The track's channel through which the note event will be played.</param> /// <param name="nMidiNoteNumber">The note number (see MIDI specification for standard note numbers) that will be played or released.</param> /// <param name="offset">The time-tick offset after which this event will take place. A note is defined by the following sequence: /// 1. Call the AddNoteEvent() function with onOff defined as true for a given note, offset = 0. /// 2. Call the AddNoteEvent() function with onOff defined as false for a given note, offset = duration of note. /// The duration of the note can be found by viewing the documentation for the AddNote() and AddNotes() functions. A quarter-note is defined as 12 time-ticks. /// </param> private void AddNoteEvent(bool onOff, int nChannel, int nMidiNoteNumber, byte offset) { List <byte> newByteArray = new List <byte>(); // write out the duration of the note as a variable length quantity. VariableLength.WriteVariableLength(newByteArray, offset); // newByteArray.Add(0xFF); // if the user selected true for onOff (note pressed), the 0x9X MIDI command must be used. // otherwise, the 0x8X MIDI command must be used. if (onOff == true) { newByteArray.Add((byte)((0x9 << 4) | (byte)nChannel)); } else { newByteArray.Add((byte)((0x8 << 4) | (byte)nChannel)); } // write out the standard MIDI note number that will be played, followed by its velocity. // the velocity is analogous to the pressure a musician would apply on a key. It is defined as 0x7F (full). newByteArray.Add((byte)nMidiNoteNumber); newByteArray.Add(0x7F); // write out the new event. Events.Add(newByteArray); }
/// <summary> /// Save() outputs a complete MIDI file. It accepts a FileStream that must be defined and instantiated by the calling code blocks. /// </summary> /// <param name="objWriter">A FileStream pointing to an open .mid or .midi file for output.</param> public void Save(MemoryStream objWriter) { // go back to the beginning of the file. objWriter.Seek(0, SeekOrigin.Begin); // write the MIDI header: objWriter.WriteByte(0x4D); objWriter.WriteByte(0x54); objWriter.WriteByte(0x68); objWriter.WriteByte(0x64); // write three bytes of 0x00. for (int x = 0; x < 3; x++) { objWriter.WriteByte(0x00); } // define the length of the MIDI header (always 0x6). objWriter.WriteByte(0x06); objWriter.WriteByte(0x00); // define the format of the file. If only one track, the file will be MIDI format 0. // if multiple tracks, the file will be MIDI format 1. if (Tracks.Count > 1) { if (asynchronous) { objWriter.WriteByte(0x02); } else { objWriter.WriteByte(0x01); } } else { objWriter.WriteByte(0x00); } if (Tracks.Count < 0x80) { objWriter.WriteByte(0x00); } // write out the number of tracks as a variable length quantity. VariableLength.WriteVariableLength(objWriter, (ulong)Tracks.Count); // write out the number of time-ticks (see AddNote() and AddNotes() methods) that define a quarter-note. // by design, this is defined to be 12 time-ticks. objWriter.WriteByte(0x00); VariableLength.WriteVariableLength(objWriter, 12); // go through each track in the list, and output its contents to the file. for (int x = 0; x < Tracks.Count; x++) { Tracks[x].Save(objWriter); } }