问题
I'm trying to read a MIDI file and I want to determine the exact time of a NoteOn event from it in C#.
I tried to use absolute time, but the output was something like 256632.
What is this number ?
This is the line of my code that returns the time :
(note as NoteOnEvent).AbsoluteTime
回答1:
A MIDI file only contains incremental times. Included as a variable length value between 1 and 4 bytes before each MIDI event. The library you are using is being helpful in providing you with the AbsoluteTime property. Simply calculated by summing the incremental times for each event.
The unit is "delta ticks". The length of a delta tick is not a fixed value, it is specified in the MIDI file header. NAudio exposes it as the MidiFile.DeltaTicksPerQuarterNote property. So you'll need to divide the value you get from AbsoluteTime by this value to get the note position from the start of the song.
This is of course still a relative value, it depends on the tempo of the song. The rate at which you play quarter notes. The recommended tempo is included in the file as well, it is the TempoEvent in NAudio. Its MicrosecondsPerQuarterNote property tells you how long a quarter note should be for subsequent events. Beware that there can be more than one tempo event in a song.
回答2:
Delta-times
Time attached to every event in a MIDI file is an offset from the previous event. This offset is called delta-time.
As said by Hans Passant it is stored in a file before an event in special form called variable-length quantity (VLQ). Yes, standard says that VLQ representations must fit in 32 bits (4 bytes). But, theoretically (and there are some real files on the web), larger numbers are possible, so it is much better if a library which provides MIDI file parsing uses integer type bigger than regular int
. long
for the AbsoluteTime
in NAudio is a good choice.
Absolute time
AbsoluteTime
property returns just sum of all preceding delta-times and the current event's one.
Meaning of time
What every delta-time or an absolute one actually means depends on time division of a MIDI file. There are two different types of time division:
- Ticks Per Quarter Note
- SMPTE Time Division
In first case all times expressed as number of ticks. For example, if division is 96, then a delta-time of 48 defines interval of an eighth-note. As also said by Hans Passant NAudio exposes it as the MidiFile.DeltaTicksPerQuarterNote
property
In second case all times expressed as number of subdivisions of a second in a way consistent with SMPTE and MIDI Time Code. In practice it is very very very rare type of time division.
"Understandable" representations of time
I think the most "understandable" format for time is metric time (hours, minutes, seconds). As said by Hans Passant and CL you need to know changes of tempo through a MIDI file to calculate metric time of a MIDi event.
There are some libraries that do this calculation for you. For example, with DryWetMIDI you can get metric time of an event with this code:
MidiFile midiFile = MidiFile.Read("Some MIDI file.mid");
TempoMap tempoMap = midiFile.GetTempoMap();
MetricTimeSpan timeOf10thEvent = midiFile.GetTimedEvents()
.Skip(9)
.First()
.TimeAs<MetricTimeSpan>(tempoMap);
With this library you can also get time as bars, beats (using BarBeatTimeSpan
) or a fraction of the whole note's length (using MusicalTimeSpan
).
Calculation of musical time uses changes of time signature. Both tempo and time signature changes provided by tempo map of a MIDI file that can be obtained with GetTempoMap
extension method for MidiFile
.
来源:https://stackoverflow.com/questions/23070510/how-to-get-exact-time-of-a-midi-event