Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ghost notes for the automation editor #6940

Merged
merged 15 commits into from
Nov 25, 2023
2 changes: 2 additions & 0 deletions data/themes/classic/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ lmms--gui--AutomationEditor {
qproperty-scaleColor: qlineargradient(spread:reflect,
x1:0, y1:0.5, x2:1, y2:0.5,
stop:0 #333, stop:1 #202020);

qproperty-ghostNoteColor: rgba(248, 248, 255, 125);
}

/* text box */
Expand Down
Binary file added data/themes/default/automation_ghost_note.png
sakertooth marked this conversation as resolved.
Show resolved Hide resolved
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions data/themes/default/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ lmms--gui--AutomationEditor {

qproperty-graphColor: rgba(69,42,153,180);
qproperty-scaleColor: #262b30;
qproperty-ghostNoteColor: rgba(248, 248, 255, 125);
}

/* text box */
Expand Down
28 changes: 24 additions & 4 deletions include/AutomationEditor.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,16 +26,17 @@
#ifndef LMMS_GUI_AUTOMATION_EDITOR_H
#define LMMS_GUI_AUTOMATION_EDITOR_H

#include <QPushButton>
#include <QWidget>
#include <array>

#include "AutomationClip.h"
#include "ComboBoxModel.h"
#include "Editor.h"

#include "lmms_basics.h"
#include "JournallingObject.h"
#include "MidiClip.h"
#include "TimePos.h"
#include "AutomationClip.h"
#include "ComboBoxModel.h"
#include "lmms_basics.h"

class QPainter;
class QPixmap;
Expand Down Expand Up @@ -68,8 +69,10 @@ class AutomationEditor : public QWidget, public JournallingObject
Q_PROPERTY(QBrush graphColor MEMBER m_graphColor)
Q_PROPERTY(QColor crossColor MEMBER m_crossColor)
Q_PROPERTY(QColor backgroundShade MEMBER m_backgroundShade)
Q_PROPERTY(QColor ghostNoteColor MEMBER m_ghostNoteColor)
public:
void setCurrentClip(AutomationClip * new_clip);
void setGhostMidiClip(MidiClip* newMidiClip);

inline const AutomationClip * currentClip() const
{
Expand Down Expand Up @@ -159,6 +162,12 @@ protected slots:
/// Updates the clip's quantization using the current user selected value.
void setQuantization();

void resetGhostNotes()
{
m_ghostNotes = nullptr;
update();
}

private:

enum class Action
Expand All @@ -183,6 +192,10 @@ protected slots:

static const int VALUES_WIDTH = 64;

static const int NOTE_HEIGHT = 10; // height of individual notes
static const int NOTE_MARGIN = 40; // total border margin for notes
static const int MIN_NOTE_RANGE = 20; // min number of keys for fixed size

AutomationEditor();
AutomationEditor( const AutomationEditor & );
~AutomationEditor() override;
Expand Down Expand Up @@ -211,6 +224,8 @@ protected slots:
float m_bottomLevel;
float m_topLevel;

MidiClip* m_ghostNotes;

void centerTopBottomScroll();
void updateTopBottomLevels();

Expand Down Expand Up @@ -261,6 +276,7 @@ protected slots:
QBrush m_scaleColor;
QColor m_crossColor;
QColor m_backgroundShade;
QColor m_ghostNoteColor;

friend class AutomationEditorWindow;

Expand All @@ -284,6 +300,8 @@ class AutomationEditorWindow : public Editor
~AutomationEditorWindow() override = default;

void setCurrentClip(AutomationClip* clip);
void setGhostMidiClip(MidiClip* clip) { m_editor->setGhostMidiClip(clip); };

const AutomationClip* currentClip();

void dropEvent( QDropEvent * _de ) override;
Expand Down Expand Up @@ -337,6 +355,8 @@ private slots:
ComboBox * m_zoomingXComboBox;
ComboBox * m_zoomingYComboBox;
ComboBox * m_quantizeComboBox;

QPushButton* m_resetGhostNotes;
};

} // namespace gui
Expand Down
3 changes: 2 additions & 1 deletion include/MidiClipView.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ public slots:
protected slots:
void openInPianoRoll();
void setGhostInPianoRoll();
void setGhostInAutomationEditor();

