Skip to content

Commit

Permalink
fix #26364: draw accidentals in input by duration
Browse files Browse the repository at this point in the history
  • Loading branch information
RomanPudashkin committed Feb 10, 2025
1 parent a193790 commit 93558c3
Show file tree
Hide file tree
Showing 5 changed files with 102 additions and 44 deletions.
44 changes: 37 additions & 7 deletions src/engraving/dom/utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@

#include "containers.h"

#include "accidental.h"
#include "chord.h"
#include "chordrest.h"
#include "clef.h"
Expand Down Expand Up @@ -1133,6 +1134,23 @@ int chromaticPitchSteps(const Note* noteL, const Note* noteR, const int nominalD
return halfsteps;
}

static void noteValToEffectivePitchAndTpc(const NoteVal& nval, const Staff* staff, const Fraction& tick, int& epitch, int& tpc)
{
const bool concertPitch = staff->concertPitch();

if (concertPitch) {
epitch = nval.pitch;
} else {
const int pitchOffset = staff->part()->instrument(tick)->transpose().chromatic;
epitch = nval.pitch - pitchOffset;
}

tpc = nval.tpc(concertPitch);
if (tpc == static_cast<int>(mu::engraving::Tpc::TPC_INVALID)) {
tpc = pitch2tpc(epitch, staff->key(tick), mu::engraving::Prefer::NEAREST);
}
}

