任务是使用NAudio库从MIDI文件中获取所有笔记和时间.到目前为止,我从文件中获取所有笔记,但我无法得到他们的时间.
Note noteOn = new Note(); //custom class Note
MidiFile midi = new MidiFile(open.FileName);
List<TempoEvent> tempo = new List<TempoEvent>();
for (int i = 0; i < midi.Events.Count(); i++)
{
foreach (MidiEvent note in midi.Events[i])
{
TempoEvent tempoE;
try { tempoE = (TempoEvent)note; tempo.Add(tempoE); }
catch { }
if (note.CommandCode == MidiCommandCode.NoteOn)
{
var t_note = ( NoteOnEvent)note;
var noteOffEvent = t_note.OffEvent;
noteOn.NoteName.Add(t_note.NoteName);
noteOn.NoteNumber.Add(t_note.NoteNumber);
noteOn.NoteVelocity.Add(t_note.Velocity);
noteOn.NoteLenght.Add(t_note.NoteLength);
double d = (t_note.AbsoluteTime / midi.DeltaTicksPerQuarterNote) * tempo[tempo.Count() - 1].Tempo;
noteOn.StartTime.Add(TimeSpan.FromSeconds(d));
}
}
}
Run Code Online (Sandbox Code Playgroud)
问题:
1)获取我刚才看的笔记列表NoteOnEvents?如果我理解正确,每个音符都有'开始'和'结束',开头是由NoteOnEvent'和'结束'定义的NoteOffEvent.如果我查看这两个事件(NoteOn和NoteOff)我会得到重复的笔记.我对吗?
2)如何记录笔记的时间?根据这篇文章,我得到了一些值,但似乎第一个音符的时间是正确的,但其他人没有.同样在这篇文章中,有一条评论说计算时间的公式必须是:
((note.AbsTime - lastTempoEvent.AbsTime) / midi.ticksPerQuarterNote) * tempo + lastTempoEvent.RealTime.
Run Code Online (Sandbox Code Playgroud)
我不知道参数lastTempoEvent.RealTime和tempo.这是最后一次节奏活动的节奏还是?
3)读取MIDI文件非常慢,对于较小的文件,它可以,但对于大文件则没有.这个小文件大约有150个,NoteOnEvents而这个大文件大约有1250个NoteOnEvents,这个文件并不那么"重".为什么这么慢?
在MIDI文件中,音符具有单独的音符开和音符关事件.NAudio已经搜索相应的音符关闭事件并为您计算长度,因此您不需要自己处理音符关闭事件.(但是,速度可能会在音符开启和音符关闭事件之间发生变化,因此您必须分别计算两次.)
这些是值的描述,而不是实际的字段名称.
tempo是MicrosecondsPerQuarterNote最后一个节奏事件的值.
lastTempoEvent.RealTime是您为最后一个速度事件计算的时间(以微秒为单位).
最后一个速度事件是具有最大绝对时间的速度事件,该事件仍然在此事件的绝对时间之前.该节奏事件可能在另一个轨道中,因此midi.Events.MidiFileType在处理事件之前合并所有轨道(设置为零)可能是个好主意.