Pitch Bending Directly in the Piano Roll (#7759)

This PR modifies how the Detuning tool works in the piano roll to let the user modify the automation curve right on the notes. This is actually fairly simple, as automation clips already contain the functions for dragging and removing points like in the Automation Editor. So essentially all that's being done is calculating the relative pos of the mouse to the nearest note, and setting the drag value in the automation clip to that position and key.

You can still access the old automation editor version by shift-click

messmerd asked if the code could be made general for any future note parameter besides detuning, in preparation for CLAP per-note parameter automation. I have refactored the relevant functions to accept an enum type for the kind of note parameter, although currently only detuning is supported.

---------

Co-authored-by: Sotonye Atemie <sakertooth@gmail.com>
Co-authored-by: Sotonye Atemie <satemiej@gmail.com>
Co-authored-by: szeli1 <143485814+szeli1@users.noreply.github.com>
This commit is contained in:
regulus79
2026-01-04 14:18:06 -05:00
committed by GitHub
parent 2db75bd5d9
commit 11b4a9bddc
4 changed files with 263 additions and 16 deletions

View File

@@ -41,6 +41,7 @@ namespace lmms
class DetuningHelper;
class AutomationClip;
enum class Key : int
@@ -123,6 +124,13 @@ public:
Type type() const { return m_type; }
inline void setType(Type t) { m_type = t; }
//! Types of per-note automation. Currently only detuning/pitch bending is supported.
enum class ParameterType
{
Detuning = 0
};
AutomationClip* parameterCurve(ParameterType paramType);
// used by GUI
inline void setSelected( const bool selected ) { m_selected = selected; }
inline void setOldKey( const int oldKey ) { m_oldKey = oldKey; }

View File

@@ -456,6 +456,8 @@ private:
void drawDetuningInfo( QPainter & _p, const Note * _n, int _x, int _y ) const;
bool mouseOverNote();
Note * noteUnderMouse();
//! Calculates the closest note to the mouse given their parameter automation curve
Note* parameterEditNoteUnderMouse(Note::ParameterType paramType);
// turn a selection rectangle into selected notes
void computeSelectedNotes( bool shift );
@@ -473,6 +475,20 @@ private:
void updateKnifePos(QMouseEvent* me, bool initial);
//! Varaibles which hold which mouse buttons are being held while editing the detuning/parameter of notes.
bool m_parameterEditDownLeft = false;
bool m_parameterEditDownRight = false;
//! Stores the last edited position for the note detuning/parameter curves.
//! When erasing nodes when dragging the mouse, all nodes in the range of the last mouse pos to the current mouse pos are removed. Without this, when dragging the mouse super fast, some nodes could get missed; this ensures all nodes from the previous mouse position to the current one will get deleted.
std::optional<int> m_lastParameterEditTick = std::nullopt;
//! The current note whose detuning/parameter curve is being edited.
Note* m_parameterEditClickedNote;
//! Updates the currently dragged node position in the detuning/parameter curves of the selected notes.
void updateParameterEditPos(QMouseEvent* me, Note::ParameterType paramType);
//! Finishes the dragging of the current node of the detuning/parameter curves
void applyParameterEditPos(Note::ParameterType paramType);
//! Stores the chords for the strum tool
std::vector<NoteVector> m_selectedChords;
//! Computes which notes belong to which chords from the selection