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) 2021 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 "spannersmetaparser.h"
24 :
25 : #include "dom/glissando.h"
26 : #include "dom/note.h"
27 : #include "dom/spanner.h"
28 : #include "dom/trill.h"
29 : #include "dom/pedal.h"
30 :
31 : #include "playback/utils/pitchutils.h"
32 : #include "playback/filters/spannerfilter.h"
33 :
34 : using namespace mu::engraving;
35 : using namespace muse;
36 :
37 67 : bool SpannersMetaParser::isAbleToParse(const EngravingItem* spannerItem)
38 : {
39 : static const std::unordered_set<ElementType> SUPPORTED_TYPES {
40 : ElementType::SLUR,
41 : ElementType::HAMMER_ON_PULL_OFF,
42 : ElementType::PEDAL,
43 : ElementType::LET_RING,
44 : ElementType::PALM_MUTE,
45 : ElementType::TRILL,
46 : ElementType::GLISSANDO,
47 : ElementType::GUITAR_BEND,
48 : ElementType::VIBRATO,
49 69 : };
50 :
51 67 : return muse::contains(SUPPORTED_TYPES, spannerItem->type());
52 : }
53 :
54 46 : void SpannersMetaParser::doParse(const EngravingItem* item, const RenderingContext& spannerCtx, mpe::ArticulationMap& result)
55 : {
56 46 : IF_ASSERT_FAILED(item->isSpanner()) {
57 1 : return;
58 : }
59 :
60 46 : const Spanner* spanner = toSpanner(item);
61 46 : if (!spanner->playSpanner()) {
62 1 : return;
63 : }
64 :
65 45 : const int overallDurationTicks = SpannerFilter::spannerActualDurationTicks(spanner, spannerCtx.nominalDurationTicks);
66 :
67 45 : mpe::ArticulationType type = mpe::ArticulationType::Undefined;
68 45 : mpe::pitch_level_t overallPitchRange = 0;
69 45 : mpe::dynamic_level_t overallDynamicRange = 0;
70 :
71 45 : switch (spanner->type()) {
72 2 : case ElementType::SLUR:
73 : case ElementType::HAMMER_ON_PULL_OFF:
74 2 : type = mpe::ArticulationType::Legato;
75 2 : break;
76 12 : case ElementType::PEDAL:
77 : case ElementType::LET_RING:
78 12 : type = mpe::ArticulationType::Pedal;
79 12 : break;
80 0 : case ElementType::PALM_MUTE:
81 0 : type = mpe::ArticulationType::PalmMute;
82 0 : break;
83 18 : case ElementType::GUITAR_BEND:
84 18 : type = mpe::ArticulationType::Multibend;
85 18 : break;
86 0 : case ElementType::VIBRATO:
87 0 : type = mpe::ArticulationType::Vibrato;
88 0 : break;
89 5 : case ElementType::TRILL: {
90 5 : const Trill* trill = toTrill(spanner);
91 :
92 5 : if (trill->trillType() == TrillType::TRILL_LINE) {
93 5 : type = mpe::ArticulationType::Trill;
94 0 : } else if (trill->trillType() == TrillType::UPPRALL_LINE) {
95 0 : type = mpe::ArticulationType::UpPrall;
96 0 : } else if (trill->trillType() == TrillType::DOWNPRALL_LINE) {
97 0 : type = mpe::ArticulationType::PrallDown;
98 0 : } else if (trill->trillType() == TrillType::PRALLPRALL_LINE) {
99 0 : type = mpe::ArticulationType::LinePrall;
100 : }
101 5 : break;
102 : }
103 8 : case ElementType::GLISSANDO: {
104 8 : const Glissando* glissando = toGlissando(spanner);
105 8 : const Note* startNote = toNote(glissando->startElement());
106 8 : const Note* endNote = toNote(glissando->endElement());
107 :
108 8 : if (!startNote || !endNote) {
109 : break;
110 : }
111 :
112 8 : if (glissando->glissandoStyle() == GlissandoStyle::PORTAMENTO) {
113 3 : type = mpe::ArticulationType::ContinuousGlissando;
114 : } else {
115 5 : type = mpe::ArticulationType::DiscreteGlissando;
116 : }
117 :
118 8 : int startNoteTpc = startNote->playingTpc();
119 8 : int endNoteTpc = endNote->playingTpc();
120 :
121 8 : mpe::PitchClass startNotePitchClass = pitchClassFromTpc(startNoteTpc);
122 8 : mpe::PitchClass endNotePitchClass = pitchClassFromTpc(endNoteTpc);
123 :
124 8 : mpe::octave_t startNoteOctave = actualOctave(startNote->playingOctave(), startNotePitchClass, tpc2alter(startNoteTpc));
125 8 : mpe::octave_t endNoteOctave = actualOctave(endNote->playingOctave(), endNotePitchClass, tpc2alter(endNoteTpc));
126 :
127 8 : overallPitchRange = mpe::pitchLevelDiff(endNotePitchClass, endNoteOctave, startNotePitchClass, startNoteOctave);
128 :
129 8 : break;
130 : }
131 0 : default:
132 0 : break;
133 : }
134 :
135 45 : if (type == mpe::ArticulationType::Undefined) {
136 0 : return;
137 : }
138 :
139 45 : const mpe::ArticulationPattern& pattern = spannerCtx.profile->pattern(type);
140 45 : if (pattern.empty()) {
141 0 : return;
142 : }
143 :
144 90 : mpe::ArticulationMeta articulationMeta;
145 45 : articulationMeta.type = type;
146 45 : articulationMeta.pattern = pattern;
147 45 : articulationMeta.timestamp = spannerCtx.nominalTimestamp;
148 45 : articulationMeta.overallPitchChangesRange = overallPitchRange;
149 45 : articulationMeta.overallDynamicChangesRange = overallDynamicRange;
150 90 : articulationMeta.overallDuration = durationFromStartAndTicks(spannerCtx.score,
151 45 : spannerCtx.nominalPositionStartTick,
152 : overallDurationTicks,
153 45 : spannerCtx.positionTickOffset);
154 :
155 45 : appendArticulationData(std::move(articulationMeta), result);
156 : }
|