Skip to content

Commit

Permalink
Update math functions to C++ standard library (#7685)
Browse files Browse the repository at this point in the history
* use c++ std::* math functions
This updates usages of sin, cos, tan, pow, exp, log, log10, sqrt, fmod, fabs, and fabsf,
excluding any usages that look like they might be part of a submodule or 3rd-party code.
There's probably some std math functions not listed here that haven't been updated yet.

* fix std::sqrt typo

lmao one always sneaks by

* Apply code review suggestions
- std::pow(2, x) -> std::exp2(x)
- std::pow(10, x) -> lmms::fastPow10f(x)
- std::pow(x, 2) -> x * x, std::pow(x, 3) -> x * x * x, etc.
- Resolve TODOs, fix typos, and so forth

Co-authored-by: Rossmaxx <[email protected]>

* Fix double -> float truncation, DrumSynth fix

I mistakenly introduced a bug in my recent PR regarding template
constants, in which a -1 that was supposed to appear outside of an abs()
instead was moved inside it, screwing up the generated waveform. I fixed
that and also simplified the function by factoring out the phase domain
wrapping using the new `ediv()` function from this PR. It should behave
how it's supposed to now... assuming all my parentheses are in the right
place lol

* Annotate magic numbers with TODOs for C++20

* On second thought, why wait?

What else is lmms::numbers for?

* begone inline

Co-authored-by: Rossmaxx <[email protected]>

* begone other inline

Co-authored-by: Rossmaxx <[email protected]>

* Re-inline function in lmms_math.h

For functions, constexpr implies inline so this just re-adds inline to
the one that isn't constexpr yet

* Formatting fixes, readability improvements

Co-authored-by: Dalton Messmer <[email protected]>

* Fix previously missed pow() calls, cleanup

Co-authored-by: Dalton Messmer <[email protected]>

* Just delete ediv() entirely lmao

No ediv(), no std::fmod(), no std::remainder(), just std::floor().
It should all work for negative phase inputs as well. If I end up
needing ediv() in the future, I can add it then.

* Simplify DrumSynth triangle waveform

This reuses more work and is also a lot more easy to visualize.

It's probably a meaningless micro-optimization, but it might be worth changing it back to a switch-case and just calculating ph_tau and saw01 at the beginning of the function in all code paths, even if it goes unused for the first two cases. Guess I'll see if anybody has strong opinions about it.

* Move multiplication inside abs()

* Clean up a few more pow(x, 2) -> x * x

* Remove numbers::inv_pi, numbers::inv_tau

* delete spooky leading 0

Co-authored-by: Dalton Messmer <[email protected]>

---------

Co-authored-by: Rossmaxx <[email protected]>
Co-authored-by: Dalton Messmer <[email protected]>
  • Loading branch information
3 people authored Feb 9, 2025
1 parent cb7c6d1 commit 4a089a1
Show file tree
Hide file tree
Showing 48 changed files with 256 additions and 295 deletions.
4 changes: 2 additions & 2 deletions include/BasicFilters.h
Original file line number Diff line number Diff line change
Expand Up @@ -806,8 +806,8 @@ class BasicFilters
// other filters
_freq = std::clamp(_freq, minFreq(), 20000.0f);
const float omega = numbers::tau_v<float> * _freq * m_sampleRatio;
const float tsin = sinf( omega ) * 0.5f;
const float tcos = cosf( omega );
const float tsin = std::sin(omega) * 0.5f;
const float tcos = std::cos(omega);

const float alpha = tsin / _q;

Expand Down
8 changes: 4 additions & 4 deletions include/DspEffectLibrary.h
Original file line number Diff line number Diff line change
Expand Up @@ -289,7 +289,7 @@ namespace lmms::DspEffectLibrary
{
if( in >= m_threshold || in < -m_threshold )
{
return ( fabsf( fabsf( fmodf( in - m_threshold, m_threshold*4 ) ) - m_threshold*2 ) - m_threshold ) * m_gain;
return (std::abs(std::abs(std::fmod(in - m_threshold, m_threshold * 4)) - m_threshold * 2) - m_threshold) * m_gain;
}
return in * m_gain;
}
Expand All @@ -303,7 +303,7 @@ namespace lmms::DspEffectLibrary

sample_t nextSample( sample_t in )
{
return m_gain * ( in * ( fabsf( in )+m_threshold ) / ( in*in +( m_threshold-1 )* fabsf( in ) + 1 ) );
return m_gain * (in * (std::abs(in) + m_threshold) / (in * in + (m_threshold - 1) * std::abs(in) + 1));
}
} ;

