From e6ec376a0728ada5833824c436242959579ac050 Mon Sep 17 00:00:00 2001 From: Unknown Date: Tue, 5 May 2020 09:13:22 -0400 Subject: [PATCH] fix #304906 Update Piano Levels Filter to shift to the new Fraction based note measurement system Upgrading the Piano Levels Filter system to use Fration of whole note instead of ticks. Selecting a single note now updates the Set box. Changes to tooltip descriptions of filters. Can now use negative values for specifying note lengths. --- libmscore/duration.h | 1 + libmscore/fraction.h | 12 +++- mscore/pianoroll/pianolevels.cpp | 9 +-- mscore/pianoroll/pianolevelschooser.cpp | 44 +++++++++++++-- mscore/pianoroll/pianolevelschooser.h | 4 ++ mscore/pianoroll/pianolevelsfilter.cpp | 74 ++++++++++--------------- mscore/pianoroll/pianolevelsfilter.h | 10 ++-- mscore/pianoroll/pianoroll.cpp | 2 + 8 files changed, 91 insertions(+), 65 deletions(-) diff --git a/libmscore/duration.h b/libmscore/duration.h index 862acf34df9bf..9b920ca8ffe0f 100644 --- a/libmscore/duration.h +++ b/libmscore/duration.h @@ -59,6 +59,7 @@ class DurationElement : public Element { Fraction actualTicks() const; + //Length expressed as a fraction of a whole note virtual Fraction ticks() const { return _duration; } Fraction globalTicks() const; void setTicks(const Fraction& f) { _duration = f; } diff --git a/libmscore/fraction.h b/libmscore/fraction.h index 0c05c55c2102c..9be0a6c263c8f 100644 --- a/libmscore/fraction.h +++ b/libmscore/fraction.h @@ -188,20 +188,26 @@ class Fraction { return *this; } - #if 0 + Fraction& operator/=(int val) { _denominator *= val; + if (_denominator < 0) { + _denominator = -_denominator; + _numerator = -_numerator; + } + reduce(); return *this; } - #endif + + Fraction operator+(const Fraction& v) const { return Fraction(*this) += v; } Fraction operator-(const Fraction& v) const { return Fraction(*this) -= v; } Fraction operator-() const { return Fraction(-_numerator, _denominator); } Fraction operator*(const Fraction& v) const { return Fraction(*this) *= v; } Fraction operator/(const Fraction& v) const { return Fraction(*this) /= v; } - // Fraction operator/(int v) const { return Fraction(*this) /= v; } + Fraction operator/(int v) const { return Fraction(*this) /= v; } //--------------------------------------------------------- diff --git a/mscore/pianoroll/pianolevels.cpp b/mscore/pianoroll/pianolevels.cpp index 2ea7806e8ef84..0223b971a2c71 100644 --- a/mscore/pianoroll/pianolevels.cpp +++ b/mscore/pianoroll/pianolevels.cpp @@ -183,9 +183,6 @@ void PianoLevels::paintEvent(QPaintEvent* e) //Round down to first bar to be a multiple of barSkip bar1 = (bar1 / barSkip) * barSkip; -// int subExp = qMin((int)floor(log2(pixPerBeat / minBeatGap)), _subBeats); -// int numSubBeats = pow(2, subExp); - for (int bar = bar1; bar <= bar2; bar += barSkip) { Pos stick(_score->tempomap(), _score->sigmap(), bar, 0, 0); @@ -222,13 +219,13 @@ void PianoLevels::paintEvent(QPaintEvent* e) //draw horiz lines PianoLevelsFilter* filter = PianoLevelsFilter::FILTER_LIST[_levelsIndex]; - QFont f("FreeSans", 7); - p.setFont(f); - int div = filter->divisionGap(); int minGuide = (int)floor(filter->minRange() / (qreal)div); int maxGuide = (int)ceil(filter->maxRange() / (qreal)div); + QFont f("FreeSans", 7); + p.setFont(f); + for (int i = minGuide; i <= maxGuide; ++i) { p.setPen(i == 0 || i == minGuide || i == maxGuide ? penLineMajor : penLineMinor); diff --git a/mscore/pianoroll/pianolevelschooser.cpp b/mscore/pianoroll/pianolevelschooser.cpp index 7a3c230c2a07b..94a754129efb7 100644 --- a/mscore/pianoroll/pianolevelschooser.cpp +++ b/mscore/pianoroll/pianolevelschooser.cpp @@ -1,5 +1,6 @@ #include "pianolevelschooser.h" #include "pianolevelsfilter.h" +#include "pianoview.h" #include "libmscore/score.h" @@ -11,7 +12,7 @@ namespace Ms { PianoLevelsChooser::PianoLevelsChooser(QWidget *parent) : QWidget(parent) -{ + { setupUi(this); _levelsIndex = 0; @@ -24,24 +25,55 @@ PianoLevelsChooser::PianoLevelsChooser(QWidget *parent) connect(levelsCombo, SIGNAL(activated(int)), SLOT(setLevelsIndex(int))); connect(setEventsBn, SIGNAL(clicked(bool)), SLOT(setEventDataPressed())); -} + } +//--------------------------------------------------------- +// setPianoView +//--------------------------------------------------------- + +void PianoLevelsChooser::setPianoView(PianoView* pianoView) + { + _pianoView = pianoView; + } //--------------------------------------------------------- -// PianoLevelsChooser +// updateSetboxValue +//--------------------------------------------------------- + +void PianoLevelsChooser::updateSetboxValue() + { + QList items = _pianoView->getSelectedItems(); + + if (items.size() == 1) { + PianoLevelsFilter* filter = PianoLevelsFilter::FILTER_LIST[_levelsIndex]; + + PianoItem* item = items[0]; + Note* note = item->note(); + + NoteEvent* event = item->getTweakNoteEvent(); + int value = filter->value(_staff, note, event); + eventValSpinBox->setValue(value); + } + + } + + +//--------------------------------------------------------- +// setLevelsIndex //--------------------------------------------------------- void PianoLevelsChooser::setLevelsIndex(int index) -{ + { if (_levelsIndex != index) { _levelsIndex = index; + updateSetboxValue(); emit levelsIndexChanged(index); } -} + } //--------------------------------------------------------- -// PianoLevelsChooser +// setEventDataPressed //--------------------------------------------------------- void PianoLevelsChooser::setEventDataPressed() diff --git a/mscore/pianoroll/pianolevelschooser.h b/mscore/pianoroll/pianolevelschooser.h index 162a7c681bfda..5d818f311ac3f 100644 --- a/mscore/pianoroll/pianolevelschooser.h +++ b/mscore/pianoroll/pianolevelschooser.h @@ -26,6 +26,7 @@ namespace Ms { +class PianoView; //--------------------------------------------------------- // PianoLevelsChooser @@ -37,16 +38,19 @@ class PianoLevelsChooser : public QWidget, public Ui::PianoLevelsChooser int _levelsIndex; Staff* _staff; + PianoView* _pianoView = nullptr; public: Staff* staff() { return _staff; } void setStaff(Staff* staff) { _staff = staff; } + void setPianoView(PianoView* pianoView); signals: void levelsIndexChanged(int); void notesChanged(); public slots: + void updateSetboxValue(); void setLevelsIndex(int index); void setEventDataPressed(); diff --git a/mscore/pianoroll/pianolevelsfilter.cpp b/mscore/pianoroll/pianolevelsfilter.cpp index 6bd651533d424..384b93322fdee 100644 --- a/mscore/pianoroll/pianolevelsfilter.cpp +++ b/mscore/pianoroll/pianolevelsfilter.cpp @@ -10,29 +10,29 @@ namespace Ms { -static const char* STRN_NOTE_ON_NAME = QT_TRANSLATE_NOOP("PianoLevelsFilter", "Note start time"); -static const char* STRN_NOTE_ON_TT = QT_TRANSLATE_NOOP("PianoLevelsFilter", "Add (or subtract) a bit to the start time of a note"); +static const char* STRN_NOTE_ON_NAME = QT_TRANSLATE_NOOP("PianoLevelsFilter", "Position"); +static const char* STRN_NOTE_ON_TT = QT_TRANSLATE_NOOP("PianoLevelsFilter", "Move the selected note(s) forward or backward by thousandths of the full note duration"); -static const char* STRN_LEN_MUL_NAME = QT_TRANSLATE_NOOP("PianoLevelsFilter", "Length (multiplier)"); -static const char* STRN_LEN_MUL_TT = QT_TRANSLATE_NOOP("PianoLevelsFilter", "Multiply the note length by a bit"); +static const char* STRN_LEN_MUL_NAME = QT_TRANSLATE_NOOP("PianoLevelsFilter", "Duration (multiplier)"); +static const char* STRN_LEN_MUL_TT = QT_TRANSLATE_NOOP("PianoLevelsFilter", "Multiply the duration by thousandths of the full note duration"); -static const char* STRN_LEN_OFF_NAME = QT_TRANSLATE_NOOP("PianoLevelsFilter", "Length (offset)"); -static const char* STRN_LEN_OFF_TT = QT_TRANSLATE_NOOP("PianoLevelsFilter", "Add (or subtract) a bit from the end of the note"); +static const char* STRN_LEN_OFF_NAME = QT_TRANSLATE_NOOP("PianoLevelsFilter", "Duration"); +static const char* STRN_LEN_OFF_TT = QT_TRANSLATE_NOOP("PianoLevelsFilter", "Shorten or lengthen by thousandths of a whole note"); static const char* STRN_VEL_DYN_NAME = QT_TRANSLATE_NOOP("PianoLevelsFilter", "Velocity (relative)"); -static const char* STRN_VEL_DYN_TT = QT_TRANSLATE_NOOP("PianoLevelsFilter", "Raise or lower loudness relative to current dynamics value"); +static const char* STRN_VEL_DYN_TT = QT_TRANSLATE_NOOP("PianoLevelsFilter", "Increase or decrease the velocity by the specified value"); static const char* STRN_VEL_ABS_NAME = QT_TRANSLATE_NOOP("PianoLevelsFilter", "Velocity (absolute)"); -static const char* STRN_VEL_ABS_TT = QT_TRANSLATE_NOOP("PianoLevelsFilter", "Ignore dynamic markings and use this as the MIDI output value"); +static const char* STRN_VEL_ABS_TT = QT_TRANSLATE_NOOP("PianoLevelsFilter", "Ignore dynamic markings and set the velocity directly"); PianoLevelsFilter* PianoLevelsFilter::FILTER_LIST[] = { - new PianoLevelFilterLen, - new PianoLevelFilterLenOfftime, + new PianoLevelFilterLenWholenote, + new PianoLevelFilterLenMultiplier, new PianoLevelFilterVeloOffset, new PianoLevelFilterVeloUser, new PianoLevelFilterOnTime, - 0 //end of list indicator + nullptr //end of list indicator }; //--------------------------------------------------------- @@ -82,7 +82,7 @@ void PianoLevelFilterOnTime::setValue(Staff* staff, Note* note, NoteEvent* evt, // name //--------------------------------------------------------- -QString PianoLevelFilterLen::name() +QString PianoLevelFilterLenMultiplier::name() { return qApp->translate("PianoLevelsFilter", STRN_LEN_MUL_NAME); } @@ -91,7 +91,7 @@ QString PianoLevelFilterLen::name() // tooltip //--------------------------------------------------------- -QString PianoLevelFilterLen::tooltip() +QString PianoLevelFilterLenMultiplier::tooltip() { return qApp->translate("PianoLevelsFilter", STRN_LEN_MUL_TT); } @@ -100,7 +100,7 @@ QString PianoLevelFilterLen::tooltip() // value //--------------------------------------------------------- -int PianoLevelFilterLen::value(Staff* /*staff*/, Note* /*note*/, NoteEvent* evt) +int PianoLevelFilterLenMultiplier::value(Staff* /*staff*/, Note* /*note*/, NoteEvent* evt) { return evt->len(); } @@ -109,7 +109,7 @@ int PianoLevelFilterLen::value(Staff* /*staff*/, Note* /*note*/, NoteEvent* evt) // setValue //--------------------------------------------------------- -void PianoLevelFilterLen::setValue(Staff* staff, Note* note, NoteEvent* evt, int value) +void PianoLevelFilterLenMultiplier::setValue(Staff* staff, Note* note, NoteEvent* evt, int value) { Score* score = staff->score(); @@ -126,7 +126,7 @@ void PianoLevelFilterLen::setValue(Staff* staff, Note* note, NoteEvent* evt, int // name //--------------------------------------------------------- -QString PianoLevelFilterLenOfftime::name() +QString PianoLevelFilterLenWholenote::name() { return qApp->translate("PianoLevelsFilter", STRN_LEN_OFF_NAME); } @@ -135,59 +135,43 @@ QString PianoLevelFilterLenOfftime::name() // tooltip //--------------------------------------------------------- -QString PianoLevelFilterLenOfftime::tooltip() +QString PianoLevelFilterLenWholenote::tooltip() { return qApp->translate("PianoLevelsFilter", STRN_LEN_OFF_TT); } -//--------------------------------------------------------- -// maxRange -//--------------------------------------------------------- - -int PianoLevelFilterLenOfftime::maxRange() - { - return MScore::division; - } - -//--------------------------------------------------------- -// divisionGap -//--------------------------------------------------------- - -int PianoLevelFilterLenOfftime::divisionGap() - { - return MScore::division / 4; - } - //--------------------------------------------------------- // value //--------------------------------------------------------- -int PianoLevelFilterLenOfftime::value(Staff* /*staff*/, Note* note, NoteEvent* evt) +int PianoLevelFilterLenWholenote::value(Staff* /*staff*/, Note* note, NoteEvent* evt) { Chord* chord = note->chord(); - int ticks = chord->ticks().ticks(); - int gate = evt->len(); - int offTicks = ticks - (ticks * gate / 1000); + Fraction noteLen = chord->ticks(); + int evtLen = evt->len(); + Fraction offsetLen = noteLen - (noteLen * evtLen / 1000); - return offTicks; + return -offsetLen.numerator() * 1000 / offsetLen.denominator(); } //--------------------------------------------------------- // setValue //--------------------------------------------------------- -void PianoLevelFilterLenOfftime::setValue(Staff* staff, Note* note, NoteEvent* evt, int value) +void PianoLevelFilterLenWholenote::setValue(Staff* staff, Note* note, NoteEvent* evt, int value) { Chord* chord = note->chord(); - int ticks = chord->ticks().ticks(); - int onTicks = qMax(ticks - value, 1); - int gate = 1000 * onTicks / ticks; + Fraction noteLen = chord->ticks(); + Fraction cutLen(-value, 1000); + Fraction playLen = noteLen - cutLen; + Fraction evtLenFrac = playLen / noteLen; + int evtLen = qMax(evtLenFrac.numerator() * 1000 / evtLenFrac.denominator(), 1); Score* score = staff->score(); NoteEvent ne = *evt; - ne.setLen(gate); + ne.setLen(evtLen); score->startCmd(); score->undo(new ChangeNoteEvent(note, evt, ne)); diff --git a/mscore/pianoroll/pianolevelsfilter.h b/mscore/pianoroll/pianolevelsfilter.h index 72ba21b95c01c..be15734efd4ee 100644 --- a/mscore/pianoroll/pianolevelsfilter.h +++ b/mscore/pianoroll/pianolevelsfilter.h @@ -72,7 +72,7 @@ class PianoLevelFilterOnTime : public PianoLevelsFilter { //--------------------------------------------------------- -class PianoLevelFilterLen : public PianoLevelsFilter { +class PianoLevelFilterLenMultiplier : public PianoLevelsFilter { Q_DECLARE_TR_FUNCTIONS(PianoLevelFilterLen) public: @@ -92,15 +92,15 @@ class PianoLevelFilterLen : public PianoLevelsFilter { //--------------------------------------------------------- -class PianoLevelFilterLenOfftime : public PianoLevelsFilter { +class PianoLevelFilterLenWholenote : public PianoLevelsFilter { Q_DECLARE_TR_FUNCTIONS(PianoLevelFilterLenOfftime) public: QString name() override; QString tooltip() override; - int maxRange() override; - int minRange() override { return 0; } - int divisionGap() override; + int maxRange() override { return 1000; } + int minRange() override { return -1000; } + int divisionGap() override { return 1000 / 4; } bool isPerEvent() override { return true; } int value(Staff* staff, Note* note, NoteEvent* evt) override; void setValue(Staff* staff, Note* note, NoteEvent* evt, int value) override; diff --git a/mscore/pianoroll/pianoroll.cpp b/mscore/pianoroll/pianoroll.cpp index e3fcaef188bac..d7be7b43ca324 100644 --- a/mscore/pianoroll/pianoroll.cpp +++ b/mscore/pianoroll/pianoroll.cpp @@ -359,6 +359,7 @@ PianorollEditor::PianorollEditor(QWidget* parent) // levels area pianoLevelsChooser = new PianoLevelsChooser; + pianoLevelsChooser->setPianoView(pianoView); pianoLevelsChooser->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding); pianoLevelsChooser->setFixedWidth(PIANO_KEYBOARD_WIDTH); @@ -692,6 +693,7 @@ void PianorollEditor::updateSelection() veloType->setEnabled(enabled); onTime->setEnabled(enabled); tickLen->setEnabled(enabled); + pianoLevelsChooser->updateSetboxValue(); } //---------------------------------------------------------