Skip to content

Commit

Permalink
Initial Implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
regulus79 committed Feb 16, 2025
1 parent d145f78 commit 56ae721
Show file tree
Hide file tree
Showing 4 changed files with 71 additions and 45 deletions.
3 changes: 3 additions & 0 deletions include/MidiClip.h
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,9 @@ class LMMS_EXPORT MidiClip : public Clip
// Split the list of notes on the given position
void splitNotes(const NoteVector& notes, TimePos pos);

// Split the list of notes along a line
void splitNotesAlongLine(TimePos pos1, int key1, TimePos pos2, int key2);

// clip-type stuff
inline Type type() const
{
Expand Down
11 changes: 8 additions & 3 deletions include/PianoRoll.h
Original file line number Diff line number Diff line change
Expand Up @@ -456,9 +456,14 @@ protected slots:
// did we start a mouseclick with shift pressed
bool m_startedWithShift;

// Variable that holds the position in ticks for the knife action
int m_knifeTickPos;
void updateKnifePos(QMouseEvent* me);
// Variables that hold the start and end position for the knife line
TimePos m_knifeStartTickPos;
int m_knifeStartKey;
TimePos m_knifeEndTickPos;
int m_knifeEndKey;
bool m_knifeDown;

void updateKnifePos(QMouseEvent* me, bool initial);

friend class PianoRollWindow;

Expand Down
72 changes: 30 additions & 42 deletions src/gui/editors/PianoRoll.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1610,19 +1610,8 @@ void PianoRoll::mousePressEvent(QMouseEvent * me )
// -- Knife
if (m_editMode == EditMode::Knife && me->button() == Qt::LeftButton)
{
NoteVector n;
Note* note = noteUnderMouse();

if (note)
{
n.push_back(note);

updateKnifePos(me);

// Call splitNotes for the note
m_midiClip->splitNotes(n, TimePos(m_knifeTickPos));
}

updateKnifePos(me, true);
m_knifeDown = true;
update();
return;
}
Expand Down Expand Up @@ -2140,6 +2129,7 @@ void PianoRoll::setKnifeAction()
m_knifeMode = m_editMode;
m_editMode = EditMode::Knife;
m_action = Action::Knife;
m_knifeDown = false;
setCursor(Qt::ArrowCursor);
update();
}
Expand All @@ -2149,6 +2139,7 @@ void PianoRoll::cancelKnifeAction()
{
m_editMode = m_knifeMode;
m_action = Action::None;
m_knifeDown = false;
update();
}

Expand Down Expand Up @@ -2277,6 +2268,11 @@ void PianoRoll::mouseReleaseEvent( QMouseEvent * me )
m_midiClip->rearrangeAllNotes();

}
else if (m_action == Action::Knife)
{
m_midiClip->splitNotesAlongLine(TimePos(m_knifeStartTickPos), m_knifeStartKey, TimePos(m_knifeEndTickPos), m_knifeEndKey);
m_knifeDown = false;
}

if( m_action == Action::MoveNote || m_action == Action::ResizeNote )
{
Expand Down Expand Up @@ -2380,7 +2376,7 @@ void PianoRoll::mouseMoveEvent( QMouseEvent * me )
// Update Knife position if we are on knife mode
if (m_editMode == EditMode::Knife)
{
updateKnifePos(me);
updateKnifePos(me, false);
}

if( me->y() > PR_TOP_MARGIN || m_action != Action::None )
Expand Down Expand Up @@ -2761,19 +2757,27 @@ void PianoRoll::mouseMoveEvent( QMouseEvent * me )



void PianoRoll::updateKnifePos(QMouseEvent* me)
void PianoRoll::updateKnifePos(QMouseEvent* me, bool initial)
{
// Calculate the TimePos from the mouse
int mouseViewportPos = me->x() - m_whiteKeyWidth;
int mouseTickPos = mouseViewportPos * TimePos::ticksPerBar() / m_ppb + m_currentPosition;
int mouseViewportPosX = me->x() - m_whiteKeyWidth;
int mouseViewportPosY = keyAreaBottom() - 1 - me->y();
int mouseTickPos = mouseViewportPosX * TimePos::ticksPerBar() / m_ppb + m_currentPosition;
int mouseKey = mouseViewportPosY / m_keyLineHeight + m_startKey - 1;

// If ctrl is not pressed, quantize the position
if (!(me->modifiers() & Qt::ControlModifier))
{
mouseTickPos = floor(mouseTickPos / quantization()) * quantization();
}

m_knifeTickPos = mouseTickPos;
if (initial)
{
m_knifeStartTickPos = mouseTickPos;
m_knifeStartKey = mouseKey;
}
m_knifeEndTickPos = mouseTickPos;
m_knifeEndKey = mouseKey;
}


Expand Down Expand Up @@ -3533,37 +3537,21 @@ void PianoRoll::paintEvent(QPaintEvent * pe )
}

// -- Knife tool (draw cut line)
if (m_action == Action::Knife)
if (m_action == Action::Knife && m_knifeDown)
{
auto xCoordOfTick = [this](int tick) {
return m_whiteKeyWidth + (
(tick - m_currentPosition) * m_ppb / TimePos::ticksPerBar());
};
Note* n = noteUnderMouse();
if (n)
{
const int key = n->key() - m_startKey + 1;
int y = y_base - key * m_keyLineHeight;
int x1 = xCoordOfTick(m_knifeStartTickPos);
int y1 = y_base - (m_knifeStartKey - m_startKey + 1) * m_keyLineHeight;
int x2 = xCoordOfTick(m_knifeEndTickPos);
int y2 = y_base - (m_knifeEndKey - m_startKey + 1) * m_keyLineHeight;

int x = xCoordOfTick(m_knifeTickPos);
p.setPen(QPen(m_knifeCutLineColor, 1));
p.drawLine(x1, y1, x2, y2);

if (x > xCoordOfTick(n->pos()) &&
x < xCoordOfTick(n->pos() + n->length()))
{
p.setPen(QPen(m_knifeCutLineColor, 1));
p.drawLine(x, y, x, y + m_keyLineHeight);

setCursor(Qt::BlankCursor);
}
else
{
setCursor(Qt::ArrowCursor);
}
}
else
{
setCursor(Qt::ArrowCursor);
}
setCursor(Qt::BlankCursor);
}
// -- End knife tool

Expand Down
30 changes: 30 additions & 0 deletions src/tracks/MidiClip.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -344,6 +344,36 @@ void MidiClip::splitNotes(const NoteVector& notes, TimePos pos)
}
}

void MidiClip::splitNotesAlongLine(TimePos pos1, int key1, TimePos pos2, int key2)
{
if (m_notes.empty()) { return; }
// Don't split if the line is horitzontal
if (key1 == key2) { return; }

addJournalCheckPoint();

NoteVector notesCopy = m_notes;

float slope = 1.f * (pos2 - pos1) / (key2 - key1);

for (const auto& note : notesCopy)
{
TimePos keyIntercept = slope * (note->key() - key1) + pos1;
if (note->pos() < keyIntercept && note->endPos() > keyIntercept)
{
Note newNote1 = Note(*note);
newNote1.setLength(keyIntercept - note->pos());
addNote(newNote1, false);

Note newNote2 = Note(*note);
newNote2.setPos(keyIntercept);
newNote2.setLength(note->endPos() - keyIntercept);
addNote(newNote2, false);

removeNote(note);
}
}
}



Expand Down

0 comments on commit 56ae721

Please sign in to comment.