Expand All @@ -330,8 +330,8 @@ namespace lmms::DspEffectLibrary
{
const float toRad = numbers::pi_v<float> / 180;
const sample_t tmp = inLeft;
inLeft += inRight * sinf( m_wideCoeff * ( .5 * toRad ) );
inRight -= tmp * sinf( m_wideCoeff * ( .5 * toRad ) );
inLeft += inRight * std::sin(m_wideCoeff * toRad * .5f);
inRight -= tmp * std::sin(m_wideCoeff * toRad * .5f);
}

private:
Expand Down
7 changes: 3 additions & 4 deletions include/QuadratureLfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,11 +77,10 @@ class QuadratureLfo

void tick( float *l, float *r )
{
*l = sinf( m_phase );
*r = sinf( m_phase + m_offset );
*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; }
while (m_phase >= numbers::tau) { m_phase -= numbers::tau; }
}

private:
Expand Down
2 changes: 1 addition & 1 deletion include/RmsHelper.h
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ class RmsHelper
m_sum -= m_buffer[ m_pos ];
m_sum += m_buffer[ m_pos ] = in * in;
++m_pos %= m_size;
return sqrtf( m_sum * m_sizef );
return std::sqrt(m_sum * m_sizef);
}

private:
Expand Down
1 change: 1 addition & 0 deletions include/lmms_constants.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ 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>;
Expand Down
2 changes: 1 addition & 1 deletion include/lmms_math.h
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ inline float sign(float val)
}


