Use C++20 std::numbers, std::lerp() (#7696)
* use c++20 concepts and numbers for lmms_constants.h * replace lmms::numbers::sqrt2 with std::numbers::sqrt2 * replace lmms::numbers::e with std::numbers::e Also replace the only use of lmms::numbers::inv_e with a local constexpr instead * remove lmms::numbers::pi_half and lmms::numbers::pi_sqr They were only used in one or two places each * replace lmms::numbers::pi with std::numbers::pi * add #include <numbers> to every file touched so far This is probably not needed for some of these files. I'll remove those later * Remove lmms::numbers Rest in peace lmms::numbers::tau, my beloved * Add missing #include <numbers> * replace stray use of F_EPSILON with approximatelyEqual() * make many constants inline constexpr A lot of the remaining constants in lmms_constants.h are specific to SaProcessor. If they are only used there, shouldn't they be in SaProcessor.h? * ok then, it's allowed to be signed * remove #include "lmms_constants.h" for files that don't need it - And also move F_EPSILON into lmms_math.h - And also add an overload for fast_rand() to specify a higher and lower bound - And a bunch of other nonsense * ok then, it's allowed to be inferred * ok then, it can accept an integral * fix typo * appease msvc * appease msvc again * Replace linearInterpolate with std::lerp() As well as time travel to undo several foolish decisions and squash tiny commits together * Fix msvc constexpr warnings * Fix msvc float to double truncation warning * Apply two suggestions from code review Co-authored-by: Dalton Messmer <messmer.dalton@gmail.com> * Apply suggestions from code review Co-authored-by: Dalton Messmer <messmer.dalton@gmail.com> * fix silly mistake * Remove SlicerT's dependence on lmms_math.h * Allow more type inference on fastRand() and fastPow10f() * Apply suggestions from code review Co-authored-by: Dalton Messmer <messmer.dalton@gmail.com> * Clean up fastRand() a little bit more --------- Co-authored-by: Dalton Messmer <messmer.dalton@gmail.com>
This commit is contained in:
@@ -156,11 +156,11 @@ public:
|
||||
t += 1;
|
||||
const sample_t s3 = s_waveforms[ static_cast<std::size_t>(_wave) ].sampleAt( t, lookup );
|
||||
const sample_t s4 = s_waveforms[ static_cast<std::size_t>(_wave) ].sampleAt( t, ( lookup + 1 ) % tlen );
|
||||
const sample_t s34 = linearInterpolate( s3, s4, ip );
|
||||
const sample_t s34 = std::lerp(s3, s4, ip);
|
||||
|
||||
const float ip2 = ( ( tlen - _wavelen ) / tlen - 0.5 ) * 2.0;
|
||||
|
||||
return linearInterpolate( s12, s34, ip2 );
|
||||
return std::lerp(s12, s34, ip2);
|
||||
*/
|
||||
};
|
||||
|
||||
|
||||
@@ -31,12 +31,12 @@
|
||||
#ifndef LMMS_BASIC_FILTERS_H
|
||||
#define LMMS_BASIC_FILTERS_H
|
||||
|
||||
#include <cmath>
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <cmath>
|
||||
#include <numbers>
|
||||
|
||||
#include "lmms_basics.h"
|
||||
#include "lmms_constants.h"
|
||||
#include "interpolation.h"
|
||||
|
||||
namespace lmms
|
||||
{
|
||||
@@ -69,21 +69,22 @@ public:
|
||||
|
||||
inline void setCoeffs( float freq )
|
||||
{
|
||||
using namespace std::numbers;
|
||||
// wc
|
||||
const double wc = numbers::tau * freq;
|
||||
const double wc = 2 * pi * freq;
|
||||
const double wc2 = wc * wc;
|
||||
const double wc3 = wc2 * wc;
|
||||
m_wc4 = wc2 * wc2;
|
||||
|
||||
// k
|
||||
const double k = wc / std::tan(numbers::pi * freq / m_sampleRate);
|
||||
const double k = wc / std::tan(pi * freq / m_sampleRate);
|
||||
const double k2 = k * k;
|
||||
const double k3 = k2 * k;
|
||||
m_k4 = k2 * k2;
|
||||
|
||||
// a
|
||||
const double sq_tmp1 = numbers::sqrt2 * wc3 * k;
|
||||
const double sq_tmp2 = numbers::sqrt2 * wc * k3;
|
||||
const double sq_tmp1 = sqrt2 * wc3 * k;
|
||||
const double sq_tmp2 = sqrt2 * wc * k3;
|
||||
|
||||
m_a = 1.0 / ( 4.0 * wc2 * k2 + 2.0 * sq_tmp1 + m_k4 + 2.0 * sq_tmp2 + m_wc4 );
|
||||
|
||||
@@ -206,7 +207,7 @@ public:
|
||||
|
||||
inline float update( float s, ch_cnt_t ch )
|
||||
{
|
||||
if (std::abs(s) < 1.0e-10f && std::abs(m_z1[ch]) < 1.0e-10f) return 0.0f;
|
||||
if (std::abs(s) < 1.0e-10f && std::abs(m_z1[ch]) < 1.0e-10f) { return 0.0f; }
|
||||
return m_z1[ch] = s * m_a0 + m_z1[ch] * m_b1;
|
||||
}
|
||||
|
||||
@@ -375,7 +376,7 @@ public:
|
||||
for( int i = 0; i < 4; ++i )
|
||||
{
|
||||
ip += 0.25f;
|
||||
sample_t x = linearInterpolate( m_last[_chnl], _in0, ip ) - m_r * m_y3[_chnl];
|
||||
sample_t x = std::lerp(m_last[_chnl], _in0, ip) - m_r * m_y3[_chnl];
|
||||
|
||||
m_y1[_chnl] = std::clamp((x + m_oldx[_chnl]) * m_p
|
||||
- m_k * m_y1[_chnl], -10.0f,
|
||||
@@ -701,6 +702,7 @@ public:
|
||||
|
||||
inline void calcFilterCoeffs( float _freq, float _q )
|
||||
{
|
||||
using namespace std::numbers;
|
||||
// temp coef vars
|
||||
_q = std::max(_q, minQ());
|
||||
|
||||
@@ -713,7 +715,7 @@ public:
|
||||
{
|
||||
_freq = std::clamp(_freq, 50.0f, 20000.0f);
|
||||
const float sr = m_sampleRatio * 0.25f;
|
||||
const float f = 1.0f / (_freq * numbers::tau_v<float>);
|
||||
const float f = 1.0f / (_freq * 2 * pi_v<float>);
|
||||
|
||||
m_rca = 1.0f - sr / ( f + sr );
|
||||
m_rcb = 1.0f - m_rca;
|
||||
@@ -746,8 +748,8 @@ public:
|
||||
const float fract = vowelf - vowel;
|
||||
|
||||
// interpolate between formant frequencies
|
||||
const float f0 = 1.0f / (linearInterpolate(_f[vowel+0][0], _f[vowel+1][0], fract) * numbers::tau_v<float>);
|
||||
const float f1 = 1.0f / (linearInterpolate(_f[vowel+0][1], _f[vowel+1][1], fract) * numbers::tau_v<float>);
|
||||
const float f0 = 1.f / (std::lerp(_f[vowel+0][0], _f[vowel+1][0], fract) * 2 * pi_v<float>);
|
||||
const float f1 = 1.f / (std::lerp(_f[vowel+0][1], _f[vowel+1][1], fract) * 2 * pi_v<float>);
|
||||
|
||||
// samplerate coeff: depends on oversampling
|
||||
const float sr = m_type == FilterType::FastFormant ? m_sampleRatio : m_sampleRatio * 0.25f;
|
||||
@@ -796,7 +798,7 @@ public:
|
||||
m_type == FilterType::Highpass_SV ||
|
||||
m_type == FilterType::Notch_SV )
|
||||
{
|
||||
const float f = std::sin(std::max(minFreq(), _freq) * m_sampleRatio * numbers::pi_v<float>);
|
||||
const float f = std::sin(std::max(minFreq(), _freq) * m_sampleRatio * pi_v<float>);
|
||||
m_svf1 = std::min(f, 0.825f);
|
||||
m_svf2 = std::min(f * 2.0f, 0.825f);
|
||||
m_svq = std::max(0.0001f, 2.0f - (_q * 0.1995f));
|
||||
@@ -805,7 +807,7 @@ public:
|
||||
|
||||
// other filters
|
||||
_freq = std::clamp(_freq, minFreq(), 20000.0f);
|
||||
const float omega = numbers::tau_v<float> * _freq * m_sampleRatio;
|
||||
const float omega = 2 * pi_v<float> * _freq * m_sampleRatio;
|
||||
const float tsin = std::sin(omega) * 0.5f;
|
||||
const float tcos = std::cos(omega);
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#ifndef LMMS_GUI_COLOR_HELPER_H
|
||||
#define LMMS_GUI_COLOR_HELPER_H
|
||||
|
||||
#include <cmath>
|
||||
#include <QColor>
|
||||
|
||||
namespace lmms::gui
|
||||
@@ -40,10 +41,11 @@ public:
|
||||
qreal br, bg, bb, ba;
|
||||
b.getRgbF(&br, &bg, &bb, &ba);
|
||||
|
||||
const float interH = lerp(ar, br, t);
|
||||
const float interS = lerp(ag, bg, t);
|
||||
const float interV = lerp(ab, bb, t);
|
||||
const float interA = lerp(aa, ba, t);
|
||||
const auto t2 = static_cast<qreal>(t);
|
||||
const float interH = std::lerp(ar, br, t2);
|
||||
const float interS = std::lerp(ag, bg, t2);
|
||||
const float interV = std::lerp(ab, bb, t2);
|
||||
const float interA = std::lerp(aa, ba, t2);
|
||||
|
||||
return QColor::fromRgbF(interH, interS, interV, interA);
|
||||
}
|
||||
|
||||
@@ -26,9 +26,9 @@
|
||||
#ifndef LMMS_DELAY_H
|
||||
#define LMMS_DELAY_H
|
||||
|
||||
#include <cmath>
|
||||
|
||||
#include "lmms_basics.h"
|
||||
#include "lmms_math.h"
|
||||
#include "interpolation.h"
|
||||
|
||||
namespace lmms
|
||||
{
|
||||
@@ -114,7 +114,7 @@ public:
|
||||
int readPos = m_position - m_delay;
|
||||
if( readPos < 0 ) { readPos += m_size; }
|
||||
|
||||
const double y = linearInterpolate( m_buffer[readPos][ch], m_buffer[( readPos + 1 ) % m_size][ch], m_fraction );
|
||||
const double y = std::lerp(m_buffer[readPos][ch], m_buffer[(readPos + 1) % m_size][ch], m_fraction);
|
||||
|
||||
++m_position %= m_size;
|
||||
|
||||
@@ -185,7 +185,7 @@ class CombFeedfwd
|
||||
int readPos = m_position - m_delay;
|
||||
if( readPos < 0 ) { readPos += m_size; }
|
||||
|
||||
const double y = linearInterpolate( m_buffer[readPos][ch], m_buffer[( readPos + 1 ) % m_size][ch], m_fraction ) + in * m_gain;
|
||||
const double y = std::lerp(m_buffer[readPos][ch], m_buffer[(readPos + 1) % m_size][ch], m_fraction) + in * m_gain;
|
||||
|
||||
++m_position %= m_size;
|
||||
|
||||
@@ -262,8 +262,8 @@ class CombFeedbackDualtap
|
||||
int readPos2 = m_position - m_delay2;
|
||||
if( readPos2 < 0 ) { readPos2 += m_size; }
|
||||
|
||||
const double y = linearInterpolate( m_buffer[readPos1][ch], m_buffer[( readPos1 + 1 ) % m_size][ch], m_fraction1 ) +
|
||||
linearInterpolate( m_buffer[readPos2][ch], m_buffer[( readPos2 + 1 ) % m_size][ch], m_fraction2 );
|
||||
const double y = std::lerp(m_buffer[readPos1][ch], m_buffer[(readPos1 + 1) % m_size][ch], m_fraction1)
|
||||
+ std::lerp(m_buffer[readPos2][ch], m_buffer[(readPos2 + 1) % m_size][ch], m_fraction2);
|
||||
|
||||
++m_position %= m_size;
|
||||
|
||||
@@ -337,7 +337,7 @@ public:
|
||||
int readPos = m_position - m_delay;
|
||||
if( readPos < 0 ) { readPos += m_size; }
|
||||
|
||||
const double y = linearInterpolate( m_buffer[readPos][ch], m_buffer[( readPos + 1 ) % m_size][ch], m_fraction ) + in * -m_gain;
|
||||
const double y = std::lerp(m_buffer[readPos][ch], m_buffer[(readPos + 1) % m_size][ch], m_fraction) + in * -m_gain;
|
||||
const double x = in + m_gain * y;
|
||||
|
||||
++m_position %= m_size;
|
||||
|
||||
@@ -25,8 +25,9 @@
|
||||
#ifndef LMMS_DSPEFFECTLIBRARY_H
|
||||
#define LMMS_DSPEFFECTLIBRARY_H
|
||||
|
||||
#include <numbers>
|
||||
|
||||
#include "lmms_math.h"
|
||||
#include "lmms_constants.h"
|
||||
#include "lmms_basics.h"
|
||||
#include "SampleFrame.h"
|
||||
|
||||
@@ -328,7 +329,7 @@ namespace lmms::DspEffectLibrary
|
||||
|
||||
void nextSample( sample_t& inLeft, sample_t& inRight )
|
||||
{
|
||||
const float toRad = numbers::pi_v<float> / 180;
|
||||
constexpr float toRad = std::numbers::pi_v<float> / 180.f;
|
||||
const sample_t tmp = inLeft;
|
||||
inLeft += inRight * std::sin(m_wideCoeff * toRad * .5f);
|
||||
inRight -= tmp * std::sin(m_wideCoeff * toRad * .5f);
|
||||
|
||||
@@ -30,10 +30,10 @@
|
||||
#include <fftw3.h>
|
||||
#include <memory>
|
||||
#include <cstdlib>
|
||||
#include "interpolation.h"
|
||||
#include <cmath>
|
||||
|
||||
#include "Engine.h"
|
||||
#include "lmms_constants.h"
|
||||
#include "lmms_math.h"
|
||||
#include "lmmsconfig.h"
|
||||
#include "AudioEngine.h"
|
||||
#include "OscillatorConstants.h"
|
||||
@@ -114,7 +114,7 @@ public:
|
||||
// now follow the wave-shape-routines...
|
||||
static inline sample_t sinSample( const float _sample )
|
||||
{
|
||||
return std::sin(_sample * numbers::tau_v<float>);
|
||||
return std::sin(_sample * 2 * std::numbers::pi_v<float>);
|
||||
}
|
||||
|
||||
static inline sample_t triangleSample( const float _sample )
|
||||
@@ -173,7 +173,7 @@ public:
|
||||
const auto frame = absFraction(sample) * frames;
|
||||
const auto f1 = static_cast<f_cnt_t>(frame);
|
||||
|
||||
return linearInterpolate(buffer->data()[f1][0], buffer->data()[(f1 + 1) % frames][0], fraction(frame));
|
||||
return std::lerp(buffer->data()[f1][0], buffer->data()[(f1 + 1) % frames][0], fraction(frame));
|
||||
}
|
||||
|
||||
struct wtSampleControl {
|
||||
@@ -202,24 +202,25 @@ public:
|
||||
{
|
||||
assert(table != nullptr);
|
||||
wtSampleControl control = getWtSampleControl(sample);
|
||||
return linearInterpolate(table[control.band][control.f1],
|
||||
table[control.band][control.f2], fraction(control.frame));
|
||||
return std::lerp(table[control.band][control.f1], table[control.band][control.f2], fraction(control.frame));
|
||||
}
|
||||
|
||||
sample_t wtSample(const OscillatorConstants::waveform_t* table, const float sample) const
|
||||
{
|
||||
assert(table != nullptr);
|
||||
wtSampleControl control = getWtSampleControl(sample);
|
||||
return linearInterpolate((*table)[control.band][control.f1],
|
||||
(*table)[control.band][control.f2], fraction(control.frame));
|
||||
return std::lerp(
|
||||
(*table)[control.band][control.f1],
|
||||
(*table)[control.band][control.f2],
|
||||
fraction(control.frame)
|
||||
);
|
||||
}
|
||||
|
||||
inline sample_t wtSample(sample_t **table, const float sample) const
|
||||
{
|
||||
assert(table != nullptr);
|
||||
wtSampleControl control = getWtSampleControl(sample);
|
||||
return linearInterpolate(table[control.band][control.f1],
|
||||
table[control.band][control.f2], fraction(control.frame));
|
||||
return std::lerp(table[control.band][control.f1], table[control.band][control.f2], fraction(control.frame));
|
||||
}
|
||||
|
||||
static inline int waveTableBandFromFreq(float freq)
|
||||
|
||||
@@ -25,7 +25,8 @@
|
||||
#ifndef LMMS_QUADRATURE_LFO_H
|
||||
#define LMMS_QUADRATURE_LFO_H
|
||||
|
||||
#include "lmms_math.h"
|
||||
#include <numbers>
|
||||
#include <cmath>
|
||||
|
||||
namespace lmms
|
||||
{
|
||||
@@ -37,7 +38,7 @@ public:
|
||||
QuadratureLfo( int sampleRate ) :
|
||||
m_frequency(0),
|
||||
m_phase(0),
|
||||
m_offset(numbers::pi_half)
|
||||
m_offset(std::numbers::pi * 0.5)
|
||||
{
|
||||
setSampleRate(sampleRate);
|
||||
}
|
||||
@@ -64,7 +65,7 @@ public:
|
||||
inline void setSampleRate ( int samplerate )
|
||||
{
|
||||
m_samplerate = samplerate;
|
||||
m_twoPiOverSr = numbers::tau_v<float> / samplerate;
|
||||
m_twoPiOverSr = 2 * std::numbers::pi_v<float> / samplerate;
|
||||
m_increment = m_frequency * m_twoPiOverSr;
|
||||
}
|
||||
|
||||
@@ -80,7 +81,7 @@ public:
|
||||
*l = std::sin(m_phase);
|
||||
*r = std::sin(m_phase + m_offset);
|
||||
m_phase += m_increment;
|
||||
while (m_phase >= numbers::tau) { m_phase -= numbers::tau; }
|
||||
m_phase = std::fmod(m_phase, 2 * std::numbers::pi);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
@@ -26,8 +26,7 @@
|
||||
#define LMMS_INTERPOLATION_H
|
||||
|
||||
#include <cmath>
|
||||
#include "lmms_constants.h"
|
||||
#include "lmms_math.h"
|
||||
#include <numbers>
|
||||
|
||||
namespace lmms
|
||||
{
|
||||
@@ -78,17 +77,11 @@ inline float cubicInterpolate( float v0, float v1, float v2, float v3, float x )
|
||||
|
||||
inline float cosinusInterpolate( float v0, float v1, float x )
|
||||
{
|
||||
const float f = (1.0f - std::cos(x * numbers::pi_v<float>)) * 0.5f;
|
||||
const float f = (1.0f - std::cos(x * std::numbers::pi_v<float>)) * 0.5f;
|
||||
return f * (v1 - v0) + v0;
|
||||
}
|
||||
|
||||
|
||||
inline float linearInterpolate( float v0, float v1, float x )
|
||||
{
|
||||
return x * (v1 - v0) + v0;
|
||||
}
|
||||
|
||||
|
||||
inline float optimalInterpolate( float v0, float v1, float x )
|
||||
{
|
||||
const float z = x - 0.5f;
|
||||
|
||||
@@ -25,65 +25,20 @@
|
||||
#ifndef LMMS_CONSTANTS_H
|
||||
#define LMMS_CONSTANTS_H
|
||||
|
||||
// #include <numbers>
|
||||
// #include <concepts>
|
||||
|
||||
namespace lmms::numbers
|
||||
{
|
||||
|
||||
//TODO C++20: Use std::floating_point instead of typename
|
||||
//TODO C++20: Use std::numbers::pi_v<T> instead of literal value
|
||||
template<typename T>
|
||||
inline constexpr T pi_v = T(3.14159265358979323846264338327950288419716939937510);
|
||||
inline constexpr double pi = pi_v<double>;
|
||||
|
||||
//TODO C++20: Use std::floating_point instead of typename
|
||||
template<typename T>
|
||||
inline constexpr T tau_v = T(pi_v<T> * 2.0);
|
||||
inline constexpr double tau = tau_v<double>;
|
||||
|
||||
//TODO C++20: Use std::floating_point instead of typename
|
||||
template<typename T>
|
||||
inline constexpr T pi_half_v = T(pi_v<T> / 2.0);
|
||||
inline constexpr double pi_half = pi_half_v<double>;
|
||||
|
||||
//TODO C++20: Use std::floating_point instead of typename
|
||||
template<typename T>
|
||||
inline constexpr T pi_sqr_v = T(pi_v<T> * pi_v<T>);
|
||||
inline constexpr double pi_sqr = pi_sqr_v<double>;
|
||||
|
||||
//TODO C++20: Use std::floating_point instead of typename
|
||||
//TODO C++20: Use std::numbers::e_v<T> instead of literal value
|
||||
template<typename T>
|
||||
inline constexpr T e_v = T(2.71828182845904523536028747135266249775724709369995);
|
||||
inline constexpr double e = e_v<double>;
|
||||
|
||||
//TODO C++20: Use std::floating_point instead of typename
|
||||
template<typename T>
|
||||
inline constexpr T inv_e_v = T(1.0 / e_v<T>);
|
||||
inline constexpr double inv_e = e_v<double>;
|
||||
|
||||
//TODO C++20: Use std::floating_point instead of typename
|
||||
//TODO C++20: Use std::numbers::sqrt2_v<T> instead of literal value
|
||||
//TODO C++26: Remove since std::sqrt(2.0) is constexpr
|
||||
template<typename T>
|
||||
inline constexpr T sqrt2_v = T(1.41421356237309504880168872420969807856967187537695);
|
||||
inline constexpr double sqrt2 = sqrt2_v<double>;
|
||||
|
||||
}
|
||||
|
||||
namespace lmms
|
||||
{
|
||||
|
||||
constexpr float F_EPSILON = 1.0e-10f; // 10^-10
|
||||
// Prefer using `approximatelyEqual()` from lmms_math.h rather than
|
||||
// using this directly
|
||||
inline constexpr float F_EPSILON = 1.0e-10f; // 10^-10
|
||||
|
||||
// Microtuner
|
||||
constexpr unsigned int MaxScaleCount = 10; //!< number of scales per project
|
||||
constexpr unsigned int MaxKeymapCount = 10; //!< number of keyboard mappings per project
|
||||
inline constexpr unsigned MaxScaleCount = 10; //!< number of scales per project
|
||||
inline constexpr unsigned MaxKeymapCount = 10; //!< number of keyboard mappings per project
|
||||
|
||||
// Frequency ranges (in Hz).
|
||||
// Arbitrary low limit for logarithmic frequency scale; >1 Hz.
|
||||
constexpr int LOWEST_LOG_FREQ = 5;
|
||||
inline constexpr auto LOWEST_LOG_FREQ = 5;
|
||||
|
||||
// Full range is defined by LOWEST_LOG_FREQ and current sample rate.
|
||||
enum class FrequencyRange
|
||||
@@ -95,14 +50,14 @@ enum class FrequencyRange
|
||||
High
|
||||
};
|
||||
|
||||
constexpr int FRANGE_AUDIBLE_START = 20;
|
||||
constexpr int FRANGE_AUDIBLE_END = 20000;
|
||||
constexpr int FRANGE_BASS_START = 20;
|
||||
constexpr int FRANGE_BASS_END = 300;
|
||||
constexpr int FRANGE_MIDS_START = 200;
|
||||
constexpr int FRANGE_MIDS_END = 5000;
|
||||
constexpr int FRANGE_HIGH_START = 4000;
|
||||
constexpr int FRANGE_HIGH_END = 20000;
|
||||
inline constexpr auto FRANGE_AUDIBLE_START = 20;
|
||||
inline constexpr auto FRANGE_AUDIBLE_END = 20000;
|
||||
inline constexpr auto FRANGE_BASS_START = 20;
|
||||
inline constexpr auto FRANGE_BASS_END = 300;
|
||||
inline constexpr auto FRANGE_MIDS_START = 200;
|
||||
inline constexpr auto FRANGE_MIDS_END = 5000;
|
||||
inline constexpr auto FRANGE_HIGH_START = 4000;
|
||||
inline constexpr auto FRANGE_HIGH_END = 20000;
|
||||
|
||||
// Amplitude ranges (in dBFS).
|
||||
// Reference: full scale sine wave (-1.0 to 1.0) is 0 dB.
|
||||
@@ -115,15 +70,14 @@ enum class AmplitudeRange
|
||||
Silent
|
||||
};
|
||||
|
||||
constexpr int ARANGE_EXTENDED_START = -80;
|
||||
constexpr int ARANGE_EXTENDED_END = 20;
|
||||
constexpr int ARANGE_AUDIBLE_START = -50;
|
||||
constexpr int ARANGE_AUDIBLE_END = 0;
|
||||
constexpr int ARANGE_LOUD_START = -30;
|
||||
constexpr int ARANGE_LOUD_END = 0;
|
||||
constexpr int ARANGE_SILENT_START = -60;
|
||||
constexpr int ARANGE_SILENT_END = -10;
|
||||
|
||||
inline constexpr auto ARANGE_EXTENDED_START = -80;
|
||||
inline constexpr auto ARANGE_EXTENDED_END = 20;
|
||||
inline constexpr auto ARANGE_AUDIBLE_START = -50;
|
||||
inline constexpr auto ARANGE_AUDIBLE_END = 0;
|
||||
inline constexpr auto ARANGE_LOUD_START = -30;
|
||||
inline constexpr auto ARANGE_LOUD_END = 0;
|
||||
inline constexpr auto ARANGE_SILENT_START = -60;
|
||||
inline constexpr auto ARANGE_SILENT_END = -10;
|
||||
|
||||
} // namespace lmms
|
||||
|
||||
|
||||
@@ -31,18 +31,22 @@
|
||||
#include <cmath>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <numbers>
|
||||
#include <concepts>
|
||||
|
||||
#include "lmms_constants.h"
|
||||
#include "lmmsconfig.h"
|
||||
#include "lmms_constants.h"
|
||||
|
||||
namespace lmms
|
||||
{
|
||||
|
||||
inline bool approximatelyEqual(float x, float y)
|
||||
// TODO C++23: Make constexpr since std::abs() will be constexpr
|
||||
inline bool approximatelyEqual(float x, float y) noexcept
|
||||
{
|
||||
return x == y ? true : std::abs(x - y) < F_EPSILON;
|
||||
return x == y || std::abs(x - y) < F_EPSILON;
|
||||
}
|
||||
|
||||
// TODO C++23: Make constexpr since std::trunc() will be constexpr
|
||||
/*!
|
||||
* @brief Returns the fractional part of a float, a value between -1.0f and 1.0f.
|
||||
*
|
||||
@@ -52,11 +56,13 @@ inline bool approximatelyEqual(float x, float y)
|
||||
* Note that if the return value is used as a phase of an oscillator, that the oscillator must support
|
||||
* negative phases.
|
||||
*/
|
||||
inline float fraction(const float x)
|
||||
inline auto fraction(std::floating_point auto x) noexcept
|
||||
{
|
||||
return x - std::trunc(x);
|
||||
}
|
||||
|
||||
|
||||
// TODO C++23: Make constexpr since std::floor() will be constexpr
|
||||
/*!
|
||||
* @brief Returns the wrapped fractional part of a float, a value between 0.0f and 1.0f.
|
||||
*
|
||||
@@ -67,25 +73,30 @@ inline float fraction(const float x)
|
||||
* If the result is interpreted as a phase of an oscillator, it makes that negative phases are
|
||||
* converted to positive phases.
|
||||
*/
|
||||
inline float absFraction(const float x)
|
||||
inline auto absFraction(std::floating_point auto x) noexcept
|
||||
{
|
||||
return x - std::floor(x);
|
||||
}
|
||||
|
||||
|
||||
constexpr float FAST_RAND_RATIO = 1.0f / 32767;
|
||||
inline int fast_rand()
|
||||
inline auto fastRand() noexcept
|
||||
{
|
||||
static unsigned long next = 1;
|
||||
next = next * 1103515245 + 12345;
|
||||
return( (unsigned)( next / 65536 ) % 32768 );
|
||||
return next / 65536 % 32768;
|
||||
}
|
||||
|
||||
inline float fastRandf(float range)
|
||||
template<std::floating_point T>
|
||||
inline auto fastRand(T range) noexcept
|
||||
{
|
||||
return fast_rand() * range * FAST_RAND_RATIO;
|
||||
constexpr T FAST_RAND_RATIO = static_cast<T>(1.0 / 32767);
|
||||
return fastRand() * range * FAST_RAND_RATIO;
|
||||
}
|
||||
|
||||
template<std::floating_point T>
|
||||
inline auto fastRand(T from, T to) noexcept
|
||||
{
|
||||
return from + fastRand(to - from);
|
||||
}
|
||||
|
||||
//! Round `value` to `where` depending on step size
|
||||
template<class T>
|
||||
@@ -112,10 +123,11 @@ inline double fastPow(double a, double b)
|
||||
}
|
||||
|
||||
|
||||
//! returns 1.0f if val >= 0.0f, -1.0 else
|
||||
inline float sign(float val)
|
||||
//! returns +1 if val >= 0, else -1
|
||||
template<typename T>
|
||||
constexpr T sign(T val) noexcept
|
||||
{
|
||||
return val >= 0.0f ? 1.0f : -1.0f;
|
||||
return val >= 0 ? 1 : -1;
|
||||
}
|
||||
|
||||
|
||||
@@ -136,14 +148,15 @@ inline float signedPowf(float v, float e)
|
||||
//! Value should be within [0,1]
|
||||
inline float logToLinearScale(float min, float max, float value)
|
||||
{
|
||||
using namespace std::numbers;
|
||||
if (min < 0)
|
||||
{
|
||||
const float mmax = std::max(std::abs(min), std::abs(max));
|
||||
const float val = value * (max - min) + min;
|
||||
float result = signedPowf(val / mmax, numbers::e_v<float>) * mmax;
|
||||
float result = signedPowf(val / mmax, e_v<float>) * mmax;
|
||||
return std::isnan(result) ? 0 : result;
|
||||
}
|
||||
float result = std::pow(value, numbers::e_v<float>) * (max - min) + min;
|
||||
float result = std::pow(value, e_v<float>) * (max - min) + min;
|
||||
return std::isnan(result) ? 0 : result;
|
||||
}
|
||||
|
||||
@@ -151,26 +164,37 @@ inline float logToLinearScale(float min, float max, float value)
|
||||
//! @brief Scales value from logarithmic to linear. Value should be in min-max range.
|
||||
inline float linearToLogScale(float min, float max, float value)
|
||||
{
|
||||
constexpr auto inv_e = static_cast<float>(1.0 / std::numbers::e);
|
||||
const float valueLimited = std::clamp(value, min, max);
|
||||
const float val = (valueLimited - min) / (max - min);
|
||||
if (min < 0)
|
||||
{
|
||||
const float mmax = std::max(std::abs(min), std::abs(max));
|
||||
float result = signedPowf(valueLimited / mmax, numbers::inv_e_v<float>) * mmax;
|
||||
float result = signedPowf(valueLimited / mmax, inv_e) * mmax;
|
||||
return std::isnan(result) ? 0 : result;
|
||||
}
|
||||
float result = std::pow(val, numbers::inv_e_v<float>) * (max - min) + min;
|
||||
float result = std::pow(val, inv_e) * (max - min) + min;
|
||||
return std::isnan(result) ? 0 : result;
|
||||
}
|
||||
|
||||
inline float fastPow10f(float x)
|
||||
// TODO C++26: Make constexpr since std::exp() will be constexpr
|
||||
template<std::floating_point T>
|
||||
inline auto fastPow10f(T x)
|
||||
{
|
||||
return std::exp(2.302585092994046f * x);
|
||||
return std::exp(std::numbers::ln10_v<T> * x);
|
||||
}
|
||||
|
||||
inline float fastLog10f(float x)
|
||||
// TODO C++26: Make constexpr since std::exp() will be constexpr
|
||||
inline auto fastPow10f(std::integral auto x)
|
||||
{
|
||||
return std::log(x) * 0.4342944819032518f;
|
||||
return std::exp(std::numbers::ln10_v<float> * x);
|
||||
}
|
||||
|
||||
// TODO C++26: Make constexpr since std::log() will be constexpr
|
||||
inline auto fastLog10f(float x)
|
||||
{
|
||||
constexpr auto inv_ln10 = static_cast<float>(1.0 / std::numbers::ln10);
|
||||
return std::log(x) * inv_ln10;
|
||||
}
|
||||
|
||||
//! @brief Converts linear amplitude (>0-1.0) to dBFS scale.
|
||||
@@ -209,16 +233,8 @@ inline float safeDbfsToAmp(float dbfs)
|
||||
}
|
||||
|
||||
|
||||
|
||||
//! Returns the linear interpolation of the two values
|
||||
template<class T, class F>
|
||||
constexpr T lerp(T a, T b, F t)
|
||||
{
|
||||
return (1. - t) * a + t * b;
|
||||
}
|
||||
|
||||
// TODO C++20: use std::formatted_size
|
||||
// @brief Calculate number of digits which LcdSpinBox would show for a given number
|
||||
// @note Once we upgrade to C++20, we could probably use std::formatted_size
|
||||
inline int numDigitsAsInt(float f)
|
||||
{
|
||||
// use rounding:
|
||||
|
||||
Reference in New Issue
Block a user