Line data Source code
1 : /*
2 : * SPDX-License-Identifier: GPL-3.0-only
3 : * MuseScore-Studio-CLA-applies
4 : *
5 : * MuseScore Studio
6 : * Music Composition & Notation
7 : *
8 : * Copyright (C) 2022 MuseScore Limited and others
9 : *
10 : * This program is free software: you can redistribute it and/or modify
11 : * it under the terms of the GNU General Public License version 3 as
12 : * published by the Free Software Foundation.
13 : *
14 : * This program is distributed in the hope that it will be useful,
15 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 : * GNU General Public License for more details.
18 : *
19 : * You should have received a copy of the GNU General Public License
20 : * along with this program. If not, see <https://www.gnu.org/licenses/>.
21 : */
22 :
23 : #include "chordarticulationsrenderer.h"
24 :
25 : #include "bendsrenderer.h"
26 : #include "noterenderer.h"
27 : #include "gracechordcontext.h"
28 : #include "ornamentsrenderer.h"
29 : #include "tremolorenderer.h"
30 : #include "arpeggiorenderer.h"
31 :
32 : #include "playback/utils/expressionutils.h"
33 :
34 : using namespace mu::engraving;
35 : using namespace muse;
36 : using namespace muse::mpe;
37 :
38 0 : const mpe::ArticulationTypeSet& ChordArticulationsRenderer::supportedTypes()
39 : {
40 0 : static mpe::ArticulationTypeSet SUPPORTED_TYPES;
41 :
42 0 : if (SUPPORTED_TYPES.empty()) {
43 0 : SUPPORTED_TYPES = GRACE_NOTE_ARTICULATION_TYPES;
44 :
45 0 : SUPPORTED_TYPES.insert(OrnamentsRenderer::supportedTypes().cbegin(),
46 0 : OrnamentsRenderer::supportedTypes().cend());
47 0 : SUPPORTED_TYPES.insert(TremoloRenderer::supportedTypes().cbegin(),
48 0 : TremoloRenderer::supportedTypes().cend());
49 0 : SUPPORTED_TYPES.insert(ArpeggioRenderer::supportedTypes().cbegin(),
50 0 : ArpeggioRenderer::supportedTypes().cend());
51 : }
52 :
53 0 : return SUPPORTED_TYPES;
54 : }
55 :
56 1071 : void ChordArticulationsRenderer::doRender(const EngravingItem* item, const mpe::ArticulationType /*type*/, const RenderingContext& ctx,
57 : mpe::PlaybackEventList& result)
58 : {
59 1071 : IF_ASSERT_FAILED(item->isChord()) {
60 0 : return;
61 : }
62 :
63 1136 : for (const auto& type : ctx.commonArticulations) {
64 72 : if (muse::contains(GRACE_NOTE_ARTICULATION_TYPES, type.first)) {
65 7 : renderChordWithGraceChords(toChord(item), type.first, ctx, result);
66 7 : return;
67 : }
68 : }
69 :
70 1064 : renderChord(toChord(item), ctx, result);
71 : }
72 :
73 1080 : void ChordArticulationsRenderer::renderChord(const Chord* chord, const RenderingContext& ctx, muse::mpe::PlaybackEventList& result)
74 : {
75 1080 : if (renderChordArticulations(chord, ctx, result)) {
76 52 : return;
77 : }
78 :
79 1028 : const bool supportsMultibend = ctx.profile->contains(ArticulationType::Multibend);
80 :
81 2066 : for (const Note* note: chord->notes()) {
82 1038 : if (supportsMultibend && BendsRenderer::isMultibendPart(note)) {
83 0 : BendsRenderer::render(note, ctx, result);
84 : } else {
85 1038 : NoteRenderer::render(note, ctx, result);
86 : }
87 : }
88 : }
89 :
90 7 : void ChordArticulationsRenderer::renderChordWithGraceChords(const Chord* chord, const muse::mpe::ArticulationType type,
91 : const RenderingContext& ctx,
92 : muse::mpe::PlaybackEventList& result)
93 : {
94 7 : const GraceChordCtx graceChordCtx = GraceChordCtx::buildCtx(chord, type, ctx);
95 :
96 7 : if (isGraceNotePlacedBeforePrincipalNote(type)) {
97 9 : for (const auto& pair : graceChordCtx.graceChordCtxList) {
98 5 : renderChord(pair.first, pair.second, result);
99 : }
100 4 : renderChord(chord, graceChordCtx.principalChordCtx, result);
101 : } else {
102 3 : renderChord(chord, graceChordCtx.principalChordCtx, result);
103 7 : for (const auto& pair : graceChordCtx.graceChordCtxList) {
104 4 : renderChord(pair.first, pair.second, result);
105 : }
106 : }
107 7 : }
108 :
109 1080 : bool ChordArticulationsRenderer::renderChordArticulations(const Chord* chord, const RenderingContext& ctx,
110 : mpe::PlaybackEventList& result)
111 : {
112 1102 : for (const auto& pair : ctx.commonArticulations) {
113 74 : const mpe::ArticulationType type = pair.first;
114 :
115 74 : if (OrnamentsRenderer::isAbleToRender(type)) {
116 14 : OrnamentsRenderer::render(chord, type, ctx, result);
117 52 : return true;
118 : }
119 :
120 60 : if (TremoloRenderer::isAbleToRender(type)) {
121 28 : TremoloRenderer::render(chord, type, ctx, result);
122 28 : return true;
123 : }
124 :
125 32 : if (ArpeggioRenderer::isAbleToRender(type)) {
126 10 : ArpeggioRenderer::render(chord, type, ctx, result);
127 10 : return true;
128 : }
129 : }
130 :
131 1028 : return false;
132 : }
|