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

add "a Tempo" in the Tempo palette #15563

Merged
merged 19 commits into from
Nov 14, 2023
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/engraving/dom/engravingitem.h
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,10 @@ class EngravingItem : public EngravingObject

virtual int subtype() const { return -1; } // for select gui

// Index to a set of properties if the same element type can represent
// different set of properties
virtual int propset() const { return subtype(); }
rtbo marked this conversation as resolved.
Show resolved Hide resolved

void drawAt(mu::draw::Painter* p, const PointF& pt) const
{
p->translate(pt);
Expand Down
7 changes: 7 additions & 0 deletions src/engraving/dom/masterscore.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,8 @@ class MasterScore : public Score
UndoStack* _undoStack = nullptr;
TimeSigMap* _sigmap;
TempoMap* _tempomap;
BeatsPerSecond _tempoPrimo;
bool _tempoPrimoSet = false;
rtbo marked this conversation as resolved.
Show resolved Hide resolved
RepeatList* _expandedRepeatList;
RepeatList* _nonExpandedRepeatList;
bool _expandRepeats = true;
Expand Down Expand Up @@ -141,6 +143,11 @@ class MasterScore : public Score
TempoMap* tempomap() const override { return _tempomap; }
async::Channel<ScoreChangesRange> changesChannel() const override { return m_changesRangeChannel; }

BeatsPerSecond tempoPrimo() const override { return _tempoPrimo; }
void resetTempoPrimo() { _tempoPrimo = Constants::DEFAULT_TEMPO; _tempoPrimoSet = false; }
void setTempoPrimo(BeatsPerSecond tempoPrimo) { _tempoPrimo = tempoPrimo; _tempoPrimoSet = true; }
bool tempoPrimoSet() const { return _tempoPrimoSet; }
rtbo marked this conversation as resolved.
Show resolved Hide resolved

bool playlistDirty() const override { return _playlistDirty; }
void setPlaylistDirty() override;
void setPlaylistClean() { _playlistDirty = false; }
Expand Down
20 changes: 18 additions & 2 deletions src/engraving/dom/score.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -410,6 +410,8 @@ void Score::setUpTempoMap()
sigmap()->add(0, SigEvent(fm->ticks(), fm->timesig(), 0));
}

m_masterScore->resetTempoPrimo();

