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

Input by duration: various fixes #26367

Merged
Original file line number Diff line number Diff line change
Expand Up @@ -30,15 +30,15 @@ BaseSection {
id: root

property alias playNotesWhenEditing: playNotesToggle.checked
property alias playPreviewNotesInInputByDuration: playPreviewNotesInInputByDurationBox.checked
property alias playChordWhenEditing: playChordBox.checked
property alias playChordSymbolWhenEditing: playChordSymbolBox.checked
property alias playPreviewNotesInInputByDuration: playPreviewNotesInInputByDurationBox.checked
property alias notePlayDurationMilliseconds: notePlayDurationControl.currentValue

signal playNotesWhenEditingChangeRequested(bool play)
signal playPreviewNotesInInputByDurationChangeRequested(bool play)
signal playChordWhenEditingChangeRequested(bool play)
signal playChordSymbolWhenEditingChangeRequested(bool play)
signal playPreviewNotesInInputByDurationChangeRequested(bool play)
signal notePlayDurationChangeRequested(int duration)

title: qsTrc("appshell/preferences", "Note preview")
Expand Down Expand Up @@ -71,23 +71,6 @@ BaseSection {
}
}

CheckBox {
id: playPreviewNotesInInputByDurationBox
width: parent.width

text: qsTrc("appshell/preferences", "Include preview notes in playback (input by duration only)")

enabled: root.playNotesWhenEditing

navigation.name: "PlayPreviewNotesInInputByDurationBox"
navigation.panel: root.navigation
navigation.row: 1

onClicked: {
root.playPreviewNotesInInputByDurationChangeRequested(!checked)
}
}

