实例介绍
【实例截图】
【核心代码】
using System; using System.IO; using System.Text; namespace NAudio.Midi { /// <summary> /// Represents an individual MIDI event /// </summary> public class MidiEvent { /// <summary>The MIDI command code</summary> private MidiCommandCode commandCode; private int channel; private int deltaTime; private long absoluteTime; /// <summary> /// Creates a MidiEvent from a raw message received using /// the MME MIDI In APIs /// </summary> /// <param name="rawMessage">The short MIDI message</param> /// <returns>A new MIDI Event</returns> public static MidiEvent FromRawMessage(int rawMessage) { long absoluteTime = 0; int b = rawMessage & 0xFF; int data1 = (rawMessage >> 8) & 0xFF; int data2 = (rawMessage >> 16) & 0xFF; MidiCommandCode commandCode; int channel = 1; if ((b & 0xF0) == 0xF0) { // both bytes are used for command code in this case commandCode = (MidiCommandCode)b; } else { commandCode = (MidiCommandCode)(b & 0xF0); channel = (b & 0x0F) 1; } MidiEvent me; switch (commandCode) { case MidiCommandCode.NoteOn: case MidiCommandCode.NoteOff: case MidiCommandCode.KeyAfterTouch: if (data2 > 0 && commandCode == MidiCommandCode.NoteOn) { me = new NoteOnEvent(absoluteTime, channel, data1, data2, 0); } else { me = new NoteEvent(absoluteTime, channel, commandCode, data1, data2); } break; case MidiCommandCode.ControlChange: me = new ControlChangeEvent(absoluteTime,channel,(MidiController)data1,data2); break; case MidiCommandCode.PatchChange: me = new PatchChangeEvent(absoluteTime,channel,data1); break; case MidiCommandCode.ChannelAfterTouch: me = new ChannelAfterTouchEvent(absoluteTime,channel,data1); break; case MidiCommandCode.PitchWheelChange: me = new PitchWheelChangeEvent(absoluteTime, channel, data1 (data2 << 7)); break; case MidiCommandCode.TimingClock: case MidiCommandCode.StartSequence: case MidiCommandCode.ContinueSequence: case MidiCommandCode.StopSequence: case MidiCommandCode.AutoSensing: me = new MidiEvent(absoluteTime,channel,commandCode); break; case MidiCommandCode.MetaEvent: case MidiCommandCode.Sysex: default: throw new FormatException(String.Format("Unsupported MIDI Command Code for Raw Message {0}", commandCode)); } return me; } /// <summary> /// Constructs a MidiEvent from a BinaryStream /// </summary> /// <param name="br">The binary stream of MIDI data</param> /// <param name="previous">The previous MIDI event (pass null for first event)</param> /// <returns>A new MidiEvent</returns> public static MidiEvent ReadNextEvent(BinaryReader br, MidiEvent previous) { int deltaTime = MidiEvent.ReadVarInt(br); MidiCommandCode commandCode; int channel = 1; byte b = br.ReadByte(); if((b & 0x80) == 0) { // a running command - command & channel are same as previous commandCode = previous.CommandCode; channel = previous.Channel; br.BaseStream.Position--; // need to push this back } else { if((b & 0xF0) == 0xF0) { // both bytes are used for command code in this case commandCode = (MidiCommandCode) b; } else { commandCode = (MidiCommandCode) (b & 0xF0); channel = (b & 0x0F) 1; } } MidiEvent me; switch(commandCode) { case MidiCommandCode.NoteOn: me = new NoteOnEvent(br); break; case MidiCommandCode.NoteOff: case MidiCommandCode.KeyAfterTouch: me = new NoteEvent(br); break; case MidiCommandCode.ControlChange: me = new ControlChangeEvent(br); break; case MidiCommandCode.PatchChange: me = new PatchChangeEvent(br); break; case MidiCommandCode.ChannelAfterTouch: me = new ChannelAfterTouchEvent(br); break; case MidiCommandCode.PitchWheelChange: me = new PitchWheelChangeEvent(br); break; case MidiCommandCode.TimingClock: case MidiCommandCode.StartSequence: case MidiCommandCode.ContinueSequence: case MidiCommandCode.StopSequence: me = new MidiEvent(); break; case MidiCommandCode.Sysex: me = SysexEvent.ReadSysexEvent(br); break; case MidiCommandCode.MetaEvent: me = MetaEvent.ReadMetaEvent(br); break; default: throw new FormatException(String.Format("Unsupported MIDI Command Code {0:X2}",(byte) commandCode)); } me.channel = channel; me.deltaTime = deltaTime; me.commandCode = commandCode; return me; } /// <summary> /// Converts this MIDI event to a short message (32 bit integer) that /// can be sent by the Windows MIDI out short message APIs /// Cannot be implemented for all MIDI messages /// </summary> /// <returns>A short message</returns> public virtual int GetAsShortMessage() { return (channel - 1) (int)commandCode; } /// <summary> /// Default constructor /// </summary> protected MidiEvent() { } /// <summary> /// Creates a MIDI event with specified parameters /// </summary> /// <param name="absoluteTime">Absolute time of this event</param> /// <param name="channel">MIDI channel number</param> /// <param name="commandCode">MIDI command code</param> public MidiEvent(long absoluteTime, int channel, MidiCommandCode commandCode) { this.absoluteTime = absoluteTime; this.Channel = channel; this.commandCode = commandCode; } /// <summary> /// The MIDI Channel Number for this event (1-16) /// </summary> public virtual int Channel { get { return channel; } set { if ((value < 1) || (value > 16)) { throw new ArgumentOutOfRangeException("value", value, String.Format("Channel must be 1-16 (Got {0})",value)); } channel = value; } } /// <summary> /// The Delta time for this event /// </summary> public int DeltaTime { get { return deltaTime; } } /// <summary> /// The absolute time for this event /// </summary> public long AbsoluteTime { get { return absoluteTime; } set { absoluteTime = value; } } /// <summary> /// The command code for this event /// </summary> public MidiCommandCode CommandCode { get { return commandCode; } } /// <summary> /// Whether this is a note off event /// </summary> public static bool IsNoteOff(MidiEvent midiEvent) { if (midiEvent != null) { if (midiEvent.CommandCode == MidiCommandCode.NoteOn) { NoteEvent ne = (NoteEvent)midiEvent; return (ne.Velocity == 0); } return (midiEvent.CommandCode == MidiCommandCode.NoteOff); } return false; } /// <summary> /// Whether this is a note on event /// </summary> public static bool IsNoteOn(MidiEvent midiEvent) { if (midiEvent != null) { if (midiEvent.CommandCode == MidiCommandCode.NoteOn) { NoteEvent ne = (NoteEvent)midiEvent; return (ne.Velocity > 0); } } return false; } /// <summary> /// Determines if this is an end track event /// </summary> public static bool IsEndTrack(MidiEvent midiEvent) { if (midiEvent != null) { MetaEvent me = midiEvent as MetaEvent; if (me != null) { return me.MetaEventType == MetaEventType.EndTrack; } } return false; } /// <summary> /// Displays a summary of the MIDI event /// </summary> /// <returns>A string containing a brief description of this MIDI event</returns> public override string ToString() { if(commandCode >= MidiCommandCode.Sysex) return String.Format("{0} {1}",absoluteTime,commandCode); else return String.Format("{0} {1} Ch: {2}", absoluteTime, commandCode, channel); } /// <summary> /// Utility function that can read a variable length integer from a binary stream /// </summary> /// <param name="br">The binary stream</param> /// <returns>The integer read</returns> public static int ReadVarInt(BinaryReader br) { int value = 0; byte b; for(int n = 0; n < 4; n ) { b = br.ReadByte(); value <<= 7; value = (b & 0x7F); if((b & 0x80) == 0) { return value; } } throw new FormatException("Invalid Var Int"); } /// <summary> /// Writes a variable length integer to a binary stream /// </summary> /// <param name="writer">Binary stream</param> /// <param name="value">The value to write</param> public static void WriteVarInt(BinaryWriter writer, int value) { if (value < 0) { throw new ArgumentOutOfRangeException("value", value, "Cannot write a negative Var Int"); } if (value > 0x0FFFFFFF) { throw new ArgumentOutOfRangeException("value", value, "Maximum allowed Var Int is 0x0FFFFFFF"); } int n = 0; byte[] buffer = new byte[4]; do { buffer[n ] = (byte)(value & 0x7F); value >>= 7; } while (value > 0); while (n > 0) { n--; if(n > 0) writer.Write((byte) (buffer[n] | 0x80)); else writer.Write(buffer[n]); } } /// <summary> /// Exports this MIDI event's data /// Overriden in derived classes, but they should call this version /// </summary> /// <param name="absoluteTime">Absolute time used to calculate delta. /// Is updated ready for the next delta calculation</param> /// <param name="writer">Stream to write to</param> public virtual void Export(ref long absoluteTime, BinaryWriter writer) { if (this.absoluteTime < absoluteTime) { throw new FormatException("Can't export unsorted MIDI events"); } WriteVarInt(writer,(int) (this.absoluteTime - absoluteTime)); absoluteTime = this.absoluteTime; int output = (int) commandCode; if (commandCode != MidiCommandCode.MetaEvent) { output = (channel - 1); } writer.Write((byte)output); } } }
标签: 音频
小贴士
感谢您为本站写下的评论,您的评论对其它用户来说具有重要的参考价值,所以请认真填写。
- 类似“顶”、“沙发”之类没有营养的文字,对勤劳贡献的楼主来说是令人沮丧的反馈信息。
- 相信您也不想看到一排文字/表情墙,所以请不要反馈意义不大的重复字符,也请尽量不要纯表情的回复。
- 提问之前请再仔细看一遍楼主的说明,或许是您遗漏了。
- 请勿到处挖坑绊人、招贴广告。既占空间让人厌烦,又没人会搭理,于人于己都无利。
关于好例子网
本站旨在为广大IT学习爱好者提供一个非营利性互相学习交流分享平台。本站所有资源都可以被免费获取学习研究。本站资源来自网友分享,对搜索内容的合法性不具有预见性、识别性、控制性,仅供学习研究,请务必在下载后24小时内给予删除,不得用于其他任何用途,否则后果自负。基于互联网的特殊性,平台无法对用户传输的作品、信息、内容的权属或合法性、安全性、合规性、真实性、科学性、完整权、有效性等进行实质审查;无论平台是否已进行审查,用户均应自行承担因其传输的作品、信息、内容而可能或已经产生的侵权或权属纠纷等法律责任。本站所有资源不代表本站的观点或立场,基于网友分享,根据中国法律《信息网络传播权保护条例》第二十二与二十三条之规定,若资源存在侵权或相关问题请联系本站客服人员,点此联系我们。关于更多版权及免责申明参见 版权及免责申明
网友评论
我要评论