public static NotationTrack[] parseMidiFile(Midi.Sequence file) { NotationTrack[] tracks = new NotationTrack[file.Count]; Regex fingerPattern = null; for (int i = 0; i < file.Count; ++i) { tracks[i] = parseMidiTrack(file[i], file.Division, ref fingerPattern); } return(tracks); }
public static NotationTrack parseMidiTrack(Midi.Track track, int division, ref Regex fingerPattern) { int microsecondsPerBeat = Midi.PpqnClock.DefaultTempo; float time = 0; TrackStatus trackStatus = new TrackStatus(); FingerChordMap fingerMap = new FingerChordMap(); List <Note> notes = new List <Note>(); Regex fingerMetaPattern = new Regex("fingering-marker-pattern:(.*)"); string name = ""; foreach (Midi.MidiEvent e in track.Iterator()) { time += e.DeltaTicks * microsecondsPerBeat / (division * 1000); switch (e.MidiMessage.MessageType) { case Midi.MessageType.Meta: Midi.MetaMessage mm = e.MidiMessage as Midi.MetaMessage; switch (mm.MetaType) { case Midi.MetaType.Tempo: Midi.TempoChangeBuilder builder = new Midi.TempoChangeBuilder(mm); microsecondsPerBeat = builder.Tempo; break; case Midi.MetaType.Text: { string text = Encoding.Default.GetString(mm.GetBytes()); var match = fingerMetaPattern.Match(text); if (match.Success) { fingerPattern = new Regex(match.Groups[1].ToString()); Debug.LogFormat("Finger Pattern found: {0}", fingerPattern.ToString()); } } break; case Midi.MetaType.Marker: if (fingerPattern != null) { string text = Encoding.Default.GetString(mm.GetBytes()); var match = fingerPattern.Match(text); if (match.Success) { //Debug.LogFormat("Finger: {0}", text); try { int pitch = int.Parse(match.Groups[1].ToString()); Finger finger = (Finger)int.Parse(match.Groups[2].ToString()); if (!fingerMap.ContainsKey(e.AbsoluteTicks)) { fingerMap[e.AbsoluteTicks] = new FingerChord(); } fingerMap[e.AbsoluteTicks][pitch] = finger; } catch (System.Exception except) { Debug.LogWarningFormat("fingering marker parse failed: {0}, {1}", text, except.Message); } } //else // Debug.LogWarningFormat("fail marker: {0}", text); } break; case Midi.MetaType.TrackName: name = Encoding.Default.GetString(mm.GetBytes()); break; } break; case Midi.MessageType.Channel: Midi.ChannelMessage cm = e.MidiMessage as Midi.ChannelMessage; if (!trackStatus.ContainsKey(cm.MidiChannel)) { trackStatus[cm.MidiChannel] = new ChannelStatus(); } var commandType = cm.Command; if (commandType == Midi.ChannelCommand.NoteOn && cm.Data2 == 0) { commandType = Midi.ChannelCommand.NoteOff; } switch (commandType) { case Midi.ChannelCommand.NoteOn: { int pitch = cm.Data1; int velocity = cm.Data2; if (pitch >= Piano.PitchMin && pitch <= Piano.PitchMax) { trackStatus[cm.MidiChannel][pitch] = new PitchStatus { tick = e.AbsoluteTicks, startTime = time, velocity = velocity } } ; } break; case Midi.ChannelCommand.NoteOff: { int pitch = cm.Data1; if (!trackStatus[cm.MidiChannel].ContainsKey(pitch)) { Debug.LogWarningFormat("Unexpected noteOff: {0}, {1}", e.AbsoluteTicks, pitch); } else { PitchStatus status = trackStatus[cm.MidiChannel][pitch]; Note note = new Note { tick = status.tick, start = status.startTime, duration = time - status.startTime, pitch = pitch, velocity = status.velocity }; if (fingerMap.ContainsKey(note.tick) && fingerMap[note.tick].ContainsKey(note.pitch)) { note.finger = fingerMap[note.tick][note.pitch]; } notes.Add(note); } } break; } break; } } NotationTrack notation = new NotationTrack(); notation.notes = notes.ToArray(); notation.name = name; return(notation); }
public void run() { if (MidiSeq.Count == 0) { Debug.LogWarning("MIDI no track found."); return; } if (!HandConfigLib) { HandConfigLib = GetComponent <HandConfigLibrary>(); } if (!HandConfigLib) { Debug.LogError("HandConfigLibrary is null."); } var trackMap = HandTracksMap; Fingering[] results = new Fingering[trackMap.Count]; int resultIndex = 0; foreach (var pair in trackMap) { if (pair.Key >= Hands.Length) { Debug.LogErrorFormat("Hand index {0} out of hand config range.", pair.Key); return; } Hand hand = Hands[pair.Key]; int[] trackList = pair.Value; NotationTrack[] tracks = new NotationTrack[trackList.Length]; for (int track = 0; track < trackList.Length; ++track) { tracks[track] = Notation[trackList[track]]; } Navigator.Track = NotationTrack.merge(tracks); Navigator.Config = HandConfigLib.getConfig(hand.Config); Navigator.KeepConstraints = KeepConstraints; Navigator.MinStepCount = StepCountMin; Navigator.MaxStepCount = StepCountMax; Navigator.BubbleLength = BubbleLength; Navigator.EstimationStepIncrement = EstimationStepIncrement; if (Navigator.Config == null) { Debug.LogErrorFormat("Hand config of {0} is null.", hand.Config); return; } Navigator.HandType = hand.Type; Navigator.AdaptionSpeed = hand.AdaptionSpeed; results[resultIndex++] = Navigator.run(); if (DumpTree) { #if UNITY_EDITOR UnityEditor.EditorUtility.DisplayProgressBar("FingeringGenerator", "DumpTree ...", 0); #endif FileStream file = new FileStream(Application.dataPath + "/Editor/Log/FingeringNavigatorTreeDump" + pair.Key.ToString() + ".txt", FileMode.Create); byte[] bytes = System.Text.Encoding.Default.GetBytes(Navigator.getTreeJsonDump()); #if UNITY_EDITOR UnityEditor.EditorUtility.DisplayProgressBar("FingeringGenerator", string.Format("DumpTree {0:n} bytes...", bytes.Length), 0); #endif file.Write(bytes, 0, bytes.Length); file.Close(); #if UNITY_EDITOR UnityEditor.EditorUtility.ClearProgressBar(); #endif } /*// dump leaf nodes * { * FileStream file = new FileStream(Application.dataPath + "/Editor/Log/leaves.txt", FileMode.Create); * * file.WriteByte((byte)'['); * List<FingeringNavigator.TreeNode> leaves = Navigator.TreeLeaves; * leaves.Sort(delegate(FingeringNavigator.TreeNode node1, FingeringNavigator.TreeNode node2) * { * double cost1 = node1.CommittedCost; * double cost2 = node2.CommittedCost; * * return cost1.CompareTo(cost2); * }); * foreach(var leaf in leaves) * { * byte[] bytes = System.Text.Encoding.Default.GetBytes(leaf.JsonDump); * file.Write(bytes, 0, bytes.Length); * file.WriteByte((byte)','); * } * file.WriteByte((byte)'{'); * file.WriteByte((byte)'}'); * file.WriteByte((byte)']'); * * file.Close(); * }*/ } NotationUtils.appendFingeringToMidiFile(MidiSeq, results); }