//! if val >= 0.0f, returns sqrtf(val), else: -sqrtf(-val)
//! if val >= 0.0f, returns sqrt(val), else: -sqrt(-val)
inline float sqrt_neg(float val)
{
return std::sqrt(std::abs(val)) * sign(val);
Expand Down
6 changes: 3 additions & 3 deletions plugins/BitInvader/BitInvader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ BSynth::BSynth( float * _shape, NotePlayHandle * _nph, bool _interpolation,
i.e., the absolute value of all samples is <= 1.0 if _factor
is different to the default normalization factor. If there is
a value > 1.0, clip the sample to 1.0 to limit the range. */
if ((_factor != defaultNormalizationFactor) && (fabsf(buf) > 1.0f))
if ((_factor != defaultNormalizationFactor) && (std::abs(buf) > 1.0f))
{
buf = (buf < 0) ? -1.0f : 1.0f;
}
Expand Down Expand Up @@ -238,7 +238,7 @@ void BitInvader::normalize()
const float* samples = m_graph.samples();
for(int i=0; i < m_graph.length(); i++)
{
const float f = fabsf( samples[i] );
const float f = std::abs(samples[i]);
if (f > max) { max = f; }
}
m_normalizeFactor = 1.0 / max;
Expand Down Expand Up @@ -554,4 +554,4 @@ PLUGIN_EXPORT Plugin * lmms_plugin_main( Model *m, void * )
}


} // namespace lmms
} // namespace lmms
28 changes: 7 additions & 21 deletions plugins/Compressor/Compressor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ CompressorEffect::CompressorEffect(Model* parent, const Descriptor::SubPluginFea
m_yL[0] = m_yL[1] = COMP_NOISE_FLOOR;

// 200 ms
m_crestTimeConst = exp(-1.f / (0.2f * m_sampleRate));
m_crestTimeConst = std::exp(-1.f / (0.2f * m_sampleRate));

connect(&m_compressorControls.m_attackModel, SIGNAL(dataChanged()), this, SLOT(calcAttack()), Qt::DirectConnection);
connect(&m_compressorControls.m_releaseModel, SIGNAL(dataChanged()), this, SLOT(calcRelease()), Qt::DirectConnection);
Expand Down Expand Up @@ -97,7 +97,7 @@ CompressorEffect::CompressorEffect(Model* parent, const Descriptor::SubPluginFea
float CompressorEffect::msToCoeff(float ms)
{
// Convert time in milliseconds to applicable lowpass coefficient
return exp(m_coeffPrecalc / ms);
return std::exp(m_coeffPrecalc / ms);
}


Expand Down Expand Up @@ -175,7 +175,7 @@ void CompressorEffect::calcRange()
void CompressorEffect::resizeRMS()
{
const float rmsValue = m_compressorControls.m_rmsModel.value();
m_rmsTimeConst = (rmsValue > 0) ? exp(-1.f / (rmsValue * 0.001f * m_sampleRate)) : 0;
m_rmsTimeConst = (rmsValue > 0) ? std::exp(-1.f / (rmsValue * 0.001f * m_sampleRate)) : 0;
}

void CompressorEffect::calcLookaheadLength()
Expand Down Expand Up @@ -211,14 +211,14 @@ void CompressorEffect::calcTiltCoeffs()
{
m_tiltVal = m_compressorControls.m_tiltModel.value();

const float amp = 6 / log(2);
const float amp = 6.f / std::log(2.f);

const float gfactor = 5;
const float g1 = m_tiltVal > 0 ? -gfactor * m_tiltVal : -m_tiltVal;
const float g2 = m_tiltVal > 0 ? m_tiltVal : gfactor * m_tiltVal;

m_lgain = exp(g1 / amp) - 1;
m_hgain = exp(g2 / amp) - 1;
m_lgain = std::exp(g1 / amp) - 1;
m_hgain = std::exp(g2 / amp) - 1;

const float omega = numbers::tau_v<float> * m_compressorControls.m_tiltFreqModel.value();
const float n = 1 / (m_sampleRate * 3 + omega);
Expand Down Expand Up @@ -528,20 +528,6 @@ void CompressorEffect::processBypassedImpl()
}
}

// Regular modulo doesn't handle negative numbers correctly. This does.
inline int CompressorEffect::realmod(int k, int n)
{
return (k %= n) < 0 ? k+n : k;
}

// Regular fmod doesn't handle negative numbers correctly. This does.
inline float CompressorEffect::realfmod(float k, float n)
{
return (k = fmod(k, n)) < 0 ? k+n : k;
}



inline void CompressorEffect::calcTiltFilter(sample_t inputSample, sample_t &outputSample, int filtNum)
{
m_tiltOut[filtNum] = m_a0 * inputSample + m_b1 * m_tiltOut[filtNum];
Expand All @@ -557,7 +543,7 @@ void CompressorEffect::changeSampleRate()
m_coeffPrecalc = COMP_LOG / (m_sampleRate * 0.001f);

// 200 ms
m_crestTimeConst = exp(-1.f / (0.2f * m_sampleRate));
m_crestTimeConst = std::exp(-1.f / (0.2f * m_sampleRate));

m_lookBufLength = std::ceil((20.f / 1000.f) * m_sampleRate) + 2;
for (int i = 0; i < 2; ++i)
Expand Down
2 changes: 0 additions & 2 deletions plugins/Compressor/Compressor.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,6 @@ private slots:
float msToCoeff(float ms);

inline void calcTiltFilter(sample_t inputSample, sample_t &outputSample, int filtNum);
inline int realmod(int k, int n);
inline float realfmod(float k, float n);

enum class StereoLinkMode { Unlinked, Maximum, Average, Minimum, Blend };

Expand Down
2 changes: 1 addition & 1 deletion plugins/Delay/Lfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ Lfo::Lfo( int samplerate )

float Lfo::tick()
{
float output = sinf( m_phase );
float output = std::sin(m_phase);
m_phase += m_increment;

return output;
Expand Down
51 changes: 26 additions & 25 deletions plugins/Eq/EqCurve.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,21 +68,21 @@ QRectF EqHandle::boundingRect() const
float EqHandle::freqToXPixel( float freq , int w )
{
if (approximatelyEqual(freq, 0.0f)) { return 0.0f; }
float min = log10f( 20 );
float max = log10f( 20000 );
float min = std::log10(20);
float max = std::log10(20000);
float range = max - min;
return ( log10f( freq ) - min ) / range * w;
return (std::log10(freq) - min) / range * w;
}




float EqHandle::xPixelToFreq( float x , int w )
{
float min = log10f( 20 );
float max = log10f( 20000 );
float min = std::log10(20);
float max = std::log10(20000);
float range = max - min;
return powf( 10 , x * ( range / w ) + min );
return fastPow10f(x * (range / w) + min);
}


Expand Down Expand Up @@ -202,11 +202,11 @@ float EqHandle::getPeakCurve( float x )
{
double freqZ = xPixelToFreq( EqHandle::x(), m_width );
double w0 = numbers::tau * freqZ / Engine::audioEngine()->outputSampleRate();
double c = cosf( w0 );
double s = sinf( w0 );
double c = std::cos(w0);
double s = std::sin(w0);
double Q = getResonance();
double A = pow( 10, yPixelToGain( EqHandle::y(), m_heigth, m_pixelsPerUnitHeight ) / 40 );
double alpha = s * sinh( log( 2 ) / 2 * Q * w0 / sinf( w0 ) );
double A = fastPow10f(yPixelToGain(EqHandle::y(), m_heigth, m_pixelsPerUnitHeight) / 40);
double alpha = s * std::sinh(std::log(2.0) / 2 * Q * w0 / std::sin(w0));

//calc coefficents
double b0 = 1 + alpha * A;
Expand Down Expand Up @@ -238,10 +238,10 @@ float EqHandle::getHighShelfCurve( float x )
{
double freqZ = xPixelToFreq( EqHandle::x(), m_width );
double w0 = numbers::tau * freqZ / Engine::audioEngine()->outputSampleRate();
double c = cosf( w0 );
double s = sinf( w0 );
double A = pow( 10, yPixelToGain( EqHandle::y(), m_heigth, m_pixelsPerUnitHeight ) * 0.025 );
double beta = sqrt( A ) / m_resonance;
double c = std::cos(w0);
double s = std::sin(w0);
double A = fastPow10f(yPixelToGain(EqHandle::y(), m_heigth, m_pixelsPerUnitHeight) * 0.025);
double beta = std::sqrt(A) / m_resonance;

//calc coefficents
double b0 = A * ((A + 1) + (A - 1) * c + beta * s);
Expand Down Expand Up @@ -273,10 +273,10 @@ float EqHandle::getLowShelfCurve( float x )
{
double freqZ = xPixelToFreq( EqHandle::x(), m_width );
double w0 = numbers::tau * freqZ / Engine::audioEngine()->outputSampleRate();
double c = cosf( w0 );
double s = sinf( w0 );
double A = pow( 10, yPixelToGain( EqHandle::y(), m_heigth, m_pixelsPerUnitHeight ) / 40 );
double beta = sqrt( A ) / m_resonance;
double c = std::cos(w0);
double s = std::sin(w0);
double A = fastPow10f(yPixelToGain(EqHandle::y(), m_heigth, m_pixelsPerUnitHeight) / 40);
double beta = std::sqrt(A) / m_resonance;

//calc coefficents
double b0 = A * ((A + 1) - (A - 1) * c + beta * s);
Expand Down Expand Up @@ -308,8 +308,8 @@ float EqHandle::getLowCutCurve( float x )
{
double freqZ = xPixelToFreq( EqHandle::x(), m_width );
double w0 = numbers::tau * freqZ / Engine::audioEngine()->outputSampleRate();
double c = cosf( w0 );
double s = sinf( w0 );
double c = std::cos(w0);
double s = std::sin(w0);
double resonance = getResonance();
double alpha = s / (2 * resonance);

Expand Down Expand Up @@ -350,8 +350,8 @@ float EqHandle::getHighCutCurve( float x )
{
double freqZ = xPixelToFreq( EqHandle::x(), m_width );
double w0 = numbers::tau * freqZ / Engine::audioEngine()->outputSampleRate();
double c = cosf( w0 );
double s = sinf( w0 );
double c = std::cos(w0);
double s = std::sin(w0);
double resonance = getResonance();
double alpha = s / (2 * resonance);

Expand Down Expand Up @@ -525,9 +525,10 @@ double EqHandle::calculateGain(const double freq, const double a1, const double
const double w = std::sin(numbers::pi * freq / Engine::audioEngine()->outputSampleRate());
const double PHI = w * w * 4;

double gain = 10 * log10( pow( b0 + b1 + b2 , 2 ) + ( b0 * b2 * PHI - ( b1 * ( b0 + b2 )
+ 4 * b0 * b2 ) ) * PHI ) - 10 * log10( pow( 1 + a1 + a2, 2 )
+ ( 1 * a2 * PHI - ( a1 * ( 1 + a2 ) + 4 * 1 * a2 ) ) * PHI );
auto bb = b0 + b1 + b2;
auto aa = 1 + a1 + a2;
double gain = 10 * std::log10(bb * bb + (b0 * b2 * PHI - (b1 * (b0 + b2) + 4 * b0 * b2)) * PHI)
- 10 * std::log10(aa * aa + (1 * a2 * PHI - (a1 * (1 + a2) + 4 * 1 * a2)) * PHI);
return gain;
}

Expand Down
34 changes: 17 additions & 17 deletions plugins/Eq/EqFilter.h
Original file line number Diff line number Diff line change
Expand Up @@ -186,8 +186,8 @@ public :

// calc intermediate
float w0 = numbers::tau_v<float> * m_freq / m_sampleRate;
float c = cosf( w0 );
float s = sinf( w0 );
float c = std::cos(w0);
float s = std::sin(w0);
float alpha = s / ( 2 * m_res );

//calc coefficents
Expand Down Expand Up @@ -229,8 +229,8 @@ public :

// calc intermediate
float w0 = numbers::tau_v<float> * m_freq / m_sampleRate;
float c = cosf( w0 );
float s = sinf( w0 );
float c = std::cos(w0);
float s = std::sin(w0);
float alpha = s / ( 2 * m_res );

//calc coefficents
Expand Down Expand Up @@ -270,10 +270,10 @@ class EqPeakFilter : public EqFilter
{
// calc intermediate
float w0 = numbers::tau_v<float> * m_freq / m_sampleRate;
float c = cosf( w0 );
float s = sinf( w0 );
float A = pow( 10, m_gain * 0.025);
float alpha = s * sinh( log( 2 ) / 2 * m_bw * w0 / sinf(w0) );
float c = std::cos(w0);
float s = std::sin(w0);
float A = fastPow10f(m_gain * 0.025);
float alpha = s * std::sinh(std::log(2.f) / 2 * m_bw * w0 / std::sin(w0));

//calc coefficents
float b0 = 1 + alpha * A;
Expand Down Expand Up @@ -333,11 +333,11 @@ public :

// calc intermediate
float w0 = numbers::tau_v<float> * m_freq / m_sampleRate;
float c = cosf( w0 );
float s = sinf( w0 );
float A = pow( 10, m_gain * 0.025);
// float alpha = s / ( 2 * m_res );
float beta = sqrt( A ) / m_res;
float c = std::cos(w0);
float s = std::sin(w0);
float A = fastPow10f(m_gain * 0.025);
// float alpha = s / (2 * m_res);
float beta = std::sqrt(A) / m_res;

//calc coefficents
float b0 = A * ((A + 1) - (A - 1) * c + beta * s);
Expand Down Expand Up @@ -370,10 +370,10 @@ public :

// calc intermediate
float w0 = numbers::tau_v<float> * m_freq / m_sampleRate;
float c = cosf( w0 );
float s = sinf( w0 );
float A = pow( 10, m_gain * 0.025 );
float beta = sqrt( A ) / m_res;
float c = std::cos(w0);
float s = std::sin(w0);
float A = fastPow10f(m_gain * 0.025);
float beta = std::sqrt(A) / m_res;

//calc coefficents
float b0 = A * ((A + 1) + (A - 1) * c + beta * s);
Expand Down
4 changes: 2 additions & 2 deletions plugins/Eq/EqSpectrumView.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,7 @@ EqSpectrumView::EqSpectrumView(EqAnalyser *b, QWidget *_parent) :
connect( getGUI()->mainWindow(), SIGNAL( periodicUpdate() ), this, SLOT( periodicalUpdate() ) );
setAttribute( Qt::WA_TranslucentBackground, true );
m_skipBands = MAX_BANDS * 0.5;
float totalLength = log10( 20000 );
const float totalLength = std::log10(20000);
m_pixelsPerUnitWidth = width() / totalLength ;
m_scale = 1.5;
m_color = QColor( 255, 255, 255, 255 );
Expand Down Expand Up @@ -233,7 +233,7 @@ void EqSpectrumView::paintEvent(QPaintEvent *event)
const float fallOff = 1.07f;
for( int x = 0; x < MAX_BANDS; ++x, ++bands )
{
float peak = *bands != 0. ? (fh * 2.0 / 3.0 * (20. * log10(*bands / energy) - LOWER_Y) / (-LOWER_Y)) : 0.;
float peak = *bands != 0. ? (fh * 2.0 / 3.0 * (20. * std::log10(*bands / energy) - LOWER_Y) / (-LOWER_Y)) : 0.;

if( peak < 0 )
{
Expand Down
Loading

0 comments on commit 4a089a1

Please sign in to comment.