Skip to content

Commit

Permalink
documentation for MidiFile
Browse files Browse the repository at this point in the history
  • Loading branch information
markheath committed Nov 23, 2017
1 parent d3d1900 commit 763e935
Show file tree
Hide file tree
Showing 3 changed files with 69 additions and 2 deletions.
65 changes: 65 additions & 0 deletions Docs/MidiFile.md
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();
```

3 changes: 2 additions & 1 deletion NAudio.sln
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.27004.2009
VisualStudioVersion = 15.0.27004.2006
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NAudio", "NAudio\NAudio.csproj", "{DA4F02E3-0B5E-42CD-B8D9-5583FA51D66E}"
EndProject
Expand Down Expand Up @@ -39,6 +39,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Docs", "Docs", "{BA7F6DBB-9
Docs\EnumerateMediaFoundationTransforms.md = Docs\EnumerateMediaFoundationTransforms.md
Docs\EnumerateOutputDevices.md = Docs\EnumerateOutputDevices.md
Docs\MediaFoundationEncoder.md = Docs\MediaFoundationEncoder.md
Docs\MidiFile.md = Docs\MidiFile.md
Docs\MidiInAndOut.md = Docs\MidiInAndOut.md
Docs\MixTwoAudioFilesToWav.md = Docs\MixTwoAudioFilesToWav.md
Docs\OffsetSampleProvider.md = Docs\OffsetSampleProvider.md
Expand Down
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -118,9 +118,10 @@ NAudio comes with several demo applications which are the quickest way to see ho

- [WaveForm Rendering to PNG](http://markheath.net/post/naudio-png-waveform-rendering)

## MIDI
### MIDI

- [Sending and Receiving MIDI Events](Docs/MidiInAndOut.md)
- [Exploring MIDI Files with MidiFile](Docs/MidiFile.md)

### More...

Expand Down

0 comments on commit 763e935

Please sign in to comment.