LCOV - code coverage report
Current view: top level - muse/framework/audio/engine/internal/dsp - smoothlinearvalue.h Coverage Total Hit
Test: filtered_coverage.info Lines: 0.0 % 38 0
Test Date: 2026-11-05 04:07:02

            Line data    Source code
       1              : /*
       2              :  * SPDX-License-Identifier: GPL-3.0-only
       3              :  * MuseScore-CLA-applies
       4              :  *
       5              :  * MuseScore Studio
       6              :  * Music Composition & Notation
       7              :  *
       8              :  * Copyright (C) 2023 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 MUSE_AUDIO_SMOOTHLINEARVALUE_H
      24              : #define MUSE_AUDIO_SMOOTHLINEARVALUE_H
      25              : 
      26              : #include <algorithm>
      27              : #include <type_traits>
      28              : 
      29              : namespace muse::audio::dsp {
      30              : template<typename ValueT, int _initialSteps = 1024, typename StepT = double>
      31              : class SmoothLinearValue
      32              : {
      33              : public:
      34            0 :     SmoothLinearValue(const ValueT& startValue = ValueT(0))
      35              :     {
      36              :         static_assert(std::is_floating_point<StepT>::value, "Internal step type needs to be floating point.");
      37            0 :         m_targetValue = m_currentValue = startValue;
      38            0 :         m_currentSteps = (StepT)_initialSteps;
      39            0 :         m_targetSteps = 0;
      40            0 :         m_deltaValue = 0;
      41            0 :     }
      42              : 
      43            0 :     void setSteps(int steps)
      44              :     {
      45            0 :         m_currentSteps = (StepT)std::max(1, steps);
      46            0 :     }
      47              : 
      48              :     /** Advance one tick by just adding the delta. Can lead to error accumulation.
      49              :      * @return true if target was reached
      50              :      */
      51            0 :     bool tick()
      52              :     {
      53            0 :         if (m_targetSteps <= 0) {
      54            0 :             m_currentValue = m_targetValue; // get rid of error accumulation
      55            0 :             return true;
      56              :         }
      57              : 
      58            0 :         m_targetSteps--;
      59            0 :         m_currentValue += m_deltaValue;
      60            0 :         return false;
      61              :     }
      62              : 
      63              :     /** Advance one tick and use multiplication to avoid error accumulation
      64              :      * @return true if target was reached
      65              :      */
      66              :     bool preciseTick()
      67              :     {
      68              :         if (m_targetSteps <= 0) {
      69              :             return true;
      70              :         }
      71              : 
      72              :         m_targetSteps--;
      73              :         m_currentValue = m_targetValue - m_targetSteps * m_deltaValue; // if n reaches 0, _value will be exactly targetvalue
      74              :         return false;
      75              :     }
      76              : 
      77              :     /** Advance one tick without checking whether target was reached
      78              :      * can lead to error accumulation for large n and small delta
      79              :      * warning! will overshoot target if called too many times
      80              :      */
      81              :     void tickUnchecked()
      82              :     {
      83              :         m_targetSteps--;
      84              :         m_currentValue += m_deltaValue;
      85              :     }
      86              : 
      87              :     /** Advance one tick without checking whether target was reached
      88              :      * uses an extra multiplication to avoid error accumulation
      89              :      * warning! will overshoot target if called too many times
      90              :      */
      91              :     void preciseTickUnchecked()
      92              :     {
      93              :         m_targetSteps--;
      94              :         m_currentValue = m_targetValue - m_targetSteps * m_deltaValue;
      95              :     }
      96              : 
      97              :     /** Advance multiple ticks
      98              :      *  @param n num ticks to advance
      99              :      */
     100              :     void advanceTicks(int n)
     101              :     {
     102              :         m_targetSteps -= (double)n;
     103              :         if (m_targetSteps < 0) {
     104              :             m_targetSteps = 0;
     105              :         }
     106              :         m_currentValue = m_targetValue - m_targetSteps * m_deltaValue;
     107              :     }
     108              : 
     109              :     /// Set the value instantly (for initialization)
     110            0 :     void initWithValue(const ValueT& val)
     111              :     {
     112            0 :         m_targetValue = m_currentValue = val;
     113            0 :         m_targetSteps = 0;
     114            0 :     }
     115              : 
     116              :     /// Set value and target instantly
     117              :     void initWithValueAndTarget(const ValueT& val, const ValueT& target)
     118              :     {
     119              :         initWithValue(val);
     120              :         setTargetValue(target);
     121              :     }
     122              : 
     123              :     /** Sets the target value which is reached after "steps" calls to smoothTick */
     124            0 :     void setTargetValue(const ValueT& val)
     125              :     {
     126            0 :         if (m_targetValue != val) {
     127            0 :             m_targetValue = val;
     128            0 :             m_deltaValue = ValueT((1.0 / m_currentSteps) * (m_targetValue - m_currentValue));
     129            0 :             m_targetSteps = m_currentSteps;
     130              :         }
     131            0 :     }
     132              : 
     133              :     /** @returns the value the smoothed value will reach eventually */
     134            0 :     const ValueT& getTargetValue() const
     135              :     {
     136            0 :         return m_targetValue;
     137              :     }
     138              : 
     139              :     /** @return the current (smoothed) value */
     140            0 :     inline const ValueT& getValue() const
     141              :     {
     142            0 :         return m_currentValue;
     143              :     }
     144              : 
     145              :     /** Go to target immediately.
     146              :      * @returns value
     147              :      */
     148            0 :     inline const ValueT& setToTarget()
     149              :     {
     150            0 :         m_currentValue = m_targetValue;
     151            0 :         m_targetSteps = 0.f;
     152            0 :         return m_currentValue;
     153              :     }
     154              : 
     155              :     /// check if the smoothed value isn't moving and has a specific (target)value
     156            0 :     bool isStaticAtValue(const ValueT& static_value) const
     157              :     {
     158            0 :         return isAtTargetValue() && (getTargetValue() == static_value);
     159              :     }
     160              : 
     161            0 :     inline bool isAtTargetValue() const
     162              :     {
     163            0 :         return m_targetSteps <= (StepT)0;
     164              :     }
     165              : 
     166              :     int getRemainingSteps() const
     167              :     {
     168              :         return (int)m_targetSteps;
     169              :     }
     170              : 
     171              :     int smoothingSteps() const
     172              :     {
     173              :         return (int)m_currentSteps;
     174              :     }
     175              : 
     176              : protected:
     177              :     ValueT m_currentValue;
     178              :     ValueT m_targetValue;
     179              :     ValueT m_deltaValue;
     180              :     StepT m_targetSteps;
     181              :     StepT m_currentSteps;
     182              : };
     183              : } // namespace muse::audio::dsp
     184              : 
     185              : #endif // MUSE_AUDIO_SMOOTHLINEARVALUE_H
        

Generated by: LCOV version 2.0-1