LCOV - code coverage report
Current view: top level - src/importexport/guitarpro/internal/guitarbendimport - diveinfoconverter.cpp Coverage Total Hit
Test: filtered_coverage.info Lines: 90.5 % 74 67
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) 2026 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              : #include "diveinfoconverter.h"
      23              : 
      24              : #include <engraving/dom/note.h>
      25              : 
      26              : #include <cmath>
      27              : 
      28              : using namespace mu::engraving;
      29              : 
      30              : namespace mu::iex::guitarpro {
      31           92 : static std::vector<SegmentData> classifyDiveSegments(const PitchValues& pitchValues)
      32              : {
      33              :     enum class Dir {
      34              :         NONE, UP, DOWN
      35              :     };
      36              : 
      37           92 :     std::vector<SegmentData> segments;
      38           92 :     Dir prevDir = Dir::NONE;
      39           92 :     size_t segStartIdx = 0;
      40              : 
      41          276 :     for (size_t i = 0; i + 1 < pitchValues.size(); ++i) {
      42          184 :         const int dp = pitchValues[i + 1].pitch - pitchValues[i].pitch;
      43          184 :         if (dp == 0) {
      44           84 :             continue;
      45              :         }
      46              : 
      47          159 :         const int qt = gpPitchToQuarterTones(dp);
      48          159 :         if (qt == 0) {
      49            0 :             continue;
      50              :         }
      51              : 
      52          159 :         Dir curDir = dp > 0 ? Dir::UP : Dir::DOWN;
      53              : 
      54          159 :         if (curDir == prevDir && !segments.empty()) {
      55           59 :             SegmentData& last = segments.back();
      56          118 :             last.quarterTones = gpPitchToQuarterTones(
      57           59 :                 pitchValues[i + 1].pitch - pitchValues[segStartIdx].pitch);
      58           59 :             last.endFactor = static_cast<double>(pitchValues[i + 1].time) / PitchValue::MAX_TIME;
      59           59 :             continue;
      60           59 :         }
      61              : 
      62          100 :         segStartIdx = i;
      63          100 :         SegmentData seg;
      64          100 :         seg.quarterTones = qt;
      65          100 :         seg.startFactor = static_cast<double>(pitchValues[i].time) / PitchValue::MAX_TIME;
      66          100 :         seg.endFactor = static_cast<double>(pitchValues[i + 1].time) / PitchValue::MAX_TIME;
      67          100 :         segments.push_back(std::move(seg));
      68              : 
      69          100 :         prevDir = curDir;
      70              :     }
      71              : 
      72           92 :     return segments;
      73            0 : }
      74              : 
      75          353 : int gpPitchToQuarterTones(int gpPitch)
      76              : {
      77          353 :     return static_cast<int>(std::lround(static_cast<float>(gpPitch) / GP_PITCH_PER_QUARTERTONE));
      78              : }
      79              : 
      80           92 : ImportedDiveInfo DiveInfoConverter::fromPitchValues(const PitchValues& pitchValues, bool isContinuedWhammy)
      81              : {
      82           92 :     ImportedDiveInfo info;
      83              : 
      84           92 :     if (pitchValues.size() < 2) {
      85            0 :         return info;
      86              :     }
      87              : 
      88           92 :     const int originPitch = pitchValues.front().pitch;
      89           92 :     const int destPitch = pitchValues.back().pitch;
      90           92 :     const int originQuarterTones = gpPitchToQuarterTones(originPitch);
      91              : 
      92           92 :     std::vector<SegmentData> chain = classifyDiveSegments(pitchValues);
      93              : 
      94           92 :     if (isContinuedWhammy && destPitch == originPitch) {
      95            1 :         return info;
      96           91 :     } else if (!isContinuedWhammy && originPitch != 0 && destPitch == originPitch) {
      97            8 :         info.type = DiveType::PRE_DIVE;
      98            8 :         info.quarterTones = -gpPitchToQuarterTones(originPitch);
      99            8 :         info.endFactor = 1.0;
     100            8 :         return info;
     101           83 :     } else if (!isContinuedWhammy && originPitch != 0) {
     102           34 :         info.type = DiveType::PRE_DIVE;
     103           34 :         info.quarterTones = -originQuarterTones;
     104           34 :         info.endFactor = 1.0;
     105           34 :         info.graceDiveSegments = std::move(chain);
     106           34 :         return info;
     107           49 :     } else if (chain.empty()) {
     108            0 :         return info;
     109              :     }
     110              : 
     111           49 :     info.type = DiveType::DIVE;
     112           49 :     info.graceDiveSegments = std::move(chain);
     113              : 
     114           49 :     if (info.graceDiveSegments.size() == 1) {
     115           35 :         SegmentData& only = info.graceDiveSegments.front();
     116           35 :         only.quarterTones = gpPitchToQuarterTones(destPitch - originPitch);
     117           35 :         only.startFactor = static_cast<double>(pitchValues.front().time) / PitchValue::MAX_TIME;
     118           35 :         only.endFactor = static_cast<double>(pitchValues.back().time) / PitchValue::MAX_TIME;
     119              :     }
     120              : 
     121           49 :     return info;
     122           92 : }
     123              : 
     124           92 : ImportedDiveInfo DiveInfoConverter::fillDiveInfo(const Note* note, const PitchValues& pitchValues, bool isContinuedWhammy)
     125              : {
     126           92 :     if (!note || pitchValues.size() < 2) {
     127            0 :         return {};
     128              :     }
     129              : 
     130           92 :     ImportedDiveInfo info = fromPitchValues(pitchValues, isContinuedWhammy);
     131              : 
     132           92 :     if (info.type == DiveType::NONE) {
     133            1 :         return info;
     134              :     }
     135              : 
     136           91 :     if (info.type == DiveType::DIVE && info.graceDiveSegments.empty()) {
     137            0 :         info.type = DiveType::NONE;
     138            0 :         return info;
     139              :     }
     140              : 
     141           91 :     info.note = note;
     142           91 :     return info;
     143           92 : }
     144              : } // namespace mu::iex::guitarpro
        

Generated by: LCOV version 2.0-1