LCOV - code coverage report
Current view: top level - src/engraving/playback/utils - expressionutils.h Coverage Total Hit
Test: filtered_coverage.info Lines: 46.2 % 39 18
Test Date: 2026-11-05 04:07:02

            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
        

Generated by: LCOV version 2.0-1