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 : #ifndef MU_ENGRAVING_DYNAMICUTILS_H
24 : #define MU_ENGRAVING_DYNAMICUTILS_H
25 :
26 : #include "mpe/mpetypes.h"
27 :
28 : #include "../types/types.h"
29 :
30 : namespace mu::engraving {
31 : constexpr muse::mpe::dynamic_level_t NATURAL_DYNAMIC_LEVEL = muse::mpe::dynamicLevelFromType(muse::mpe::DynamicType::Natural);
32 :
33 : inline const std::unordered_map<DynamicType, muse::mpe::dynamic_level_t> ORDINARY_DYNAMIC_LEVELS {
34 : { DynamicType::N, muse::mpe::dynamicLevelFromType(muse::mpe::DynamicType::ppppppppp) },
35 : { DynamicType::PPPPPP, muse::mpe::dynamicLevelFromType(muse::mpe::DynamicType::pppppp) },
36 : { DynamicType::PPPPP, muse::mpe::dynamicLevelFromType(muse::mpe::DynamicType::ppppp) },
37 : { DynamicType::PPPP, muse::mpe::dynamicLevelFromType(muse::mpe::DynamicType::pppp) },
38 : { DynamicType::PPP, muse::mpe::dynamicLevelFromType(muse::mpe::DynamicType::ppp) },
39 : { DynamicType::PP, muse::mpe::dynamicLevelFromType(muse::mpe::DynamicType::pp) },
40 : { DynamicType::P, muse::mpe::dynamicLevelFromType(muse::mpe::DynamicType::p) },
41 : { DynamicType::MP, muse::mpe::dynamicLevelFromType(muse::mpe::DynamicType::mp) },
42 : { DynamicType::MF, muse::mpe::dynamicLevelFromType(muse::mpe::DynamicType::mf) },
43 : { DynamicType::F, muse::mpe::dynamicLevelFromType(muse::mpe::DynamicType::f) },
44 : { DynamicType::FF, muse::mpe::dynamicLevelFromType(muse::mpe::DynamicType::ff) },
45 : { DynamicType::FFF, muse::mpe::dynamicLevelFromType(muse::mpe::DynamicType::fff) },
46 : { DynamicType::FFFF, muse::mpe::dynamicLevelFromType(muse::mpe::DynamicType::ffff) },
47 : { DynamicType::FFFFF, muse::mpe::dynamicLevelFromType(muse::mpe::DynamicType::fffff) },
48 : { DynamicType::FFFFFF, muse::mpe::dynamicLevelFromType(muse::mpe::DynamicType::ffffff) }
49 : };
50 :
51 : inline bool isOrdinaryDynamicType(const DynamicType type)
52 : {
53 : return ORDINARY_DYNAMIC_LEVELS.find(type) != ORDINARY_DYNAMIC_LEVELS.cend();
54 : }
55 :
56 : inline muse::mpe::dynamic_level_t dynamicLevelFromOrdinaryType(const DynamicType type,
57 : const muse::mpe::dynamic_level_t defLevel = NATURAL_DYNAMIC_LEVEL)
58 : {
59 : auto search = ORDINARY_DYNAMIC_LEVELS.find(type);
60 : if (search != ORDINARY_DYNAMIC_LEVELS.cend()) {
61 : return search->second;
62 : }
63 :
64 : return defLevel;
65 : }
66 :
67 : inline const std::unordered_map<DynamicType, muse::mpe::dynamic_level_t> SINGLE_NOTE_DYNAMIC_LEVELS {
68 : { DynamicType::SF, muse::mpe::dynamicLevelFromType(muse::mpe::DynamicType::f) },
69 : { DynamicType::SFZ, muse::mpe::dynamicLevelFromType(muse::mpe::DynamicType::f) },
70 : { DynamicType::SFF, muse::mpe::dynamicLevelFromType(muse::mpe::DynamicType::ff) },
71 : { DynamicType::SFFZ, muse::mpe::dynamicLevelFromType(muse::mpe::DynamicType::ff) },
72 : { DynamicType::SFFF, muse::mpe::dynamicLevelFromType(muse::mpe::DynamicType::fff) },
73 : { DynamicType::SFFFZ, muse::mpe::dynamicLevelFromType(muse::mpe::DynamicType::fff) },
74 : { DynamicType::RFZ, muse::mpe::dynamicLevelFromType(muse::mpe::DynamicType::f) },
75 : { DynamicType::RF, muse::mpe::dynamicLevelFromType(muse::mpe::DynamicType::f) }
76 : };
77 :
78 : inline bool isSingleNoteDynamicType(const DynamicType type)
79 : {
80 : return SINGLE_NOTE_DYNAMIC_LEVELS.find(type) != SINGLE_NOTE_DYNAMIC_LEVELS.cend();
81 : }
82 :
83 : inline muse::mpe::dynamic_level_t dynamicLevelFromSingleNoteType(const DynamicType type,
84 : const muse::mpe::dynamic_level_t defLevel = NATURAL_DYNAMIC_LEVEL)
85 : {
86 : auto search = SINGLE_NOTE_DYNAMIC_LEVELS.find(type);
87 : if (search != SINGLE_NOTE_DYNAMIC_LEVELS.cend()) {
88 : return search->second;
89 : }
90 :
91 : return defLevel;
92 : }
93 :
94 : struct CompoundDynamic {
95 : DynamicType from = DynamicType::OTHER;
96 : DynamicType to = DynamicType::OTHER;
97 :
98 : bool isValid() const
99 : {
100 : return from != DynamicType::OTHER && to != DynamicType::OTHER;
101 : }
102 : };
103 :
104 : inline const std::unordered_map<DynamicType, CompoundDynamic> COMPOUND_DYNAMICS {
105 : { DynamicType::FP, { DynamicType::F, DynamicType::P } },
106 : { DynamicType::PF, { DynamicType::P, DynamicType::F } },
107 : { DynamicType::SFP, { DynamicType::F, DynamicType::P } },
108 : { DynamicType::SFPP, { DynamicType::F, DynamicType::PP } }
109 : };
110 :
111 : inline bool isCompoundDynamicType(const DynamicType type)
112 : {
113 : return COMPOUND_DYNAMICS.find(type) != COMPOUND_DYNAMICS.cend();
114 : }
115 :
116 : inline const CompoundDynamic& compoundDynamicFromType(const DynamicType type)
117 : {
118 : auto search = COMPOUND_DYNAMICS.find(type);
119 : if (search != COMPOUND_DYNAMICS.cend()) {
120 : return search->second;
121 : }
122 :
123 : static CompoundDynamic empty;
124 : return empty;
125 : }
126 :
127 1544 : inline muse::mpe::ArticulationType articulationFromPlayTechType(const PlayingTechniqueType technique)
128 : {
129 1544 : switch (technique) {
130 1494 : case PlayingTechniqueType::Natural: return muse::mpe::ArticulationType::Standard;
131 5 : case PlayingTechniqueType::Pizzicato: return muse::mpe::ArticulationType::Pizzicato;
132 0 : case PlayingTechniqueType::Open: return muse::mpe::ArticulationType::Open;
133 0 : case PlayingTechniqueType::Mute: return muse::mpe::ArticulationType::Mute;
134 0 : case PlayingTechniqueType::Tremolo: return muse::mpe::ArticulationType::Tremolo64th;
135 4 : case PlayingTechniqueType::Detache: return muse::mpe::ArticulationType::Detache;
136 0 : case PlayingTechniqueType::Martele: return muse::mpe::ArticulationType::Martele;
137 0 : case PlayingTechniqueType::ColLegno: return muse::mpe::ArticulationType::ColLegno;
138 0 : case PlayingTechniqueType::SulPonticello: return muse::mpe::ArticulationType::SulPont;
139 0 : case PlayingTechniqueType::SulTasto: return muse::mpe::ArticulationType::SulTasto;
140 25 : case PlayingTechniqueType::Distortion: return muse::mpe::ArticulationType::Distortion;
141 0 : case PlayingTechniqueType::Overdrive: return muse::mpe::ArticulationType::Overdrive;
142 0 : case PlayingTechniqueType::Harmonics: return muse::mpe::ArticulationType::Harmonic;
143 0 : case PlayingTechniqueType::JazzTone: return muse::mpe::ArticulationType::JazzTone;
144 0 : case PlayingTechniqueType::Vibrato: return muse::mpe::ArticulationType::Vibrato;
145 0 : case PlayingTechniqueType::Legato: return muse::mpe::ArticulationType::Legato;
146 0 : case PlayingTechniqueType::HandbellsSwing: return muse::mpe::ArticulationType::Swing;
147 0 : case PlayingTechniqueType::HandbellsSwingUp: return muse::mpe::ArticulationType::Swing;
148 0 : case PlayingTechniqueType::HandbellsSwingDown: return muse::mpe::ArticulationType::Swing;
149 0 : case PlayingTechniqueType::HandbellsEcho1: return muse::mpe::ArticulationType::Echo;
150 0 : case PlayingTechniqueType::HandbellsEcho2: return muse::mpe::ArticulationType::Echo;
151 12 : case PlayingTechniqueType::HandbellsLV: return muse::mpe::ArticulationType::Pedal;
152 4 : case PlayingTechniqueType::HandbellsDamp: return muse::mpe::ArticulationType::Standard;
153 0 : case PlayingTechniqueType::HandbellsR: return muse::mpe::ArticulationType::Ring;
154 0 : case PlayingTechniqueType::Undefined: return muse::mpe::ArticulationType::Undefined;
155 : }
156 :
157 0 : return muse::mpe::ArticulationType::Undefined;
158 : }
159 :
160 : static const muse::mpe::ArticulationTypeSet GRACE_NOTE_ARTICULATION_TYPES {
161 : muse::mpe::ArticulationType::Acciaccatura,
162 : muse::mpe::ArticulationType::PostAppoggiatura,
163 : muse::mpe::ArticulationType::PreAppoggiatura,
164 : };
165 :
166 21 : inline bool isGraceNotePlacedBeforePrincipalNote(const muse::mpe::ArticulationType type)
167 : {
168 21 : return type == muse::mpe::ArticulationType::Acciaccatura || type == muse::mpe::ArticulationType::PreAppoggiatura;
169 : }
170 :
171 665 : inline void updateArticulationBoundaries(const muse::mpe::ArticulationType type, const muse::mpe::timestamp_t nominalTimestamp,
172 : const muse::mpe::duration_t nominalDuration,
173 : muse::mpe::ArticulationMap& articulations)
174 : {
175 665 : if (articulations.empty()) {
176 0 : return;
177 : }
178 :
179 665 : const muse::mpe::ArticulationAppliedData& articulationData = articulations.at(type);
180 :
181 665 : muse::mpe::timestamp_t articulationOccupiedFrom = nominalTimestamp - articulationData.meta.timestamp;
182 665 : muse::mpe::timestamp_t articulationOccupiedTo = nominalTimestamp + nominalDuration - articulationData.meta.timestamp;
183 :
184 665 : articulations.updateOccupiedRange(type,
185 : muse::mpe::occupiedPercentage(articulationOccupiedFrom,
186 665 : articulationData.meta.overallDuration),
187 : muse::mpe::occupiedPercentage(articulationOccupiedTo,
188 665 : articulationData.meta.overallDuration));
189 : }
190 : }
191 :
192 : #endif // MU_ENGRAVING_DYNAMICUTILS_H
|