Add Midi Reversing (#7606)

Adds the ability to reverse the selected midi notes in the PianoRoll.

The tool is located under the wrench icon in the PianoRoll and can also be triggered with Shift-R.

---------

Co-authored-by: szeli1 <143485814+szeli1@users.noreply.github.com>
This commit is contained in:
regulus79
2025-04-19 15:40:21 -04:00
committed by GitHub
parent cb8badc0bb
commit 32c427eab4
4 changed files with 42 additions and 0 deletions

View File

@@ -79,6 +79,9 @@ public:
Note * addStepNote( int step );
void setStep( int step, bool enabled );
//! Horizontally flip the positions of the given notes.
void reverseNotes(const NoteVector& notes);
// Split the list of notes on the given position
void splitNotes(const NoteVector& notes, TimePos pos);

View File

@@ -248,6 +248,7 @@ protected slots:
void clearGhostClip();
void glueNotes();
void fitNoteLengths(bool fill);
void reverseNotes();
void constrainNoteLengths(bool constrainMax);
void changeSnapMode();

View File

@@ -786,6 +786,20 @@ void PianoRoll::constrainNoteLengths(bool constrainMax)
Engine::getSong()->setModified();
}
void PianoRoll::reverseNotes()
{
if (!hasValidMidiClip()) { return; }
const NoteVector selectedNotes = getSelectedNotes();
const auto& notes = selectedNotes.empty() ? m_midiClip->notes() : selectedNotes;
m_midiClip->reverseNotes(notes);
update();
getGUI()->songEditor()->update();
Engine::getSong()->setModified();
}
void PianoRoll::loadMarkedSemiTones(const QDomElement & de)
{
@@ -5035,6 +5049,10 @@ PianoRollWindow::PianoRollWindow() :
auto maxLengthAction = new QAction(embed::getIconPixmap("max_length"), tr("Max length as last"), noteToolsButton);
connect(maxLengthAction, &QAction::triggered, [this](){ m_editor->constrainNoteLengths(true); });
auto reverseAction = new QAction(embed::getIconPixmap("flip_x"), tr("Reverse Notes"), noteToolsButton);
connect(reverseAction, &QAction::triggered, [this](){ m_editor->reverseNotes(); });
reverseAction->setShortcut(combine(Qt::SHIFT, Qt::Key_R));
noteToolsButton->addAction(glueAction);
noteToolsButton->addAction(knifeAction);
noteToolsButton->addAction(strumAction);
@@ -5042,6 +5060,7 @@ PianoRollWindow::PianoRollWindow() :
noteToolsButton->addAction(cutOverlapsAction);
noteToolsButton->addAction(minLengthAction);
noteToolsButton->addAction(maxLengthAction);
noteToolsButton->addAction(reverseAction);
notesActionsToolBar->addWidget(noteToolsButton);

View File

@@ -314,6 +314,25 @@ void MidiClip::setStep( int step, bool enabled )
void MidiClip::reverseNotes(const NoteVector& notes)
{
addJournalCheckPoint();
// Find the very first start position and the very last end position of all the notes.
TimePos firstPos = (*std::min_element(notes.begin(), notes.end(), [](const Note* n1, const Note* n2){ return Note::lessThan(n1, n2); }))->pos();
TimePos lastPos = (*std::max_element(notes.begin(), notes.end(), [](const Note* n1, const Note* n2){ return n1->endPos() < n2->endPos(); }))->endPos();
for (auto note : notes)
{
TimePos newStart = lastPos - (note->pos() - firstPos) - note->length();
note->setPos(newStart);
}
rearrangeAllNotes();
emit dataChanged();
}
void MidiClip::splitNotes(const NoteVector& notes, TimePos pos)
{