如何获得MIDI事件的准确时间

时间:2014-04-14 21:11:51

标签: c# midi naudio

我试图读取一个MIDI文件,我想在C#中确定它的NoteOn事件的确切时间。
我试图使用绝对时间,但输出类似于256632 这个号码是多少? 这是我的代码行返回时间:

(note as NoteOnEvent).AbsoluteTime

2 个答案:

答案 0 :(得分:11)

MIDI文件仅包含增量时间。在每个MIDI事件之前包含1到4个字节之间的可变长度值。您正在使用的库有助于为您提供AbsoluteTime属性。简单地计算每个事件的增量时间。

单位为" delta ticks"。增量刻度的长度不是固定值,它在MIDI文件头中指定。 NAudio将其公开为MidiFile.DeltaTicksPerQuarterNote属性。因此,您需要将从AbsoluteTime获得的值除以此值,以便从歌曲开头获取音符位置。

这当然仍然是一个相对值,它取决于歌曲的节奏。您打四分音符的比率。推荐的速度也包含在文件中,它是NAudio中的TempoEvent。它的MicrosecondsPerQuarterNote属性告诉您后续事件的四分音符应该有多长。请注意,歌曲中可能有多个速度事件。

答案 1 :(得分:1)

Δ-倍

附加到MIDI文件中每个事件的时间是与前一个事件的偏移量。此偏移称为 delta-time

正如Hans Passant所说,它在一个名为variable-length quantity (VLQ)的特殊形式的事件之前存储在一个文件中。是的,标准说VLQ表示必须符合32位(4字节)。但是,从理论上讲(网上有一些真实的文件),更大的数字是可能的,所以如果提供MIDI文件解析的库使用比常规int更大的整数类型,那就更好了。 <{1}}对于NAudio中的long来说是个不错的选择。

绝对时间

AbsoluteTime属性只返回所有前面的delta-times和当前事件的总和。

时间的意义

每个delta时间或绝对值实际意味着什么取决于MIDI文件的时间划分。有两种不同类型的时间划分:

  • Ticks Per Quarter Note
  • SMPTE时间分部

在第一种情况下,所有时间都表示为刻度的数量。例如,如果除法是96,则delta时间48定义了八分音符的间隔。正如Hans Passant所说,NAudio将其公开为AbsoluteTime属性

在第二种情况下,所有时间都以与SMPTEMIDI Time Code一致的方式表示为细分的数量。在实践中,它是非常非常罕见的时分类型。

&#34;可理解&#34;时间表示

我认为最容易理解&#34;时间格式为指标时间(小时,分钟,秒)。正如Hans Passant和CL所说,您需要通过MIDI文件了解速度的变化,以计算MIDi事件的度量时间。

有些库可以为您进行此计算。例如,使用DryWetMIDI,您可以使用以下代码获取事件的指标时间:

MidiFile.DeltaTicksPerQuarterNote

使用此库,您还可以获得时间条形,节拍(使用MidiFile midiFile = MidiFile.Read("Some MIDI file.mid"); TempoMap tempoMap = midiFile.GetTempoMap(); MetricTimeSpan timeOf10thEvent = midiFile.GetTimedEvents() .Skip(9) .First() .TimeAs<MetricTimeSpan>(tempoMap); )或整个音符长度的一小部分(使用BarBeatTimeSpan)。

音乐时间的计算使用拍号的变化。由MusicalTimeSpan的{​​{1}}扩展方法获得的MIDI文件的速度图提供的速度和时间签名更改。