diff --git a/include/SampleBuffer.h b/include/SampleBuffer.h index e53e4ab8c..8da7fd572 100644 --- a/include/SampleBuffer.h +++ b/include/SampleBuffer.h @@ -232,23 +232,13 @@ public: inline sample_t userWaveSample( const float _sample ) const { - // Precise implementation -// const float frame = fraction( _sample ) * m_frames; -// const f_cnt_t f1 = static_cast( frame ); -// const f_cnt_t f2 = ( f1 + 1 ) % m_frames; -// sample_t waveSample = linearInterpolate( m_data[f1][0], -// m_data[f2][0], -// fraction( frame ) ); -// return waveSample; - - // Fast implementation const float frame = _sample * m_frames; f_cnt_t f1 = static_cast( frame ) % m_frames; if( f1 < 0 ) { f1 += m_frames; } - return m_data[f1][0]; + return linearInterpolate( m_data[f1][0], m_data[ (f1 + 1) % m_frames ][0], fraction( frame ) ); } static QString tryToMakeRelative( const QString & _file ); diff --git a/include/interpolation.h b/include/interpolation.h index 4ff582775..43c50e102 100644 --- a/include/interpolation.h +++ b/include/interpolation.h @@ -23,8 +23,8 @@ */ -#ifndef _INTERPOLATION_H -#define _INTERPOLATION_H +#ifndef INTERPOLATION_H +#define INTERPOLATION_H #ifndef __USE_XOPEN #define __USE_XOPEN @@ -80,14 +80,21 @@ inline float cubicInterpolate( float v0, float v1, float v2, float v3, float x ) inline float cosinusInterpolate( float v0, float v1, float x ) { float f = cosf( x * ( F_PI_2 ) ); - return( v0*f + v1*( 1.0f-f ) ); + return( v1 - f * (v1-v0) ); +// return( v0*f + v1*( 1.0f-f ) ); } inline float linearInterpolate( float v0, float v1, float x ) { - return( v0*( 1.0f-x ) + v1*x ); +// take advantage of fma function if present in hardware + +#ifdef FP_FAST_FMAF + return fmaf( x, v1-v0, v0 ); +#else + return x * (v1-v0) + v0; +#endif } diff --git a/plugins/bit_invader/bit_invader.cpp b/plugins/bit_invader/bit_invader.cpp index 852115afb..682f470a6 100644 --- a/plugins/bit_invader/bit_invader.cpp +++ b/plugins/bit_invader/bit_invader.cpp @@ -37,6 +37,7 @@ #include "templates.h" #include "tooltip.h" #include "song.h" +#include "interpolation.h" #include "embed.cpp" @@ -108,9 +109,9 @@ sample_t bSynth::nextStringSample() } // Nachkommaanteil - float frac = sample_realindex - static_cast(sample_realindex); + const float frac = fraction( sample_realindex ); - sample = sample_shape[a]*(1-frac) + sample_shape[b]*(frac); + sample = linearInterpolate( sample_shape[a], sample_shape[b], frac ); } else { // No interpolation diff --git a/plugins/dynamics_processor/dynamics_processor.cpp b/plugins/dynamics_processor/dynamics_processor.cpp index e5bea78d8..c3eb4eb35 100644 --- a/plugins/dynamics_processor/dynamics_processor.cpp +++ b/plugins/dynamics_processor/dynamics_processor.cpp @@ -25,7 +25,9 @@ #include "dynamics_processor.h" -#include +#include "lmms_math.h" +#include "interpolation.h" + #include "embed.cpp" #ifdef LMMS_BUILD_WIN32 @@ -107,8 +109,7 @@ bool dynProcEffect::processAudioBuffer( sampleFrame * _buf, // variables for effect int i = 0; - float lookup; - float frac; + float sm_peak[2] = { 0.0f, 0.0f }; float gain; @@ -182,22 +183,20 @@ bool dynProcEffect::processAudioBuffer( sampleFrame * _buf, for ( i=0; i <= 1; i++ ) { - if( sm_peak[i] != 0 ) + const int lookup = static_cast( sm_peak[i] * 200.0f ); + const float frac = fraction( sm_peak[i] * 200.0f ); + + if( sm_peak[i] > 0 ) { - lookup = sm_peak[i] * 200.0f; - if ( lookup < 1 ) { - frac = lookup - truncf(lookup); gain = frac * m_dpControls.m_wavegraphModel.samples()[0]; } else if ( lookup < 200 ) { - frac = lookup - truncf(lookup); - gain = - (( (1.0f-frac) * m_dpControls.m_wavegraphModel.samples()[ (int)truncf(lookup) - 1 ] ) + - ( frac * m_dpControls.m_wavegraphModel.samples()[ (int)truncf(lookup) ] )); + gain = linearInterpolate( m_dpControls.m_wavegraphModel.samples()[ lookup - 1 ], + m_dpControls.m_wavegraphModel.samples()[ lookup ], frac ); } else { @@ -206,8 +205,6 @@ bool dynProcEffect::processAudioBuffer( sampleFrame * _buf, s[i] *= ( gain / sm_peak[i] ); } - else { s[i] = 0.0f; } - } // apply output gain diff --git a/plugins/monstro/Monstro.cpp b/plugins/monstro/Monstro.cpp index 900fb4b5d..313bffb8c 100644 --- a/plugins/monstro/Monstro.cpp +++ b/plugins/monstro/Monstro.cpp @@ -33,6 +33,7 @@ #include "tooltip.h" #include "song.h" #include "lmms_math.h" +#include "interpolation.h" #include "embed.cpp" @@ -103,10 +104,10 @@ void MonstroSynth::renderOutput( fpp_t _frames, sampleFrame * _buf ) { // macros for modulating with env/lfos #define modulatefreq( car, mod ) \ - if( mod##_e1 != 0.0 ) car = qBound( MIN_FREQ, car * static_cast( fastPow( 2.0, m_env1_buf[f] * mod##_e1 * 2 ) ), MAX_FREQ ); \ - if( mod##_e2 != 0.0 ) car = qBound( MIN_FREQ, car * static_cast( fastPow( 2.0, m_env2_buf[f] * mod##_e2 * 2 ) ), MAX_FREQ ); \ - if( mod##_l1 != 0.0 ) car = qBound( MIN_FREQ, car * static_cast( fastPow( 2.0, m_lfo1_buf[f] * mod##_l1 ) ), MAX_FREQ ); \ - if( mod##_l2 != 0.0 ) car = qBound( MIN_FREQ, car * static_cast( fastPow( 2.0, m_lfo2_buf[f] * mod##_l2 ) ), MAX_FREQ ); + if( mod##_e1 != 0.0 ) car = qBound( MIN_FREQ, car * powf( 2.0, m_env1_buf[f] * mod##_e1 * 2 ), MAX_FREQ ); \ + if( mod##_e2 != 0.0 ) car = qBound( MIN_FREQ, car * powf( 2.0, m_env2_buf[f] * mod##_e2 * 2 ), MAX_FREQ ); \ + if( mod##_l1 != 0.0 ) car = qBound( MIN_FREQ, car * powf( 2.0, m_lfo1_buf[f] * mod##_l1 ), MAX_FREQ ); \ + if( mod##_l2 != 0.0 ) car = qBound( MIN_FREQ, car * powf( 2.0, m_lfo2_buf[f] * mod##_l2 ), MAX_FREQ ); #define modulateabs( car, mod ) \ if( mod##_e1 != 0.0 ) car = qBound( 0.0f, car + mod##_e1 * m_env1_buf[f], 1.0f ); \ @@ -251,14 +252,14 @@ void MonstroSynth::renderOutput( fpp_t _frames, sampleFrame * _buf ) for( f_cnt_t f = 0; f < _frames; f++ ) { -/* - // debug code + +/* // debug code if( f % 10 == 0 ) { qDebug( "env1 %f -- env1 phase %f", m_env1_buf[f], m_env1_phase ); qDebug( "env1 pre %f att %f dec %f rel %f ", m_parent->m_env1_pre, m_parent->m_env1_att, m_parent->m_env1_dec, m_parent->m_env1_rel ); - } -*/ + }*/ + ///////////////////////////// // // @@ -378,8 +379,8 @@ void MonstroSynth::renderOutput( fpp_t _frames, sampleFrame * _buf ) // o2 modulation? if( omod == MOD_FM ) { - o3l_f = qBound( MIN_FREQ, o3l_f * powf( 4.0f, O2L ), MAX_FREQ ); - o3r_f = qBound( MIN_FREQ, o3r_f * powf( 4.0f, O2R ), MAX_FREQ ); + o3l_f = qBound( MIN_FREQ, o3l_f * powf( 2.0f, O2L * 2 ), MAX_FREQ ); + o3r_f = qBound( MIN_FREQ, o3r_f * powf( 2.0f, O2R * 2 ), MAX_FREQ ); } // check for sync @@ -417,8 +418,8 @@ void MonstroSynth::renderOutput( fpp_t _frames, sampleFrame * _buf ) float sub = o3sub; modulateabs( sub, o3s ) - sample_t O3L = interpolate( O3AL, O3BL, sub ); - sample_t O3R = interpolate( O3AR, O3BR, sub ); + sample_t O3L = linearInterpolate( O3AL, O3BL, sub ); + sample_t O3R = linearInterpolate( O3AR, O3BR, sub ); // modulate volume O3L *= o3lv; diff --git a/plugins/monstro/Monstro.h b/plugins/monstro/Monstro.h index 79acbcced..83a687cd6 100644 --- a/plugins/monstro/Monstro.h +++ b/plugins/monstro/Monstro.h @@ -183,11 +183,10 @@ private: void renderModulators( fpp_t _frames ); // linear interpolation - inline sample_t interpolate( sample_t s1, sample_t s2, float x ) +/* inline sample_t interpolate( sample_t s1, sample_t s2, float x ) { return s1 + ( s2 - s1 ) * x; - } - + }*/ // using interpolation.h from now on inline sample_t calcSlope( sample_t _s, float _slope ) { diff --git a/plugins/watsyn/Watsyn.cpp b/plugins/watsyn/Watsyn.cpp index 3b7c93265..ab1393aeb 100644 --- a/plugins/watsyn/Watsyn.cpp +++ b/plugins/watsyn/Watsyn.cpp @@ -31,6 +31,7 @@ #include "tooltip.h" #include "song.h" #include "lmms_math.h" +#include "interpolation.h" #include "embed.cpp" @@ -132,10 +133,10 @@ void WatsynObject::renderOutput( fpp_t _frames ) if( A1_rphase < 0 ) A1_rphase += WAVELEN; } // A1 - sample_t A1_L = interpolate( m_A1wave[ static_cast( A1_lphase ) ], + sample_t A1_L = linearInterpolate( m_A1wave[ static_cast( A1_lphase ) ], m_A1wave[ static_cast( A1_lphase + 1 ) % WAVELEN ], fraction( A1_lphase ) ) * m_parent->m_lvol[A1_OSC]; - sample_t A1_R = interpolate( m_A1wave[ static_cast( A1_rphase ) ], + sample_t A1_R = linearInterpolate( m_A1wave[ static_cast( A1_rphase ) ], m_A1wave[ static_cast( A1_rphase + 1 ) % WAVELEN ], fraction( A1_rphase ) ) * m_parent->m_rvol[A1_OSC]; @@ -168,10 +169,10 @@ void WatsynObject::renderOutput( fpp_t _frames ) if( B1_rphase < 0 ) B1_rphase += WAVELEN; } // B1 - sample_t B1_L = interpolate( m_B1wave[ static_cast( B1_lphase ) % WAVELEN ], + sample_t B1_L = linearInterpolate( m_B1wave[ static_cast( B1_lphase ) % WAVELEN ], m_B1wave[ static_cast( B1_lphase + 1 ) % WAVELEN ], fraction( B1_lphase ) ) * m_parent->m_lvol[B1_OSC]; - sample_t B1_R = interpolate( m_B1wave[ static_cast( B1_rphase ) % WAVELEN ], + sample_t B1_R = linearInterpolate( m_B1wave[ static_cast( B1_rphase ) % WAVELEN ], m_B1wave[ static_cast( B1_rphase + 1 ) % WAVELEN ], fraction( B1_rphase ) ) * m_parent->m_rvol[B1_OSC]; diff --git a/plugins/watsyn/Watsyn.h b/plugins/watsyn/Watsyn.h index 66a2b4757..37c607d0f 100644 --- a/plugins/watsyn/Watsyn.h +++ b/plugins/watsyn/Watsyn.h @@ -103,10 +103,10 @@ public: private: // linear interpolation - inline sample_t interpolate( sample_t s1, sample_t s2, float x ) +/* inline sample_t interpolate( sample_t s1, sample_t s2, float x ) { return s1 + ( s2 - s1 ) * x; - } + }*/ // we use the one in interpolation.h now int m_amod; int m_bmod; diff --git a/plugins/waveshaper/waveshaper.cpp b/plugins/waveshaper/waveshaper.cpp index 905e37af5..293d97d29 100644 --- a/plugins/waveshaper/waveshaper.cpp +++ b/plugins/waveshaper/waveshaper.cpp @@ -25,8 +25,9 @@ #include "waveshaper.h" -#include +#include "lmms_math.h" #include "embed.cpp" +#include "interpolation.h" extern "C" @@ -77,9 +78,6 @@ bool waveShaperEffect::processAudioBuffer( sampleFrame * _buf, // variables for effect int i = 0; - float lookup; - float frac; - float posneg; double out_sum = 0.0; const float d = dryLevel(); @@ -101,23 +99,20 @@ bool waveShaperEffect::processAudioBuffer( sampleFrame * _buf, // start effect - for ( i=0; i <= 1; ++i ) + for( i=0; i <= 1; ++i ) { - lookup = fabsf( s[i] ) * 200.0f; - posneg = s[i] < 0 ? -1.0f : 1.0f; + const int lookup = static_cast( fabsf( s[i] ) * 200.0f ); + const float frac = fraction( fabsf( s[i] ) * 200.0f ); + const float posneg = s[i] < 0 ? -1.0f : 1.0f; - if ( lookup < 1 ) + if( lookup < 1 ) { - frac = lookup - truncf(lookup); s[i] = frac * m_wsControls.m_wavegraphModel.samples()[0] * posneg; } - else - if ( lookup < 200 ) - { - frac = lookup - truncf(lookup); - s[i] = - (( (1.0f-frac) * m_wsControls.m_wavegraphModel.samples()[ (int)truncf(lookup) - 1 ] ) + - ( frac * m_wsControls.m_wavegraphModel.samples()[ (int)truncf(lookup) ] )) + else if( lookup < 200 ) + { + s[i] = linearInterpolate( m_wsControls.m_wavegraphModel.samples()[ lookup - 1 ], + m_wsControls.m_wavegraphModel.samples()[ lookup ], frac ) * posneg; } else