diff --git a/TuneLab/Data/IMidiPart.cs b/TuneLab/Data/IMidiPart.cs index 5c5337d..1adca87 100644 --- a/TuneLab/Data/IMidiPart.cs +++ b/TuneLab/Data/IMidiPart.cs @@ -342,6 +342,69 @@ public static void ClearParameters(this IMidiPart part, double start, double end automation.Clear(start, end, 5); } } + internal static MidiPartInfo MergePartInfos(MidiPartInfo[] SortedPartInfos) + { + double PosAxisTrans(PartInfo curPart, double pos) + { + var startPos = SortedPartInfos[0].Pos; + var absPos = pos + curPart.Pos; + return absPos - startPos; + } + var ret = new MidiPartInfo(); + var basePart = SortedPartInfos[0]; + ret.Pos = SortedPartInfos.First().Pos; + ret.Dur = SortedPartInfos.Last().Dur + SortedPartInfos.Last().Pos - ret.Pos; + ret.Voice = basePart.Voice; + ret.Gain = basePart.Gain; + ret.Name = basePart.Name; + ret.Properties = basePart.Properties; + + for (int i = 0; i < SortedPartInfos.Length; i++) + { + var curPart = SortedPartInfos[i]; + var curPartPos = PosAxisTrans(curPart, 0); + var nextPartPos = i + 1 < SortedPartInfos.Length ? PosAxisTrans(SortedPartInfos[i + 1], 0) : double.MaxValue; + foreach(var item in curPart.Notes) + { + item.Pos=PosAxisTrans(curPart,item.Pos); + if (item.Pos < curPartPos) continue; + if (item.Pos >= nextPartPos) break; + ret.Notes.Add(item); + } + foreach (var item in curPart.Vibratos) + { + item.Pos = PosAxisTrans(curPart, item.Pos); + if (item.Pos < curPartPos) continue; + if (item.Pos >= nextPartPos) break; + ret.Vibratos.Add(item); + } + foreach (var item in curPart.Pitch) + { + List line= new List(); + foreach (var point in item) + { + var X = PosAxisTrans(curPart, point.X); + if (X < curPartPos) continue; + if (X >= nextPartPos) break; + line.Add(new Base.Structures.Point(X, point.Y)); + } + ret.Pitch.Add(line); + } + foreach (var kvp in curPart.Automations) + { + if (!ret.Automations.ContainsKey(kvp.Key)) { ret.Automations.Add(kvp.Key, new AutomationInfo() { DefaultValue = kvp.Value.DefaultValue, Points = new List() }); } + + foreach (var point in kvp.Value.Points) + { + var X = PosAxisTrans(curPart, point.X); + if (X < curPartPos) continue; + if (X >= nextPartPos) break; + ret.Automations[kvp.Key].Points.Add(new Base.Structures.Point(X, point.Y)); + } + } + } + return ret; + } public static MidiPartInfo RangeInfo(this IMidiPart part, double start, double end) { diff --git a/TuneLab/UI/MainWindow/Editor/TrackWindow/TrackScrollView/TrackScrollViewOperation.cs b/TuneLab/UI/MainWindow/Editor/TrackWindow/TrackScrollView/TrackScrollViewOperation.cs index 5c4a03f..b3fb545 100644 --- a/TuneLab/UI/MainWindow/Editor/TrackWindow/TrackScrollView/TrackScrollViewOperation.cs +++ b/TuneLab/UI/MainWindow/Editor/TrackWindow/TrackScrollView/TrackScrollViewOperation.cs @@ -163,6 +163,32 @@ protected override void OnMouseDown(MouseDownEventArgs e) menu.Items.Add(menuItem); } } + { + var trackIndex = TrackVerticalAxis.GetPosition(e.Position.Y).TrackIndex; + var track = Project.Tracks[trackIndex]; + if (part.IsSelected && track.Parts.Count(p => p.IsSelected) > 1) + { + var partArray = track.Parts.OrderBy(p => p.StartTime).ToArray(); + int partIndex = Array.FindIndex(partArray, p => p == part); + int prevIndex = partIndex; + int nextIndex = partIndex; + while (prevIndex > 0) { if (!partArray[prevIndex - 1].IsSelected || partArray[prevIndex - 1] is not MidiPart) break;prevIndex--; } + while (nextIndex < partArray.Length-1) { if (!partArray[nextIndex + 1].IsSelected || partArray[nextIndex+1] is not MidiPart) break; nextIndex++; } + if (nextIndex > prevIndex) + { + var menuItem = new MenuItem().SetName("Merge".Tr(TC.Menu)).SetAction(() => + { + var oldParts = partArray.Skip(prevIndex).Take(nextIndex - prevIndex + 1); + var oldPartInfos = oldParts.Select(p=>(MidiPartInfo)p.GetInfo()).ToArray(); + var newPartInfo = IMidiPartExtension.MergePartInfos(oldPartInfos); + foreach(var oldPart in oldParts) track.RemovePart(oldPart); + track.InsertPart(track.CreatePart(newPartInfo)); + track.Commit(); + }); + menu.Items.Add(menuItem); + } + } + } { var menuItem = new MenuItem() { Header = "Set Voice".Tr(TC.Menu) }; var allEngines = VoicesManager.GetAllVoiceEngines();