using System;
using System.IO;
using System.Text;
namespace NAudio.Midi
{
///
/// Represents a MIDI meta event
///
public class MetaEvent : MidiEvent
{
private MetaEventType metaEvent;
internal int metaDataLength;
///
/// Gets the type of this meta event
///
public MetaEventType MetaEventType
{
get
{
return metaEvent;
}
}
///
/// Empty constructor
///
protected MetaEvent()
{
}
///
/// Custom constructor for use by derived types, who will manage the data themselves
///
/// Meta event type
/// Meta data length
/// Absolute time
public MetaEvent(MetaEventType metaEventType, int metaDataLength, long absoluteTime)
: base(absoluteTime,1,MidiCommandCode.MetaEvent)
{
this.metaEvent = metaEventType;
this.metaDataLength = metaDataLength;
}
///
/// Creates a deep clone of this MIDI event.
///
public override MidiEvent Clone() => new MetaEvent(metaEvent, metaDataLength, AbsoluteTime);
///
/// Reads a meta-event from a stream
///
/// A binary reader based on the stream of MIDI data
/// A new MetaEvent object
public static MetaEvent ReadMetaEvent(BinaryReader br)
{
MetaEventType metaEvent = (MetaEventType) br.ReadByte();
int length = ReadVarInt(br);
MetaEvent me = new MetaEvent();
switch(metaEvent)
{
case MetaEventType.TrackSequenceNumber: // Sets the track's sequence number.
me = new TrackSequenceNumberEvent(br,length);
break;
case MetaEventType.TextEvent: // Text event
case MetaEventType.Copyright: // Copyright
case MetaEventType.SequenceTrackName: // Sequence / Track Name
case MetaEventType.TrackInstrumentName: // Track instrument name
case MetaEventType.Lyric: // lyric
case MetaEventType.Marker: // marker
case MetaEventType.CuePoint: // cue point
case MetaEventType.ProgramName:
case MetaEventType.DeviceName:
me = new TextEvent(br,length);
break;
case MetaEventType.EndTrack: // This event must come at the end of each track
if(length != 0)
{
throw new FormatException("End track length");
}
break;
case MetaEventType.SetTempo: // Set tempo
me = new TempoEvent(br,length);
break;
case MetaEventType.TimeSignature: // Time signature
me = new TimeSignatureEvent(br,length);
break;
case MetaEventType.KeySignature: // Key signature
me = new KeySignatureEvent(br, length);
break;
case MetaEventType.SequencerSpecific: // Sequencer specific information
me = new SequencerSpecificEvent(br, length);
break;
case MetaEventType.SmpteOffset:
me = new SmpteOffsetEvent(br, length);
break;
default:
//System.Windows.Forms.MessageBox.Show(String.Format("Unsupported MetaEvent {0} length {1} pos {2}",metaEvent,length,br.BaseStream.Position));
var data = br.ReadBytes(length);
if (data.Length != length)
{
throw new FormatException("Failed to read metaevent's data fully");
}
return new RawMetaEvent(metaEvent, default(long), data);
}
me.metaEvent = metaEvent;
me.metaDataLength = length;
return me;
}
///
/// Describes this meta event
///
public override string ToString()
{
return $"{AbsoluteTime} {metaEvent}";
}
///
///
///
public override void Export(ref long absoluteTime, BinaryWriter writer)
{
base.Export(ref absoluteTime, writer);
writer.Write((byte)metaEvent);
WriteVarInt(writer, metaDataLength);
}
}
}