forked from naudio/NAudio
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
3 changed files
with
69 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
# Exploring MIDI Files with MidiFile | ||
|
||
The `MidiFile` class in NAudio allows you to open and examine the MIDI events in a standard MIDI file. It can also be used to create or update MIDI files, but this article focuses on reading. | ||
|
||
## Opening a MIDI file | ||
|
||
Opening a `MidiFile` is as simple as creating a new `MidiFile` object and passing in the path. You can choose to enable `strictMode` which will throw exceptions if various faults are found with the file such as note on events missing a paired note off or controller values out of range. | ||
|
||
```c# | ||
var strictMode = false; | ||
var mf = new MidiFile(fileName, strictMode); | ||
``` | ||
|
||
We can discover what MIDI file format the file is (Type 0 or type 1), as well as how many tracks are present and what the `DeltaTicksPerQuarterNote` value is. | ||
|
||
```c# | ||
Console.WriteLine("Format {0}, Tracks {1}, Delta Ticks Per Quarter Note {2}", | ||
mf.FileFormat, mf.Tracks, mf.DeltaTicksPerQuarterNote); | ||
``` | ||
|
||
## Examining the MIDI events | ||
|
||
The MIDI events can be accessed with the `Events` property, passing in the index of the track whose events you want to access. This gives you a `MidiEventCollection` you can iterate through. | ||
|
||
All the events in the MIDI file will be represented by a class inheriting from `MidiEvent`. The `MidiFile` class will also have set an `AbsoluteTime` property on each note, which represents the timestamp of the MIDI event from the start of file in terms of delta ticks. | ||
|
||
For note on events, `MidiFile` will also try to pair up the corresponding `NoteOffEvent` events. This allows you to see the duration of each note (which is simply the difference in time between the absolute time of the `NoteOffEvent` and `NoteOnEvent`. | ||
|
||
Each `MidiEvent` has a `ToString` overload with basic information, so we can print out details of all the events in the file like this. (we don't print out the `NoteOffEvent` instances, because they are each paired to a `NoteOnEvent` which reports the duration) | ||
|
||
|
||
```c# | ||
for (int n = 0; n < mf.Tracks; n++) | ||
{ | ||
foreach (var midiEvent in mf.Events[n]) | ||
{ | ||
if(!MidiEvent.IsNoteOff(midiEvent)) | ||
{ | ||
Console.WriteLine("{0} {1}\r\n", ToMBT(midiEvent.AbsoluteTime, mf.DeltaTicksPerQuarterNote, timeSignature), midiEvent); | ||
} | ||
} | ||
} | ||
``` | ||
|
||
You'll see that a helper `ToMBT` method is being used above to convert the `AbsoluteTime` into a more helpful Measures Beats Ticks format. Here's a basic implementation (that doesn't take into account any possible time signature events that might take place) | ||
|
||
```c# | ||
private string ToMBT(long eventTime, int ticksPerQuarterNote, TimeSignatureEvent timeSignature) | ||
{ | ||
int beatsPerBar = timeSignature == null ? 4 : timeSignature.Numerator; | ||
int ticksPerBar = timeSignature == null ? ticksPerQuarterNote * 4 : (timeSignature.Numerator * ticksPerQuarterNote * 4) / (1 << timeSignature.Denominator); | ||
int ticksPerBeat = ticksPerBar / beatsPerBar; | ||
long bar = 1 + (eventTime / ticksPerBar); | ||
long beat = 1 + ((eventTime % ticksPerBar) / ticksPerBeat); | ||
long tick = eventTime % ticksPerBeat; | ||
return String.Format("{0}:{1}:{2}", bar, beat, tick); | ||
} | ||
``` | ||
|
||
Note that to get the `TimeSignatureEvent` needed by this function we can simply do something like: | ||
|
||
```c# | ||
var timeSignature = mf.Events[0].OfType<TimeSignatureEvent>().FirstOrDefault(); | ||
``` | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters