Feature: Glue notes (#5721)
Tool to glue selected notes together. Selected notes that are adjacent to each other or overlapping are transformed into one note stretching over the combined notes on/off times. Key command: <Shift> + G Partially fixes: #746 which is part of #4877 Co-authored-by: Hyunjin Song <tteu.ingog@gmail.com> Co-authored-by: IanCaio <iancaio_dev@hotmail.com> Co-authored-by: Spekular <Spekularr@gmail.com> Co-authored-by: Kevin Zander <veratil@gmail.com> Co-authored-by: Oskar Wallgren <oskar.wallgren13@gmail.com>
This commit is contained in:
BIN
data/themes/default/glue.png
Normal file
BIN
data/themes/default/glue.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 407 B |
BIN
data/themes/default/tool.png
Normal file
BIN
data/themes/default/tool.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 466 B |
@@ -208,6 +208,7 @@ protected slots:
|
||||
void selectRegionFromPixels( int xStart, int xEnd );
|
||||
|
||||
void clearGhostPattern();
|
||||
void glueNotes();
|
||||
|
||||
|
||||
signals:
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
#include <QScrollBar>
|
||||
#include <QStyleOption>
|
||||
#include <QtMath>
|
||||
#include <QToolButton>
|
||||
|
||||
#ifndef __USE_XOPEN
|
||||
#define __USE_XOPEN
|
||||
@@ -644,6 +645,73 @@ void PianoRoll::clearGhostPattern()
|
||||
}
|
||||
|
||||
|
||||
void PianoRoll::glueNotes()
|
||||
{
|
||||
if (hasValidPattern())
|
||||
{
|
||||
NoteVector selectedNotes = getSelectedNotes();
|
||||
if (selectedNotes.empty())
|
||||
{
|
||||
TextFloat::displayMessage( tr( "Glue notes failed" ),
|
||||
tr( "Please select notes to glue first." ),
|
||||
embed::getIconPixmap( "glue", 24, 24 ),
|
||||
3000 );
|
||||
return;
|
||||
}
|
||||
|
||||
// Make undo possible
|
||||
m_pattern->addJournalCheckPoint();
|
||||
|
||||
// Sort notes on key and then pos.
|
||||
std::sort(selectedNotes.begin(), selectedNotes.end(),
|
||||
[](const Note * note, const Note * compareNote) -> bool
|
||||
{
|
||||
if (note->key() == compareNote->key())
|
||||
{
|
||||
return note->pos() < compareNote->pos();
|
||||
}
|
||||
return note->key() < compareNote->key();
|
||||
});
|
||||
|
||||
QList<Note *> noteToRemove;
|
||||
|
||||
NoteVector::iterator note = selectedNotes.begin();
|
||||
auto nextNote = note+1;
|
||||
NoteVector::iterator end = selectedNotes.end();
|
||||
|
||||
while (note != end && nextNote != end)
|
||||
{
|
||||
// key and position match for glue. The notes are already
|
||||
// sorted so we don't need to test that nextNote is the same
|
||||
// position or next in sequence.
|
||||
if ((*note)->key() == (*nextNote)->key()
|
||||
&& (*nextNote)->pos() <= (*note)->pos()
|
||||
+ qMax(MidiTime(0), (*note)->length()))
|
||||
{
|
||||
(*note)->setLength(qMax((*note)->length(),
|
||||
MidiTime((*nextNote)->endPos() - (*note)->pos())));
|
||||
noteToRemove.push_back(*nextNote);
|
||||
++nextNote;
|
||||
}
|
||||
// key or position doesn't match
|
||||
else
|
||||
{
|
||||
note = nextNote;
|
||||
nextNote = note+1;
|
||||
}
|
||||
}
|
||||
|
||||
// Remove old notes
|
||||
for (int i = 0; i < noteToRemove.count(); ++i)
|
||||
{
|
||||
m_pattern->removeNote(noteToRemove[i]);
|
||||
}
|
||||
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void PianoRoll::loadMarkedSemiTones(const QDomElement & de)
|
||||
{
|
||||
// clear marked semitones to prevent leftover marks
|
||||
@@ -4361,6 +4429,21 @@ PianoRollWindow::PianoRollWindow() :
|
||||
DropToolBar *timeLineToolBar = addDropToolBarToTop( tr( "Timeline controls" ) );
|
||||
m_editor->m_timeLine->addToolButtons( timeLineToolBar );
|
||||
|
||||
// -- Note modifier tools
|
||||
// Toolbar
|
||||
QToolButton * noteToolsButton = new QToolButton(m_toolBar);
|
||||
noteToolsButton->setIcon(embed::getIconPixmap("tool"));
|
||||
noteToolsButton->setPopupMode(QToolButton::InstantPopup);
|
||||
|
||||
// Glue
|
||||
QAction * glueAction = new QAction(embed::getIconPixmap("glue"),
|
||||
tr("Glue"), noteToolsButton);
|
||||
connect(glueAction, SIGNAL(triggered()), m_editor, SLOT(glueNotes()));
|
||||
glueAction->setShortcut( Qt::SHIFT | Qt::Key_G );
|
||||
|
||||
noteToolsButton->addAction(glueAction);
|
||||
|
||||
notesActionsToolBar->addWidget(noteToolsButton);
|
||||
|
||||
addToolBarBreak();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user