/// <summary> /// 通过Midi生成时间序列 /// </summary> /// <param name="fileName">Midi文件路径</param> /// <param name="timeLine">时间序列</param> /// <param name="rate">播放速率(New BPM = BPM * rate)</param> /// <param name="synchroTick">节奏间隔(MidiTick),设置此项后将忽略播放速率</param> /// <returns>时间序列</returns> public TimeLine Serialize(string fileName, TimeLine timeLine, double rate = -1, int synchroTick = -1, ShowProgress showProgress = null) { try { if (timeLine == null) { timeLine = new TimeLine(); } var midiFile = new MidiFile(fileName, false); #region HeadParam timeLine.Param["MidiFileFormat"].Value = midiFile.FileFormat; timeLine.Param["MidiTracksCount"].Value = midiFile.Tracks; timeLine.Param["MidiDeltaTicksPerQuarterNote"].Value = midiFile.DeltaTicksPerQuarterNote; #endregion #region Nodes //Public Event var timeSignature = midiFile.Events[0].OfType <TimeSignatureEvent>().FirstOrDefault(); double bpm = 0; timeLine.BeatsPerBar = timeSignature == null ? 4 : timeSignature.Numerator; timeLine.TicksPerBar = timeSignature == null ? midiFile.DeltaTicksPerQuarterNote * 4 : (timeSignature.Numerator * midiFile.DeltaTicksPerQuarterNote * 4) / (1 << timeSignature.Denominator); timeLine.TicksPerBeat = timeLine.TicksPerBar / timeLine.BeatsPerBar; #region MidiFile -> MidiNodes(Unordered) List <MidiNode> MidiNodes = new List <MidiNode>(); //Foreach Events in MidiFile for (int i = 0; i < midiFile.Tracks; i++) { //Track Events var track = ""; var instrument = ""; var vol = -1; var pan = -1; foreach (MidiEvent midiEvent in midiFile.Events[i]) { //Event BPM if (new Regex("(?<=SetTempo )\\d+(?=bpm \\(\\d+\\))").Match(midiEvent.ToString()).Success) { bpm = Int32.Parse(new Regex("(?<=SetTempo )\\d+(?=bpm \\(\\d+\\))").Match(midiEvent.ToString()).Value); if (rate > 0) { bpm *= rate; } MidiNodes.Add(new MidiNode() { IsEvent = true, Param = new Dictionary <string, _Node_INT>() { { "BeatPerMinute", new _Node_INT() { Value = (int)bpm } }, { "DeltaTickStart", new _Node_INT() { Value = midiEvent.DeltaTime } }, { "MinecraftTickStart", new _Node_INT() { Value = 0 } } } }); } //Event Track Name if (new Regex("(?<=SequenceTrackName ).+(?=$)").Match(midiEvent.ToString()).Success) { track = new Regex("(?<=SequenceTrackName ).+(?=$)").Match(midiEvent.ToString()).Value; } //Event Instrument Name if (new Regex("(?<=PatchChange Ch: \\d+ ).+(?=$)").Match(midiEvent.ToString()).Success) { instrument = new Regex("(?<=PatchChange Ch: \\d+ ).+(?=$)").Match(midiEvent.ToString()).Value; } //Event Track Volume if (new Regex("(?<=MainVolume Value )\\d*(?=$)").Match(midiEvent.ToString()).Success) { Int32.TryParse(new Regex("(?<=MainVolume Value )\\d*(?=$)").Match(midiEvent.ToString()).Value, out vol); } //Event Track Pan if (new Regex("(?<=Pan Value )\\d*(?=$)").Match(midiEvent.ToString()).Success) { Int32.TryParse(new Regex("(?<=Pan Value )\\d*(?=$)").Match(midiEvent.ToString()).Value, out pan); } if (!MidiEvent.IsNoteOff(midiEvent)) { //Get Param var MBT = GetMBT(midiEvent.AbsoluteTime, midiFile.DeltaTicksPerQuarterNote, timeSignature); var EventAnalysis = AnalysisEvent(midiEvent, instrument); //Write into MidiNodes if (EventAnalysis != null) { var MidiNode = new MidiNode(); #region Param //Time-related MidiNode.Param["DeltaTickStart"].Value = (int)EventAnalysis.StartTick; //MidiNode Starts Needs more Calculation MidiNode.Param["DeltaTickDuration"].Value = (int)EventAnalysis.Length; MidiNode.Param["MinecraftTickDuration"].Value = (int)MinecraftTickDuration(EventAnalysis.Length, midiFile.DeltaTicksPerQuarterNote, timeSignature, (int)bpm); MidiNode.Param["BeatPerMinute"].Value = (int)bpm; //Bar-related MidiNode.Param["BarIndex"].Value = (int)MBT[0]; MidiNode.Param["BeatDuration"].Value = (int)MBT[1]; //Note-related MidiNode.Param["Channel"].Value = (int)EventAnalysis.Channel; MidiNode.Param["Pitch"].Value = (int)EventAnalysis.Pitch; MidiNode.Param["Velocity"].Value = (int)EventAnalysis.Velocity; MidiNode.Param["Panning"].Value = pan; //Track-related MidiNode.Instrument = EventAnalysis.Instrument; MidiNode.TrackName = track; //PlaySound-related MidiNode.PlaySound = new PlaySoundInfo(); MidiNode.PlaySound.MandaVolume = (vol < 0) ? 100 : vol; MidiNode.PlaySound.SetPan(pan); //Generate Track & Instrument List var currentTrack = timeLine.TrackList.AsEnumerable().FirstOrDefault(t => t.Name == track); if (currentTrack == null) { currentTrack = new TimeLine.MidiSettingInspector { Name = track, Type = TimeLine.MidiSettingType.Track, Enable = true }; timeLine.TrackList.Add(currentTrack); } //Add new Track var currentInstrument = timeLine.InstrumentList.AsEnumerable().FirstOrDefault(ins => ins.Name == EventAnalysis.Instrument); if (currentInstrument == null) { currentInstrument = new TimeLine.MidiSettingInspector { Name = EventAnalysis.Instrument, Type = TimeLine.MidiSettingType.Instrument, Enable = true }; timeLine.InstrumentList.Add(currentInstrument); } //Add new Instrument if (!currentTrack.Instruments.Any(ins => ins.Name == EventAnalysis.Instrument)) { currentTrack.Instruments.Add(currentInstrument); currentTrack.InstrumentsUid.Add(currentInstrument.Uid); }//Line Track if (!currentInstrument.Tracks.Any(t => t.Name == track)) { currentInstrument.Tracks.Add(currentTrack); currentInstrument.TracksUid.Add(currentTrack.Uid); } #endregion MidiNodes.Add(MidiNode); } } } } #endregion #region MidiNodes in Order /* Set Total Progress */ timeLine.totalProgress = MidiNodes.Count * 2; bpm = 0; long bpm_key_t = 0; //When BPM Changes long bpm_key_mt = 0; MidiNodes = (from n in MidiNodes orderby n.Param["DeltaTickStart"].Value select n).ToList(); //Make Nodes in Order int synchroCount = 0; for (int i = 0; i < MidiNodes.Count; i++) //Calculate Tick Start { var n = MidiNodes[i]; if (n.IsEvent) { if (bpm != 0) { bpm_key_mt = MinecraftTickStart(n.Param["DeltaTickStart"].Value, midiFile.DeltaTicksPerQuarterNote, timeSignature, bpm, bpm_key_t, bpm_key_mt); } bpm = n.Param["BeatPerMinute"].Value; bpm_key_t = n.Param["DeltaTickStart"].Value; } else { n.Param["BeatPerMinute"].Value = (int)bpm; } if (synchroTick <= 0) { n.Param["MinecraftTickStart"].Value = (int)MinecraftTickStart(n.Param["DeltaTickStart"].Value, midiFile.DeltaTicksPerQuarterNote, timeSignature, bpm, bpm_key_t, bpm_key_mt); } else { //Using synchroTick n.Param["MinecraftTickStart"].Value = n.Param["DeltaTickStart"].Value / synchroTick; if (n.Param["DeltaTickStart"].Value % synchroTick == 0) { synchroCount++; } } /* Update Current Progress */ timeLine.currentProgress++; if (showProgress != null && timeLine.totalProgress > 0) { showProgress((double)timeLine.currentProgress / timeLine.totalProgress); } } timeLine.SynchronousRate = (double)synchroCount / MidiNodes.Count; #endregion #region MidiNodes -> TickNodes //Creat and Set Lenth of TickNodes if (timeLine.TickNodes == null) { timeLine.TickNodes = new List <TickNode>(); } var maxTick = MidiNodes.Max(n => n.Param["MinecraftTickStart"].Value); if (maxTick >= timeLine.TickNodes.Count) { var nowCount = timeLine.TickNodes.Count; for (int i = 0; i < maxTick - nowCount + 1; i++) { timeLine.TickNodes.Add(new TickNode()); } } //MidiNodes -> TickNodes foreach (MidiNode node in MidiNodes) { var index = node.Param["MinecraftTickStart"].Value; var track = node.TrackName; var instrument = node.Instrument; if (timeLine.TickNodes[index].MidiTracks.ContainsKey(track) == false) { timeLine.TickNodes[index].MidiTracks.Add(track, new Dictionary <string, List <MidiNode> >()); } if (timeLine.TickNodes[index].MidiTracks[track].ContainsKey(instrument) == false) { timeLine.TickNodes[index].MidiTracks[track].Add(instrument, new List <MidiNode>()); } timeLine.TickNodes[index].MidiTracks[track][instrument].Add(node); timeLine.TickNodes[index].BPM = node.Param["BeatPerMinute"].Value; timeLine.TickNodes[index].CurrentTick = index; /* Update Current Progress */ timeLine.currentProgress++; if (showProgress != null && timeLine.totalProgress > 0) { showProgress((double)timeLine.currentProgress / timeLine.totalProgress); } } #endregion timeLine.Param["TotalTicks"].Value = timeLine.TickNodes.Count; return(timeLine); //minecraft tick = AbsoluteTime / (bpm * ticksPerBeat) * 1200 #endregion } catch { return(null); } }
} //选中/取消选中元素 private void Update(TimeLine.MidiSettingInspector i) { if (计分板输出.IsChecked != null) { i.EnableScore = 计分板输出.IsChecked == true; } if (Playsound输出.IsChecked != null) { i.EnablePlaysound = Playsound输出.IsChecked == true; } if (小节索引.IsChecked != null) { i.BarIndex = 小节索引.IsChecked == true; } if (小节长度.IsChecked != null) { i.BeatDuration = 小节长度.IsChecked == true; } if (频道.IsChecked != null) { i.Channel = 频道.IsChecked == true; } if (键持续时间.IsChecked != null) { i.DeltaTickDuration = 键持续时间.IsChecked == true; } if (键起始时间.IsChecked != null) { i.DeltaTickStart = 键起始时间.IsChecked == true; } if (力度.IsChecked != null) { i.Velocity = 力度.IsChecked == true; } if (音高.IsChecked != null) { i.Pitch = 音高.IsChecked == true; } if (键持续刻数.IsChecked != null) { i.MinecraftTickDuration = 键持续刻数.IsChecked == true; } if (键起始刻数.IsChecked != null) { i.MinecraftTickStart = 键起始刻数.IsChecked == true; } if (Stopsound.IsChecked != null) { i.PlaysoundSetting.StopSound = Stopsound.IsChecked == true; } if (音高播放.IsChecked != null) { i.PlaysoundSetting.PitchPlayable = 音高播放.IsChecked == true; } if (播放相对坐标X.GetValue(TextBoxHelper.WatermarkProperty).ToString() == "") { i.PlaysoundSetting.ExecuteCood[0] = (播放相对坐标X.Text != "") ? Double.Parse(播放相对坐标X.Text) : 0; } if (播放相对坐标Y.GetValue(TextBoxHelper.WatermarkProperty).ToString() == "") { i.PlaysoundSetting.ExecuteCood[1] = (播放相对坐标X.Text != "") ? Double.Parse(播放相对坐标Y.Text) : 0; } if (播放相对坐标Z.GetValue(TextBoxHelper.WatermarkProperty).ToString() == "") { i.PlaysoundSetting.ExecuteCood[2] = (播放相对坐标X.Text != "") ? Double.Parse(播放相对坐标Z.Text) : 0; } if (相对玩家.GetValue(TextBoxHelper.WatermarkProperty).ToString() == "") { i.PlaysoundSetting.ExecuteTarget = 相对玩家.Text; } if (播放对象.GetValue(TextBoxHelper.WatermarkProperty).ToString() == "") { i.PlaysoundSetting.PlayTarget = 播放对象.Text; } if (源.GetValue(TextBoxHelper.WatermarkProperty).ToString() == "") { i.PlaysoundSetting.PlaySource = 源.Text; } if (子表达式.GetValue(TextBoxHelper.WatermarkProperty).ToString() == "") { i.PlaysoundSetting.InheritExpression = (子表达式.Text != "") ? 子表达式.Text : null; } if (额外延时.GetValue(TextBoxHelper.WatermarkProperty).ToString() == "") { i.PlaysoundSetting.ExtraDelay = (额外延时.Text != "") ? Int32.Parse(额外延时.Text) : -1; } if (音色名称.GetValue(TextBoxHelper.WatermarkProperty).ToString() == "") { i.PlaysoundSetting.SoundName = 音色名称.Text; } if (音量大小.Visibility == Visibility.Visible) { i.PlaysoundSetting.PercVolume = (音量增益.Value != -1) ? (int)(音量增益.Value * 2) : -1; } }