using static QuikDawEditor.EDITING.MidiMethods; namespace QuikDawEditor { public partial class ClipControl : UserControl, INotifyPropertyChanged { public string RelRes() { ReleaseResources(); return "Resources released"; } public delegate void CoverMessageForChangingClipProperty(string message); public event CoverMessageForChangingClipProperty ChangingClipProperty; public delegate void MouseDownOnClipLabelHandler(ClipControl clipControl, MouseButtonEventArgs e); public event MouseDownOnClipLabelHandler MouseDownOnClipLabel; public delegate void MouseUpOnClipLabelHandler(ClipControl clipControl, MouseButtonEventArgs e); public event MouseDownOnClipLabelHandler MouseUpOnClipLabel; public delegate void MouseMoveOnClipLabelHandler(ClipControl clipControl, MouseEventArgs e); public event MouseMoveOnClipLabelHandler MouseMoveOnClipLabel; public event PropertyChangedEventHandler PropertyChanged; private void NotifyPropertyChanged([CallerMemberName] String propertyName = "") { if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); } } public ClipControl() { InitializeComponent(); } public Clip thisClip { get { return (Clip)this.DataContext; } } private void ClipControl_Loaded(object sender, RoutedEventArgs e) { this.SelectionRect.ContextMenu.Opened += ContextMenu_Opened; this.MouseLeave += ClipControl_MouseLeave; this.MouseEnter += ClipControl_MouseEnter; if (thisClip.IsMidiClip) { thisClip.UpdateMidiImageSource(); return; } } private void ContextMenu_Opened(object sender, RoutedEventArgs e) { thisClip.GainPointsVisible = true; } private void GainPath_PreviewMouseDown(object sender, MouseButtonEventArgs e) { if (e.ChangedButton == MouseButton.Right) return; if (MouseOverClipUnitLeft | MouseOverClipUnitRight) return; e.Handled = true; SelectionRect.Visibility = Visibility.Hidden; double newPointMs = PixelsToMsecZoomed(e.GetPosition(this).X) + thisClip.ClipRelativeLoopStartMs; float newGainValue = 2f - 2* (float)(e.GetPosition(ClipAreaGrid).Y / thisClip.ClipAreaHeight) ; GainPoint lastGainPoint = thisClip.GainPoints.LastOrDefault(gp => gp.sourcePointms < newPointMs); int insertIdx = lastGainPoint == null ? 0 : thisClip.GainPoints.IndexOf(lastGainPoint) + 1; GainPoint newGainPoint = new GainPoint() { GainValue = newGainValue, sourcePointms = newPointMs }; thisClip.GainPoints.Insert(insertIdx, newGainPoint); thisClip.NotifyGainPointsChanged(); undoActions.Add(new GainPointAddedUndo(thisClip.UndoClipID, insertIdx)); editingProject.NeedsSaving = true; } private void SplitClipMenuItem_Click(object sender, RoutedEventArgs e) { double splitPointms = thisClip.ClipLeftMs + PixelsToMsecZoomed(thisClip.SplitButLineX); splitPointms = Math.Round(splitPointms / 10) * 10; SplitThisClip(thisClip, splitPointms); thisClip.IsSplitLineVisible = false; } private void GainPointThumb_DragStarted(object sender, System.Windows.Controls.Primitives.DragStartedEventArgs e) { thisGP = (GainPoint)((System.Windows.Controls.Primitives.Thumb)sender).DataContext; preDragGPMs = thisGP.sourcePointms; preDragGPVal = thisGP.GainValue; GainPoint prevGP = thisClip.GainPoints.LastOrDefault(gp => gp.sourcePointms < thisGP.sourcePointms); bool isLeftMostGP = thisGP.sourcePointms == thisClip.ClipRelativeLoopStartMs | prevGP == null; GainPoint nextGP = thisClip.GainPoints.FirstOrDefault(gp => gp.sourcePointms > thisGP.sourcePointms); bool isRightMostGP = thisGP.sourcePointms == thisClip.ClipRelativeLoopEndMs | nextGP == null; RightMax = isLeftMostGP ? thisClip.ClipRelativeLoopStartMs : (isRightMostGP ? thisClip.ClipRelativeLoopEndMs : nextGP.sourcePointms - 1); LeftMin = isRightMostGP ? thisClip.ClipRelativeLoopEndMs : (isLeftMostGP ? thisClip.ClipRelativeLoopStartMs : prevGP.sourcePointms + 1); thisGP.GainPointValVisibility = Visibility.Visible; } GainPoint thisGP; double LeftMin; double RightMax; double preDragGPMs; float preDragGPVal; private void GainPointThumb_DragDelta(object sender, System.Windows.Controls.Primitives.DragDeltaEventArgs e) { thisGP.sourcePointms = Math.Min(Math.Max(thisGP.sourcePointms + PixelsToMsec(e.HorizontalChange), LeftMin), RightMax); thisGP.GainValue = Math.Max(Math.Min(2, thisGP.GainValue - (float)(2D * e.VerticalChange / thisClip.ClipAreaHeight)), 0); thisClip.NotifyGainPointsChanged(); } private void GainPointThumb_DragCompleted(object sender, System.Windows.Controls.Primitives.DragCompletedEventArgs e) { thisGP.GainPointValVisibility = Visibility.Hidden; undoActions.Add(new GainPointMovedUndoClass(thisClip.UndoClipID, thisClip.GainPoints.IndexOf(thisGP), preDragGPMs, preDragGPVal)); } private void ClearAllGainPointsMenuItem_Click(object sender, RoutedEventArgs e) { List removedGainPoints = new List(); for (int gpno = thisClip.GainPoints.Count - 2; gpno > 0; gpno -= 1) removedGainPoints.Add(thisClip.GainPoints[gpno]); undoActions.Add(new GainPointsClearedUndoClass(thisClip.UndoClipID, removedGainPoints, thisClip.ClipStartGainPoint.GainValue, thisClip.ClipEndGainPoint.GainValue)); thisClip.GainPoints.Clear(); thisClip.GainPoints.Add(new GainPoint() { sourcePointms = thisClip.ClipRelativeLoopStartMs, IsLeftEdgeGainPoint = true, GainValue = 1 }); thisClip.GainPoints.Add(new GainPoint() { sourcePointms = thisClip.ClipRelativeLoopEndMs, IsRightEdgeGainPoint = true, GainValue = 1 }); thisClip.NotifyGainPointsChanged(); editingProject.NeedsSaving = true; } private void ContextMenu_Closed(object sender, RoutedEventArgs e) { foreach (Track t in editingProject.GetAllTracksInProject) foreach (Clip c in t.Clips) c.IsSplitLineVisible = false; } private void NormalizeMenuItem_Click(object sender, RoutedEventArgs e) { normalizingClipControl = this; if (thisClip.ClipSourceFileName.Contains("_NORMALIZED")) { MessageBox.Show("This clip source has already been normalized"); return; } if (MessageBox.Show("Normalize this clip?:\n" + thisClip.ClipSourceFileName, "Normalize ciip", MessageBoxButton.YesNo) == MessageBoxResult.No) return; NormalizeClip(); } private void RenameClipMenuItem_Click(object sender, RoutedEventArgs e) { InputBox inpb = new InputBox("Rename clip", thisClip.ClipName) { Owner = Application.Current.MainWindow }; inpb.ShowDialog(); if (inpb.Result == "Cancel") return; undoActions.Add(new ClipNameChangedUndoClass(thisClip.UndoClipID, thisClip.ClipName)); thisClip.ClipName = inpb.TextBoxText; } private void DeleteClipMenuItem_Click(object sender, RoutedEventArgs e) { if (MessageBox.Show("Delete clip?\n" + thisClip.ClipName, "Delete clips", MessageBoxButton.YesNo) == MessageBoxResult.No) return; Clip deletingClip = thisClip; undoActions.Add(new ClipDeleteUndo(deletingClip.myTrack.UndoTrackID, deletingClip.GetIndexInTrack, GetJsonForClip(deletingClip))); deletingClip.myTrack.RemoveAndDisposeClip(deletingClip); editingProject.NeedsSaving = true; } private void MuteClipMenuItem_Click(object sender, RoutedEventArgs e) { if (thisClip == null) return; thisClip.IsMuted =!thisClip.IsMuted; undoActions.Add(new ClipMuteUndoClass(thisClip.UndoClipID)); if (!thisClip.IsMuted) { thisClip.ResetMe(projPlayer.CurrentPlayingPosMS); //projPlayer.mmsp.ResetAllClips(projPlayer.CurrentPlayingPosMS); } editingProject.NeedsSaving = true; } private void LoopClipMenuItem_Click(object sender, RoutedEventArgs e) { thisClip.IsLooped = !thisClip.IsLooped; undoActions.Add(new ClipLoopUndoClass(thisClip.UndoClipID, thisClip.ClipWidthMs, thisClip.ClipEndGainPoint.GainValue)); if (!thisClip.IsLooped) { if (thisClip.ClipRightMs > thisClip.ClipVirtualStartMs + thisClip.ClipSourceLenMilliseconds - thisClip.ClipLeftMs) thisClip.ClipWidthMs = thisClip.ClipVirtualStartMs + thisClip.ClipSourceLenMilliseconds - thisClip.ClipLeftMs; } editingProject.NeedsSaving = true; } private void FuseToNewClipMenuItem_Click(object sender, RoutedEventArgs e) { if (MessageBox.Show("Fuse this clip into a new clip?\n\n" + thisClip.ClipName + "\n\n(Length: " + thisClip.ClipWidthInfo + ")", "Fuse clip", MessageBoxButton.YesNo) == MessageBoxResult.No) return; FuseToNewClip(); } private void MuteSelectionMenuItem_Click(object sender, RoutedEventArgs e) { double rectStartMs = Math.Max(thisClip.ClipRelativeLoopStartMs + 1, PixelsToMsecZoomed(SelectionRect.Margin.Left)); double rectEndMs = Math.Min(thisClip.ClipRelativeLoopEndMs - 1, PixelsToMsecZoomed(SelectionRect.Margin.Left + SelectionRect.Width)); InsertMuteGainPoints(rectStartMs + 1, rectEndMs - 1); //+-1 to make sure the start and end are not included SelectionRect.Visibility = Visibility.Hidden; editingProject.NeedsSaving = true; thisClip.GainPointsVisible = true; } private void CutSelectionMenuItem_Click(object sender, RoutedEventArgs e) { double rectStartMs = PixelsToMsecZoomed(SelectionRect.Margin.Left ); double rectEndMs = PixelsToMsecZoomed(SelectionRect.Margin.Left + SelectionRect.Width); double absRectStartMs = rectStartMs + thisClip.ClipLeftMs; double absRectEndMs = rectEndMs + thisClip.ClipLeftMs; CutOutSelectionToNewClip(absRectStartMs, absRectEndMs); SelectionRect.Visibility = Visibility.Hidden; } private void FadeOutToEndMenuItem_Click(object sender, RoutedEventArgs e) { double startPointms = thisClip.ClipRelativeLoopStartMs + PixelsToMsecZoomed(thisClip.SplitButLineX); FadeOutToEnd(startPointms); thisClip.GainPointsVisible = true; } private void FadeInFromStartMenuItem_Click(object sender, RoutedEventArgs e) { double endPointms = thisClip.ClipRelativeLoopStartMs + PixelsToMsecZoomed(thisClip.SplitButLineX); FadeInFromStart(endPointms); thisClip.GainPointsVisible = true; } private void ResetSelectionGainPointsMenuItem_Click(object sender, RoutedEventArgs e) { double rectStartMs = Math.Max(thisClip.ClipRelativeLoopStartMs + 1, PixelsToMsecZoomed(SelectionRect.Margin.Left)); double rectEndMs = Math.Min(thisClip.ClipRelativeLoopEndMs - 1, PixelsToMsecZoomed(SelectionRect.Margin.Left + SelectionRect.Width)); ResetSelectionGainPoints(rectStartMs, rectEndMs, true); thisClip.GainPointsVisible = true; } private void ClearSelectionGainPointsMenuItem_Click(object sender, RoutedEventArgs e) { double rectStartMs = Math.Max(thisClip.ClipRelativeLoopStartMs + 1, PixelsToMsecZoomed(SelectionRect.Margin.Left)); double rectEndMs = Math.Min(thisClip.ClipRelativeLoopEndMs - 1, PixelsToMsecZoomed(SelectionRect.Margin.Left + SelectionRect.Width)); ResetSelectionGainPoints(rectStartMs, rectEndMs, false); } private void ClipInfoTBMenuItem_ContextMenuOpening(object sender, ContextMenuEventArgs e) { OpenAudioSourceLocationMenuItem.Visibility = thisClip.IsAudioClip ? Visibility.Visible : Visibility.Collapsed; ClipDetailedInfoMenuItem.Header = new TextBlock() { Text = thisClip.ClipInfo, TextWrapping = TextWrapping.Wrap }; DeleteClipMI.IsEnabled = projPlayer.IsProjectNotPlaying; TrackContentControlChildBeingModified = false; } private void SelectionRect_PreviewKeyDown(object sender, KeyEventArgs e) { switch (e.Key) { //case Key.M: // InsertMutedGainPoints((Clip)this.DataContext); // break; //case Key.C: // ClearSelection(); // break; } } private void SelectionRect_PreviewMouseUp(object sender, MouseButtonEventArgs e) { //SelectionRect.Focus(); } private void ClipContextMenu_Opened(object sender, RoutedEventArgs e) { ContextMenu thisCM = (ContextMenu)sender; if (thisClip.IsOrphanClip) { thisCM.IsEnabled = false; thisCM.IsOpen = false; } LoopedMI.DataContext = thisClip; NormalizeMI.DataContext = thisClip; MidiFunctionsMI.DataContext = thisClip; MutedMI.DataContext = thisClip; ChangePitchMI.DataContext = thisClip; AdjustClipGainMI.DataContext = thisClip; } private void thisClipControl_DragOver(object sender, DragEventArgs e) { e.Effects = DragDropEffects.None; } private void GainPath_MouseEnter(object sender, MouseEventArgs e) { mouseOverGainPath = true; } private void GainPath_MouseLeave(object sender, MouseEventArgs e) { mouseOverGainPath = false; } private void GainPointThumb_MouseLeave(object sender, MouseEventArgs e) { mouseOverGainPoint = false; } private void GainPointDeleteMenuItem_Click(object sender, RoutedEventArgs e) { if (thisGP.IsLeftOrRightEdgeGainPoint) return; undoActions.Add(new GainPointDeletedUndoClass(thisClip.UndoClipID, thisClip.GainPoints.IndexOf(thisGP), thisGP)); thisClip.GainPoints.Remove(thisGP); thisClip.NotifyGainPointsChanged(); editingProject.NeedsSaving = true; } bool mouseOverGainPoint = false; bool mouseOverGainPath = false; System.Windows.Controls.Primitives.Thumb thisThumb = null; private void GainPointThumb_MouseEnter(object sender, MouseEventArgs e) { mouseOverGainPoint = true; thisThumb = (System.Windows.Controls.Primitives.Thumb)sender; thisGP = (GainPoint)thisThumb.DataContext; } private void thisClipControl_PreviewMouseUp(object sender, MouseButtonEventArgs e) { TrackContentControlChildBeingModified = false; if (e.ChangedButton == MouseButton.Right) { if (mouseOverGainPoint) { e.Handled = true; thisThumb.ContextMenu.IsOpen = thisGP.IsLeftOrRightEdgeGainPoint ? false : true; thisClip.GainPointsVisible = true; return; } } } private void thisClipControl_PreviewMouseDown(object sender, MouseButtonEventArgs e) { TrackContentControlChildBeingModified = true; editingProject.GainAdjustingClip = null; editingProject.ClipGainSliderVisibility = Visibility.Hidden; } private void ReverseClipMenuItem_Click(object sender, RoutedEventArgs e) { thisClip.IsReversed = !thisClip.IsReversed; undoActions.Add(new ClipReverseUndoClass(thisClip.UndoClipID)); } private void QuantizeMI_Click(object sender, RoutedEventArgs e) { QuantizeWindow qWin = new QuantizeWindow() { Owner = App.Current.MainWindow, ShowInTaskbar = false }; qWin.ShowDialog(); if (qWin.Result == "Ok") { QuantizeMidiNotes(thisClip, thisClip.ClipMidiEvents, qWin.snapTo, (bool)qWin.QuantizeNoteStartsCB.IsChecked, (bool)qWin.QuantizeNoteLengthsCB.IsChecked, (bool)qWin.ApplySwingCB.IsChecked); } } private void ClipPitchSlider_PreviewMouseUp(object sender, MouseButtonEventArgs e) { undoActions.Add(new ClipPitchChangeUndoClass(thisClip.UndoClipID, thisClip.preslidePitchChangeValue)); } private void ClipPitchSlider_PreviewMouseDown(object sender, MouseButtonEventArgs e) { thisClip.preslidePitchChangeValue = thisClip.PitchChangeValue; } private void ClipPitchSlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs e) { thisClip.floatPitchValue = thisClip.GetPitchFloatFromHalfStepValue((int)thisClip.PitchChangeValue); if (editingProject != null) editingProject.NeedsSaving = true; } private void ExtendMidiClipBut_Click(object sender, RoutedEventArgs e) { undoActions.Add(new ClipExtendMidiClipUndoClass(thisClip.UndoClipID, thisClip.ClipSourceLenMilliseconds, thisClip.ClipWidthMs)); thisClip.ClipSourceLenMilliseconds += editingProject.BeatsPerMeasure * MillisecondsPerBeat; thisClip.ClipWidthMs = thisClip.ClipSourceLenMilliseconds; thisClip.UpdateMidiImageSource(); thisClip.UpdateClipSourceSizeChanged(); if (editingProject.pianoRoll.IsVisible) editingProject.pianoRoll.myClip = editingProject.pianoRoll.myClip; //to trigger redraw of pianoroll MouseInExtendButton = false; } private void ThisClip_SizeChanged(object sender, SizeChangedEventArgs e) { thisClip.ClipAreaHeight = this.ActualHeight - 20; thisClip.RedrawGainPoints(); } private void AdjustClipGainMenuItem_Click(object sender, RoutedEventArgs e) { editingProject.ClipGainSliderVisibility = Visibility.Visible; editingProject.ClipGainSliderMargin = new Thickness(this.Margin.Left - 6 / editingProject.ViewXZoomFac + Mouse.GetPosition(this).X / editingProject.ViewXZoomFac, thisClip.myTrack.GetActualTrackTop + MouseUpY, 0, 0); editingProject.GainSliderValue = (float)Math.Log(thisClip.ClipGainFactor); editingProject.GainAdjustingClip = thisClip; } } }