Add basic ghost notes feature. (#4575)

Lets you set a melody pattern as visible in the background of the Piano Roll
as support when building a new pattern. The pattern is visible throughout
the session or until cleared via the provided button.
This commit is contained in:
https://gitlab.com/users/CYBERDEViLNL
2019-01-17 19:07:52 +01:00
committed by Oskar Wallgren
parent 68cefc15c4
commit 5126070bb1
10 changed files with 181 additions and 4 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 452 B

View File

@@ -127,6 +127,10 @@ PianoRoll {
qproperty-noteOpacity: 128;
qproperty-noteBorders: true; /* boolean property, set false to have borderless notes */
qproperty-selectedNoteColor: rgb( 0, 125, 255 );
qproperty-ghostNoteColor: #000000;
qproperty-ghostNoteTextColor: #ffffff;
qproperty-ghostNoteOpacity: 50;
qproperty-ghostNoteBorders: true;
qproperty-barColor: #4afd85;
qproperty-markedSemitoneColor: rgba( 0, 255, 200, 60 );
/* Grid colors */

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

View File

@@ -146,6 +146,10 @@ PianoRoll {
qproperty-noteOpacity: 165;
qproperty-noteBorders: false; /* boolean property, set false to have borderless notes */
qproperty-selectedNoteColor: #064d79;
qproperty-ghostNoteColor: #000000;
qproperty-ghostNoteTextColor: #ffffff;
qproperty-ghostNoteOpacity: 50;
qproperty-ghostNoteBorders: false;
qproperty-barColor: #078f3a;
qproperty-markedSemitoneColor: rgba(255, 255, 255, 30);
/* Grid colors */

View File

@@ -187,6 +187,7 @@ public slots:
protected slots:
void openInPianoRoll();
void setGhostInPianoRoll();
void resetName();
void changeName();

View File

@@ -59,7 +59,9 @@ class PianoRoll : public QWidget
Q_PROPERTY( QColor lineColor READ lineColor WRITE setLineColor )
Q_PROPERTY( QColor noteModeColor READ noteModeColor WRITE setNoteModeColor )
Q_PROPERTY( QColor noteColor READ noteColor WRITE setNoteColor )
Q_PROPERTY( QColor ghostNoteColor READ ghostNoteColor WRITE setGhostNoteColor )
Q_PROPERTY( QColor noteTextColor READ noteTextColor WRITE setNoteTextColor )
Q_PROPERTY( QColor ghostNoteTextColor READ ghostNoteTextColor WRITE setGhostNoteTextColor )
Q_PROPERTY( QColor barColor READ barColor WRITE setBarColor )
Q_PROPERTY( QColor selectedNoteColor READ selectedNoteColor WRITE setSelectedNoteColor )
Q_PROPERTY( QColor textColor READ textColor WRITE setTextColor )
@@ -68,6 +70,8 @@ class PianoRoll : public QWidget
Q_PROPERTY( QColor markedSemitoneColor READ markedSemitoneColor WRITE setMarkedSemitoneColor )
Q_PROPERTY( int noteOpacity READ noteOpacity WRITE setNoteOpacity )
Q_PROPERTY( bool noteBorders READ noteBorders WRITE setNoteBorders )
Q_PROPERTY( int ghostNoteOpacity READ ghostNoteOpacity WRITE setGhostNoteOpacity )
Q_PROPERTY( bool ghostNoteBorders READ ghostNoteBorders WRITE setGhostNoteBorders )
Q_PROPERTY( QColor backgroundShade READ backgroundShade WRITE setBackgroundShade )
public:
enum EditModes
@@ -87,6 +91,7 @@ public:
void showPanTextFloat(panning_t pan, const QPoint &pos, int timeout=-1);
void setCurrentPattern( Pattern* newPattern );
void setGhostPattern( Pattern* newPattern );
inline void stopRecording()
{
@@ -141,6 +146,14 @@ public:
void setNoteOpacity( const int i );
bool noteBorders() const;
void setNoteBorders( const bool b );
QColor ghostNoteColor() const;
void setGhostNoteColor( const QColor & c );
QColor ghostNoteTextColor() const;
void setGhostNoteTextColor( const QColor & c );
int ghostNoteOpacity() const;
void setGhostNoteOpacity( const int i );
bool ghostNoteBorders() const;
void setGhostNoteBorders( const bool b );
QColor backgroundShade() const;
void setBackgroundShade( const QColor & c );
@@ -206,9 +219,12 @@ protected slots:
void selectRegionFromPixels( int xStart, int xEnd );
void clearGhostPattern();
signals:
void currentPatternChanged();
void ghostPatternSet(bool);
void semiToneMarkerMenuScaleSetEnabled(bool);
void semiToneMarkerMenuChordSetEnabled(bool);
@@ -309,6 +325,7 @@ private:
static const QVector<double> m_zoomLevels;
Pattern* m_pattern;
Pattern* m_ghostPattern;
QScrollBar * m_leftRightScroll;
QScrollBar * m_topBottomScroll;
@@ -388,6 +405,8 @@ private:
QColor m_noteModeColor;
QColor m_noteColor;
QColor m_noteTextColor;
QColor m_ghostNoteColor;
QColor m_ghostNoteTextColor;
QColor m_barColor;
QColor m_selectedNoteColor;
QColor m_textColor;
@@ -395,7 +414,9 @@ private:
QColor m_textShadow;
QColor m_markedSemitoneColor;
int m_noteOpacity;
int m_ghostNoteOpacity;
bool m_noteBorders;
bool m_ghostNoteBorders;
QColor m_backgroundShade;
signals:
@@ -412,7 +433,8 @@ public:
PianoRollWindow();
const Pattern* currentPattern() const;
void setCurrentPattern(Pattern* pattern);
void setCurrentPattern( Pattern* pattern );
void setGhostPattern( Pattern* pattern );
int quantization() const;
@@ -445,6 +467,7 @@ signals:
private slots:
void patternRenamed();
void ghostPatternSet( bool state );
private:
void focusInEvent(QFocusEvent * event);
@@ -456,6 +479,7 @@ private:
ComboBox * m_noteLenComboBox;
ComboBox * m_scaleComboBox;
ComboBox * m_chordComboBox;
QPushButton * m_clearGhostButton;
};

View File

@@ -182,6 +182,8 @@ PianoRoll::PianoRoll() :
m_lineColor( 0, 0, 0 ),
m_noteModeColor( 0, 0, 0 ),
m_noteColor( 0, 0, 0 ),
m_ghostNoteColor( 0, 0, 0 ),
m_ghostNoteTextColor( 0, 0, 0 ),
m_barColor( 0, 0, 0 ),
m_selectedNoteColor( 0, 0, 0 ),
m_textColor( 0, 0, 0 ),
@@ -189,7 +191,9 @@ PianoRoll::PianoRoll() :
m_textShadow( 0, 0, 0 ),
m_markedSemitoneColor( 0, 0, 0 ),
m_noteOpacity( 255 ),
m_ghostNoteOpacity( 255 ),
m_noteBorders( true ),
m_ghostNoteBorders( true ),
m_backgroundShade( 0, 0, 0 )
{
// gui names of edit modes
@@ -599,6 +603,26 @@ PianoRoll::~PianoRoll()
}
void PianoRoll::setGhostPattern( Pattern* newPattern )
{
m_ghostPattern = newPattern;
if( newPattern != nullptr )
{
// make sure to always get informed about the pattern being destroyed
connect( m_ghostPattern, SIGNAL( destroyedPattern( Pattern* ) ), this, SLOT( clearGhostPattern() ) );
emit ghostPatternSet( true );
}
}
void PianoRoll::clearGhostPattern()
{
setGhostPattern( nullptr );
emit ghostPatternSet( false );
update();
}
void PianoRoll::setCurrentPattern( Pattern* newPattern )
{
if( hasValidPattern() )
@@ -801,6 +825,30 @@ bool PianoRoll::noteBorders() const
void PianoRoll::setNoteBorders( const bool b )
{ m_noteBorders = b; }
QColor PianoRoll::ghostNoteColor() const
{ return m_ghostNoteColor; }
void PianoRoll::setGhostNoteColor( const QColor & c )
{ m_ghostNoteColor = c; }
QColor PianoRoll::ghostNoteTextColor() const
{ return m_ghostNoteTextColor; }
void PianoRoll::setGhostNoteTextColor( const QColor & c )
{ m_ghostNoteTextColor = c; }
int PianoRoll::ghostNoteOpacity() const
{ return m_ghostNoteOpacity; }
void PianoRoll::setGhostNoteOpacity( const int i )
{ m_ghostNoteOpacity = i; }
bool PianoRoll::ghostNoteBorders() const
{ return m_ghostNoteBorders; }
void PianoRoll::setGhostNoteBorders( const bool b )
{ m_ghostNoteBorders = b; }
QColor PianoRoll::backgroundShade() const
{ return m_backgroundShade; }
@@ -810,7 +858,6 @@ void PianoRoll::setBackgroundShade( const QColor & c )
void PianoRoll::drawNoteRect( QPainter & p, int x, int y,
int width, const Note * n, const QColor & noteCol, const QColor & noteTextColor,
const QColor & selCol, const int noteOpc, const bool borders, bool drawNoteName )
@@ -3024,6 +3071,50 @@ void PianoRoll::paintEvent(QPaintEvent * pe )
QPolygonF editHandles;
// -- Begin ghost pattern
if( m_ghostPattern != nullptr && m_ghostPattern != m_pattern )
{
for( const Note *note : m_ghostPattern->notes() )
{
int len_ticks = note->length();
if( len_ticks == 0 )
{
continue;
}
else if( len_ticks < 0 )
{
len_ticks = 4;
}
const int key = note->key() - m_startKey + 1;
int pos_ticks = note->pos();
int note_width = len_ticks * m_ppt / MidiTime::ticksPerTact();
const int x = ( pos_ticks - m_currentPosition ) *
m_ppt / MidiTime::ticksPerTact();
// skip this note if not in visible area at all
if( !( x + note_width >= 0 && x <= width() - WHITE_KEY_WIDTH ) )
{
continue;
}
// is the note in visible area?
if( key > 0 && key <= visible_keys )
{
// we've done and checked all, let's draw the
// note
drawNoteRect( p, x + WHITE_KEY_WIDTH,
y_base - key * KEY_LINE_HEIGHT,
note_width, note, ghostNoteColor(), ghostNoteTextColor(), selectedNoteColor(),
ghostNoteOpacity(), ghostNoteBorders(), drawNoteNames );
}
}
}
// -- End ghost pattern
for( const Note *note : m_pattern->notes() )
{
int len_ticks = note->length();
@@ -4221,8 +4312,15 @@ PianoRollWindow::PianoRollWindow() :
m_chordComboBox = new ComboBox( m_toolBar );
m_chordComboBox->setModel( &m_editor->m_chordModel );
m_chordComboBox->setFixedSize( 105, 22 );
m_chordComboBox->setToolTip( tr( "Chord") );
m_chordComboBox->setToolTip( tr( "Chord" ) );
// -- Clear ghost pattern button
m_clearGhostButton = new QPushButton( m_toolBar );
m_clearGhostButton->setIcon( embed::getIconPixmap( "clear_ghost_note" ) );
m_clearGhostButton->setToolTip( tr( "Clear ghost notes" ) );
m_clearGhostButton->setEnabled( false );
connect( m_clearGhostButton, SIGNAL( clicked() ), m_editor, SLOT( clearGhostPattern() ) );
connect( m_editor, SIGNAL( ghostPatternSet( bool ) ), this, SLOT( ghostPatternSet( bool ) ) );
zoomAndNotesToolBar->addWidget( zoom_lbl );
zoomAndNotesToolBar->addWidget( m_zoomingComboBox );
@@ -4243,6 +4341,9 @@ PianoRollWindow::PianoRollWindow() :
zoomAndNotesToolBar->addWidget( chord_lbl );
zoomAndNotesToolBar->addWidget( m_chordComboBox );
zoomAndNotesToolBar->addSeparator();
zoomAndNotesToolBar->addWidget( m_clearGhostButton );
// setup our actual window
setFocusPolicy( Qt::StrongFocus );
setFocus();
@@ -4265,6 +4366,14 @@ const Pattern* PianoRollWindow::currentPattern() const
void PianoRollWindow::setGhostPattern( Pattern* pattern )
{
m_editor->setGhostPattern( pattern );
}
void PianoRollWindow::setCurrentPattern( Pattern* pattern )
{
m_editor->setCurrentPattern( pattern );
@@ -4387,6 +4496,14 @@ void PianoRollWindow::patternRenamed()
void PianoRollWindow::ghostPatternSet( bool state )
{
m_clearGhostButton->setEnabled( state );
}
void PianoRollWindow::focusInEvent( QFocusEvent * event )
{
// when the window is given focus, also give focus to the actual piano roll

View File

@@ -637,6 +637,18 @@ void PatternView::openInPianoRoll()
void PatternView::setGhostInPianoRoll()
{
gui->pianoRoll()->setGhostPattern( m_pat );
gui->pianoRoll()->parentWidget()->show();
gui->pianoRoll()->show();
gui->pianoRoll()->setFocus();
}
void PatternView::resetName()
{
m_pat->setName( m_pat->m_instrumentTrack->name() );
@@ -663,7 +675,22 @@ void PatternView::constructContextMenu( QMenu * _cm )
_cm->insertAction( _cm->actions()[0], a );
connect( a, SIGNAL( triggered( bool ) ),
this, SLOT( openInPianoRoll() ) );
_cm->insertSeparator( _cm->actions()[1] );
if( gui->pianoRoll()->currentPattern() &&
gui->pianoRoll()->currentPattern() != m_pat &&
not m_pat->empty() )
{
QAction * b = new QAction( embed::getIconPixmap( "ghost_note" ),
tr( "Set as ghost in piano-roll" ), _cm );
_cm->insertAction( _cm->actions()[1], b );
connect( b, SIGNAL( triggered( bool ) ),
this, SLOT( setGhostInPianoRoll() ) );
_cm->insertSeparator( _cm->actions()[2] );
}
else
{
_cm->insertSeparator( _cm->actions()[1] );
}
_cm->addSeparator();