void resetName();
void changeName();
Expand Down Expand Up @@ -99,7 +100,7 @@ protected slots:
QColor m_mutedNoteBorderColor;

QStaticText m_staticTextName;

bool m_legacySEPattern;
} ;

Expand Down
39 changes: 27 additions & 12 deletions src/gui/clips/MidiClipView.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,13 @@

#include "MidiClipView.h"

#include <cmath>
#include <QApplication>
#include <QInputDialog>
#include <QMenu>
#include <QPainter>
#include <cmath>

#include "AutomationEditor.h"
#include "ConfigManager.h"
#include "DeprecationHelper.h"
#include "GuiApplication.h"
Expand Down Expand Up @@ -109,10 +110,11 @@ void MidiClipView::update()

void MidiClipView::openInPianoRoll()
{
getGUI()->pianoRoll()->setCurrentMidiClip( m_clip );
getGUI()->pianoRoll()->parentWidget()->show();
getGUI()->pianoRoll()->show();
getGUI()->pianoRoll()->setFocus();
auto pRoll = getGUI()->pianoRoll();
pRoll->setCurrentMidiClip(m_clip);
pRoll->parentWidget()->show();
pRoll->show();
pRoll->setFocus();
}


Expand All @@ -121,14 +123,21 @@ void MidiClipView::openInPianoRoll()

void MidiClipView::setGhostInPianoRoll()
{
getGUI()->pianoRoll()->setGhostMidiClip( m_clip );
getGUI()->pianoRoll()->parentWidget()->show();
getGUI()->pianoRoll()->show();
getGUI()->pianoRoll()->setFocus();
auto pRoll = getGUI()->pianoRoll();
pRoll->setGhostMidiClip(m_clip);
pRoll->parentWidget()->show();
pRoll->show();
pRoll->setFocus();
}



void MidiClipView::setGhostInAutomationEditor()
{
auto aEditor = getGUI()->automationEditor();
aEditor->setGhostMidiClip(m_clip);
aEditor->parentWidget()->show();
aEditor->show();
aEditor->setFocus();
}

void MidiClipView::resetName() { m_clip->setName(""); }

Expand Down Expand Up @@ -216,7 +225,13 @@ void MidiClipView::constructContextMenu( QMenu * _cm )
_cm->insertAction( _cm->actions()[1], b );
connect( b, SIGNAL(triggered(bool)),
this, SLOT(setGhostInPianoRoll()));
_cm->insertSeparator( _cm->actions()[2] );

auto c = new QAction(embed::getIconPixmap("automation_ghost_note"), tr("Set as ghost in automation editor"), _cm);
if (m_clip->empty()) { c->setEnabled(false); }
_cm->insertAction(_cm->actions()[2], c);
connect(c, SIGNAL(triggered(bool)), this, SLOT(setGhostInAutomationEditor()));
DanielKauss marked this conversation as resolved.
Show resolved Hide resolved

_cm->insertSeparator(_cm->actions()[3]);
_cm->addSeparator();

