我试图用C#编写MIDI文件。我正在使用Sanford MIDI工具包。以下是我用来编写NoteOn
和NoteOff
事件的代码段。
private static void InsertNoteOn(Track t, int pitch, int velocity, int position, int duration, int channel)
{
ChannelMessageBuilder builder = new ChannelMessageBuilder();
builder.Command = ChannelCommand.NoteOn;
builder.Data1 = pitch;
builder.Data2 = velocity;
builder.MidiChannel = channel;
builder.Build();
t.Insert(position, builder.Result);
}
private static void InsertNoteOff(Track t, int pitch, int velocity, int position, int duration, int channel)
{
ChannelMessageBuilder builder = new ChannelMessageBuilder();
builder.Command = ChannelCommand.NoteOff;
builder.Data1 = pitch;
builder.Data2 = velocity;
builder.MidiChannel = channel;
builder.Build();
t.Insert((position + duration), builder.Result);
}
首先,我为曲目的所有音符插入所有
NoteOn
事件,然后插入曲目的所有NoteOff
事件。该方法大多数时候都有效。但是,有时生成的MIDI文件显示不正确。当两个相同音高的音符接连写入时,有时会出现问题。第一个音符的长度等于两个音符的长度,第二个音符的长度为零。
我的假设是,第一个音符的
NoteOff
事件被解释为第二个音符的NoteOff
,反之亦然。我尝试了以下变体:
在轨道中按时间顺序添加每个音符及其
NoteOn
和NoteOff
事件如果音符的位置相同,则从上音高到下音高
如果音符的位置相同,则从下音高到上音高
按时间顺序添加所有
NoteOn
事件,然后按时间顺序添加所有NoteOff
事件按时间顺序添加所有
NoteOff
事件,然后按时间顺序添加所有NoteOn
事件尽可能减少所有音符的长度
只有最后一种方法有效,但是音符的长度较短,不能解决问题。
有没有解决的办法?跟踪中的
NoteOn
和NoteOff
事件是否有特定顺序?是否有特定的顺序调用轨道插入方法?编辑:在以下情况下会出现问题:
为了提高可见性,将较高的音符从C移至C#。这些应该是两个具有相同长度的音符,但是相反,一个具有两个音符的长度,而另一个具有零长度。
最佳答案
在MIDI文件中,多个事件可能具有相同的时间戳。在这种情况下,它们以与写入文件时相同的顺序通过电线发送。
Sanford MIDI工具包仅使用时间戳来指定事件的位置,而没有说明如何处理具有相同时间戳的多个事件。
为了确保音符关闭事件先于音符打开事件,您必须使用不同的时间戳,即减少音符的长度。 (要降低实际差异,请增加时间戳分辨率。)
关于c# - MIDI音符长度不正确,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/34107258/