for (MeasureBase* mb = first(); mb; mb = mb->next()) {
if (mb->type() != ElementType::MEASURE) {
mb->setTick(tick);
Expand Down Expand Up @@ -539,10 +541,23 @@ void Score::rebuildTempoAndTimeSigMaps(Measure* measure)
stretch = std::max(stretch, toFermata(e)->timeStretch());
} else if (e->isTempoText()) {
TempoText* tt = toTempoText(e);
if (tt->isRelative()) {

if (tt->isNormal() && !tt->isRelative() && !m_masterScore->tempoPrimoSet()) {
m_masterScore->setTempoPrimo(tt->tempo());
} else if (tt->isRelative()) {
tt->updateRelative();
}
tempomap()->setTempo(tt->segment()->tick().ticks(), tt->tempo());

int ticks = tt->segment()->tick().ticks();
if (tt->isRestorePrevious() && tt->followText()) {
// this will effectively reset the tempo to the previous one
// when a progressive change was active
tempomap()->setTempo(ticks, tempomap()->tempo(ticks));
} else if (tt->isRestorePrimo() && tt->followText()) {
tempomap()->setTempo(ticks, m_masterScore->tempoPrimo());
} else {
tempomap()->setTempo(ticks, tt->tempo());
}
}
}
if (stretch != 0.0 && stretch != 1.0) {
Expand Down Expand Up @@ -5976,6 +5991,7 @@ const RepeatList& Score::repeatList() const { return m_masterScore->repeatList(
const RepeatList& Score::repeatList(bool expandRepeats) const { return m_masterScore->repeatList(expandRepeats); }
TempoMap* Score::tempomap() const { return m_masterScore->tempomap(); }
TimeSigMap* Score::sigmap() const { return m_masterScore->sigmap(); }
BeatsPerSecond Score::tempoPrimo() const { return m_masterScore->tempoPrimo(); }
//QQueue<MidiInputEvent>* Score::midiInputQueue() { return _masterScore->midiInputQueue(); }
std::list<MidiInputEvent>& Score::activeMidiPitches() { return m_masterScore->activeMidiPitches(); }
async::Channel<ScoreChangesRange> Score::changesChannel() const { return m_masterScore->changesChannel(); }
Expand Down
1 change: 1 addition & 0 deletions src/engraving/dom/score.h
Original file line number Diff line number Diff line change
Expand Up @@ -677,6 +677,7 @@ class Score : public EngravingObject
void setTempo(const Fraction& tick, BeatsPerSecond bps);
void removeTempo(const Fraction& tick);
void setPause(const Fraction& tick, double seconds);
virtual BeatsPerSecond tempoPrimo() const;
BeatsPerSecond tempo(const Fraction& tick) const;

Text* getText(TextStyleType subtype) const;
Expand Down
20 changes: 16 additions & 4 deletions src/engraving/dom/tempotext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,10 +63,22 @@ TempoText::TempoText(Segment* parent)
: TextBase(ElementType::TEMPO_TEXT, parent, TextStyleType::TEMPO, ElementFlag::SYSTEM | ElementFlag::ON_STAFF)
{
initElementStyle(&tempoStyle);
_tempo = 2.0; // propertyDefault(P_TEMPO).toDouble();
_followText = false;
_relative = 1.0;
_isRelative = false;
_tempoTextType = TempoTextType::NORMAL;
_tempo = 2.0; // propertyDefault(P_TEMPO).toDouble();
_followText = false;
_relative = 1.0;
_isRelative = false;
}

int TempoText::propset() const
{
return static_cast<int>(_tempoTextType);
}

void TempoText::setTempoTextType(TempoTextType ttt)
{
_tempoTextType = ttt;
score()->setUpTempoMapLater();
}

double TempoText::tempoBpm() const
Expand Down
22 changes: 22 additions & 0 deletions src/engraving/dom/tempotext.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,13 @@
#include "textbase.h"

namespace mu::engraving {
enum class TempoTextType : signed char
{
NORMAL,
RESTORE_PREVIOUS, // "a tempo"
RESTORE_PRIMO, // "tempo primo"
};

//-------------------------------------------------------------------
// @@ TempoText
/// Tempo marker which determines the midi tempo.
Expand All @@ -45,16 +52,30 @@ class TempoText final : public TextBase

TempoText* clone() const override { return new TempoText(*this); }

virtual int propset() const override;

Segment* segment() const { return toSegment(explicitParent()); }
Measure* measure() const { return toMeasure(explicitParent()->explicitParent()); }

TempoTextType tempoTextType() const { return _tempoTextType; }
void setTempoTextType(TempoTextType);

BeatsPerSecond tempo() const { return _tempo; }
double tempoBpm() const;
void setTempo(BeatsPerSecond v);
void undoSetTempo(double v);
bool isRelative() { return _isRelative; }
void setRelative(double v) { _isRelative = true; _relative = v; }

bool isNormal() const { return _tempoTextType == TempoTextType::NORMAL; }
void setNormal() { setTempoTextType(TempoTextType::NORMAL); }

bool isRestorePrevious() const { return _tempoTextType == TempoTextType::RESTORE_PREVIOUS; }
void setRestorePrevious() { setTempoTextType(TempoTextType::RESTORE_PREVIOUS); }

bool isRestorePrimo() const { return _tempoTextType == TempoTextType::RESTORE_PRIMO; }
void setRestorePrimo() { setTempoTextType(TempoTextType::RESTORE_PRIMO); }

bool followText() const { return _followText; }
void setFollowText(bool v) { _followText = v; }
void undoSetFollowText(bool v);
Expand All @@ -81,6 +102,7 @@ class TempoText final : public TextBase
void updateScore();
void updateTempo();

TempoTextType _tempoTextType;
BeatsPerSecond _tempo; // beats per second
bool _followText; // parse text to determine tempo
double _relative;
Expand Down
11 changes: 11 additions & 0 deletions src/engraving/rw/read410/tread.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -487,6 +487,17 @@ void TRead::read(TempoText* t, XmlReader& e, ReadContext& ctx)
t->setTempo(TConv::fromXml(e.readAsciiText(), Constants::DEFAULT_TEMPO));
} else if (tag == "followText") {
t->setFollowText(e.readInt());
} else if (tag == "type") {
auto type = e.readAsciiText();
if (type == "restorePrevious") {
t->setTempoTextType(TempoTextType::RESTORE_PREVIOUS);
} else if (type == "restorePrimo") {
t->setTempoTextType(TempoTextType::RESTORE_PRIMO);
} else if (type == "normal") {
t->setTempoTextType(TempoTextType::NORMAL);
} else {
e.unknown();
}
} else if (!readProperties(static_cast<TextBase*>(t), e, ctx)) {
e.unknown();
}
Expand Down
6 changes: 6 additions & 0 deletions src/engraving/rw/write/twrite.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2654,6 +2654,12 @@ void TWrite::write(const TempoText* item, XmlWriter& xml, WriteContext& ctx)
if (item->followText()) {
xml.tag("followText", item->followText());
}
if (item->isRestorePrevious()) {
xml.tag("type", "restorePrevious");
}
if (item->isRestorePrimo()) {
xml.tag("type", "restorePrimo");
}
writeProperties(static_cast<const TextBase*>(item), xml, ctx, true);
xml.endElement();
}
Expand Down
17 changes: 15 additions & 2 deletions src/inspector/models/abstractinspectormodel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@

#include "types/texttypes.h"

#include "dom/tempotext.h"

#include "log.h"

using namespace mu::inspector;
Expand Down Expand Up @@ -116,6 +118,12 @@ static QMap<mu::engraving::LayoutBreakType, InspectorModelType> LAYOUT_BREAK_ELE
{ mu::engraving::LayoutBreakType::SECTION, InspectorModelType::TYPE_SECTIONBREAK }
};

static QMap<mu::engraving::TempoTextType, InspectorModelType> TEMPO_TEXT_ELEMENT_MODEL_TYPES = {
{ mu::engraving::TempoTextType::NORMAL, InspectorModelType::TYPE_TEMPO },
{ mu::engraving::TempoTextType::RESTORE_PREVIOUS, InspectorModelType::TYPE_TEMPO_RESTORE_PREVIOUS },
{ mu::engraving::TempoTextType::RESTORE_PRIMO, InspectorModelType::TYPE_TEMPO_RESTORE_PRIMO },
};

AbstractInspectorModel::AbstractInspectorModel(QObject* parent, IElementRepositoryService* repository,
mu::engraving::ElementType elementType)
: QObject(parent), m_elementType(elementType), m_updatePropertiesAllowed(true)
Expand Down Expand Up @@ -190,15 +198,20 @@ InspectorModelType AbstractInspectorModel::modelType() const
InspectorModelType AbstractInspectorModel::modelTypeByElementKey(const ElementKey& elementKey)
{
if (elementKey.type == mu::engraving::ElementType::HAIRPIN || elementKey.type == mu::engraving::ElementType::HAIRPIN_SEGMENT) {
return HAIRPIN_ELEMENT_MODEL_TYPES.value(static_cast<mu::engraving::HairpinType>(elementKey.subtype),
return HAIRPIN_ELEMENT_MODEL_TYPES.value(static_cast<mu::engraving::HairpinType>(elementKey.propset),
InspectorModelType::TYPE_UNDEFINED);
}

if (elementKey.type == mu::engraving::ElementType::LAYOUT_BREAK) {
return LAYOUT_BREAK_ELEMENT_MODEL_TYPES.value(static_cast<mu::engraving::LayoutBreakType>(elementKey.subtype),
return LAYOUT_BREAK_ELEMENT_MODEL_TYPES.value(static_cast<mu::engraving::LayoutBreakType>(elementKey.propset),
InspectorModelType::TYPE_UNDEFINED);
}

if (elementKey.type == mu::engraving::ElementType::TEMPO_TEXT) {
return TEMPO_TEXT_ELEMENT_MODEL_TYPES.value(static_cast<mu::engraving::TempoTextType>(elementKey.propset),
InspectorModelType::TYPE_UNDEFINED);
}

return NOTATION_ELEMENT_MODEL_TYPES.value(elementKey.type, InspectorModelType::TYPE_UNDEFINED);
}

Expand Down
2 changes: 2 additions & 0 deletions src/inspector/models/abstractinspectormodel.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,8 @@ class AbstractInspectorModel : public QObject, public async::Asyncable
TYPE_HOOK,
TYPE_FERMATA,
TYPE_TEMPO,
TYPE_TEMPO_RESTORE_PREVIOUS,
TYPE_TEMPO_RESTORE_PRIMO,
TYPE_GLISSANDO,
TYPE_BARLINE,
TYPE_BREATH,
Expand Down
2 changes: 1 addition & 1 deletion src/inspector/models/inspectorlistmodel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ void InspectorListModel::setElementList(const QList<mu::engraving::EngravingItem
ElementKeySet newElementKeySet;

for (const mu::engraving::EngravingItem* element : selectedElementList) {
newElementKeySet << ElementKey(element->type(), element->subtype());
newElementKeySet << ElementKey(element->type(), element->propset());
}

buildModelsForSelectedElements(newElementKeySet, selectionState == SelectionState::RANGE, selectedElementList);
Expand Down
4 changes: 3 additions & 1 deletion src/inspector/models/inspectormodelcreator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,9 @@ AbstractInspectorModel* InspectorModelCreator::newInspectorModel(InspectorModelT
case InspectorModelType::TYPE_FERMATA:
return new FermataSettingsModel(parent, repository);
case InspectorModelType::TYPE_TEMPO:
return new TempoSettingsModel(parent, repository);
case InspectorModelType::TYPE_TEMPO_RESTORE_PREVIOUS:
case InspectorModelType::TYPE_TEMPO_RESTORE_PRIMO:
return new TempoSettingsModel(parent, repository, modelType);
case InspectorModelType::TYPE_GLISSANDO:
return new GlissandoSettingsModel(parent, repository);
case InspectorModelType::TYPE_BARLINE:
Expand Down
35 changes: 27 additions & 8 deletions src/inspector/models/notation/tempos/temposettingsmodel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,18 +27,37 @@

using namespace mu::inspector;

TempoSettingsModel::TempoSettingsModel(QObject* parent, IElementRepositoryService* repository)
TempoSettingsModel::TempoSettingsModel(QObject* parent, IElementRepositoryService* repository, InspectorModelType modelType)
: AbstractInspectorModel(parent, repository)
{
setModelType(InspectorModelType::TYPE_TEMPO);
setTitle(qtrc("inspector", "Tempo"));
Q_ASSERT(modelType == InspectorModelType::TYPE_TEMPO
|| modelType == InspectorModelType::TYPE_TEMPO_RESTORE_PREVIOUS
|| modelType == InspectorModelType::TYPE_TEMPO_RESTORE_PRIMO
);

setModelType(modelType);

switch (modelType) {
case InspectorModelType::TYPE_TEMPO:
setTitle(qtrc("inspector", "Tempo"));
break;
case InspectorModelType::TYPE_TEMPO_RESTORE_PREVIOUS:
setTitle(qtrc("inspector", "Restore previous tempo"));
break;
case InspectorModelType::TYPE_TEMPO_RESTORE_PRIMO:
setTitle(qtrc("inspector", "Restore initial tempo"));
break;
default:
break;
}

setIcon(ui::IconCode::Code::METRONOME);
createProperties();
}

void TempoSettingsModel::createProperties()
{
m_isDefaultTempoForced
m_isFollowText
= buildPropertyItem(mu::engraving::Pid::TEMPO_FOLLOW_TEXT, [this](const mu::engraving::Pid pid, const QVariant& newValue) {
onPropertyValueChanged(pid, newValue);

Expand All @@ -55,19 +74,19 @@ void TempoSettingsModel::requestElements()

void TempoSettingsModel::loadProperties()
{
loadPropertyItem(m_isDefaultTempoForced);
loadPropertyItem(m_isFollowText);
loadPropertyItem(m_tempo, formatDoubleFunc);
}

void TempoSettingsModel::resetProperties()
{
m_isDefaultTempoForced->resetToDefault();
m_isFollowText->resetToDefault();
m_tempo->resetToDefault();
}

PropertyItem* TempoSettingsModel::isDefaultTempoForced() const
PropertyItem* TempoSettingsModel::isFollowText() const
{
return m_isDefaultTempoForced;
return m_isFollowText;
}

PropertyItem* TempoSettingsModel::tempo() const
Expand Down
8 changes: 4 additions & 4 deletions src/inspector/models/notation/tempos/temposettingsmodel.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,22 +29,22 @@ class TempoSettingsModel : public AbstractInspectorModel
{
Q_OBJECT

Q_PROPERTY(PropertyItem * isDefaultTempoForced READ isDefaultTempoForced CONSTANT)
Q_PROPERTY(PropertyItem * followText READ isFollowText CONSTANT)
Q_PROPERTY(PropertyItem * tempo READ tempo CONSTANT)

public:
explicit TempoSettingsModel(QObject* parent, IElementRepositoryService* repository);
explicit TempoSettingsModel(QObject* parent, IElementRepositoryService* repository, InspectorModelType modelType);

void createProperties() override;
void requestElements() override;
void loadProperties() override;
void resetProperties() override;

PropertyItem* isDefaultTempoForced() const;
PropertyItem* isFollowText() const;
PropertyItem* tempo() const;

private:
PropertyItem* m_isDefaultTempoForced = nullptr;
PropertyItem* m_isFollowText = nullptr;
PropertyItem* m_tempo = nullptr;
};
}
Expand Down
12 changes: 6 additions & 6 deletions src/inspector/types/commontypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,18 +33,18 @@ namespace mu::inspector {
struct ElementKey
{
mu::engraving::ElementType type = mu::engraving::ElementType::INVALID;
int subtype = -1;
int propset = -1;

ElementKey() = default;

ElementKey(mu::engraving::ElementType type, int subtype = -1)
: type(type), subtype(subtype)
ElementKey(mu::engraving::ElementType type, int propset = -1)
: type(type), propset(propset)
{
}

bool operator==(const ElementKey& key) const
{
return type == key.type && subtype == key.subtype;
return type == key.type && propset == key.propset;
}

bool operator!=(const ElementKey& key) const
Expand All @@ -58,8 +58,8 @@ using ElementKeySet = QSet<ElementKey>;

inline uint qHash(const ElementKey& key)
{
QString subtypePart = key.subtype >= 0 ? QString::number(key.subtype) : "";
return qHash(QString::number(static_cast<int>(key.type)) + subtypePart);
QString propsetPart = key.propset >= 0 ? QString::number(key.propset) : "";
return qHash(QString::number(static_cast<int>(key.type)) + propsetPart);
}

class CommonTypes
Expand Down
Loading