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:
@@ -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);
|
||||
|
||||
|
||||
@@ -248,6 +248,7 @@ protected slots:
|
||||
void clearGhostClip();
|
||||
void glueNotes();
|
||||
void fitNoteLengths(bool fill);
|
||||
void reverseNotes();
|
||||
void constrainNoteLengths(bool constrainMax);
|
||||
|
||||
void changeSnapMode();
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user