Audio and MIDI library for .NET
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

131 lines
4.7 KiB

  1. using System;
  2. using System.IO;
  3. using System.Text;
  4. namespace NAudio.Midi
  5. {
  6. /// <summary>
  7. /// Represents a MIDI meta event
  8. /// </summary>
  9. public class MetaEvent : MidiEvent
  10. {
  11. private MetaEventType metaEvent;
  12. internal int metaDataLength;
  13. /// <summary>
  14. /// Gets the type of this meta event
  15. /// </summary>
  16. public MetaEventType MetaEventType
  17. {
  18. get
  19. {
  20. return metaEvent;
  21. }
  22. }
  23. /// <summary>
  24. /// Empty constructor
  25. /// </summary>
  26. protected MetaEvent()
  27. {
  28. }
  29. /// <summary>
  30. /// Custom constructor for use by derived types, who will manage the data themselves
  31. /// </summary>
  32. /// <param name="metaEventType">Meta event type</param>
  33. /// <param name="metaDataLength">Meta data length</param>
  34. /// <param name="absoluteTime">Absolute time</param>
  35. public MetaEvent(MetaEventType metaEventType, int metaDataLength, long absoluteTime)
  36. : base(absoluteTime,1,MidiCommandCode.MetaEvent)
  37. {
  38. this.metaEvent = metaEventType;
  39. this.metaDataLength = metaDataLength;
  40. }
  41. /// <summary>
  42. /// Creates a deep clone of this MIDI event.
  43. /// </summary>
  44. public override MidiEvent Clone() => new MetaEvent(metaEvent, metaDataLength, AbsoluteTime);
  45. /// <summary>
  46. /// Reads a meta-event from a stream
  47. /// </summary>
  48. /// <param name="br">A binary reader based on the stream of MIDI data</param>
  49. /// <returns>A new MetaEvent object</returns>
  50. public static MetaEvent ReadMetaEvent(BinaryReader br)
  51. {
  52. MetaEventType metaEvent = (MetaEventType) br.ReadByte();
  53. int length = ReadVarInt(br);
  54. MetaEvent me = new MetaEvent();
  55. switch(metaEvent)
  56. {
  57. case MetaEventType.TrackSequenceNumber: // Sets the track's sequence number.
  58. me = new TrackSequenceNumberEvent(br,length);
  59. break;
  60. case MetaEventType.TextEvent: // Text event
  61. case MetaEventType.Copyright: // Copyright
  62. case MetaEventType.SequenceTrackName: // Sequence / Track Name
  63. case MetaEventType.TrackInstrumentName: // Track instrument name
  64. case MetaEventType.Lyric: // lyric
  65. case MetaEventType.Marker: // marker
  66. case MetaEventType.CuePoint: // cue point
  67. case MetaEventType.ProgramName:
  68. case MetaEventType.DeviceName:
  69. me = new TextEvent(br,length);
  70. break;
  71. case MetaEventType.EndTrack: // This event must come at the end of each track
  72. if(length != 0)
  73. {
  74. throw new FormatException("End track length");
  75. }
  76. break;
  77. case MetaEventType.SetTempo: // Set tempo
  78. me = new TempoEvent(br,length);
  79. break;
  80. case MetaEventType.TimeSignature: // Time signature
  81. me = new TimeSignatureEvent(br,length);
  82. break;
  83. case MetaEventType.KeySignature: // Key signature
  84. me = new KeySignatureEvent(br, length);
  85. break;
  86. case MetaEventType.SequencerSpecific: // Sequencer specific information
  87. me = new SequencerSpecificEvent(br, length);
  88. break;
  89. case MetaEventType.SmpteOffset:
  90. me = new SmpteOffsetEvent(br, length);
  91. break;
  92. default:
  93. //System.Windows.Forms.MessageBox.Show(String.Format("Unsupported MetaEvent {0} length {1} pos {2}",metaEvent,length,br.BaseStream.Position));
  94. var data = br.ReadBytes(length);
  95. if (data.Length != length)
  96. {
  97. throw new FormatException("Failed to read metaevent's data fully");
  98. }
  99. return new RawMetaEvent(metaEvent, default(long), data);
  100. }
  101. me.metaEvent = metaEvent;
  102. me.metaDataLength = length;
  103. return me;
  104. }
  105. /// <summary>
  106. /// Describes this meta event
  107. /// </summary>
  108. public override string ToString()
  109. {
  110. return $"{AbsoluteTime} {metaEvent}";
  111. }
  112. /// <summary>
  113. /// <see cref="MidiEvent.Export"/>
  114. /// </summary>
  115. public override void Export(ref long absoluteTime, BinaryWriter writer)
  116. {
  117. base.Export(ref absoluteTime, writer);
  118. writer.Write((byte)metaEvent);
  119. WriteVarInt(writer, metaDataLength);
  120. }
  121. }
  122. }