// A good MIDI Files Specification: http://www.somascape.org/midi/tech/mfile.html #region MetaMessage Extension Methods /// <summary> /// Get the values that represent the given META event. /// The returned array consists of <ol> /// <li>the event name as a String</li> /// <li>the length of the event data as an Integer</li> /// <li>the event data as a String</li> /// </ol> /// </summary> /// <param name="mess">the META message to format</param> /// <returns>the representation of the message</returns> public static object[] GetMetaStrings(this MetaMessage mess) { // Some data is String some is a series of bytes others are neither bool dumpText = false; bool dumpBytes = false; int type = mess.GetMetaMessageType(); byte[] data = mess.GetMetaMessageData(); // The returned Object array // { type name, length, value string } object[] result = { "M:", null, "" }; result[1] = data.Length; switch (type) { case (int)MidiHelper.MetaEventType.SequenceNumber: result[0] = "M:SequenceNumber"; dumpBytes = true; break; case (int)MidiHelper.MetaEventType.TextEvent: result[0] = "M:TextEvent"; dumpText = true; break; case (int)MidiHelper.MetaEventType.CopyrightNotice: result[0] = "M:CopyrightNotice"; dumpText = true; break; case (int)MidiHelper.MetaEventType.SequenceOrTrackName: result[0] = "M:SequenceOrTrackName"; dumpText = true; break; case (int)MidiHelper.MetaEventType.InstrumentName: result[0] = "M:InstrumentName"; dumpText = true; break; case (int)MidiHelper.MetaEventType.LyricText: result[0] = "M:LyricText"; dumpText = true; break; case (int)MidiHelper.MetaEventType.MarkerText: result[0] = "M:MarkerText"; dumpText = true; break; case (int)MidiHelper.MetaEventType.CuePoint: result[0] = "M:CuePoint"; dumpText = true; break; case (int)MidiHelper.MetaEventType.ProgramName: result[0] = "M:ProgramName"; dumpText = true; break; case (int)MidiHelper.MetaEventType.DeviceName: result[0] = "M:DeviceName"; dumpText = true; break; case (int)MidiHelper.MetaEventType.SmpteOffset: result[0] = "M:SmpteOffset"; // Hour, Minute, Second, Frame, Field // hr mn se fr ff result[2] = string.Format("{0:00}:{1:00}:{2:00}:{3:00}:{4:00}", data[0] & 0x00FF, data[1] & 0x00FF, data[2] & 0x00FF, data[3] & 0x00FF, data[4] & 0x00FF); break; case (int)MidiHelper.MetaEventType.TimeSignature: result[0] = "M:TimeSignature"; int nn = (data[0] & 0x00FF); // numerator int dd = (int)(Math.Pow(2, (data[1] & 0x00FF))); // denominator int cc = (data[2] & 0x00FF); // midiClocksPerMetronomeClick int bb = (data[3] & 0x00FF); // notated 32nd-notes in a MIDI quarter-note result[2] = nn + "/" + dd + ", " + cc + " clicks per metronome, " + bb + " 32nd notes per quarter-note"; break; case (int)MidiHelper.MetaEventType.KeySignature: result[0] = "M:KeySignature"; result[2] = KeySignatures.GetKeyName(data); break; case (int)MidiHelper.MetaEventType.Tempo: result[0] = "M:Tempo"; int bpm = MicroSecsToBpm(data); result[2] = string.Format("{0}", bpm); break; case (int)MidiHelper.MetaEventType.EndOfTrack: result[0] = "M:EndOfTrack"; break; case (int)MidiHelper.MetaEventType.SequencerSpecificEvent: result[0] = "M:SequencerSpecificEvent"; dumpBytes = true; break; default: result[0] = "M:" + type; dumpBytes = true; break; } if (dumpText) { result[2] = MidiHelper.GetStringWithoutNewlines(data); } if (dumpBytes) { result[2] = MidiHelper.ByteArrayToHexString(data, ","); } return(result); }
/// <summary> /// Create a C# code line for this meta event /// </summary> /// <param name="mess">the META message to process</param> /// <param name="tick">the position of the event in the sequence</param> /// <param name="ticksPerBeat">the tick resolution of the sequence</param> /// <returns>a C# code line</returns> public static string CreateMetaEventGeneratedCode(this MetaMessage mess, long tick, int ticksPerBeat) { int type = mess.GetMetaMessageType(); string typeName = MidiHelper.GetMetaString(type); byte[] data = mess.GetMetaMessageData(); int dataLength = data.Length; string value = ""; switch (type) { // First handle the text based events (0x01 - 0x09) case (int)MidiHelper.MetaEventType.TextEvent: case (int)MidiHelper.MetaEventType.CopyrightNotice: case (int)MidiHelper.MetaEventType.SequenceOrTrackName: case (int)MidiHelper.MetaEventType.InstrumentName: case (int)MidiHelper.MetaEventType.LyricText: case (int)MidiHelper.MetaEventType.MarkerText: case (int)MidiHelper.MetaEventType.CuePoint: case (int)MidiHelper.MetaEventType.ProgramName: case (int)MidiHelper.MetaEventType.DeviceName: string text = MidiHelper.GetString(data); value = MidiHelper.TextString(text); break; // And then the special events case (int)MidiHelper.MetaEventType.SmpteOffset: // Hour, Minute, Second, Frame, Field // hr mn se fr ff value = string.Format("{0:00}:{1:00}:{2:00}:{3:00}:{4:00}", data[0] & 0x00FF, data[1] & 0x00FF, data[2] & 0x00FF, data[3] & 0x00FF, data[4] & 0x00FF); break; case (int)MidiHelper.MetaEventType.TimeSignature: int nn = (data[0] & 0x00FF); // numerator int dd = (int)(Math.Pow(2, (data[1] & 0x00FF))); // denominator int cc = (data[2] & 0x00FF); // midiClocksPerMetronomeClick int bb = (data[3] & 0x00FF); // notated 32nd-notes in a MIDI quarter-note value = nn + "/" + dd; break; case (int)MidiHelper.MetaEventType.KeySignature: value = KeySignatures.GetKeyName(data); break; case (int)MidiHelper.MetaEventType.Tempo: int bpm = MicroSecsToBpm(data); value = string.Format("{0}", bpm); break; case (int)MidiHelper.MetaEventType.EndOfTrack: break; default: value = MidiHelper.ByteArrayToString(data, " "); break; } return(string.Format("MetaEvent.CreateMetaEvent((int) MidiHelper.MetaEventType.{0}, \"{1}\", {2}, {3})", typeName, value, tick, ticksPerBeat)); }