【发布时间】:2016-07-08 00:00:25
【问题描述】:
我正在尝试用 C# 编写一个 MIDI 文件。我正在使用 Sanford MIDI 工具包。以下是我用来编写NoteOn 和NoteOff 事件的代码sn-p。
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 文件,事件的顺序无论是打开还是关闭都不是问题,但播放当然会像一个音符一样永远播放。 (或者直到下一个音符关闭事件相同的可能不是以后的措施)
-
所以问题是on1 - - on2 - - off2 - - off1。并且这种行为是设计良好的。注意 1 将播放到 off2。这是按下钢琴键并再次按下而不释放它,这是不可能的。
-
天哪。但是,您应该以确切的顺序提供您的开启和关闭事件,因为软件无法确定在同一时间戳上发生的所需事件顺序