using Jacobi.Vst.Core; using QuikDawEditor.EDITING.PianoRollModel; using static QuikDawEditor.EDITING.MidiMethods; namespace QuikDawEditor { public partial class PianoRoll { bool MouseDownMovingInNotesIC = false; bool MouseDownInNotesIC = false; Point MouseDownInNotesICPoint = new Point(0, 0); double previousSourceLengthMs; private void NotesIC_PreviewMouseDown(object sender, MouseButtonEventArgs e) { if (e.ChangedButton == MouseButton.Right) return; if (MouseDownOnNote | MouseDownOnNoteRightEdge) return; if (MidiClipExtendMouseRightOver) { MidiClipExtendMouseRightDown = true; NotesIC.CaptureMouse(); previousSourceLengthMs = myClip.ClipSourceLenMilliseconds; return; } if (e.Source.GetType() == typeof(ItemsControl)) { MouseDownInNotesIC = true; MouseDownInNotesICPoint = e.GetPosition(NotesIC); NotesIC.CaptureMouse(); thisPianoRoll.SelVisible = false; if (newMNote != null) { foreach (ActiveVstPlugin thisVsti in myClip.myTrack.TrackInstrumentVsts.Where(vsti => vsti.IsActive)) thisVsti.SendStopNoteMessage(newMNote.Note); PianoKeyPlayOff(newMNote.Note); } int addNote = GetNoteFromYLocation(e.GetPosition(NotesIC).Y, NotesIC.ActualHeight); double noteonms = GetMsFromXLocationTruncated(e.GetPosition(NotesIC).X, currentSnapToMs); double noteoffms = SnapToMilliseconds == -1 ? noteonms + GetSnapMsVal(.0625M) : noteonms + currentSnapToMs; newMNote = new QDMidiNote() { Note = addNote, ClipRelNoteOnTimeMs = noteonms, ClipRelNoteOffTimeMs = noteoffms, Velocity = 127, revZoomX = thisPianoRoll.WorkingGridXZoomFacReverse }; foreach (ActiveVstPlugin thisVsti in myClip.myTrack.TrackInstrumentVsts.Where(vsti => vsti.IsActive)) thisVsti.SendPlayNoteMessage(newMNote.Note, newMNote.Velocity); PianoKeyPlayOn(newMNote.Note); } } bool NotesWereMoved = false; QDMidiNote newMNote; bool MidiClipExtendMouseRightOver = false; bool MidiClipExtendMouseRightDown = false; private void NotesIC_PreviewMouseMove(object sender, MouseEventArgs e) { if (MouseDownOnNote | MouseDownOnNoteRightEdge) return; if (MouseDownInNotesIC) { double selwidthPix = e.GetPosition(NotesIC).X - MouseDownInNotesICPoint.X; double selwidthms = PixelsToMsecGrid(selwidthPix); double selheightPix = e.GetPosition(NotesIC).Y - MouseDownInNotesICPoint.Y; //if (selwidthPix > 10 || selheightPix > 10) if (Math.Abs(selwidthPix) > 10 || Math.Abs(selheightPix) > 10) { MouseDownMovingInNotesIC = true; foreach (ActiveVstPlugin thisVsti in myClip.myTrack.TrackInstrumentVsts.Where(vsti => vsti.IsActive)) thisVsti.SendStopNoteMessage(newMNote.Note); PianoKeyPlayOff(newMNote.Note); thisPianoRoll.SelVisible = true; switch (Math.Sign(selheightPix)) { case 1: thisPianoRoll.SelTopPix = MouseDownInNotesICPoint.Y; thisPianoRoll.SelHeightPix = selheightPix; break; case -1: thisPianoRoll.SelTopPix = e.GetPosition(NotesIC).Y; thisPianoRoll.SelHeightPix = -selheightPix; break; } switch (Math.Sign(selwidthPix)) { case 1: thisPianoRoll.SelLeftPix = MouseDownInNotesICPoint.X; thisPianoRoll.SelWidthMs = selwidthms; break; case -1: thisPianoRoll.SelLeftPix = e.GetPosition(NotesIC).X; thisPianoRoll.SelWidthMs = -selwidthms; break; } foreach (QDMidiNote selmnote in thisPianoRoll.SelectedMidiNotes) selmnote.Selected = false; foreach (QDMidiNote mnote in thisPianoRoll.myClip.ClipMidiNotes.Where(mn => thisPianoRoll.ContainsNote(mn))) mnote.Selected = true; //NotesWereMoved = true; } return; } if (MidiClipExtendMouseRightDown) { //changes midi clip source width thisPianoRoll.myClip.ClipSourceLenMilliseconds = Math.Max(editingProject.BeatsPerMeasure / 2 * MillisecondsPerBeat, GetMsFromXLocationRounded(e.GetPosition(WorkingGrid).X, currentSnapToMs)); thisPianoRoll.myClip.UpdateMidiImageSource(); thisPianoRoll.myClip.RecreateClipUnitBackgrounds(); thisPianoRoll.SetClip(thisPianoRoll.myClip); return; } if (Keyboard.IsKeyDown(Key.LeftCtrl) | Keyboard.IsKeyDown(Key.RightCtrl)) { if (e.GetPosition(NotesIC).X >= NotesIC.ActualWidth - 10) { MidiClipExtendMouseRightOver = true; Cursor = Cursors.ScrollWE; } else Cursor = Cursors.Arrow; } } private void NotesIC_PreviewMouseUp(object sender, MouseButtonEventArgs e) { NotesIC.ReleaseMouseCapture(); MidiClipExtendMouseRightOver = false; MouseDownInNotesIC = false; if (MouseDownMovingInNotesIC) { MouseDownMovingInNotesIC = false; thisPianoRoll.SelVisible = false; return; } if (MidiClipExtendMouseRightDown) { thisPianoRoll.DrawMeasureLines(); undoActions.Add(new ClipChangeMidiBaseLengthUndoClass(myClip.UndoClipID, previousSourceLengthMs)); } else { if (e.OriginalSource.GetType() == typeof(Border)) return; if (e.ChangedButton == MouseButton.Right) return; myClip.ClipMidiNotes.Add(newMNote); myClip.SortMidiEventSubGroup(typeof(QDMidiNote)); thisPianoRoll.UpdateMidiNotesDisplay(); undoActions.Add(new MidiNoteAddUndo(myClip.UndoClipID, myClip.ClipMidiNotes.IndexOf(newMNote))); foreach (ActiveVstPlugin thisVsti in myClip.myTrack.TrackInstrumentVsts.Where(vsti => vsti.IsActive)) thisVsti.SendStopNoteMessage(newMNote.Note); PianoKeyPlayOff(newMNote.Note); } myClip.UpdateMidiImageSource(); MidiClipExtendMouseRightDown = false; } private bool MouseDownOnNote, MouseDownMoving, MouseOverNoteRightEdge, MouseDownOnNoteRightEdge; private double MouseDownOnNoteX; int lastNote = 0; int nextNote = 0; List undoPreviousNoteOffTimes; List undoPreviousNoteOnTimes; List undoPreviousNoteNumbers; double previousNoteOffTimeMs; double previousNoteOnTimeMs; int previousNoteNumber; private void NoteRectangle_PreviewMouseDown(object sender, MouseButtonEventArgs e) { Border thisRect = (Border)sender; QDMidiNote thisDN = (QDMidiNote)thisRect.DataContext; thisRect.CaptureMouse(); if (MouseOverNoteRightEdge) { if (myClip.ClipMidiNotes.Where(cmn => cmn.Selected).Contains(thisDN)) undoPreviousNoteOffTimes = myClip.ClipMidiNotes.Where(cmn => cmn.Selected).ToList().ConvertAll(dn => dn.ClipRelNoteOffTimeMs); else previousNoteOffTimeMs = thisDN.ClipRelNoteOffTimeMs; MouseDownOnNoteRightEdge = true; } else { if (myClip.ClipMidiNotes.Where(cmn => cmn.Selected).Contains(thisDN)) { undoPreviousNoteOnTimes = myClip.ClipMidiNotes.Where(cmn => cmn.Selected).ToList().ConvertAll(dn => dn.ClipRelNoteOnTimeMs); undoPreviousNoteOffTimes = myClip.ClipMidiNotes.Where(cmn => cmn.Selected).ToList().ConvertAll(dn => dn.ClipRelNoteOffTimeMs); undoPreviousNoteNumbers = myClip.ClipMidiNotes.Where(cmn => cmn.Selected).ToList().ConvertAll(dn => dn.Note); } else { previousNoteOnTimeMs = thisDN.ClipRelNoteOnTimeMs; previousNoteOffTimeMs = thisDN.ClipRelNoteOffTimeMs; previousNoteNumber = thisDN.Note; } MouseDownOnNoteX = e.GetPosition(thisRect).X; MouseDownOnNote = true; foreach (ActiveVstPlugin thisVsti in myClip.myTrack.TrackInstrumentVsts.Where(vsti => vsti.IsActive)) { if (lastMN != null) thisVsti.SendStopNoteMessage(lastMN.Note); thisVsti.SendPlayNoteMessage(thisDN.Note, thisDN.Velocity); } lastMN = thisDN; PianoKeyPlayOn(thisDN.Note); //if (!(Keyboard.IsKeyDown(Key.LeftCtrl) | Keyboard.IsKeyDown(Key.RightCtrl))) // foreach (QDMidiNote selmnote in thisPianoRoll.SelectedMidiNotes) // selmnote.Selected = false; //thisDN.Selected = !thisDN.Selected; } } private void NoteRectangle_PreviewMouseUp(object sender, MouseButtonEventArgs e) { Border thisRect = (Border)sender; thisRect.ReleaseMouseCapture(); MouseDownOnNote = false; e.Handled = true; QDMidiNote thisDN = (QDMidiNote)thisRect.DataContext; foreach (ActiveVstPlugin thisVsti in myClip.myTrack.TrackInstrumentVsts.Where(vsti=>vsti.IsActive)) thisVsti.SendStopNoteMessage(thisDN.Note); PianoKeyPlayOff(thisDN.Note); if (MouseDownOnNoteRightEdge) { MouseDownOnNoteRightEdge = false; if (myClip.ClipMidiNotes.Where(cmn => cmn.Selected).Contains(thisDN)) { List undoNoteIndexes = myClip.ClipMidiNotes.Where(cmn => cmn.Selected).ToList().ConvertAll(dn => myClip.ClipMidiNotes.IndexOf(dn)); undoActions.Add(new MidiNoteLengthsChangeUndo(myClip.UndoClipID, undoNoteIndexes, new List(undoPreviousNoteOffTimes))); } else undoActions.Add(new MidiNoteLengthsChangeUndo(myClip.UndoClipID, new List() { myClip.ClipMidiNotes.IndexOf(thisDN) }, new List() { previousNoteOffTimeMs })); return; } if (MouseDownMoving) { myClip.SortMidiEventSubGroup(typeof(QDMidiNote)); if (myClip.ClipMidiNotes.Where(cmn => cmn.Selected).Contains(thisDN)) { List undoNoteIndexes = myClip.ClipMidiNotes.Where(cmn => cmn.Selected).ToList().ConvertAll(dn => myClip.ClipMidiNotes.IndexOf(dn)); undoActions.Add(new MidiNoteMovesUndo(myClip.UndoClipID, undoNoteIndexes, new List(undoPreviousNoteNumbers), new List(undoPreviousNoteOnTimes), new List(undoPreviousNoteOffTimes))); } else undoActions.Add(new MidiNoteMovesUndo(myClip.UndoClipID, new List() { myClip.ClipMidiNotes.IndexOf(thisDN) }, new List() { previousNoteNumber }, new List() { previousNoteOnTimeMs }, new List() { previousNoteOffTimeMs })); myClip.UpdateMidiImageSource(); MouseDownMoving = false; //projPlayer.bufferedSampleProvider.ClearBufferTapered(); return; } if (!NotesWereMoved) { if (!(Keyboard.IsKeyDown(Key.LeftCtrl) | Keyboard.IsKeyDown(Key.RightCtrl))) { foreach (QDMidiNote selmnote in thisPianoRoll.SelectedMidiNotes) selmnote.Selected = false; } thisDN.Selected = !thisDN.Selected; } NotesWereMoved = false; } private void NoteRectangle_PreviewMouseMove(object sender, MouseEventArgs e) { Border thisRect = (Border)sender; QDMidiNote thisDN = (QDMidiNote)thisRect.DataContext; if (MouseDownOnNote) { MouseDownMoving = true; nextNote = GetNoteFromYLocation(e.GetPosition(NotesIC).Y, NotesIC.ActualHeight); int noteDiff = nextNote - thisDN.Note; double snapMs = GetMsFromXLocationRounded(e.GetPosition(NotesIC).X - MouseDownOnNoteX, currentSnapToMs); int msDiff = (int)(snapMs - Math.Round(thisDN.ClipRelNoteOnTimeMs)); switch (thisDN.Selected) { case true: //This is a selected note, so do the same for any other selected notes int maxSelectedNote = thisPianoRoll.SelectedMidiNotes.Count == 0 ? thisDN.Note : thisPianoRoll.SelectedMidiNotes.ToList().Max(mn => mn.Note); int minSelectedNote = thisPianoRoll.SelectedMidiNotes.Count == 0 ? thisDN.Note : thisPianoRoll.SelectedMidiNotes.ToList().Min(mn => mn.Note); if (minSelectedNote + noteDiff < 0 || maxSelectedNote + noteDiff >= NumMidiNotesVertical) return; int minSelectedMs = thisPianoRoll.SelectedMidiNotes.Count == 0 ? (int)thisDN.ClipRelNoteOnTimeMs : thisPianoRoll.SelectedMidiNotes.ToList().Min(mn => (int)mn.ClipRelNoteOnTimeMs); if (minSelectedMs + msDiff < 0) return; QDMidiNote MaxRightMsMidiNote = thisPianoRoll.SelectedMidiNotes.Where(smn => smn.ClipRelRightMs == thisPianoRoll.SelectedMidiNotes.ToList().Max(mn => (int)mn.ClipRelRightMs)).FirstOrDefault(); double MaxSelectedVirtualRightMs = currentSnapToMs == -1 ? MaxRightMsMidiNote.ClipRelRightMs : MaxRightMsMidiNote.ClipRelNoteOnTimeMs + SnapToMilliseconds; if (MaxSelectedVirtualRightMs + msDiff > thisPianoRoll.myClip.ClipSourceLenMilliseconds) return; foreach (QDMidiNote mmnote in thisPianoRoll.SelectedMidiNotes) mmnote.Note += noteDiff; foreach (QDMidiNote mmnote in thisPianoRoll.SelectedMidiNotes) { double keepthisNoteWidthMs = mmnote.NoteLengthMs; mmnote.ClipRelNoteOnTimeMs += msDiff; mmnote.ClipRelNoteOffTimeMs = mmnote.ClipRelNoteOnTimeMs + keepthisNoteWidthMs; } break; case false: //Just this note if (thisDN.Note + noteDiff < 0 || thisDN.Note + noteDiff >= NumMidiNotesVertical) return; if (thisDN.ClipRelNoteOnTimeMs + msDiff < 0) return; double currentVirtualRightMs = currentSnapToMs == -1 ? thisDN.ClipRelRightMs : thisDN.ClipRelNoteOnTimeMs + SnapToMilliseconds; if (currentVirtualRightMs + msDiff > thisPianoRoll.myClip.ClipSourceLenMilliseconds) return; thisDN.Note += noteDiff; double keepNoteWidthMs = thisDN.NoteLengthMs; thisDN.ClipRelNoteOnTimeMs += msDiff; thisDN.ClipRelNoteOffTimeMs = thisDN.ClipRelNoteOnTimeMs + keepNoteWidthMs; break; } if (nextNote != lastNote) { foreach (ActiveVstPlugin avp in myClip.myTrack.TrackInstrumentVsts) { //Debug.WriteLine("avp=" + avp.GetProgName); avp.midEventsToSend = new List(AllNotesOffMidiEvents); avp.midEventsToSend.Add(GetMidiEvent(nextNote, thisDN.Velocity, avp.Channel)); avp.myContext.PluginCommandStub.Commands.ProcessEvents(avp.midEventsToSend.ToArray()); avp.midEventsToSend.Clear(); } PianoKeyPlayOff(lastNote); PianoKeyPlayOn(thisDN.Note); lastNote = nextNote; NotesWereMoved = true; } // if (e.GetPosition(this.UDScrollViewer).Y < yScale) // this.UDScrollViewer.ScrollToVerticalOffset(this.UDScrollViewer.VerticalOffset - 0.1); // if (e.GetPosition(this.UDScrollViewer).Y > this.UDScrollViewer.ActualHeight - yScale) // this.UDScrollViewer.ScrollToVerticalOffset(this.UDScrollViewer.VerticalOffset + 0.1); // if (e.GetPosition(this.RLScrollViewer).X < 0) // this.RLScrollBar.Value -= 0.001; // if (e.GetPosition(this.RLScrollViewer).X > this.RLScrollViewer.ActualWidth) // this.RLScrollBar.Value += 0.001; editingProject.NeedsSaving = true; return; } if (MouseDownOnNoteRightEdge) { switch (thisDN.Selected) { case true: double offDiff = GetMsFromXLocationRounded(e.GetPosition(NotesIC).X, currentSnapToMs) - thisDN.ClipRelNoteOffTimeMs; foreach (QDMidiNote mmnote in thisPianoRoll.SelectedMidiNotes) mmnote.ClipRelNoteOffTimeMs = Math.Max(mmnote.ClipRelNoteOnTimeMs + currentSnapToMs, mmnote.ClipRelNoteOffTimeMs + offDiff); break; case false: thisDN.ClipRelNoteOffTimeMs = Math.Max(thisDN.ClipRelNoteOnTimeMs + SnapToMilliseconds, GetMsFromXLocationRounded(e.GetPosition(NotesIC).X, currentSnapToMs)); break; } myClip.UpdateMidiImageSource(); editingProject.NeedsSaving = true; return; } if (e.GetPosition(thisRect).X > thisRect.ActualWidth - 3 / thisPianoRoll.WorkingGridXZoomFac) { MouseOverNoteRightEdge = true; Cursor = Cursors.SizeWE; } else { MouseOverNoteRightEdge = false; Cursor = DefCursor; } } private void Rectangle_MouseLeave(object sender, MouseEventArgs e) { MouseOverNoteRightEdge = false; Cursor = DefCursor; } QDMidiNote lastMN = null; private void WorkingGrid_MouseWheel(object sender, MouseWheelEventArgs e) { e.Handled = true; double k = 1; switch (Math.Sign(e.Delta)) { case 1: k = 1.1; break; case -1: k = 0.9; break; } double prevCursorMs = PixelsToMsecGrid(Mouse.GetPosition(UDScrollViewer).X); thisPianoRoll.WorkingGridXZoomFac = Math.Min(6, Math.Max(0.1, thisPianoRoll.WorkingGridXZoomFac * k)); MidiPlayPosLine.Width = 2 * thisPianoRoll.WorkingGridXZoomFacReverse; thisPianoRoll.DrawMeasureLines(); UDScrollViewer.ScrollToHorizontalOffset(MsecToPixelsGrid(prevCursorMs) * thisPianoRoll.WorkingGridXZoomFac - Mouse.GetPosition(UDScrollViewer).X); } private void ScaleCanvas_PreviewMouseDown(object sender, MouseButtonEventArgs e) { double newPianoRollMs = GetMsFromXLocationRounded(e.GetPosition(ScaleCanvas).X, currentSnapToMs); projPlayer.CurrentPlayingPosMS = thisPianoRoll.myClip.ClipLeftMs + newPianoRollMs; thisPianoRoll.CurrentMidiPlayingPosMS = projPlayer.CurrentPlayingPosMS; projPlayer.ChangePlayPos(projPlayer.CurrentPlayingPosMS); projPlayer.UpdatePlayPosDisplay(); } private void PianoKeysGrid_PreviewMouseMove(object sender, MouseEventArgs e) { //Debug.WriteLine("ypos=" + e.GetPosition(PianoKeysGrid).Y.ToString()); PianoKey hoveringPianoKey = thisPianoRoll.PianoKeys.Where(pk => e.GetPosition(PianoKeysGrid).Y >= pk.keyYPos && e.GetPosition(PianoKeysGrid).Y <= pk.keyYPos + 10).FirstOrDefault(); if (hoveringPianoKey != null) { foreach (PianoKey pkey in thisPianoRoll.PianoKeys.Where(pk => pk.IsHovering == true && pk.NoteNo != hoveringPianoKey.NoteNo)) pkey.IsHovering = false; hoveringPianoKey.IsHovering = true; } } private void PianoKeysGrid_MouseLeave(object sender, MouseEventArgs e) { foreach (PianoKey pkey in thisPianoRoll.PianoKeys) { pkey.IsHovering = false; pkey.IsPlaying = false; } } private void PianoKeysGrid_PreviewMouseDown(object sender, MouseButtonEventArgs e) { PianoKey hoveringPianoKey = thisPianoRoll.PianoKeys.Where(pk => pk.IsHovering == true).FirstOrDefault(); if (hoveringPianoKey != null) { hoveringPianoKey.IsPlaying = true; foreach (ActiveVstPlugin thisVsti in myClip.myTrack.TrackInstrumentVsts.Where(vsti => vsti.IsActive)) thisVsti.SendPlayNoteMessage(hoveringPianoKey.NoteNo, 127); } } private void PianoKeysGrid_PreviewMouseUp(object sender, MouseButtonEventArgs e) { PianoKey playingPianoKey = thisPianoRoll.PianoKeys.Where(pk => pk.IsPlaying == true).FirstOrDefault(); if (playingPianoKey != null) { playingPianoKey.IsPlaying = false; foreach (ActiveVstPlugin thisVsti in myClip.myTrack.TrackInstrumentVsts.Where(vsti => vsti.IsActive)) thisVsti.SendStopNoteMessage(playingPianoKey.NoteNo); } } } }