IncrementalPropertyControlWithTitle {
id: notePlayDurationControl

Expand All @@ -103,7 +86,7 @@ BaseSection {

navigation.name: "NotePlayDurationControl"
navigation.panel: root.navigation
navigation.row: 2
navigation.row: 1

onValueEdited: function(newValue) {
root.notePlayDurationChangeRequested(newValue)
Expand All @@ -120,7 +103,7 @@ BaseSection {

navigation.name: "PlayChordBox"
navigation.panel: root.navigation
navigation.row: 3
navigation.row: 2

onClicked: {
root.playChordWhenEditingChangeRequested(!checked)
Expand All @@ -137,10 +120,27 @@ BaseSection {

navigation.name: "PlayChordSymbolBox"
navigation.panel: root.navigation
navigation.row: 4
navigation.row: 3

onClicked: {
root.playChordSymbolWhenEditingChangeRequested(!checked)
}
}

CheckBox {
id: playPreviewNotesInInputByDurationBox
width: parent.width

text: qsTrc("appshell/preferences", "Play when setting pitch (input by duration mode only)")

enabled: root.playNotesWhenEditing

navigation.name: "PlayPreviewNotesInInputByDurationBox"
navigation.panel: root.navigation
navigation.row: 4

onClicked: {
root.playPreviewNotesInInputByDurationChangeRequested(!checked)
}
}
}
31 changes: 16 additions & 15 deletions src/engraving/dom/cmd.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1068,7 +1068,7 @@ Segment* Score::setNoteRest(Segment* segment, track_idx_t track, NoteVal nval, F
assert(segment->segmentType() == SegmentType::ChordRest);
InputState& is = externalInputState ? (*externalInputState) : m_is;

bool isRest = nval.pitch == -1;
bool isRest = nval.isRest();
Fraction tick = segment->tick();
EngravingItem* nr = nullptr;
Tie* tie = nullptr;
Expand Down Expand Up @@ -2155,8 +2155,8 @@ void Score::toggleAccidental(AccidentalType at)
m_is.setAccidentalType(at);
m_is.setRest(false);

if (usingNoteEntryMethod(NoteEntryMethod::BY_DURATION)) {
applyAccidentalToInputNotes();
if (!m_is.notes().empty()) {
applyAccidentalToInputNotes(at);
}
} else {
if (selection().isNone()) {
Expand All @@ -2169,23 +2169,24 @@ void Score::toggleAccidental(AccidentalType at)
}
}

void Score::applyAccidentalToInputNotes()
void Score::applyAccidentalToInputNotes(AccidentalType accidentalType)
{
const AccidentalVal acc = Accidental::subtype2value(m_is.accidentalType());
const bool concertPitch = style().styleB(Sid::concertPitch);
NoteValList notes = m_is.notes();
NoteValList notes;

for (NoteVal& nval : notes) {
const int oldPitch = nval.pitch;
const int step = mu::engraving::pitch2step(oldPitch);
const int newTpc = mu::engraving::step2tpc(step, acc);
Position pos;
pos.segment = m_is.segment();
pos.staffIdx = m_is.staffIdx();

nval.pitch += static_cast<int>(acc);
for (const NoteVal& oldVal : m_is.notes()) {
pos.line = noteValToLine(oldVal, m_is.staff(), m_is.tick());

if (concertPitch) {
nval.tpc1 = newTpc;
bool error = false;
const NoteVal newVal = noteValForPosition(pos, accidentalType, error);

if (error) {
notes.push_back(oldVal);
} else {
nval.tpc2 = newTpc;
notes.push_back(newVal);
}
}

Expand Down
90 changes: 45 additions & 45 deletions src/engraving/dom/noteentry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -150,56 +150,20 @@ NoteVal Score::noteValForPosition(Position pos, AccidentalType at, bool& error)
return nval;
}

Note* Score::addPitch(NoteVal& nval, bool addToPreviousChord, InputState* externalInputState)
{
AddToChord addType = addToPreviousChord ? AddToChord::AtPreviousPosition : AddToChord::None;
return addPitch(nval, addType, externalInputState);
}

Note* Score::addPitch(NoteVal& nval, AddToChord addFlag, InputState* externalInputState)
Note* Score::addPitch(NoteVal& nval, bool addFlag, InputState* externalInputState)
{
InputState& is = externalInputState ? (*externalInputState) : m_is;

if (addFlag != AddToChord::None) {
ChordRest* c = nullptr;
if (addFlag == AddToChord::AtPreviousPosition) {
c = toChordRest(is.lastSegment()->element(is.track()));
} else if (addFlag == AddToChord::AtCurrentPosition) {
c = is.cr();
}

if (c == 0 || !c->isChord()) {
if (addFlag) {
ChordRest* c = toChordRest(is.lastSegment()->element(is.track()));
if (!c || !c->isChord()) {
LOGD("Score::addPitch: cr %s", c ? c->typeName() : "zero");
return 0;
}

Chord* chord = toChord(c);
auto isTied = [](const Chord* ch) {
if (ch->notes().empty()) {
return false;
}
Note* n = ch->notes().at(0);
return n->tieFor() || n->tieBack();
};

Note* note = nullptr;
if (isTied(chord)) {
note = addNoteToTiedChord(chord, nval, /* forceAccidental */ false);
if (!note) {
note = addNote(chord, nval, /* forceAccidental */ false, /* articulationIds */ {}, externalInputState);
}
} else {
note = addNote(chord, nval, /* forceAccidental */ false, is.articulationIds(), externalInputState);
return nullptr;
}

if (is.lastSegment() == is.segment()) {
NoteEntryMethod entryMethod = is.noteEntryMethod();
if (entryMethod != NoteEntryMethod::REALTIME_AUTO && entryMethod != NoteEntryMethod::REALTIME_MANUAL) {
is.moveToNextInputPos();
}
}
return note;
return addPitchToChord(nval, toChord(c), externalInputState);
}

expandVoice(is.segment(), is.track());

// insert note
Expand Down Expand Up @@ -253,7 +217,7 @@ Note* Score::addPitch(NoteVal& nval, AddToChord addFlag, InputState* externalInp
note->setTrack(chord->track());
note->setNval(nval);
lastTiedNote = note;
if (addFlag == AddToChord::None) {
if (!addFlag) {
std::vector<Note*> notes = chord->notes();
// break all ties into current chord
// these will exist only if user explicitly moved cursor to a tied-into note
Expand Down Expand Up @@ -359,6 +323,42 @@ Note* Score::addPitch(NoteVal& nval, AddToChord addFlag, InputState* externalInp
return note;
}

Note* Score::addPitchToChord(NoteVal& nval, Chord* chord, InputState* externalInputState)
{
IF_ASSERT_FAILED(chord) {
return nullptr;
}

InputState& is = externalInputState ? (*externalInputState) : m_is;

auto isTied = [](const Chord* ch) {
if (ch->notes().empty()) {
return false;
}
Note* n = ch->notes().at(0);
return n->tieFor() || n->tieBack();
};

Note* note = nullptr;
if (isTied(chord)) {
note = addNoteToTiedChord(chord, nval, /* forceAccidental */ false);
if (!note) {
note = addNote(chord, nval, /* forceAccidental */ false, /* articulationIds */ {}, externalInputState);
}
} else {
note = addNote(chord, nval, /* forceAccidental */ false, is.articulationIds(), externalInputState);
}

if (is.lastSegment() == is.segment()) {
NoteEntryMethod entryMethod = is.noteEntryMethod();
if (entryMethod != NoteEntryMethod::REALTIME_AUTO && entryMethod != NoteEntryMethod::REALTIME_MANUAL) {
is.moveToNextInputPos();
}
}

return note;
}

//---------------------------------------------------------
// putNote
// mouse click in state NoteType::ENTRY
Expand Down Expand Up @@ -468,7 +468,7 @@ Ret Score::putNote(const Position& p, bool replace)
handleOverlappingChordRest(m_is);
}

auto checkTied = [&](){
auto checkTied = [&]() {
if (!cr || !cr->isChord()) {
return false;
}
Expand Down
5 changes: 5 additions & 0 deletions src/engraving/dom/noteval.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,11 @@ struct NoteVal {
{
return concertPitch ? tpc1 : tpc2;
}

bool isRest() const
{
return pitch == -1;
}
};

using NoteValList = std::vector<NoteVal>;
Expand Down
29 changes: 23 additions & 6 deletions src/engraving/dom/score.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3203,17 +3203,34 @@ void Score::padToggle(Pad p, bool toggleForSelectionOnly)
// Enter a rest
setNoteRest(m_is.segment(), m_is.track(), NoteVal(), m_is.duration().fraction());
m_is.moveToNextInputPos();
} else if (!m_is.notes().empty()) {
const ChordRest* cr = m_is.cr();
AddToChord addType = AddToChord::None;
} else {
if (usingNoteEntryMethod(NoteEntryMethod::RHYTHM)) {
const EngravingItem* selectedItem = score()->selection().element();
if (selectedItem && selectedItem->isNote()) {
m_is.setNotes({ toNote(selectedItem)->noteVal() });
}
}

ChordRest* cr = m_is.cr();
Chord* chord = nullptr;

if (cr && cr->isChord() && cr->durationType() == m_is.duration()) {
addType = AddToChord::AtCurrentPosition;
chord = toChord(cr);
}

for (const NoteVal& nval : m_is.notes()) {
NoteVal copy(nval);
addPitch(copy, addType);
addType = AddToChord::AtCurrentPosition;
const Note* note = nullptr;

if (chord) {
note = addPitchToChord(copy, chord);
} else {
note = addPitch(copy, false /*addFlag*/);
}

if (note) {
chord = note->chord();
}
}
}
} else {
Expand Down
20 changes: 7 additions & 13 deletions src/engraving/dom/score.h
Original file line number Diff line number Diff line change
Expand Up @@ -515,22 +515,12 @@ class Score : public EngravingObject, public muse::Injectable
void doUndoRemoveElement(EngravingItem*);
bool containsElement(const EngravingItem*) const;

enum class AddToChord : unsigned char {
None,
AtPreviousPosition,
AtCurrentPosition,
};

Note* addPitch(NoteVal&, bool addToPreviousChord, InputState* externalInputState = nullptr);
Note* addPitch(NoteVal&, AddToChord addFlag = AddToChord::None, InputState* externalInputState = nullptr);

Note* addTiedMidiPitch(int pitch, bool addFlag, Chord* prevChord, bool allowTransposition);
NoteVal noteVal(int pitch, bool allowTransposition) const;
Note* addPitch(NoteVal&, bool addFlag, InputState* externalInputState = nullptr);
Note* addMidiPitch(int pitch, bool addFlag, bool allowTransposition);
Note* addNote(Chord*, const NoteVal& noteVal, bool forceAccidental = false, const std::set<SymId>& articulationIds = {},
InputState* externalInputState = nullptr);
Note* addNoteToTiedChord(Chord*, const NoteVal& noteVal, bool forceAccidental = false, const std::set<SymId>& articulationIds = {});

NoteVal noteVal(int pitch, bool allowTransposition) const;
NoteVal noteValForPosition(Position pos, AccidentalType at, bool& error);

Slur* addSlur(ChordRest* firstChordRest, ChordRest* secondChordRest, const Slur* slurTemplate);
Expand Down Expand Up @@ -1117,7 +1107,11 @@ class Score : public EngravingObject, public muse::Injectable

void updateStavesNumberForSystems();

void applyAccidentalToInputNotes();
void applyAccidentalToInputNotes(AccidentalType accidentalType);

Note* addPitchToChord(NoteVal&, Chord* chord, InputState* externalInputState = nullptr);
Note* addTiedMidiPitch(int pitch, bool addFlag, Chord* prevChord, bool allowTransposition);
Note* addNoteToTiedChord(Chord*, const NoteVal& noteVal, bool forceAccidental = false, const std::set<SymId>& articulationIds = {});

int m_linkId = 0;
MasterScore* m_masterScore = nullptr;
Expand Down
Loading
Loading