private TrackEvent readMetaEvent(byte statusByte, BinaryReader reader, out uint readDataSize) { readDataSize = 0; byte eventType = reader.ReadByte(); uint dataSize; readDataSize += readVarLenNumeric(reader, out dataSize); readDataSize += dataSize + 1 /* eventType */ + 1 /* statusByte */; switch (eventType) { case 0x2f: // Track End return(null); case 0x51: // Tempo { // 四分音符の長さ(microsec, 10^-6 int tempo = (int)(readBENumeric(reader, 3)); TrackEvent ev = new TrackEvent(); ev.EventType = EventType.Tempo; ev.Params = new object[] { tempo }; return(ev); } case 0x58: // 拍子 { byte b1 = reader.ReadByte(); // 分子 byte b2 = reader.ReadByte(); // 分母(2のマイナス乗) byte b3 = reader.ReadByte(); // 1拍当たりのMIDIクロック数 byte b4 = reader.ReadByte(); // 四分音符の中に入る32分の音符数 if (b3 != 0x18 || b4 != 0x08) { throw new SMFException("対応していないMIDIファイル:拍子記号"); } } return(null); case 0x54: case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07: case 0x08: case 0x09: case 0x20: case 0x21: case 0x59: case 0x7f: default: reader.ReadBytes((int)dataSize); // 読み飛ばし return(null); } }
private TrackEvent readMidiEvent(byte statusByte, byte prevStatusByte, BinaryReader reader, out uint readDataSize) { readDataSize = 2; byte param1 = 0; byte param2 = 0; bool runningStatus = (statusByte & 0x80) == 0; if (runningStatus) { param1 = statusByte; statusByte = prevStatusByte; readDataSize--; } else { param1 = reader.ReadByte(); } int channel = (statusByte & 0x0f); switch (statusByte >> 4) { case 0x8: // SMFNote Off { param2 = reader.ReadByte(); readDataSize++; int noteNum = param1 & 0x7f; int velocity = param2 & 0x7f; TrackEvent ev = new TrackEvent(); ev.EventType = EventType.NoteOff; ev.Params = new object[] { channel, noteNum, velocity }; return(ev); } case 0x9: // SMFNote On { param2 = reader.ReadByte(); readDataSize++; int noteNum = param1 & 0x7f; int velocity = param2 & 0x7f; TrackEvent ev = new TrackEvent(); ev.EventType = velocity == 0 ? EventType.NoteOff : EventType.NoteOn; ev.Params = new object[] { channel, noteNum, velocity }; return(ev); } case 0xa: // Polyphonic Key Pressure (Aftertouch) { param2 = reader.ReadByte(); readDataSize++; int noteNum = param1 & 0x7f; int amount = param2 & 0x7f; } break; case 0xb: // Control Change { param2 = reader.ReadByte(); readDataSize++; int noteNum = param1 & 0x7f; int amount = param2 & 0x7f; } break; case 0xc: // Program Change { int programNum = param1 & 0x7f; } break; case 0xd: // Channel Pressure (After-touch) { int amount = param1 & 0x7f; } break; case 0xe: // Pitch Wheel Change { param2 = reader.ReadByte(); readDataSize++; int value = param1 + param2 << 7; } break; } return(null); }
private TrackEvent readMetaEvent(byte statusByte, BinaryReader reader, out uint readDataSize) { readDataSize = 0; byte eventType = reader.ReadByte(); uint dataSize; readDataSize += readVarLenNumeric(reader, out dataSize); readDataSize += dataSize + 1 /* eventType */ + 1 /* statusByte */; switch (eventType) { case 0x2f: // Track End return null; case 0x51: // Tempo { // 四分音符の長さ(microsec, 10^-6 int tempo = (int)(readBENumeric(reader, 3)); TrackEvent ev = new TrackEvent(); ev.EventType = EventType.Tempo; ev.Params = new object[] { tempo }; return ev; } case 0x58: // 拍子 { byte b1 = reader.ReadByte(); // 分子 byte b2 = reader.ReadByte(); // 分母(2のマイナス乗) byte b3 = reader.ReadByte(); // 1拍当たりのMIDIクロック数 byte b4 = reader.ReadByte(); // 四分音符の中に入る32分の音符数 if (b3 != 0x18 || b4 != 0x08) { throw new SMFException("対応していないMIDIファイル:拍子記号"); } } return null; case 0x54: case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07: case 0x08: case 0x09: case 0x20: case 0x21: case 0x59: case 0x7f: default: reader.ReadBytes((int)dataSize); // 読み飛ばし return null; } }
public override void Load(string filePath) { List <List <TrackEvent> > trackEvents = new List <List <TrackEvent> >(); BinaryReader reader = new BinaryReader(new FileStream(filePath, FileMode.Open), Encoding.UTF8); _header = readHeader(reader); if (!_header.DeltaTimeInPPQN) { throw new SMFException("対応していないMIDIファイル:TimeInSec Division"); } if (_header.FormatType == 2) { throw new SMFException("対応していないMIDIファイル:Format"); } for (int i = 0; i < _header.TrackNum; i++) { List <TrackEvent> evs = new List <TrackEvent>(); readTrack(reader, ref evs); trackEvents.Add(evs); } double maxPitch = double.MinValue; double minPitch = double.MaxValue; long prevTick = 0; double time = 0; int tempo = 500000; double ppqnInv = 1 / (double)_header.DeltaTime; Dictionary <int, Dictionary <int, SMFNote> > channels = new Dictionary <int, Dictionary <int, SMFNote> >(); _points = new List <MusicNote>(); while (true) { if (trackEvents.Count == 0) { break; } if (trackEvents.TrueForAll((lst) => { return(lst.Count == 0); })) { break; } int idx = -1; long minTick = long.MaxValue; for (int i = 0; i < trackEvents.Count; i++) { if (trackEvents[i].Count == 0) { continue; } long tick = trackEvents[i][0].AbsoluteTick; if (tick < minTick) { idx = i; minTick = tick; } } if (idx < 0) { break; } TrackEvent fstev = trackEvents[idx][0]; trackEvents[idx].RemoveAt(0); time += (fstev.AbsoluteTick - prevTick) * tempo * ppqnInv / 1000000.0; switch (fstev.EventType) { case EventType.Tempo: tempo = (int)fstev.Params[0]; break; case EventType.NoteOn: { int channel = (int)fstev.Params[0]; int noteNum = (int)fstev.Params[1]; Dictionary <int, SMFNote> noteNums; if (channels.ContainsKey(channel)) { noteNums = channels[channel]; } else { noteNums = new Dictionary <int, SMFNote>(); channels.Add(channel, noteNums); } SMFNote note; if (noteNums.ContainsKey(noteNum)) { note = noteNums[noteNum]; MusicNote n = new MusicNote(); n.TimeInSec = time; n.Pitch = note.Pitch; n.Start = false; _points.Add(n); } note = new SMFNote(true, pitchFromNote(noteNum)); if (noteNums.ContainsKey(noteNum)) { noteNums[noteNum] = note; } else { noteNums.Add(noteNum, note); } MusicNote nn = new MusicNote(); nn.TimeInSec = time; nn.Pitch = note.Pitch; nn.Start = true; _points.Add(nn); if (note.Pitch < minPitch) { minPitch = note.Pitch; } if (note.Pitch > maxPitch) { maxPitch = note.Pitch; } } break; case EventType.NoteOff: { int channel = (int)fstev.Params[0]; int noteNum = (int)fstev.Params[1]; Dictionary <int, SMFNote> noteNums; if (channels.ContainsKey(channel)) { noteNums = channels[channel]; } else { noteNums = new Dictionary <int, SMFNote>(); channels.Add(channel, noteNums); } SMFNote note; if (noteNums.ContainsKey(noteNum)) { note = noteNums[noteNum]; MusicNote n = new MusicNote(); n.TimeInSec = time; n.Pitch = note.Pitch; n.Start = false; _points.Add(n); if (note.Pitch < minPitch) { minPitch = note.Pitch; } if (note.Pitch > maxPitch) { maxPitch = note.Pitch; } noteNums.Remove(noteNum); } } break; } prevTick = fstev.AbsoluteTick; } _length = time; ToneResult minTone = ToneAnalyzer.Analyze(minPitch, 1.0); ToneResult maxTone = ToneAnalyzer.Analyze(maxPitch, 1.0); maxTone.ToneIdx++; if (maxTone.ToneIdx >= 12) { maxTone.ToneIdx -= 12; maxTone.Octave++; } minTone.ToneIdx--; if (minTone.ToneIdx <= 0) { minTone.ToneIdx += 12; minTone.Octave--; } MinPitch = ToneAnalyzer.PitchFromTone(minTone.ToneIdx, minTone.Octave); MaxPitch = ToneAnalyzer.PitchFromTone(maxTone.ToneIdx, maxTone.Octave); _points.Sort((MusicNote n1, MusicNote n2) => { if (n1.TimeInSec != n2.TimeInSec) { return(n1.TimeInSec.CompareTo(n2.TimeInSec)); } if (n1.Start) { if (n2.Start) { return(0); } return(1); } else { if (n2.Start) { return(-1); } return(0); } }); }
private TrackEvent readMidiEvent(byte statusByte, byte prevStatusByte, BinaryReader reader, out uint readDataSize) { readDataSize = 2; byte param1 = 0; byte param2 = 0; bool runningStatus = (statusByte & 0x80) == 0; if (runningStatus) { param1 = statusByte; statusByte = prevStatusByte; readDataSize--; } else { param1 = reader.ReadByte(); } int channel = (statusByte & 0x0f); switch (statusByte >> 4) { case 0x8: // SMFNote Off { param2 = reader.ReadByte(); readDataSize++; int noteNum = param1 & 0x7f; int velocity = param2 & 0x7f; TrackEvent ev = new TrackEvent(); ev.EventType = EventType.NoteOff; ev.Params = new object[] { channel, noteNum, velocity }; return ev; } case 0x9: // SMFNote On { param2 = reader.ReadByte(); readDataSize++; int noteNum = param1 & 0x7f; int velocity = param2 & 0x7f; TrackEvent ev = new TrackEvent(); ev.EventType = velocity == 0 ? EventType.NoteOff : EventType.NoteOn; ev.Params = new object[] { channel, noteNum, velocity }; return ev; } case 0xa: // Polyphonic Key Pressure (Aftertouch) { param2 = reader.ReadByte(); readDataSize++; int noteNum = param1 & 0x7f; int amount = param2 & 0x7f; } break; case 0xb: // Control Change { param2 = reader.ReadByte(); readDataSize++; int noteNum = param1 & 0x7f; int amount = param2 & 0x7f; } break; case 0xc: // Program Change { int programNum = param1 & 0x7f; } break; case 0xd: // Channel Pressure (After-touch) { int amount = param1 & 0x7f; } break; case 0xe: // Pitch Wheel Change { param2 = reader.ReadByte(); readDataSize++; int value = param1 + param2 << 7; } break; } return null; }