_cm->addAction( embed::getIconPixmap( "edit_erase" ),
Expand Down
68 changes: 62 additions & 6 deletions src/gui/editors/AutomationEditor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,6 @@

#include "AutomationEditor.h"

#include <cmath>

#include <QApplication>
#include <QInputDialog>
#include <QKeyEvent>
Expand All @@ -38,7 +36,10 @@
#include <QScrollBar>
#include <QStyleOption>
#include <QToolTip>
#include <cmath>

#include "MidiClip.h"
sakertooth marked this conversation as resolved.
Show resolved Hide resolved
#include "qobjectdefs.h"
sakertooth marked this conversation as resolved.
Show resolved Hide resolved
#ifndef __USE_XOPEN
#define __USE_XOPEN
#endif
Expand Down Expand Up @@ -110,7 +111,8 @@ AutomationEditor::AutomationEditor() :
m_nodeTangentLineColor(0, 0, 0),
m_scaleColor(Qt::SolidPattern),
m_crossColor(0, 0, 0),
m_backgroundShade(0, 0, 0)
m_backgroundShade(0, 0, 0),
m_ghostNoteColor(0, 0, 0)
{
connect( this, SIGNAL(currentClipChanged()),
this, SLOT(updateAfterClipChange()),
Expand Down Expand Up @@ -1074,8 +1076,11 @@ inline void AutomationEditor::drawAutomationTangents(QPainter& p, timeMap::itera
p.drawEllipse(tx - 3, ty - 3, 6, 6);
}



void AutomationEditor::setGhostMidiClip(MidiClip* newMidiClip)
{
// Expects a pointer to a MIDI clip or nullptr.
m_ghostNotes = newMidiClip;
}

void AutomationEditor::paintEvent(QPaintEvent * pe )
{
Expand Down Expand Up @@ -1261,6 +1266,47 @@ void AutomationEditor::paintEvent(QPaintEvent * pe )
p.drawLine( x, grid_bottom, x, x_line_end );
}

// draw ghost notes
if (m_ghostNotes != nullptr)
{
const NoteVector& notes = m_ghostNotes->notes();
int minKey = 128;
int maxKey = 0;

for (const Note* note : notes)
{
int noteKey = note->key();

maxKey = std::max(maxKey, noteKey);
minKey = std::min(minKey, noteKey);
}

for (const Note* note : notes)
{
int len_ticks = note->length();

if (len_ticks == 0) { continue; }
else if (len_ticks < 0) { len_ticks = 4; }
DanielKauss marked this conversation as resolved.
Show resolved Hide resolved

int note_width = len_ticks * m_ppb / TimePos::ticksPerBar();
int keyRange = maxKey - minKey;

if (keyRange < MIN_NOTE_RANGE)
{
int padding = (MIN_NOTE_RANGE - keyRange) / 2.0f;
maxKey += padding;
minKey -= padding;
keyRange = MIN_NOTE_RANGE;
}

float absNoteHeight = (float)(note->key() - minKey) / (maxKey - minKey);
DanielKauss marked this conversation as resolved.
Show resolved Hide resolved
int graphHeight = grid_bottom - NOTE_HEIGHT - NOTE_MARGIN - TOP_MARGIN;
const int y = (graphHeight - graphHeight * absNoteHeight) + NOTE_HEIGHT / 2.0f + TOP_MARGIN;

p.fillRect(xCoordOfTick(note->pos()), y, note_width, NOTE_HEIGHT, m_ghostNoteColor);
}
}

// and finally bars
for( tick = m_currentPosition - m_currentPosition % TimePos::ticksPerBar(),
x = xCoordOfTick( tick );
Expand Down Expand Up @@ -2159,8 +2205,18 @@ AutomationEditorWindow::AutomationEditorWindow() :
quantizationActionsToolBar->addWidget( quantize_lbl );
quantizationActionsToolBar->addWidget( m_quantizeComboBox );

m_resetGhostNotes = new QPushButton(m_toolBar);
m_resetGhostNotes->setIcon(embed::getIconPixmap("clear_ghost_note"));
m_resetGhostNotes->setToolTip(tr("Clear ghost notes"));
m_resetGhostNotes->setEnabled(true);

connect(m_resetGhostNotes, SIGNAL(pressed()), m_editor, SLOT(resetGhostNotes()));
DanielKauss marked this conversation as resolved.
Show resolved Hide resolved

quantizationActionsToolBar->addSeparator();
quantizationActionsToolBar->addWidget(m_resetGhostNotes);

// Setup our actual window
setFocusPolicy( Qt::StrongFocus );
setFocusPolicy(Qt::StrongFocus);
setFocus();
setWindowIcon( embed::getIconPixmap( "automation" ) );
setAcceptDrops( true );
Expand Down
Loading