实例介绍
【实例截图】
【核心代码】
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小时内给予删除,不得用于其他任何用途,否则后果自负。基于互联网的特殊性,平台无法对用户传输的作品、信息、内容的权属或合法性、安全性、合规性、真实性、科学性、完整权、有效性等进行实质审查;无论平台是否已进行审查,用户均应自行承担因其传输的作品、信息、内容而可能或已经产生的侵权或权属纠纷等法律责任。本站所有资源不代表本站的观点或立场,基于网友分享,根据中国法律《信息网络传播权保护条例》第二十二与二十三条之规定,若资源存在侵权或相关问题请联系本站客服人员,点此联系我们。关于更多版权及免责申明参见 版权及免责申明


网友评论
我要评论