| Namespace | Windows.Devices.Midi2.Utilities.Files |
|---|---|
| Type Name | MidiStandardFileWriter |
| Type | WinRT Runtime Class |
| IDL | MidiStandardFileWriter.idl |
MidiStandardFileWriter writes a MidiSequence out as a Standard MIDI File. It’s the other half of MidiStandardFileReader. Read a file, write it back, and reading the result again gives you the same sequence.
The sequence can come from anywhere. A file you read, a sequence you built with MidiSequenceBuilder, or a recording from a device are all the same to the writer.
This is a static class. There’s nothing to create.
Writing is asynchronous, and the whole file is built in memory before any of it is written. A Standard MIDI File puts each track’s length in front of the track, so the length isn’t known until the track has been laid out. And half a file is worse than no file at all.
| Method | Description |
|---|---|
WriteAsync(stream, sequence) |
Writes to an IRandomAccessStream with the default options |
WriteAsync(stream, sequence, options) |
Writes to an IRandomAccessStream with these MidiFileWriteOptions |
WriteToFileAsync(file, sequence) |
Writes to a StorageFile with the default options |
WriteToFileAsync(file, sequence, options) |
Writes to a StorageFile with these MidiFileWriteOptions |
All four return a MidiFileWriteResult. Check Succeeded before telling anyone the file was saved.
The same events at the same ticks, with the same tempo and meter maps, the same track names, and the same text. It doesn’t mean the same bytes.
There’s more than one way to write the same music in a MIDI file. The reader fixes some things as it reads: it adds a tempo event when a file has none, it keeps only the last of two tempo events at the same tick, and it converts older text to UTF-8. Those fixes stay fixed. Write a file, read it back, and write it again, and you get the same bytes the second time. So nothing slowly changes as a file is opened and saved over and over.
A Standard MIDI File is a MIDI 1.0 format. A sequence built from Universal MIDI Packets is translated where MIDI 1.0 has an equivalent:
| Universal MIDI Packet | Written as |
|---|---|
| MIDI 1.0 channel voice | The same message |
| MIDI 2.0 note on and note off | A MIDI 1.0 note, velocity scaled to 7 bits. A note on that would scale to zero is written at velocity 1, so it does not turn into a note off |
| MIDI 2.0 control change, poly pressure, channel pressure | The same message, value scaled to 7 bits |
| MIDI 2.0 pitch bend | A 14-bit pitch bend |
| MIDI 2.0 program change | A program change, with bank select in front of it when the message carries a bank |
| Registered and assignable controllers | The four control change messages MIDI 1.0 uses for RPN and NRPN |
| 7-bit system exclusive | Reassembled into one complete dump, however many packets it arrived in |
| System real time and system common | Stored in the track with the escape the file format provides |
Everything else is counted in SkippedEventCount and left out: per-note controllers, per-note pitch bend, per-note management, the relative controllers, 8-bit System Exclusive, flex data, stream messages, and the utility messages. None of them has a MIDI 1.0 form, so there’s nothing to write.
Format 2 is written as format 1. The reader puts the tracks of a format 2 file one after another on a single timeline. So by the time a sequence exists, the tracks aren’t separate anymore, and there’s no format 2 structure left to write back.
A sequence with absolute timing is laid out on a musical timeline. A Standard MIDI File has no way to say “a tick is a microsecond,” so the writer puts the sequence at 120 beats per minute, using AbsoluteTimingTicksPerQuarterNote from the options. The real-time position of each event is kept. The tick numbers aren’t.
MidiFileWriteOptions options{};
options.UseRunningStatus(true);
auto result{ co_await MidiStandardFileWriter::WriteToFileAsync(file, sequence, options) };
if (result.Succeeded())
{
if (result.SkippedEventCount() > 0)
{
// the sequence held messages MIDI 1.0 cannot express
}
}
These build a short sequence, save it in your temporary folder, and read it back to compare. The sequence includes a MIDI 2.0 controller, which is written with its value scaled to 7 bits, and two per-note pitch bends, which MIDI 1.0 can’t hold and SkippedEventCount counts. They also write the same sequence as a single track, to memory instead of to a file.
