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

tied_notes_improvements #25187

Open
wants to merge 14 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all 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
2 changes: 2 additions & 0 deletions src/engraving/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,8 @@ set(MODULE_SRC
${CMAKE_CURRENT_LIST_DIR}/playback/renderers/tremolorenderer.h
${CMAKE_CURRENT_LIST_DIR}/playback/renderers/chordarticulationsrenderer.cpp
${CMAKE_CURRENT_LIST_DIR}/playback/renderers/chordarticulationsrenderer.h
${CMAKE_CURRENT_LIST_DIR}/playback/renderers/noterenderer.cpp
${CMAKE_CURRENT_LIST_DIR}/playback/renderers/noterenderer.h
${CMAKE_CURRENT_LIST_DIR}/playback/renderers/bendsrenderer.cpp
${CMAKE_CURRENT_LIST_DIR}/playback/renderers/bendsrenderer.h
${CMAKE_CURRENT_LIST_DIR}/playback/metaparsers/internal/symbolsmetaparser.cpp
Expand Down
76 changes: 0 additions & 76 deletions src/engraving/playback/filters/chordfilter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,6 @@

#include "chordfilter.h"

#include "dom/chord.h"
#include "dom/note.h"
#include "dom/tie.h"

#include "internal/tremolofilter.h"

using namespace mu::engraving;
Expand All @@ -35,75 +31,3 @@ bool ChordFilter::isPlayable(const EngravingItem* item, const RenderingContext&
{
return TremoloFilter::isItemPlayable(item, ctx);
}

static bool containsTieEnd(const Chord* chord)
{
for (const Note* note : chord->notes()) {
if ((note->tieBack() && note->tieBack()->playSpanner()) && !(note->tieFor() && note->tieFor()->playSpanner())) {
return true;
}
}

return false;
}

static bool containsTieStart(const Chord* chord)
{
for (const Note* note : chord->notes()) {
if (!(note->tieBack() && note->tieBack()->playSpanner()) && (note->tieFor() && note->tieFor()->playSpanner())) {
return true;
}
}

return false;
}

void ChordFilter::validateArticulations(const EngravingItem* item, mpe::ArticulationMap& result)
{
IF_ASSERT_FAILED(item && item->isChord()) {
return;
}

static const mpe::ArticulationTypeSet LAST_TIED_NOTE_ALLOWED_TYPES = {
mpe::ArticulationType::Staccato,
mpe::ArticulationType::Staccatissimo,
mpe::ArticulationType::Tenuto
};

if (result.empty()) {
return;
}

if (!result.containsAnyOf(LAST_TIED_NOTE_ALLOWED_TYPES.cbegin(),
LAST_TIED_NOTE_ALLOWED_TYPES.cend())) {
return;
}

const Chord* chord = toChord(item);

if (containsTieEnd(chord)) {
mpe::ArticulationMap filteredMap;

for (const mpe::ArticulationType type : LAST_TIED_NOTE_ALLOWED_TYPES) {
auto search = result.find(type);

if (search != result.cend()) {
filteredMap.emplace(search->first, search->second);
}
}

result = filteredMap;
return;
}

if (containsTieStart(chord)) {
for (const mpe::ArticulationType type : LAST_TIED_NOTE_ALLOWED_TYPES) {
auto search = result.find(type);

if (search != result.cend()) {
result.erase(type);
}
}
return;
}
}
3 changes: 0 additions & 3 deletions src/engraving/playback/filters/chordfilter.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,6 @@
namespace mu::engraving {
class ChordFilter : public FilterBase<ChordFilter>
{
public:
static void validateArticulations(const EngravingItem* item, muse::mpe::ArticulationMap& result);

protected:
friend class FilterBase<ChordFilter>;
static bool isPlayable(const EngravingItem* item, const RenderingContext& ctx);
Expand Down
12 changes: 7 additions & 5 deletions src/engraving/playback/filters/spannerfilter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,17 +52,19 @@ bool SpannerFilter::isPlayable(const EngravingItem* item, const RenderingContext

int SpannerFilter::spannerActualDurationTicks(const Spanner* spanner, const int nominalDurationTicks)
{
if (spanner->type() == ElementType::SLUR) {
EngravingItem* startItem = spanner->startElement();
EngravingItem* endItem = spanner->endElement();
const ElementType type = spanner->type();

if (type == ElementType::SLUR || type == ElementType::TRILL) {
const EngravingItem* startItem = spanner->startElement();
const EngravingItem* endItem = spanner->endElement();

if (!startItem || !endItem) {
return nominalDurationTicks;
}

if (startItem->isChordRest() && endItem->isChordRest()) {
ChordRest* startChord = toChordRest(startItem);
ChordRest* endChord = toChordRest(endItem);
const ChordRest* startChord = toChordRest(startItem);
const ChordRest* endChord = toChordRest(endItem);
return endChord->tick().ticks() + endChord->ticks().ticks() - startChord->tick().ticks();
}
}
Expand Down
15 changes: 3 additions & 12 deletions src/engraving/playback/metaparsers/chordarticulationsparser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@
#include "dom/tremolotwochord.h"

#include "playback/utils/arrangementutils.h"
#include "playback/filters/chordfilter.h"
#include "playback/filters/spannerfilter.h"
#include "internal/spannersmetaparser.h"
#include "internal/symbolsmetaparser.h"
Expand Down Expand Up @@ -85,7 +84,6 @@ void ChordArticulationsParser::doParse(const EngravingItem* item, const Renderin
parseArpeggio(chord, ctx, result);
parseGraceNotes(chord, ctx, result);
parseChordLine(chord, ctx, result);

parseArticulationSymbols(chord, ctx, result);

if (ctx.profile->contains(ArticulationType::Multibend)) {
Expand All @@ -95,10 +93,7 @@ void ChordArticulationsParser::doParse(const EngravingItem* item, const Renderin

void ChordArticulationsParser::parseSpanners(const Chord* chord, const RenderingContext& ctx, mpe::ArticulationMap& result)
{
const Score* score = chord->score();

const SpannerMap& spannerMap = score->spannerMap();

const SpannerMap& spannerMap = ctx.score->spannerMap();
if (spannerMap.empty()) {
return;
}
Expand All @@ -108,7 +103,7 @@ void ChordArticulationsParser::parseSpanners(const Chord* chord, const Rendering
/*excludeCollisions*/ true);

for (const auto& interval : intervals) {
Spanner* spanner = interval.value;
const Spanner* spanner = interval.value;

if (!SpannersMetaParser::isAbleToParse(spanner)) {
continue;
Expand All @@ -129,7 +124,7 @@ void ChordArticulationsParser::parseSpanners(const Chord* chord, const Rendering
}

RenderingContext spannerContext = ctx;
spannerContext.nominalTimestamp = timestampFromTicks(score, interval.start + ctx.positionTickOffset);
spannerContext.nominalTimestamp = timestampFromTicks(ctx.score, interval.start + ctx.positionTickOffset);
spannerContext.nominalPositionStartTick = interval.start;
spannerContext.nominalDurationTicks = SpannerFilter::spannerActualDurationTicks(spanner, interval.stop - interval.start);
spannerContext.nominalPositionEndTick = spannerContext.nominalPositionStartTick + spannerContext.nominalDurationTicks;
Expand Down Expand Up @@ -160,8 +155,6 @@ void ChordArticulationsParser::parseArticulationSymbols(const Chord* chord, cons
for (const Articulation* articulation : chord->articulations()) {
SymbolsMetaParser::parse(articulation, ctx, result);
}

ChordFilter::validateArticulations(chord, result);
}

void ChordArticulationsParser::parseAnnotations(const Chord* chord, const RenderingContext& ctx, mpe::ArticulationMap& result)
Expand Down Expand Up @@ -197,7 +190,6 @@ void ChordArticulationsParser::parseTremolo(const Chord* chord, const RenderingC
void ChordArticulationsParser::parseArpeggio(const Chord* chord, const RenderingContext& ctx, mpe::ArticulationMap& result)
{
const Arpeggio* arpeggio = chord->arpeggio();

if (!arpeggio) {
return;
}
Expand All @@ -219,7 +211,6 @@ void ChordArticulationsParser::parseGraceNotes(const Chord* chord, const Renderi
void ChordArticulationsParser::parseChordLine(const Chord* chord, const RenderingContext& ctx, mpe::ArticulationMap& result)
{
const ChordLine* chordLine = chord->chordLine();

if (!chordLine || !chordLine->playChordLine()) {
return;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,6 @@ void SpannersMetaParser::doParse(const EngravingItem* item, const RenderingConte
}

const Spanner* spanner = toSpanner(item);

if (!spanner->playSpanner()) {
return;
}
Expand Down Expand Up @@ -154,7 +153,7 @@ void SpannersMetaParser::doParse(const EngravingItem* item, const RenderingConte
articulationMeta.timestamp = spannerCtx.nominalTimestamp;
articulationMeta.overallPitchChangesRange = overallPitchRange;
articulationMeta.overallDynamicChangesRange = overallDynamicRange;
articulationMeta.overallDuration = spannerDuration(spanner->score(),
articulationMeta.overallDuration = spannerDuration(spannerCtx.score,
spannerCtx.nominalPositionStartTick,
overallDurationTicks);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ void TremoloSingleMetaParser::doParse(const EngravingItem* item, const Rendering
articulationMeta.type = type;
articulationMeta.pattern = pattern;
articulationMeta.timestamp = ctx.nominalTimestamp;
articulationMeta.overallDuration = timestampFromTicks(tremolo->score(), ctx.nominalPositionStartTick + overallDurationTicks)
articulationMeta.overallDuration = timestampFromTicks(ctx.score, ctx.nominalPositionStartTick + overallDurationTicks)
- ctx.nominalTimestamp;

appendArticulationData(std::move(articulationMeta), result);
Expand Down Expand Up @@ -122,7 +122,7 @@ void TremoloTwoMetaParser::doParse(const EngravingItem* item, const RenderingCon
articulationMeta.type = type;
articulationMeta.pattern = pattern;
articulationMeta.timestamp = ctx.nominalTimestamp;
articulationMeta.overallDuration = timestampFromTicks(tremolo->score(), ctx.nominalPositionStartTick + overallDurationTicks)
articulationMeta.overallDuration = timestampFromTicks(ctx.score, ctx.nominalPositionStartTick + overallDurationTicks)
- ctx.nominalTimestamp;

appendArticulationData(std::move(articulationMeta), result);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -194,8 +194,6 @@ void NoteArticulationsParser::parseNoteHead(const Note* note, const RenderingCon

void NoteArticulationsParser::parseSpanners(const Note* note, const RenderingContext& ctx, mpe::ArticulationMap& result)
{
const Score* score = note->score();

for (const Spanner* spanner : note->spannerFor()) {
int spannerFrom = spanner->tick().ticks();
int spannerTo = spannerFrom + std::abs(spanner->ticks().ticks());
Expand All @@ -205,7 +203,7 @@ void NoteArticulationsParser::parseSpanners(const Note* note, const RenderingCon
continue;
}

auto spannerTnD = timestampAndDurationFromStartAndDurationTicks(score, spannerFrom, spannerDurationTicks, 0);
auto spannerTnD = timestampAndDurationFromStartAndDurationTicks(ctx.score, spannerFrom, spannerDurationTicks, 0);

RenderingContext spannerContext = ctx;
spannerContext.nominalTimestamp = spannerTnD.timestamp;
Expand Down
27 changes: 2 additions & 25 deletions src/engraving/playback/playbackeventsrenderer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -250,31 +250,7 @@ void PlaybackEventsRenderer::renderNoteEvents(const Chord* chord, const int tick
return;
}

int chordPosTick = chord->tick().ticks();
int chordDurationTicks = chord->actualTicks().ticks();
int chordPosTickWithOffset = chordPosTick + tickPositionOffset;

const Score* score = chord->score();

auto chordTnD = timestampAndDurationFromStartAndDurationTicks(score, chordPosTick, chordDurationTicks, tickPositionOffset);

BeatsPerSecond bps = score->tempomap()->tempo(chordPosTick);
TimeSigFrac timeSignatureFraction = score->sigmap()->timesig(chordPosTick).timesig();

static ArticulationMap articulations;

RenderingContext ctx(chordTnD.timestamp,
chordTnD.duration,
playbackCtx->appliableDynamicLevel(chord->track(), chordPosTickWithOffset),
chordPosTick,
tickPositionOffset,
chordDurationTicks,
bps,
timeSignatureFraction,
playbackCtx->persistentArticulationType(chordPosTickWithOffset),
articulations,
profile,
playbackCtx);
RenderingContext ctx = engraving::buildRenderingCtx(chord, tickPositionOffset, profile, playbackCtx);

if (!ChordFilter::isItemPlayable(chord, ctx)) {
return;
Expand Down Expand Up @@ -304,6 +280,7 @@ void PlaybackEventsRenderer::renderFixedNoteEvent(const Note* note, const mpe::t
TimeSigMap::DEFAULT_TIME_SIGNATURE,
persistentArticulationApplied,
articulations,
note->score(),
profile,
dummyCtx);

Expand Down
57 changes: 42 additions & 15 deletions src/engraving/playback/playbackmodel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -838,31 +838,31 @@ PlaybackModel::TickBoundaries PlaybackModel::tickBoundaries(const ScoreChangesRa
result.tickFrom = std::min(result.tickFrom, startChord->tick().ticks());
result.tickTo = std::max(result.tickTo, endChord->tick().ticks());
}

applyTiedNotesTickBoundaries(note, result);
} else if (item->isTie()) {
const Tie* tie = toTie(item);
const Note* startNote = tie->startNote();
const Note* endNote = tie->endNote();
applyTieTickBoundaries(toTie(item), result);
}

if (!startNote || !endNote) {
continue;
}
const EngravingItem* parent = item->parentItem();
if (!parent) {
continue;
}

const Note* firstTiedNote = startNote->firstTiedNote(false);
const Note* lastTiedNote = endNote->lastTiedNote(false);
if (parent->isChord()) {
const Chord* chord = toChord(parent);

IF_ASSERT_FAILED(firstTiedNote && lastTiedNote) {
continue;
for (const Note* note : chord->notes()) {
applyTiedNotesTickBoundaries(note, result);
}

result.tickFrom = std::min(result.tickFrom, firstTiedNote->tick().ticks());
result.tickTo = std::max(result.tickTo, lastTiedNote->tick().ticks());
}
if (item->parent() && item->parent()->isChord()) {
for (Spanner* spanner : toChord(item->parent())->startingSpanners()) {
for (const Spanner* spanner : chord->startingSpanners()) {
if (spanner->isTrill() && result.tickTo < spanner->tick2().ticks()) {
result.tickTo = spanner->tick2().ticks();
}
}
} else if (parent->isNote()) {
applyTiedNotesTickBoundaries(toNote(parent), result);
}
}

Expand Down Expand Up @@ -947,3 +947,30 @@ PlaybackContextPtr PlaybackModel::playbackCtx(const InstrumentTrackId& trackId)

return it->second;
}

void PlaybackModel::applyTiedNotesTickBoundaries(const Note* note, TickBoundaries& tickBoundaries)
{
if (const Tie* tie = note->tieFor()) {
applyTieTickBoundaries(tie, tickBoundaries);
} else if (const Tie* tie = note->tieBack()) {
applyTieTickBoundaries(tie, tickBoundaries);
}
}

void PlaybackModel::applyTieTickBoundaries(const Tie* tie, TickBoundaries& tickBoundaries)
{
const Note* startNote = tie->startNote();
const Note* endNote = tie->endNote();
if (!startNote || !endNote) {
return;
}

const Note* firstTiedNote = startNote->firstTiedNote();
const Note* lastTiedNote = endNote->lastTiedNote();
IF_ASSERT_FAILED(firstTiedNote && lastTiedNote) {
return;
}

tickBoundaries.tickFrom = std::min(tickBoundaries.tickFrom, firstTiedNote->tick().ticks());
tickBoundaries.tickTo = std::max(tickBoundaries.tickTo, lastTiedNote->tick().ticks());
}
3 changes: 3 additions & 0 deletions src/engraving/playback/playbackmodel.h
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,9 @@ class PlaybackModel : public muse::Injectable, public muse::async::Asyncable

PlaybackContextPtr playbackCtx(const InstrumentTrackId& trackId);

static void applyTiedNotesTickBoundaries(const Note* note, TickBoundaries& tickBoundaries);
static void applyTieTickBoundaries(const Tie* tie, TickBoundaries& tickBoundaries);

Score* m_score = nullptr;
bool m_expandRepeats = true;
bool m_playChordSymbols = true;
Expand Down
Loading