int noteValToLine(const NoteVal& nval, const Staff* staff, const Fraction& tick)
{
if (staff->isDrumStaff(tick)) {
Expand All @@ -1146,16 +1164,28 @@ int noteValToLine(const NoteVal& nval, const Staff* staff, const Fraction& tick)
return staff->middleLine(tick);
}

const bool concertPitch = staff->concertPitch();
const int pitchOffset = concertPitch ? 0 : staff->part()->instrument(tick)->transpose().chromatic;
const int epitch = nval.pitch - pitchOffset;
int epitch = nval.pitch;
int tpc = static_cast<int>(mu::engraving::Tpc::TPC_INVALID);
noteValToEffectivePitchAndTpc(nval, staff, tick, epitch, tpc);

int tpc = nval.tpc(concertPitch);
if (tpc == static_cast<int>(mu::engraving::Tpc::TPC_INVALID)) {
tpc = pitch2tpc(epitch, staff->key(tick), mu::engraving::Prefer::NEAREST);
return relStep(epitch, tpc, staff->clef(tick));
}

AccidentalType noteValToAccidentalType(const NoteVal& nval, const Staff* staff, const Fraction& tick)
{
if (nval.isRest()) {
return AccidentalType::NONE;
}

return relStep(epitch, tpc, staff->clef(tick));
if (staff->isDrumStaff(tick)) {
return AccidentalType::NONE;
}

int epitch = nval.pitch;
int tpc = static_cast<int>(mu::engraving::Tpc::TPC_INVALID);
noteValToEffectivePitchAndTpc(nval, staff, tick, epitch, tpc);

return Accidental::value2subtype(tpc2alter(tpc));
}

int compareNotesPos(const Note* n1, const Note* n2)
Expand Down
2 changes: 2 additions & 0 deletions src/engraving/dom/utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#pragma once

#include "../types/types.h"
#include "types.h"

#include "interval.h"

Expand Down Expand Up @@ -85,6 +86,7 @@ extern int pitch2step(int pitch);
extern int step2pitch(int step);
int chromaticPitchSteps(const Note* noteL, const Note* noteR, const int nominalDiatonicSteps);
extern int noteValToLine(const NoteVal& nval, const Staff* staff, const Fraction& tick);
extern AccidentalType noteValToAccidentalType(const NoteVal& nval, const Staff* staff, const Fraction& tick);
extern int compareNotesPos(const Note* n1, const Note* n2);

extern Segment* skipTuplet(Tuplet* tuplet);
Expand Down
86 changes: 52 additions & 34 deletions src/notation/internal/notationinteraction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
#include "draw/types/pen.h"
#include "engraving/internal/qmimedataadapter.h"

#include "engraving/dom/accidental.h"
#include "engraving/dom/actionicon.h"
#include "engraving/dom/anchors.h"
#include "engraving/dom/articulation.h"
Expand Down Expand Up @@ -367,23 +368,24 @@ bool NotationInteraction::showShadowNote(const PointF& pos)
const mu::engraving::InputState& inputState = score()->inputState();
mu::engraving::ShadowNote& shadowNote = *score()->shadowNote();

mu::engraving::Position position;
if (!score()->getPosition(&position, pos, inputState.voice())) {
InputNoteParams params;
if (!score()->getPosition(&params.position, pos, inputState.voice())) {
shadowNote.setVisible(false);
return false;
}

ShadowNoteParams params;
params.duration = inputState.duration();
params.accidentalType = inputState.accidentalType();
params.articulationIds = inputState.articulationIds();

showShadowNoteAtPosition(shadowNote, params, position);
showShadowNote(shadowNote, params);
return true;
}

void NotationInteraction::showShadowNoteAtPosition(ShadowNote& shadowNote, const ShadowNoteParams& params, Position& position)
void NotationInteraction::showShadowNote(ShadowNote& shadowNote, InputNoteParams& params)
{
Position& position = params.position;

const mu::engraving::InputState& inputState = score()->inputState();
const Staff* staff = score()->staff(position.staffIdx);
const mu::engraving::Instrument* instr = staff->part()->instrument();
Expand Down Expand Up @@ -2678,20 +2680,21 @@ double NotationInteraction::currentScaling(Painter* painter) const
return painter->worldTransform().m11() / guiScaling;
}

std::vector<Position> NotationInteraction::inputPositions() const
std::vector<NotationInteraction::InputNoteParams> NotationInteraction::inputNotes() const
{
std::vector<Position> result;
std::vector<InputNoteParams> result;

const InputState& is = score()->inputState();
if (!is.isValid()) {
return result;
}

Segment* segment = is.segment();
const staff_idx_t staffIdx = is.staffIdx();
const Staff* staff = score()->staff(staffIdx);
const System* system = is.segment()->system();
const System* system = segment->system();
const SysStaff* sysStaff = system ? system->staff(staffIdx) : nullptr;
const Measure* measure = is.segment()->measure();
const Measure* measure = segment->measure();

if (!staff || !sysStaff || !measure) {
return result;
Expand All @@ -2711,20 +2714,38 @@ std::vector<Position> NotationInteraction::inputPositions() const
nvals = is.notes();
}

Position pos;
pos.segment = is.segment();
pos.staffIdx = staffIdx;
InputNoteParams params;
params.duration = is.rest() ? is.duration() : TDuration();
params.position.segment = segment;
params.position.staffIdx = staffIdx;

if (!is.rest() && is.accidentalType() != AccidentalType::NONE) {
params.accidentalType = is.accidentalType();
}

for (const NoteVal& nval : nvals) {
pos.line = mu::engraving::noteValToLine(nval, staff, tick);
const double y = sysStaff->y() + pos.line * lineDist;
pos.pos = PointF(is.segment()->x(), y) + measurePos;
const int line = mu::engraving::noteValToLine(nval, staff, tick);
const double y = sysStaff->y() + line * lineDist;

if (params.accidentalType == AccidentalType::NONE) {
const AccidentalType type = mu::engraving::noteValToAccidentalType(nval, staff, tick);
if (type != AccidentalType::NATURAL) {
bool error = false;
const AccidentalVal existingAccVal = measure->findAccidental(segment, staffIdx, line, error);
if (!error && type != Accidental::value2subtype(existingAccVal)) {
params.accidentalType = type;
}
}
}

params.position.line = line;
params.position.pos = PointF(segment->x(), y) + measurePos;

result.push_back(pos);
result.push_back(params);
}

std::sort(result.begin(), result.end(), [](const Position& p1, const Position& p2) {
return p1.line < p2.line;
std::sort(result.begin(), result.end(), [](const InputNoteParams& p1, const InputNoteParams& p2) {
return p1.position.line < p2.position.line;
});

return result;
Expand All @@ -2737,31 +2758,28 @@ bool NotationInteraction::shouldDrawInputPreview() const

void NotationInteraction::drawInputPreview(Painter* painter)
{
std::vector<Position> positions = inputPositions();
if (positions.empty()) {
std::vector<InputNoteParams> inputNotes = this->inputNotes();
if (inputNotes.empty()) {
return;
}

std::vector<ShadowNote*> notes;
notes.reserve(positions.size());
std::vector<ShadowNote*> previewList;
previewList.reserve(inputNotes.size());

const InputState& is = score()->inputState();

ShadowNoteParams params;
params.duration = is.rest() ? is.duration() : TDuration();

for (Position& pos : positions) {
ShadowNote* note = new ShadowNote(score());
showShadowNoteAtPosition(*note, params, pos);
notes.push_back(note);
for (InputNoteParams& params : inputNotes) {
ShadowNote* preview = new ShadowNote(score());
showShadowNote(*preview, params);
previewList.push_back(preview);
}

const bool isUp = !is.rest() && notes.front()->computeUp();
const bool isUp = !is.rest() && previewList.front()->computeUp();
bool isLeft = isUp;
int prevLine = INT_MAX;

auto correctNotePositionIfNeed = [&](ShadowNote* note) {
if (positions.size() == 1) {
if (inputNotes.size() == 1) {
return;
}

Expand All @@ -2786,18 +2804,18 @@ void NotationInteraction::drawInputPreview(Painter* painter)
};

if (isUp) {
for (auto it = notes.rbegin(); it != notes.rend(); ++it) {
for (auto it = previewList.rbegin(); it != previewList.rend(); ++it) {
correctNotePositionIfNeed(*it);
score()->renderer()->drawItem(*it, painter);
}
} else {
for (auto it = notes.begin(); it != notes.end(); ++it) {
for (auto it = previewList.begin(); it != previewList.end(); ++it) {
correctNotePositionIfNeed(*it);
score()->renderer()->drawItem(*it, painter);
}
}

DeleteAll(notes);
DeleteAll(previewList);
}

void NotationInteraction::drawAnchorLines(Painter* painter)
Expand Down
7 changes: 4 additions & 3 deletions src/notation/internal/notationinteraction.h
Original file line number Diff line number Diff line change
Expand Up @@ -317,13 +317,14 @@ class NotationInteraction : public INotationInteraction, public muse::Injectable
void apply();
void rollback();

struct ShadowNoteParams {
struct InputNoteParams {
mu::engraving::TDuration duration;
mu::engraving::AccidentalType accidentalType = mu::engraving::AccidentalType::NONE;
std::set<SymId> articulationIds;
mu::engraving::Position position;
};

void showShadowNoteAtPosition(mu::engraving::ShadowNote& note, const ShadowNoteParams& params, mu::engraving::Position& pos);
void showShadowNote(mu::engraving::ShadowNote& note, InputNoteParams& params);

bool needStartEditGrip(QKeyEvent* event) const;
bool handleKeyPress(QKeyEvent* event);
Expand Down Expand Up @@ -379,7 +380,7 @@ class NotationInteraction : public INotationInteraction, public muse::Injectable
void resetAnchorLines();
double currentScaling(muse::draw::Painter* painter) const;

std::vector<mu::engraving::Position> inputPositions() const;
std::vector<InputNoteParams> inputNotes() const;

bool shouldDrawInputPreview() const;
void drawInputPreview(muse::draw::Painter* painter);
Expand Down
7 changes: 7 additions & 0 deletions src/notation/internal/notationnoteinput.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -458,6 +458,13 @@ void NotationNoteInput::padNote(const Pad& pad)
score()->padToggle(pad);
apply();

if (pad >= Pad::NOTE00 && pad <= Pad::NOTE1024) {
const NoteInputState& is = score()->inputState();
if (!is.rest() && is.usingNoteEntryMethod(NoteInputMethod::BY_DURATION)) {
score()->toggleAccidental(AccidentalType::NONE);
}
}

notifyAboutStateChanged();

MScoreErrorsController(iocContext()).checkAndShowMScoreError();
Expand Down

0 comments on commit 93558c3

Please sign in to comment.