任务是使用 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));
}
}
}
问题:
1)要获取笔记列表,我只查看
NoteOnEvents
或不查看?如果我理解正确,每个音符都有“开始”和“结束”,开始由 NoteOnEvent
定义,“结束”由 NoteOffEvent
定义。如果我查看两个事件( NoteOn
和 NoteOff
),我会得到重复的笔记。我对吗?2) 如何获取笔记的时间?根据 this post ,我得到了一些值,但似乎第一个音符的时间是正确的,但其他人则不然。同样在这篇文章中,有一条评论说计算时间的公式必须是:
((note.AbsTime - lastTempoEvent.AbsTime) / midi.ticksPerQuarterNote) * tempo + lastTempoEvent.RealTime.
我不知道参数
lastTempoEvent.RealTime
和 tempo
。是上次节奏事件的节奏还是?3)读取MIDI文件很慢,对于较小的文件可以,但对于大文件则不然。这个小文件有 ~150
NoteOnEvents
,这个大文件有 ~1250 NoteOnEvents
,这不是那么“重”。为什么这么慢? 最佳答案
NAudio 已经搜索到对应的音符关事件并为你计算长度,所以你不需要自己处理音符关事件。
(但是,速度可能会在音符打开和音符关闭事件之间发生变化,因此您必须分别计算这两个时间。)
tempo
是最后一个速度事件的 MicrosecondsPerQuarterNote
值。lastTempoEvent.RealTime
是您为上一个速度事件计算的时间(以微秒为单位)。最后一个节奏事件是在这个事件的绝对时间之前具有最大绝对时间的节奏事件。
该速度事件可能在另一个轨道中,因此在处理事件之前合并所有轨道(将
midi.Events.MidiFileType
设置为零)可能是个好主意。 关于c# - 使用 NAudio 从 MIDI 文件中读取音符,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/23888692/