public static MidiFileAsset Load(byte [] data) { var reader = new MidiDataStreamReader(data); // Chunk type if (reader.ReadChars(4) != "MThd") { throw new FormatException("Can't find header chunk."); } // Chunk length if (reader.ReadBEUInt32() != 6u) { throw new FormatException("Length of header chunk must be 6."); } // Format (unused) reader.Advance(2); // Number of tracks var trackCount = reader.ReadBEUInt16(); // Ticks per quarter note var tpqn = reader.ReadBEUInt16(); if ((tpqn & 0x8000u) != 0) { throw new FormatException("SMPTE time code is not supported."); } // Tracks var tracks = new MidiAnimationAsset [trackCount]; for (var i = 0; i < trackCount; i++) { tracks[i] = ReadTrack(reader, tpqn); } // Asset instantiation var asset = ScriptableObject.CreateInstance <MidiFileAsset>(); asset.tracks = tracks; return(asset); }
static MidiAnimationAsset ReadTrack(MidiDataStreamReader reader, uint tpqn) { // Chunk type if (reader.ReadChars(4) != "MTrk") { throw new FormatException("Can't find track chunk."); } // Chunk length var chunkEnd = reader.ReadBEUInt32(); chunkEnd += reader.Position; // MIDI event sequence var events = new List <MidiEvent>(); var ticks = 0u; var stat = (byte)0; while (reader.Position < chunkEnd) { // Delta time ticks += reader.ReadMultiByteValue(); // Status byte if ((reader.PeekByte() & 0x80u) != 0) { stat = reader.ReadByte(); } if (stat == 0xffu) { // 0xff: Meta event (unused) reader.Advance(1); reader.Advance(reader.ReadMultiByteValue()); } else if (stat == 0xf0u) { // 0xf0: SysEx (unused) while (reader.ReadByte() != 0xf7u) { } } else { // MIDI event var b1 = reader.ReadByte(); var b2 = (stat & 0xe0u) == 0xc0u ? (byte)0 : reader.ReadByte(); events.Add(new MidiEvent { time = ticks, status = stat, data1 = b1, data2 = b2 }); } } // Quantize duration with bars. var bars = (ticks + tpqn * 4 - 1) / (tpqn * 4); // Asset instantiation var asset = ScriptableObject.CreateInstance <MidiAnimationAsset>(); asset.template.tempo = 120; asset.template.duration = bars * tpqn * 4; asset.template.ticksPerQuarterNote = tpqn; asset.template.events = events.ToArray(); return(asset); }