diff --git a/include/Oscillator.h b/include/Oscillator.h index 84e9264c9..56e79e86a 100644 --- a/include/Oscillator.h +++ b/include/Oscillator.h @@ -162,7 +162,7 @@ public: static inline sample_t noiseSample( const float ) { - return 1.0f - rand() * 2.0f / static_cast(RAND_MAX); + return fastRandInc(-1.f, 1.f); } static sample_t userWaveSample(const SampleBuffer* buffer, const float sample) diff --git a/include/lmms_math.h b/include/lmms_math.h index cefe1265b..a0f43c3e6 100644 --- a/include/lmms_math.h +++ b/include/lmms_math.h @@ -43,6 +43,7 @@ namespace lmms { + // TODO C++23: Make constexpr since std::abs() will be constexpr inline bool approximatelyEqual(float x, float y) noexcept { @@ -81,26 +82,112 @@ inline auto absFraction(std::floating_point auto x) noexcept return x - std::floor(x); } -inline auto fastRand() noexcept + +//! @brief Returns a pseudorandom integer within [0, 32768). +//! @returns A pseudorandom integer greater than or equal to 0 and less than 32767. +inline int fastRand() noexcept { - static unsigned long next = 1; - next = next * 1103515245 + 12345; - return next / 65536 % 32768; + thread_local unsigned long s_next = 1; + s_next = s_next * 1103515245 + 12345; + return s_next / 65536 % 32768; } + +//! @brief Returns a pseudorandom number within [0, @p upper) (exclusive upper bound). +//! @returns A pseudorandom number greater than or equal to 0 and less @p upper. template -inline auto fastRand(T range) noexcept +inline T fastRand(T upper) noexcept { - constexpr T FAST_RAND_RATIO = static_cast(1.0 / 32767); - return fastRand() * range * FAST_RAND_RATIO; + constexpr auto FAST_RAND_RATIO = static_cast(1.0 / 32768); + return fastRand() * upper * FAST_RAND_RATIO; } -template -inline auto fastRand(T from, T to) noexcept + +//! @brief Returns a pseudorandom integer within [0, @p upper) (exclusive upper bound). +//! @p upper may be negative, in which case the output range is (@p upper, 0]. +//! @returns A pseudorandom integer greater than or equal to 0 and less than @p upper. +template +inline T fastRand(T upper) noexcept { - return from + fastRand(to - from); + constexpr float FAST_RAND_RATIO = 1.f / 32768; + return static_cast(fastRand() * static_cast(upper) * FAST_RAND_RATIO); } + +//! @brief Returns a pseudorandom integer within [@p from, @p to) (exclusive upper bound). +//! @returns A pseudorandom integer greater than or equal to @p from and less than @p to. +template requires std::is_arithmetic_v +inline auto fastRand(T from, T to) noexcept { return from + fastRand(to - from); } + + +//! @brief Returns a pseudorandom number within [0, @p upper] (inclusive upper bound). +//! @returns A pseudorandom number greater than or equal to 0 and less than or equal to @p upper. +template +inline T fastRandInc(T upper) noexcept +{ + constexpr auto FAST_RAND_RATIO = static_cast(1.0 / 32767); + return fastRand() * upper * FAST_RAND_RATIO; +} + + +//! @brief Returns a pseudorandom integer within [0, @p upper] (inclusive upper bound). +//! @returns A pseudorandom integer greater than or equal to 0 and less than or equal to @p upper. +template +inline T fastRandInc(T upper) noexcept +{ + // The integer specialization of this function is kind of weird, but it is + // necessary to prevent massive bias away from the maximum value. + // FAST_RAND_RATIO here is 1 greater than normal, so when multiplied by, it + // will result in a random float within [0, @p upper) instead of the usual + // [0, @p upper]. + constexpr float FAST_RAND_RATIO = 1.f / 32768; + // Since the random float will be in a range that does not include @upper + // due to the above ratio, increase the upper bound by 1. + // All values greater than @p upper get rounded down to @p upper, making the + // chance of returning a value of @p upper the same as any other of the + // possible values. + // No need to copysign() unlike the signed_integral overload, since it will always be positive + return static_cast(fastRand() * (upper + 1.f) * FAST_RAND_RATIO); +} + + +//! @brief Returns a pseudorandom integer within [0, @p upper] (inclusive upper bound). +//! @p upper may be negative, in which case the output range is [@p upper, 0]. +//! @returns A pseudorandom integer greater than or equal to 0 and less than or equal to @p upper. +template +inline T fastRandInc(T upper) noexcept +{ + // The integer specialization of this function is kind of weird, but it is + // necessary to prevent massive bias away from the maximum value. + // FAST_RAND_RATIO here is 1 greater than normal, so when multiplied by, it + // will result in a random float within [0, @p upper) instead of the usual + // [0, @p upper]. + constexpr float FAST_RAND_RATIO = 1.f / 32768; + // Since the random float will be in a range that does not include @upper + // due to the above ratio, increase the magnitude of the upper bound by 1. + // All values greater than @p upper get rounded down to @p upper, making the + // chance of returning a value of @p upper the same as any other of the + // possible values. + // HACK: Even on -O3, without this static_cast, it will convert @p upper to float twice for some reason + const auto fupper = static_cast(upper); + const float r = fupper + std::copysign(1.f, fupper); + // Always round towards 0 (implicit truncation occurs during static_cast). + return static_cast(fastRand() * r * FAST_RAND_RATIO); +} + + +//! @brief Returns a pseudorandom integer within [@p from, @p to] (inclusive upper bound). +//! This function does not require the parameters to be in the proper order. +//! fastRand(a, b) behaves identically to fastRand(b, a). +//! @returns A pseudorandom integer greater than or equal to @p from and less than or equal to @p to. +template requires std::is_arithmetic_v +inline auto fastRandInc(T from, T to) noexcept { return from + fastRandInc(to - from); } + + +//! @brief Returns true one in @p chance times at random. +inline bool oneIn(unsigned chance) noexcept { return 0 == (fastRand() % chance); } + + //! Round `value` to `where` depending on step size template static void roundAt(T& value, const T& where, const T& stepSize) @@ -180,26 +267,26 @@ inline float linearToLogScale(float min, float max, float value) return std::isnan(result) ? 0 : result; } + // TODO C++26: Make constexpr since std::exp() will be constexpr -template +template requires std::is_arithmetic_v inline auto fastPow10f(T x) { - return std::exp(std::numbers::ln10_v * x); + using F_T = std::conditional_t, T, float>; + return std::exp(std::numbers::ln10_v * x); } -// TODO C++26: Make constexpr since std::exp() will be constexpr -inline auto fastPow10f(std::integral auto x) -{ - return std::exp(std::numbers::ln10_v * x); -} // TODO C++26: Make constexpr since std::log() will be constexpr -inline auto fastLog10f(float x) +template requires std::is_arithmetic_v +inline auto fastLog10f(T x) { - constexpr auto inv_ln10 = static_cast(1.0 / std::numbers::ln10); + using F_T = std::conditional_t, T, float>; + constexpr auto inv_ln10 = static_cast(1.0 / std::numbers::ln10); return std::log(x) * inv_ln10; } + //! @brief Converts linear amplitude (>0-1.0) to dBFS scale. //! @param amp Linear amplitude, where 1.0 = 0dBFS. ** Must be larger than zero! ** //! @return Amplitude in dBFS. diff --git a/plugins/Bitcrush/Bitcrush.cpp b/plugins/Bitcrush/Bitcrush.cpp index 0bfcf62b1..f7f578d8f 100644 --- a/plugins/Bitcrush/Bitcrush.cpp +++ b/plugins/Bitcrush/Bitcrush.cpp @@ -98,7 +98,7 @@ inline float BitcrushEffect::depthCrush( float in ) inline float BitcrushEffect::noise( float amt ) { - return fastRand(-amt, +amt); + return fastRandInc(-amt, +amt); } Effect::ProcessStatus BitcrushEffect::processImpl(SampleFrame* buf, const fpp_t frames) diff --git a/plugins/Flanger/FlangerEffect.cpp b/plugins/Flanger/FlangerEffect.cpp index 66088e405..febafa4bf 100644 --- a/plugins/Flanger/FlangerEffect.cpp +++ b/plugins/Flanger/FlangerEffect.cpp @@ -106,8 +106,8 @@ Effect::ProcessStatus FlangerEffect::processImpl(SampleFrame* buf, const fpp_t f float leftLfo; float rightLfo; - buf[f][0] += fastRand(-1.f, +1.f) * noise; - buf[f][1] += fastRand(-1.f, +1.f) * noise; + buf[f][0] += fastRandInc(-1.f, 1.f) * noise; + buf[f][1] += fastRandInc(-1.f, 1.f) * noise; dryS[0] = buf[f][0]; dryS[1] = buf[f][1]; m_lfo->tick(&leftLfo, &rightLfo); diff --git a/plugins/GranularPitchShifter/GranularPitchShifterEffect.cpp b/plugins/GranularPitchShifter/GranularPitchShifterEffect.cpp index 3968fae48..45ce9fab0 100755 --- a/plugins/GranularPitchShifter/GranularPitchShifterEffect.cpp +++ b/plugins/GranularPitchShifter/GranularPitchShifterEffect.cpp @@ -156,7 +156,7 @@ Effect::ProcessStatus GranularPitchShifterEffect::processImpl(SampleFrame* buf, if (++m_timeSinceLastGrain >= m_nextWaitRandomization * waitMult) { m_timeSinceLastGrain = 0; - auto randThing = fastRand(-1.0, +1.0); + auto randThing = fastRandInc(-1.0, +1.0); m_nextWaitRandomization = std::exp2(randThing * twitch); double grainSpeed = 1. / std::exp2(randThing * jitter); diff --git a/plugins/Organic/Organic.cpp b/plugins/Organic/Organic.cpp index b9e7716ef..7ac4cbcdc 100644 --- a/plugins/Organic/Organic.cpp +++ b/plugins/Organic/Organic.cpp @@ -33,7 +33,7 @@ #include "NotePlayHandle.h" #include "Oscillator.h" #include "PixmapButton.h" - +#include "lmms_math.h" #include "embed.h" #include "plugin_export.h" @@ -231,71 +231,63 @@ void OrganicInstrument::playNote( NotePlayHandle * _n, auto oscs_l = std::array{}; auto oscs_r = std::array{}; - _n->m_pluginData = new oscPtr; + auto newOsc = new oscPtr; + _n->m_pluginData = newOsc; - for( int i = m_numOscillators - 1; i >= 0; --i ) + for (int i = m_numOscillators - 1; i >= 0; --i) { - static_cast( _n->m_pluginData )->phaseOffsetLeft[i] - = rand() / (static_cast(RAND_MAX) + 1.0f); - static_cast( _n->m_pluginData )->phaseOffsetRight[i] - = rand() / (static_cast(RAND_MAX) + 1.0f); + newOsc->phaseOffsetLeft[i] = fastRand(1.f); + newOsc->phaseOffsetRight[i] = fastRand(1.f); // initialise ocillators - - if( i == m_numOscillators - 1 ) + if (i == m_numOscillators - 1) { // create left oscillator oscs_l[i] = new Oscillator( - &m_osc[i]->m_waveShape, - &m_modulationAlgo, - _n->frequency(), - m_osc[i]->m_detuningLeft, - static_cast( _n->m_pluginData )->phaseOffsetLeft[i], - m_osc[i]->m_volumeLeft ); + &m_osc[i]->m_waveShape, + &m_modulationAlgo, + _n->frequency(), + m_osc[i]->m_detuningLeft, + newOsc->phaseOffsetLeft[i], + m_osc[i]->m_volumeLeft); // create right oscillator oscs_r[i] = new Oscillator( - &m_osc[i]->m_waveShape, - &m_modulationAlgo, - _n->frequency(), - m_osc[i]->m_detuningRight, - static_cast( _n->m_pluginData )->phaseOffsetRight[i], - m_osc[i]->m_volumeRight ); + &m_osc[i]->m_waveShape, + &m_modulationAlgo, + _n->frequency(), + m_osc[i]->m_detuningRight, + newOsc->phaseOffsetRight[i], + m_osc[i]->m_volumeRight); } else { // create left oscillator oscs_l[i] = new Oscillator( - &m_osc[i]->m_waveShape, - &m_modulationAlgo, - _n->frequency(), - m_osc[i]->m_detuningLeft, - static_cast( _n->m_pluginData )->phaseOffsetLeft[i], - m_osc[i]->m_volumeLeft, - oscs_l[i + 1] ); + &m_osc[i]->m_waveShape, + &m_modulationAlgo, + _n->frequency(), + m_osc[i]->m_detuningLeft, + newOsc->phaseOffsetLeft[i], + m_osc[i]->m_volumeLeft, + oscs_l[i + 1]); // create right oscillator oscs_r[i] = new Oscillator( - &m_osc[i]->m_waveShape, - &m_modulationAlgo, - _n->frequency(), - m_osc[i]->m_detuningRight, - static_cast( _n->m_pluginData )->phaseOffsetRight[i], - m_osc[i]->m_volumeRight, - oscs_r[i + 1] ); + &m_osc[i]->m_waveShape, + &m_modulationAlgo, + _n->frequency(), + m_osc[i]->m_detuningRight, + newOsc->phaseOffsetRight[i], + m_osc[i]->m_volumeRight, + oscs_r[i + 1]); } - - } - - static_cast( _n->m_pluginData )->oscLeft = oscs_l[0]; - static_cast( _n->m_pluginData )->oscRight = oscs_r[0]; + newOsc->oscLeft = oscs_l[0]; + newOsc->oscRight = oscs_r[0]; } - Oscillator * osc_l = static_cast( _n->m_pluginData )->oscLeft; - Oscillator * osc_r = static_cast( _n->m_pluginData)->oscRight; - - osc_l->update( _working_buffer + offset, frames, 0 ); - osc_r->update( _working_buffer + offset, frames, 1 ); - + auto osc = static_cast(_n->m_pluginData); + osc->oscLeft->update(_working_buffer + offset, frames, 0); + osc->oscRight->update(_working_buffer + offset, frames, 1); // -- fx section -- @@ -346,27 +338,18 @@ float inline OrganicInstrument::waveshape(float in, float amount) } - - void OrganicInstrument::randomiseSettings() { - - for( int i = 0; i < m_numOscillators; i++ ) + for (auto i = 0; i < m_numOscillators; ++i) { - m_osc[i]->m_volModel.setValue( intRand( 0, 100 ) ); - - m_osc[i]->m_detuneModel.setValue( intRand( -5, 5 ) ); - - m_osc[i]->m_panModel.setValue( 0 ); - - m_osc[i]->m_oscModel.setValue( intRand( 0, 5 ) ); + m_osc[i]->m_volModel.setValue(fastRandInc(100)); + m_osc[i]->m_detuneModel.setValue(fastRandInc(-5, 5)); + m_osc[i]->m_panModel.setValue(0); + m_osc[i]->m_oscModel.setValue(fastRandInc(5)); } - } - - void OrganicInstrument::updateAllDetuning() { for( int i = 0; i < m_numOscillators; ++i ) @@ -376,17 +359,6 @@ void OrganicInstrument::updateAllDetuning() } - - -int OrganicInstrument::intRand( int min, int max ) -{ -// int randn = min+int((max-min)*rand()/(RAND_MAX + 1.0)); -// cout << randn << endl; - int randn = ( rand() % (max - min) ) + min; - return( randn ); -} - - gui::PluginView * OrganicInstrument::instantiateView( QWidget * _parent ) { return( new gui::OrganicInstrumentView( this, _parent ) ); diff --git a/plugins/Organic/Organic.h b/plugins/Organic/Organic.h index 60d41601b..967683d19 100644 --- a/plugins/Organic/Organic.h +++ b/plugins/Organic/Organic.h @@ -133,8 +133,6 @@ public: QString nodeName() const override; - int intRand( int min, int max ); - static float * s_harmonics; public slots: diff --git a/plugins/PeakControllerEffect/PeakControllerEffect.cpp b/plugins/PeakControllerEffect/PeakControllerEffect.cpp index e66a4fcde..5bd7c02b9 100644 --- a/plugins/PeakControllerEffect/PeakControllerEffect.cpp +++ b/plugins/PeakControllerEffect/PeakControllerEffect.cpp @@ -66,7 +66,7 @@ PeakControllerEffect::PeakControllerEffect( Model * _parent, const Descriptor::SubPluginFeatures::Key * _key ) : Effect( &peakcontrollereffect_plugin_descriptor, _parent, _key ), - m_effectId( rand() ), + m_effectId(fastRand()), m_peakControls( this ), m_lastSample( 0 ), m_autoController( nullptr ) diff --git a/plugins/PeakControllerEffect/PeakControllerEffectControls.cpp b/plugins/PeakControllerEffect/PeakControllerEffectControls.cpp index 0060b535b..2f190c706 100644 --- a/plugins/PeakControllerEffect/PeakControllerEffectControls.cpp +++ b/plugins/PeakControllerEffect/PeakControllerEffectControls.cpp @@ -29,6 +29,7 @@ #include "PeakControllerEffectControls.h" #include "PeakControllerEffect.h" #include "Song.h" +#include "lmms_math.h" namespace lmms { @@ -81,7 +82,7 @@ void PeakControllerEffectControls::loadSettings( const QDomElement & _this ) else { // TODO: Fix possible collision - m_effect->m_effectId = rand(); + m_effect->m_effectId = fastRand(); } } diff --git a/plugins/ReverbSC/ReverbSC.cpp b/plugins/ReverbSC/ReverbSC.cpp index f10c2815a..6ffca912f 100644 --- a/plugins/ReverbSC/ReverbSC.cpp +++ b/plugins/ReverbSC/ReverbSC.cpp @@ -90,10 +90,10 @@ Effect::ProcessStatus ReverbSCEffect::processImpl(SampleFrame* buf, const fpp_t { auto s = std::array{buf[f][0], buf[f][1]}; - const auto inGain = static_cast(fastPow10f( - (inGainBuf ? inGainBuf->values()[f] : m_reverbSCControls.m_inputGainModel.value()) / 20.f)); - const auto outGain = static_cast(fastPow10f( - (outGainBuf ? outGainBuf->values()[f] : m_reverbSCControls.m_outputGainModel.value()) / 20.f)); + const auto inGain = fastPow10f( + (inGainBuf ? inGainBuf->values()[f] : m_reverbSCControls.m_inputGainModel.value()) / 20.f); + const auto outGain = fastPow10f( + (outGainBuf ? outGainBuf->values()[f] : m_reverbSCControls.m_outputGainModel.value()) / 20.f); s[0] *= inGain; s[1] *= inGain; diff --git a/plugins/Sfxr/Sfxr.cpp b/plugins/Sfxr/Sfxr.cpp index 5603b7138..a3a718be9 100644 --- a/plugins/Sfxr/Sfxr.cpp +++ b/plugins/Sfxr/Sfxr.cpp @@ -23,23 +23,13 @@ * Boston, MA 02110-1301 USA. */ +#include "Sfxr.h" + #include #include - -#define rnd(n) (rand()%(n+1)) - -#define PI 3.14159265f - -float frnd(float range) -{ - return (float)rnd(10000)/10000*range; -} - #include - #include -#include "Sfxr.h" #include "AudioEngine.h" #include "Engine.h" #include "InstrumentTrack.h" @@ -47,9 +37,8 @@ float frnd(float range) #include "NotePlayHandle.h" #include "PixmapButton.h" #include "MidiEvent.h" - +#include "lmms_math.h" #include "embed.h" - #include "plugin_export.h" namespace lmms @@ -145,7 +134,7 @@ void SfxrSynth::resetSample( bool restart ) phaser_buffer.fill(0.0f); for (auto& noiseSample : noise_buffer) { - noiseSample = frnd(2.0f) - 1.0f; + noiseSample = fastRandInc(-1.f, 1.f); } rep_time=0; @@ -239,12 +228,14 @@ void SfxrSynth::update( SampleFrame* buffer, const int32_t frameNum ) if(phase>=period) { // phase=0; - phase%=period; - if(s->m_waveFormModel.value()==3) - for (auto& noiseSample : noise_buffer) + phase %= period; + if (s->m_waveFormModel.value() == 3) + { + for (auto& noiseSample : noise_buffer) { - noiseSample = frnd(2.0f) - 1.0f; + noiseSample = fastRandInc(-1.f, 1.f); } + } } // base waveform float fp=(float)phase/period; @@ -260,7 +251,7 @@ void SfxrSynth::update( SampleFrame* buffer, const int32_t frameNum ) sample=1.0f-fp*2; break; case 2: // sine - sample=(float)sin(fp*2*PI); + sample = std::sin(fp * 2.f * std::numbers::pi_v); break; case 3: // noise sample=noise_buffer[phase*32/period]; @@ -593,7 +584,6 @@ SfxrInstrumentView::SfxrInstrumentView( Instrument * _instrument, QWidget * _parent ) : InstrumentViewFixedSize( _instrument, _parent ) { - srand(time(nullptr)); setAutoFillBackground( true ); QPalette pal; pal.setBrush( backgroundRole(), PLUGIN_NAME::getIconPixmap( "artwork" ) ); @@ -745,359 +735,307 @@ void SfxrInstrumentView::modelChanged() } - - void SfxrInstrumentView::genPickup() { auto s = castModel(); s->resetModels(); - s->m_startFreqModel.setValue( 0.4f+frnd(0.5f) ); - s->m_attModel.setValue( 0.0f ); - s->m_holdModel.setValue( frnd(0.1f) ); - s->m_decModel.setValue( 0.1f+frnd(0.4f) ); - s->m_susModel.setValue( 0.3f+frnd(0.3f) ); + s->m_startFreqModel.setValue(fastRandInc(0.4f, 0.9f)); + s->m_attModel.setValue(0.f); + s->m_holdModel.setValue(fastRandInc(0.1f)); + s->m_decModel.setValue(fastRandInc(0.1f, 0.5f)); + s->m_susModel.setValue(fastRandInc(0.3f, 0.6f)); - if(rnd(1)) + if (oneIn(2)) { - s->m_changeSpeedModel.setValue( 0.5f+frnd(0.2f) ); - s->m_changeAmtModel.setValue( 0.2f+frnd(0.4f) ); + s->m_changeSpeedModel.setValue(fastRandInc(0.5f, 0.7f)); + s->m_changeAmtModel.setValue(fastRandInc(0.2f, 0.6f)); } } - - void SfxrInstrumentView::genLaser() { auto s = castModel(); s->resetModels(); - s->m_waveFormModel.setValue( rnd(2) ); - if(s->m_waveFormModel.value()==2 && rnd(1)) - s->m_waveFormModel.setValue( rnd(1) ); + s->m_waveFormModel.setValue(fastRandInc(2)); + if (s->m_waveFormModel.value() == 2 && oneIn(2)) { s->m_waveFormModel.setValue(fastRand() & 1); } + s->m_startFreqModel.setValue(fastRandInc(0.5f, 1.f)); + s->m_minFreqModel.setValue(std::max(0.2f, s->m_startFreqModel.value() - fastRandInc(0.2f, 0.8f))); + s->m_slideModel.setValue(fastRandInc(-0.15f, -0.35f)); - s->m_startFreqModel.setValue( 0.5f+frnd(0.5f) ); - s->m_minFreqModel.setValue( s->m_startFreqModel.value()-0.2f-frnd(0.6f) ); - - if(s->m_minFreqModel.value()<0.2f) + if (oneIn(3)) { - s->m_minFreqModel.setValue(0.2f); + s->m_startFreqModel.setValue(fastRandInc(0.3f, 0.9f)); + s->m_minFreqModel.setValue(fastRandInc(0.1f)); + s->m_slideModel.setValue(fastRandInc(-0.65f,-0.35f)); } - s->m_slideModel.setValue( -0.15f-frnd(0.2f) ); - - if(rnd(2)==0) + if (oneIn(2)) { - s->m_startFreqModel.setValue( 0.3f+frnd(0.6f) ); - s->m_minFreqModel.setValue( frnd(0.1f) ); - s->m_slideModel.setValue( -0.35f-frnd(0.3f) ); - } - - if(rnd(1)) - { - s->m_sqrDutyModel.setValue( frnd(0.5f) ); - s->m_sqrSweepModel.setValue( 0.2f ); + s->m_sqrDutyModel.setValue(fastRandInc(0.5f)); + s->m_sqrSweepModel.setValue(0.2f); } else { - s->m_sqrDutyModel.setValue( 0.4f+frnd(0.5f) ); - s->m_sqrSweepModel.setValue( -frnd(0.7f) ); + s->m_sqrDutyModel.setValue(fastRandInc(0.4f, 0.9f)); + s->m_sqrSweepModel.setValue(fastRandInc(-0.7f)); } - s->m_attModel.setValue( 0.0f ); - s->m_holdModel.setValue( 0.1f+frnd(0.2f) ); - s->m_decModel.setValue( frnd(0.4f) ); + s->m_attModel.setValue(0.f); + s->m_holdModel.setValue(fastRandInc(0.1f, 0.3f)); + s->m_decModel.setValue(fastRandInc(0.4f)); - if(rnd(1)) + if (oneIn(2)) { s->m_susModel.setValue(fastRandInc(0.3f)); } + + if (oneIn(3)) { - s->m_susModel.setValue( frnd(0.3f) ); + s->m_phaserOffsetModel.setValue(fastRandInc(0.2f)); + s->m_phaserSweepModel.setValue(fastRandInc(-0.2f)); } - if(rnd(2)==0) - { - s->m_phaserOffsetModel.setValue( frnd(0.2f) ); - s->m_phaserSweepModel.setValue( -frnd(0.2f) ); - } - - if(rnd(1)) - s->m_hpFilCutModel.setValue( frnd(0.3f) ); + if (oneIn(2)) { s->m_hpFilCutModel.setValue(fastRandInc(0.3f)); } } - - void SfxrInstrumentView::genExplosion() { auto s = castModel(); s->resetModels(); - s->m_waveFormModel.setValue( 3 ); + s->m_waveFormModel.setValue(3); - if(rnd(1)) + if (oneIn(2)) { - s->m_startFreqModel.setValue( 0.1f+frnd(0.4f) ); - s->m_slideModel.setValue( -0.1f+frnd(0.4f) ); + s->m_startFreqModel.setValue(fastRandInc(0.1f, 0.5f)); + s->m_slideModel.setValue(fastRandInc(-0.1f, 0.3f)); } else { - s->m_startFreqModel.setValue( 0.2f+frnd(0.7f) ); - s->m_slideModel.setValue( -0.2f-frnd(0.2f) ); + s->m_startFreqModel.setValue(fastRandInc(0.2f, 0.9f)); + s->m_slideModel.setValue(fastRandInc(-0.4f, -0.2f)); } - s->m_startFreqModel.setValue( s->m_startFreqModel.value()*s->m_startFreqModel.value() ); + s->m_startFreqModel.setValue(s->m_startFreqModel.value() * s->m_startFreqModel.value()); - if(rnd(4)==0) + if (oneIn(5)) { s->m_slideModel.setValue(0.0f); } + if (oneIn(3)) { s->m_repeatSpeedModel.setValue(fastRandInc(0.3f, 0.8f)); } + + s->m_attModel.setValue(0.f); + s->m_holdModel.setValue(fastRandInc(0.1f, 0.4f)); + s->m_decModel.setValue(0.5f); + if (oneIn(2)) { - s->m_slideModel.setValue( 0.0f ); + s->m_phaserOffsetModel.setValue(fastRandInc(-0.3f, 0.6f)); + s->m_phaserSweepModel.setValue(fastRandInc(-0.3f)); + } + s->m_susModel.setValue(fastRandInc(0.2f, 0.8f)); + + if (oneIn(2)) + { + s->m_vibDepthModel.setValue(fastRandInc(0.7f)); + s->m_vibSpeedModel.setValue(fastRandInc(0.6f)); } - if(rnd(2)==0) + if (oneIn(3)) { - s->m_repeatSpeedModel.setValue( 0.3f+frnd(0.5f) ); + s->m_changeSpeedModel.setValue(fastRandInc(0.6f, 0.9f)); + s->m_changeAmtModel.setValue(fastRandInc(-0.8f, 0.8f)); } - - s->m_attModel.setValue( 0.0f ); - s->m_holdModel.setValue( 0.1f+frnd(0.3f) ); - s->m_decModel.setValue( 0.5f ); - if(rnd(1)==0) - { - s->m_phaserOffsetModel.setValue( -0.3f+frnd(0.9f) ); - s->m_phaserSweepModel.setValue( -frnd(0.3f) ); - } - s->m_susModel.setValue( 0.2f+frnd(0.6f) ); - - if(rnd(1)) - { - s->m_vibDepthModel.setValue( frnd(0.7f) ); - s->m_vibSpeedModel.setValue( frnd(0.6f) ); - } - if(rnd(2)==0) - { - s->m_changeSpeedModel.setValue( 0.6f+frnd(0.3f) ); - s->m_changeAmtModel.setValue( 0.8f-frnd(1.6f) ); - } - } - - void SfxrInstrumentView::genPowerup() { auto s = castModel(); s->resetModels(); - if(rnd(1)) - s->m_waveFormModel.setValue( 1 ); - else - s->m_sqrDutyModel.setValue( frnd(0.6f) ); - if(rnd(1)) + if (oneIn(2)) { s->m_waveFormModel.setValue(1); } + else { s->m_sqrDutyModel.setValue(fastRandInc(0.6f)); } + + if (oneIn(2)) { - s->m_startFreqModel.setValue( 0.2f+frnd(0.3f) ); - s->m_slideModel.setValue( 0.1f+frnd(0.4f) ); - s->m_repeatSpeedModel.setValue( 0.4f+frnd(0.4f) ); + s->m_startFreqModel.setValue(fastRandInc(0.2f, 0.5f)); + s->m_slideModel.setValue(fastRandInc(0.1f, 0.5f)); + s->m_repeatSpeedModel.setValue(fastRandInc(0.4f, 0.8f)); } else { - s->m_startFreqModel.setValue( 0.2f+frnd(0.3f) ); - s->m_slideModel.setValue( 0.05f+frnd(0.2f) ); - if(rnd(1)) + s->m_startFreqModel.setValue(fastRandInc(0.2f, 0.5f)); + s->m_slideModel.setValue(fastRandInc(0.05f, 0.25f)); + if (oneIn(2)) { - s->m_vibDepthModel.setValue( frnd(0.7f) ); - s->m_vibSpeedModel.setValue( frnd(0.6f) ); + s->m_vibDepthModel.setValue(fastRandInc(0.7f)); + s->m_vibSpeedModel.setValue(fastRandInc(0.6f)); } } - s->m_attModel.setValue( 0.0f ); - s->m_holdModel.setValue( frnd(0.4f) ); - s->m_decModel.setValue( 0.1f+frnd(0.4f) ); + s->m_attModel.setValue(0.0f); + s->m_holdModel.setValue(fastRandInc(0.4f)); + s->m_decModel.setValue(fastRandInc(0.1f, 0.5f)); } - - void SfxrInstrumentView::genHit() { auto s = castModel(); s->resetModels(); - s->m_waveFormModel.setValue( rnd(2) ); - if(s->m_waveFormModel.value()==2) - { - s->m_waveFormModel.setValue( 3 ); - } - if(s->m_waveFormModel.value()==0) - { - s->m_sqrDutyModel.setValue( frnd(0.6f) ); - } + s->m_waveFormModel.setValue(fastRandInc(2)); + if (s->m_waveFormModel.value() == 2) { s->m_waveFormModel.setValue(3); } + if (s->m_waveFormModel.value() == 0) { s->m_sqrDutyModel.setValue(fastRandInc(0.6f)); } - s->m_startFreqModel.setValue( 0.2f+frnd(0.6f) ); - s->m_slideModel.setValue( -0.3f-frnd(0.4f) ); - - s->m_attModel.setValue( 0.0f ); - s->m_holdModel.setValue( frnd(0.1f) ); - s->m_decModel.setValue( 0.1f+frnd(0.2f) ); - if(rnd(1)) - { - s->m_hpFilCutModel.setValue( frnd(0.3f) ); - } + s->m_startFreqModel.setValue(fastRandInc(0.2f, 0.8f)); + s->m_slideModel.setValue(fastRandInc(-0.7f, -0.3f)); + s->m_attModel.setValue(0.f); + s->m_holdModel.setValue(fastRandInc(0.1f)); + s->m_decModel.setValue(fastRandInc(0.1f, 0.3f)); + if (oneIn(2)) { s->m_hpFilCutModel.setValue(fastRandInc(0.3f)); } } - - void SfxrInstrumentView::genJump() { auto s = castModel(); s->resetModels(); - s->m_waveFormModel.setValue( 0 ); - s->m_sqrDutyModel.setValue( frnd(0.6f) ); + s->m_waveFormModel.setValue(0); + s->m_sqrDutyModel.setValue(fastRandInc(0.6f)); - s->m_startFreqModel.setValue( 0.3f+frnd(0.3f) ); - s->m_slideModel.setValue( 0.1f+frnd(0.2f) ); + s->m_startFreqModel.setValue(fastRandInc(0.3f, 0.6f)); + s->m_slideModel.setValue(fastRandInc(0.1f, 0.3f)); - s->m_attModel.setValue( 0.0f ); - s->m_holdModel.setValue( 0.1f+frnd(0.3f) ); - s->m_decModel.setValue( 0.1f+frnd(0.2f) ); - - if(rnd(1)) - { - s->m_hpFilCutModel.setValue( frnd(0.3f) ); - } - if(rnd(1)) - { - - s->m_lpFilCutModel.setValue( 1.0f-frnd(0.6f) ); - } + s->m_attModel.setValue(0.0f); + s->m_holdModel.setValue(fastRandInc(0.1f, 0.4f)); + s->m_decModel.setValue(fastRandInc(0.1f, 0.3f)); + if (oneIn(2)) { s->m_hpFilCutModel.setValue(fastRandInc(0.3f)); } + if (oneIn(2)) { s->m_lpFilCutModel.setValue(fastRandInc(0.4f, 1.f)); } } - - void SfxrInstrumentView::genBlip() { auto s = castModel(); s->resetModels(); - s->m_waveFormModel.setValue( rnd(1) ); - if( s->m_waveFormModel.value()==0 ) - { - s->m_sqrDutyModel.setValue( frnd(0.6f) ); - } + s->m_waveFormModel.setValue(fastRand() & 1); + if (s->m_waveFormModel.value() == 0) { s->m_sqrDutyModel.setValue(fastRandInc(0.6f)); } - s->m_startFreqModel.setValue( 0.2f+frnd(0.4f) ); - - s->m_attModel.setValue( 0.0f ); - s->m_holdModel.setValue( 0.1f+frnd(0.1f) ); - s->m_decModel.setValue( frnd(0.2f) ); - s->m_hpFilCutModel.setValue( 0.1f ); + s->m_startFreqModel.setValue(fastRandInc(0.2f, 0.6f)); + s->m_attModel.setValue(0.f); + s->m_holdModel.setValue(fastRandInc(0.1f, 0.2f)); + s->m_decModel.setValue(fastRandInc(0.2f)); + s->m_hpFilCutModel.setValue(0.1f); } +namespace +{ +// HACK This expands pow_hack<3>(5) to (5 * 5 * 5) to avoid actual pow() +template constexpr auto pow_hack(float x) { return x * pow_hack(x); } +template <> constexpr auto pow_hack<1>(float x) { return x; } +} void SfxrInstrumentView::randomize() { auto s = castModel(); - s->m_startFreqModel.setValue(std::pow(frnd(2.0f) - 1.0f, 2.0f)); - if(rnd(1)) + s->m_startFreqModel.setValue(pow_hack<2>(fastRandInc(-1.f, 1.f))); + if (oneIn(2)) { - s->m_startFreqModel.setValue(std::pow(frnd(2.0f) - 1.0f, 3.0f) + 0.5f); - } - s->m_minFreqModel.setValue( 0.0f ); - s->m_slideModel.setValue(std::pow(frnd(2.0f) - 1.0f, 5.0f)); - if( s->m_startFreqModel.value()>0.7f && s->m_slideModel.value()>0.2f ) - { - s->m_slideModel.setValue( -s->m_slideModel.value() ); - } - if( s->m_startFreqModel.value()<0.2f && s->m_slideModel.value()<-0.05f ) - { - s->m_slideModel.setValue( -s->m_slideModel.value() ); - } - s->m_dSlideModel.setValue(std::pow(frnd(2.0f) - 1.0f, 3.0f)); - - s->m_sqrDutyModel.setValue( frnd(2.0f)-1.0f ); - s->m_sqrSweepModel.setValue(std::pow(frnd(2.0f) - 1.0f, 3.0f)); - - s->m_vibDepthModel.setValue(std::pow(frnd(2.0f) - 1.0f, 3.0f)); - s->m_vibSpeedModel.setValue( frnd(2.0f)-1.0f ); - //s->m_vibDelayModel.setValue( frnd(2.0f)-1.0f ); - - s->m_attModel.setValue(std::pow(frnd(2.0f) - 1.0f, 3.0f)); - s->m_holdModel.setValue(std::pow(frnd(2.0f) - 1.0f, 2.0f)); - s->m_decModel.setValue( frnd(2.0f)-1.0f ); - s->m_susModel.setValue(std::pow(frnd(0.8f), 2.0f)); - if(s->m_attModel.value()+s->m_holdModel.value()+s->m_decModel.value()<0.2f) - { - s->m_holdModel.setValue( s->m_holdModel.value()+0.2f+frnd(0.3f) ); - s->m_decModel.setValue( s->m_decModel.value()+0.2f+frnd(0.3f) ); + s->m_startFreqModel.setValue(pow_hack<3>(fastRandInc(-1.f, 1.f)) + 0.5f); } - s->m_lpFilResoModel.setValue( frnd(2.0f)-1.0f ); - s->m_lpFilCutModel.setValue(1.0f - std::pow(frnd(1.0f), 3.0f)); - s->m_lpFilCutSweepModel.setValue(std::pow(frnd(2.0f) - 1.0f, 3.0f)); - if(s->m_lpFilCutModel.value()<0.1f && s->m_lpFilCutSweepModel.value()<-0.05f) + s->m_minFreqModel.setValue(0.0f); + s->m_slideModel.setValue(pow_hack<5>(fastRandInc(-1.f, 1.f))); + + if (s->m_startFreqModel.value() > 0.7f && s->m_slideModel.value() > 0.2f) { - s->m_lpFilCutSweepModel.setValue( -s->m_lpFilCutSweepModel.value() ); + s->m_slideModel.setValue(-s->m_slideModel.value()); } - s->m_hpFilCutModel.setValue(std::pow(frnd(1.0f), 5.0f)); - s->m_hpFilCutSweepModel.setValue(std::pow(frnd(2.0f) - 1.0f, 5.0f)); - s->m_phaserOffsetModel.setValue(std::pow(frnd(2.0f) - 1.0f, 3.0f)); - s->m_phaserSweepModel.setValue(std::pow(frnd(2.0f) - 1.0f, 3.0f)); + if (s->m_startFreqModel.value() < 0.2f && s->m_slideModel.value() < -0.05f) + { + s->m_slideModel.setValue(-s->m_slideModel.value()); + } - s->m_repeatSpeedModel.setValue( frnd(2.0f)-1.0f ); + s->m_dSlideModel.setValue(pow_hack<3>(fastRandInc(-1.f, 1.f))); - s->m_changeSpeedModel.setValue( frnd(2.0f)-1.0f ); - s->m_changeAmtModel.setValue( frnd(2.0f)-1.0f ); + s->m_sqrDutyModel.setValue(fastRandInc(-1.f, 1.f)); + s->m_sqrSweepModel.setValue(pow_hack<3>(fastRandInc(-1.f, 1.f))); + s->m_vibDepthModel.setValue(pow_hack<3>(fastRandInc(-1.f, 1.f))); + s->m_vibSpeedModel.setValue(fastRandInc(-1.f, 1.f)); + //s->m_vibDelayModel.setValue(fastRand(-1.f, 1.f)); + + s->m_attModel.setValue(pow_hack<3>(fastRandInc(-1.f, 1.f))); + s->m_holdModel.setValue(pow_hack<2>(fastRandInc(-1.f, 1.f))); + s->m_decModel.setValue(fastRandInc(-1.f, 1.f)); + s->m_susModel.setValue(pow_hack<2>(fastRandInc(0.8f))); + if (s->m_attModel.value() + s->m_holdModel.value() + s->m_decModel.value() < 0.2f) + { + s->m_holdModel.setValue(s->m_holdModel.value() + fastRandInc(0.2f, 0.5f)); + s->m_decModel.setValue(s->m_decModel.value() + fastRandInc(0.2f, 0.5f)); + } + + s->m_lpFilResoModel.setValue(fastRandInc(-1.f, 1.f)); + s->m_lpFilCutModel.setValue(1.0f - pow_hack<3>(fastRandInc(1.f))); + s->m_lpFilCutSweepModel.setValue(pow_hack<3>(fastRandInc(-1.f, 1.f))); + if (s->m_lpFilCutModel.value() < 0.1f && s->m_lpFilCutSweepModel.value() < -0.05f) + { + s->m_lpFilCutSweepModel.setValue(-s->m_lpFilCutSweepModel.value()); + } + s->m_hpFilCutModel.setValue(pow_hack<5>(fastRandInc(1.f))); + s->m_hpFilCutSweepModel.setValue(pow_hack<5>(fastRandInc(-1.f, 1.f))); + + s->m_phaserOffsetModel.setValue(pow_hack<3>(fastRandInc(-1.f, 1.f))); + s->m_phaserSweepModel.setValue(pow_hack<3>(fastRandInc(-1.f, 1.f))); + + s->m_repeatSpeedModel.setValue(fastRandInc(-1.f, 1.f)); + + s->m_changeSpeedModel.setValue(fastRandInc(-1.f, 1.f)); + s->m_changeAmtModel.setValue(fastRandInc(-1.f, 1.f)); } - - void SfxrInstrumentView::mutate() { auto s = castModel(); - if(rnd(1)) s->m_startFreqModel.setValue( s->m_startFreqModel.value()+frnd(0.1f)-0.05f ); - // if(rnd(1)) s->m_minFreqModel.setValue( s->m_minFreqModel.value()+frnd(0.1f)-0.05f ); - if(rnd(1)) s->m_slideModel.setValue( s->m_slideModel.value()+frnd(0.1f)-0.05f ); - if(rnd(1)) s->m_dSlideModel.setValue( s->m_dSlideModel.value()+frnd(0.1f)-0.05f ); + if (oneIn(2)) { s->m_startFreqModel.setValue(s->m_startFreqModel.value() + fastRandInc(-0.05f, 0.05f)); } + // if (oneIn(2)) { s->m_minFreqModel.setValue(s->m_minFreqModel.value() + fastRand(-0.05f, 0.05f))); } + if (oneIn(2)) { s->m_slideModel.setValue( s->m_slideModel.value() + fastRandInc(-0.05f, 0.05f)); } + if (oneIn(2)) { s->m_dSlideModel.setValue( s->m_dSlideModel.value() + fastRandInc(-0.05f, 0.05f)); } - if(rnd(1)) s->m_sqrDutyModel.setValue( s->m_sqrDutyModel.value()+frnd(0.1f)-0.05f ); - if(rnd(1)) s->m_sqrSweepModel.setValue( s->m_sqrSweepModel.value()+frnd(0.1f)-0.05f ); + if (oneIn(2)) { s->m_sqrDutyModel.setValue( s->m_sqrDutyModel.value() + fastRandInc(-0.05f, 0.05f)); } + if (oneIn(2)) { s->m_sqrSweepModel.setValue( s->m_sqrSweepModel.value() + fastRandInc(-0.05f, 0.05f)); } - if(rnd(1)) s->m_vibDepthModel.setValue( s->m_vibDepthModel.value()+frnd(0.1f)-0.05f ); - if(rnd(1)) s->m_vibSpeedModel.setValue( s->m_vibSpeedModel.value()+frnd(0.1f)-0.05f ); - // if(rnd(1)) s->m_vibDelayModel.setValue( s->m_vibDelayModel.value()+frnd(0.1f)-0.05f ); + if (oneIn(2)) { s->m_vibDepthModel.setValue( s->m_vibDepthModel.value() + fastRandInc(-0.05f, 0.05f)); } + if (oneIn(2)) { s->m_vibSpeedModel.setValue( s->m_vibSpeedModel.value() + fastRandInc(-0.05f, 0.05f)); } + // if (oneIn(2)) { s->m_vibDelayModel.setValue( s->m_vibDelayModel.value() + fastRand(-0.05f, 0.05f))); } - if(rnd(1)) s->m_attModel.setValue( s->m_attModel.value()+frnd(0.1f)-0.05f ); - if(rnd(1)) s->m_holdModel.setValue( s->m_holdModel.value()+frnd(0.1f)-0.05f ); - if(rnd(1)) s->m_decModel.setValue( s->m_decModel.value()+frnd(0.1f)-0.05f ); - if(rnd(1)) s->m_susModel.setValue( s->m_susModel.value()+frnd(0.1f)-0.05f ); + if (oneIn(2)) { s->m_attModel.setValue( s->m_attModel.value() + fastRandInc(-0.05f, 0.05f)); } + if (oneIn(2)) { s->m_holdModel.setValue( s->m_holdModel.value() + fastRandInc(-0.05f, 0.05f)); } + if (oneIn(2)) { s->m_decModel.setValue( s->m_decModel.value() + fastRandInc(-0.05f, 0.05f)); } + if (oneIn(2)) { s->m_susModel.setValue( s->m_susModel.value() + fastRandInc(-0.05f, 0.05f)); } - if(rnd(1)) s->m_lpFilResoModel.setValue( s->m_lpFilResoModel.value()+frnd(0.1f)-0.05f ); - if(rnd(1)) s->m_lpFilCutModel.setValue( s->m_lpFilCutModel.value()+frnd(0.1f)-0.05f ); - if(rnd(1)) s->m_lpFilCutSweepModel.setValue( s->m_lpFilCutSweepModel.value()+frnd(0.1f)-0.05f ); - if(rnd(1)) s->m_hpFilCutModel.setValue( s->m_hpFilCutModel.value()+frnd(0.1f)-0.05f ); - if(rnd(1)) s->m_hpFilCutSweepModel.setValue( s->m_hpFilCutSweepModel.value()+frnd(0.1f)-0.05f ); + if (oneIn(2)) { s->m_lpFilResoModel.setValue( s->m_lpFilResoModel.value() + fastRandInc(-0.05f, 0.05f)); } + if (oneIn(2)) { s->m_lpFilCutModel.setValue( s->m_lpFilCutModel.value() + fastRandInc(-0.05f, 0.05f)); } + if (oneIn(2)) { s->m_lpFilCutSweepModel.setValue( s->m_lpFilCutSweepModel.value() + fastRandInc(-0.05f, 0.05f)); } + if (oneIn(2)) { s->m_hpFilCutModel.setValue( s->m_hpFilCutModel.value() + fastRandInc(-0.05f, 0.05f)); } + if (oneIn(2)) { s->m_hpFilCutSweepModel.setValue( s->m_hpFilCutSweepModel.value() + fastRandInc(-0.05f, 0.05f)); } - if(rnd(1)) s->m_phaserOffsetModel.setValue( s->m_phaserOffsetModel.value()+frnd(0.1f)-0.05f ); - if(rnd(1)) s->m_phaserSweepModel.setValue( s->m_phaserSweepModel.value()+frnd(0.1f)-0.05f ); + if (oneIn(2)) { s->m_phaserOffsetModel.setValue( s->m_phaserOffsetModel.value() + fastRandInc(-0.05f, 0.05f)); } + if (oneIn(2)) { s->m_phaserSweepModel.setValue( s->m_phaserSweepModel.value() + fastRandInc(-0.05f, 0.05f)); } - if(rnd(1)) s->m_repeatSpeedModel.setValue( s->m_repeatSpeedModel.value()+frnd(0.1f)-0.05f ); - - if(rnd(1)) s->m_changeSpeedModel.setValue( s->m_changeSpeedModel.value()+frnd(0.1f)-0.05f ); - if(rnd(1)) s->m_changeAmtModel.setValue( s->m_changeAmtModel.value()+frnd(0.1f)-0.05f ); + if (oneIn(2)) { s->m_repeatSpeedModel.setValue( s->m_repeatSpeedModel.value() + fastRandInc(-0.05f, 0.05f)); } + if (oneIn(2)) { s->m_changeSpeedModel.setValue( s->m_changeSpeedModel.value() + fastRandInc(-0.05f, 0.05f)); } + if (oneIn(2)) { s->m_changeAmtModel.setValue( s->m_changeAmtModel.value() + fastRandInc(-0.05f, 0.05f)); } } - - void SfxrInstrumentView::previewSound() { auto s = castModel(); diff --git a/plugins/Sid/SidInstrument.cpp b/plugins/Sid/SidInstrument.cpp index 64bf0a091..64f0ce2cc 100644 --- a/plugins/Sid/SidInstrument.cpp +++ b/plugins/Sid/SidInstrument.cpp @@ -23,13 +23,12 @@ * */ +#include #include #include -#include - #include "SidInstrument.h" #include "AudioEngine.h" #include "Engine.h" @@ -37,20 +36,21 @@ #include "Knob.h" #include "NotePlayHandle.h" #include "PixmapButton.h" - +#include "lmms_math.h" #include "embed.h" #include "plugin_export.h" +namespace +{ +inline constexpr auto C64_PAL_CYCLES_PER_SEC = 985248; +inline constexpr auto NUMSIDREGS = 0x19; +inline constexpr auto SIDWRITEDELAY = 9; // lda $xxxx,x 4 cycles, sta $d400,x 5 cycles +inline constexpr auto SIDWAVEDELAY = 4; // and $xxxx,x 4 cycles extra +} + namespace lmms { - -#define C64_PAL_CYCLES_PER_SEC 985248 - -#define NUMSIDREGS 0x19 -#define SIDWRITEDELAY 9 // lda $xxxx,x 4 cycles, sta $d400,x 5 cycles -#define SIDWAVEDELAY 4 // and $xxxx,x 4 cycles extra - auto sidorder = std::array {0x15,0x16,0x18,0x17, 0x05,0x06,0x02,0x03,0x00,0x01,0x04, @@ -238,56 +238,49 @@ float SidInstrument::desiredReleaseTimeMs() const static int sid_fillbuffer(unsigned char* sidreg, reSID::SID *sid, int tdelta, short *ptr, int samples) { - int total = 0; -// customly added - int residdelay = 0; + int total = 0; + int badline = fastRand(NUMSIDREGS); + int residdelay = 0; // customly added - int badline = rand() % NUMSIDREGS; + for (int c = 0; c < NUMSIDREGS; ++c) + { + unsigned char o = sidorder[c]; - for (int c = 0; c < NUMSIDREGS; c++) - { - unsigned char o = sidorder[c]; + // Extra delay for loading the waveform (and mt_chngate,x) + if (o == 4 || o == 11 || o == 18) + { + auto dt = SIDWAVEDELAY; + const int result = sid->clock(dt, ptr, samples); + total += result; + ptr += result; + samples -= result; + tdelta -= SIDWAVEDELAY; + } - // Extra delay for loading the waveform (and mt_chngate,x) - if ((o == 4) || (o == 11) || (o == 18)) - { - int tdelta2 = SIDWAVEDELAY; - int result = sid->clock(tdelta2, ptr, samples); - total += result; - ptr += result; - samples -= result; - tdelta -= SIDWAVEDELAY; - } + // Possible random badline delay once per writing + if (badline == c && residdelay) + { + auto dt = residdelay; + const int result = sid->clock(dt, ptr, samples); + total += result; + ptr += result; + samples -= result; + tdelta -= residdelay; + } - // Possible random badline delay once per writing - if ((badline == c) && (residdelay)) - { - int tdelta2 = residdelay; - int result = sid->clock(tdelta2, ptr, samples); - total += result; - ptr += result; - samples -= result; - tdelta -= residdelay; - } + sid->write(o, sidreg[o]); - sid->write(o, sidreg[o]); - - int tdelta2 = SIDWRITEDELAY; - int result = sid->clock(tdelta2, ptr, samples); - total += result; - ptr += result; - samples -= result; - tdelta -= SIDWRITEDELAY; - } - int result = sid->clock(tdelta, ptr, samples); - total += result; - - return total; + auto dt = SIDWRITEDELAY; + const int result = sid->clock(dt, ptr, samples); + total += result; + ptr += result; + samples -= result; + tdelta -= SIDWRITEDELAY; + } + return total + sid->clock(tdelta, ptr, samples); } - - void SidInstrument::playNote( NotePlayHandle * _n, SampleFrame* _working_buffer ) { diff --git a/plugins/SpectrumAnalyzer/SaSpectrumView.cpp b/plugins/SpectrumAnalyzer/SaSpectrumView.cpp index 669b242ac..554a48a27 100644 --- a/plugins/SpectrumAnalyzer/SaSpectrumView.cpp +++ b/plugins/SpectrumAnalyzer/SaSpectrumView.cpp @@ -729,17 +729,18 @@ std::vector> SaSpectrumView::makeLogAmpTics(int lo // Base zoom level on selected range and how close is the current height // to the sizeHint() (denser scale for bigger window). - if ((high - low) < 20 * ((float)height() / sizeHint().height())) + const float heightScale = static_cast(height()) / sizeHint().height(); + if ((high - low) < 20 * heightScale) { - increment = fastPow10f(0.3f); // 3 dB steps when really zoomed in + increment = fastPow10f(0.3); // 3 dB steps when really zoomed in } - else if (high - low < 45 * ((float)height() / sizeHint().height())) + else if ((high - low) < 45 * heightScale) { - increment = fastPow10f(0.6f); // 6 dB steps when sufficiently zoomed in + increment = fastPow10f(0.6); // 6 dB steps when sufficiently zoomed in } else { - increment = 10; // 10 dB steps otherwise + increment = 10.0; // 10 dB steps otherwise } // Generate n dB increments, start checking at -90 dB. Limits are tweaked diff --git a/plugins/Stk/Mallets/Mallets.cpp b/plugins/Stk/Mallets/Mallets.cpp index 5c9c11cca..565c3ecef 100644 --- a/plugins/Stk/Mallets/Mallets.cpp +++ b/plugins/Stk/Mallets/Mallets.cpp @@ -307,26 +307,26 @@ void MalletsInstrument::playNote( NotePlayHandle * _n, if (p < 9) { - hardness += random * fastRand(-64.f, +64.f); + hardness += random * fastRandInc(-64.f, 64.f); hardness = std::clamp(hardness, 0.0f, 128.0f); - position += random * fastRand(-32.f, +32.f); + position += random * fastRandInc(-32.f, 32.f); position = std::clamp(position, 0.0f, 64.0f); } else if (p == 9) { - modulator += random * fastRand(-64.f, +64.f); + modulator += random * fastRandInc(-64.f, 64.f); modulator = std::clamp(modulator, 0.0f, 128.0f); - crossfade += random * fastRand(-64.f, +64.f); + crossfade += random * fastRandInc(-64.f, 64.f); crossfade = std::clamp(crossfade, 0.0f, 128.0f); } else { - pressure += random * fastRand(-64.f, +64.f); + pressure += random * fastRandInc(-64.f, 64.f); pressure = std::clamp(pressure, 0.0f, 128.0f); - speed += random * fastRand(-64.f, +64.f); + speed += random * fastRandInc(-64.f, 64.f); speed = std::clamp(speed, 0.0f, 128.0f); } diff --git a/plugins/Vibed/VibratingString.cpp b/plugins/Vibed/VibratingString.cpp index 00e178e24..b76bbe16b 100644 --- a/plugins/Vibed/VibratingString.cpp +++ b/plugins/Vibed/VibratingString.cpp @@ -40,7 +40,7 @@ VibratingString::VibratingString(float pitch, float pick, float pickup, const fl m_oversample{2 * oversample / static_cast(sampleRate / Engine::audioEngine()->baseSampleRate())}, m_randomize{randomize}, m_stringLoss{1.0f - stringLoss}, - m_choice{static_cast(m_oversample * static_cast(std::rand()) / static_cast(RAND_MAX))}, + m_choice(fastRandInc(m_oversample)), m_state{0.1f}, m_outsamp{std::make_unique(m_oversample)} { @@ -78,9 +78,7 @@ std::unique_ptr VibratingString::initDelayLine(int l dl->data = std::make_unique(len); for (int i = 0; i < dl->length; ++i) { - float r = static_cast(std::rand()) / static_cast(RAND_MAX); - float offset = (m_randomize / 2.0f - m_randomize) * r; - dl->data[i] = offset; + dl->data[i] = fastRandInc(m_randomize / 2.0f - m_randomize); } } else diff --git a/plugins/Vibed/VibratingString.h b/plugins/Vibed/VibratingString.h index 3f61e39f0..efaff966e 100644 --- a/plugins/Vibed/VibratingString.h +++ b/plugins/Vibed/VibratingString.h @@ -29,6 +29,7 @@ #include #include "LmmsTypes.h" +#include "lmms_math.h" namespace lmms { @@ -103,19 +104,16 @@ private: */ void setDelayLine(DelayLine* dl, int pick, const float* values, int len, float scale, bool state) { + const auto randAmt = m_randomize / 2.f - m_randomize; if (!state) { for (int i = 0; i < pick; ++i) { - float r = static_cast(std::rand()) / static_cast(RAND_MAX); - float offset = (m_randomize / 2.0f - m_randomize) * r; - dl->data[i] = scale * values[dl->length - i - 1] + offset; + dl->data[i] = scale * values[dl->length - i - 1] + fastRandInc(randAmt); } for (int i = pick; i < dl->length; ++i) { - float r = static_cast(std::rand()) / static_cast(RAND_MAX); - float offset = (m_randomize / 2.0f - m_randomize) * r; - dl->data[i] = scale * values[i - pick] + offset; + dl->data[i] = scale * values[i - pick] + fastRandInc(randAmt); } } else @@ -124,18 +122,14 @@ private: { for (int i = pick; i < dl->length; ++i) { - float r = static_cast(std::rand()) / static_cast(RAND_MAX); - float offset = (m_randomize / 2.0f - m_randomize) * r; - dl->data[i] = scale * values[i - pick] + offset; + dl->data[i] = scale * values[i - pick] + fastRandInc(randAmt); } } else { for (int i = 0; i < len; ++i) { - float r = static_cast(std::rand()) / static_cast(RAND_MAX); - float offset = (m_randomize / 2.0f - m_randomize) * r; - dl->data[i+pick] = scale * values[i] + offset; + dl->data[i+pick] = scale * values[i] + fastRandInc(randAmt); } } } diff --git a/src/core/DrumSynth.cpp b/src/core/DrumSynth.cpp index 6705d78b2..6f8afc7d3 100644 --- a/src/core/DrumSynth.cpp +++ b/src/core/DrumSynth.cpp @@ -294,8 +294,6 @@ int DrumSynth::GetDSFileSamples(QString dsfile, int16_t*& wave, int channels, sa long Length, tpos = 0, tplus, totmp, t, i, j; float x[3] = {0.f, 0.f, 0.f}; float MasterTune; - constexpr float randmax = 1.f / static_cast(RAND_MAX); - constexpr float randmax2 = 2.f / static_cast(RAND_MAX); int MainFilter, HighPass; long NON, NT, TON, DiON, TDroop = 0, DStep; @@ -366,7 +364,7 @@ int DrumSynth::GetDSFileSamples(QString dsfile, int16_t*& wave, int channels, sa timestretch *= Fs / 44100.f; DGain = 1.0f; // leave this here! - DGain = fastPow10f(0.05 * GetPrivateProfileFloat(sec, "Level", 0, dsfile)); + DGain = fastPow10f(0.05f * GetPrivateProfileFloat(sec, "Level", 0, dsfile)); MasterTune = GetPrivateProfileFloat(sec, "Tuning", 0.0, dsfile); MasterTune = std::pow(1.0594631f, MasterTune + mem_tune); @@ -399,9 +397,6 @@ int DrumSynth::GetDSFileSamples(QString dsfile, int16_t*& wave, int channels, sa g = NL; } - // if(GetPrivateProfileInt(sec,"FixedSeq",0,dsfile)!=0) - // srand(1); //fixed random sequence - // read tone parameters std::strcpy(sec, "Tone"); chkOn[0] = GetPrivateProfileInt(sec, "On", 0, dsfile); @@ -520,7 +515,7 @@ int DrumSynth::GetDSFileSamples(QString dsfile, int16_t*& wave, int channels, sa DAtten = DGain * static_cast(LoudestEnv()); clippoint = DAtten > 32700 ? 32700 : static_cast(DAtten); DAtten = std::exp2(2.0 * GetPrivateProfileInt(sec, "Bits", 0, dsfile)); - DGain = DAtten * DGain * fastPow10f(0.05 * GetPrivateProfileInt(sec, "Clipping", 0, dsfile)); + DGain = DAtten * DGain * fastPow10f(0.05f * GetPrivateProfileInt(sec, "Clipping", 0, dsfile)); } // prepare envelopes @@ -596,7 +591,7 @@ int DrumSynth::GetDSFileSamples(QString dsfile, int16_t*& wave, int channels, sa } x[2] = x[1]; x[1] = x[0]; - x[0] = (randmax2 * static_cast(rand())) - 1.f; + x[0] = fastRandInc(-1.f, 1.f); TT = a * x[0] + b * x[1] + c * x[2] + d * TT; DF[t - tpos] = TT * g * envData[2][ENV]; } @@ -671,7 +666,7 @@ int DrumSynth::GetDSFileSamples(QString dsfile, int16_t*& wave, int channels, sa } if ((t % BFStep) == 0) { - BdF = randmax * static_cast(rand()) - 0.5f; + BdF = fastRandInc(-0.5f, 0.5f); } BPhi = BPhi + BF + BQ * BdF; botmp = t - tpos; @@ -697,7 +692,7 @@ int DrumSynth::GetDSFileSamples(QString dsfile, int16_t*& wave, int channels, sa } if ((t % BFStep2) == 0) { - BdF2 = randmax * static_cast(rand()) - 0.5f; + BdF2 = fastRandInc(-0.5f, 0.5f); } BPhi2 = BPhi2 + BF2 + BQ2 * BdF2; botmp = t - tpos; diff --git a/src/core/InstrumentFunctions.cpp b/src/core/InstrumentFunctions.cpp index 4ed3751fe..de9c6c1d0 100644 --- a/src/core/InstrumentFunctions.cpp +++ b/src/core/InstrumentFunctions.cpp @@ -28,6 +28,7 @@ #include "embed.h" #include "Engine.h" #include "InstrumentTrack.h" +#include "lmms_math.h" #include "PresetPreviewPlayHandle.h" #include @@ -414,28 +415,20 @@ void InstrumentFunctionArpeggio::processNote( NotePlayHandle * _n ) frames_processed += remaining_frames_for_cur_arp; // Skip notes randomly - if( m_arpSkipModel.value() ) + if (m_arpSkipModel.value() && fastRandInc(100.f) <= m_arpSkipModel.value()) { - if (100 * static_cast(rand()) / (static_cast(RAND_MAX) + 1.0f) < m_arpSkipModel.value()) - { - // update counters - frames_processed += arp_frames; - cur_frame += arp_frames; - continue; - } + frames_processed += arp_frames; + cur_frame += arp_frames; + continue; } auto dir = static_cast(m_arpDirectionModel.value()); // Miss notes randomly. We intercept int dir and abuse it // after need. :) - - if( m_arpMissModel.value() ) + if (m_arpMissModel.value() && fastRandInc(100.f) <= m_arpMissModel.value()) { - if (100 * static_cast(rand()) / (static_cast(RAND_MAX) + 1.0f) < m_arpMissModel.value()) - { - dir = ArpDirection::Random; - } + dir = ArpDirection::Random; } int cur_arp_idx = 0; @@ -461,7 +454,7 @@ void InstrumentFunctionArpeggio::processNote( NotePlayHandle * _n ) else if( dir == ArpDirection::Random ) { // just pick a random chord-index - cur_arp_idx = static_cast(range * static_cast(rand()) / static_cast(RAND_MAX)); + cur_arp_idx = fastRandInc(range); } // Divide cur_arp_idx with wanted repeats. The repeat feature will not affect random notes. diff --git a/src/core/PeakController.cpp b/src/core/PeakController.cpp index e1bf0f1f8..27fc13ac6 100644 --- a/src/core/PeakController.cpp +++ b/src/core/PeakController.cpp @@ -189,7 +189,7 @@ PeakController * PeakController::getControllerBySetting(const QDomElement & _thi int effectId = _this.attribute( "effectId" ).toInt(); //Backward compatibility for bug in <= 0.4.15 . For >= 1.0.0 , - //foundCount should always be 1 because m_effectId is initialized with rand() + //foundCount should always be 1 because m_effectId is initialized with fastRand() int foundCount = 0; if( m_buggedFile == false ) { diff --git a/src/core/ProjectJournal.cpp b/src/core/ProjectJournal.cpp index ae17b2aa8..11e64810b 100644 --- a/src/core/ProjectJournal.cpp +++ b/src/core/ProjectJournal.cpp @@ -28,6 +28,7 @@ #include "ProjectJournal.h" #include "Engine.h" #include "JournallingObject.h" +#include "lmms_math.h" #include "Song.h" #include "AutomationClip.h" @@ -135,24 +136,15 @@ void ProjectJournal::addJournalCheckPoint( JournallingObject *jo ) } - - -jo_id_t ProjectJournal::allocID( JournallingObject * _obj ) +jo_id_t ProjectJournal::allocID(JournallingObject* obj) { jo_id_t id; - for( jo_id_t tid = rand(); m_joIDs.contains( id = tid % EO_ID_MSB - | EO_ID_MSB ); tid++ ) - { - } - - m_joIDs[id] = _obj; - //printf("new id: %d\n", id ); + for (jo_id_t tid = fastRand(); m_joIDs.contains(id = tid % EO_ID_MSB | EO_ID_MSB); tid++) {} + m_joIDs[id] = obj; return id; } - - void ProjectJournal::reallocID( const jo_id_t _id, JournallingObject * _obj ) { //printf("realloc %d %d\n", _id, _obj ); diff --git a/src/gui/MixerChannelView.cpp b/src/gui/MixerChannelView.cpp index 302f2b2e9..d3de94bef 100644 --- a/src/gui/MixerChannelView.cpp +++ b/src/gui/MixerChannelView.cpp @@ -46,6 +46,7 @@ #include "GuiApplication.h" #include "Knob.h" #include "LcdWidget.h" +#include "lmms_math.h" #include "Mixer.h" #include "MixerView.h" #include "PeakIndicator.h" @@ -322,7 +323,7 @@ void MixerChannelView::selectColor() void MixerChannelView::randomizeColor() { auto channel = mixerChannel(); - channel->setColor(ColorChooser::getPalette(ColorChooser::Palette::Mixer)[rand() % 48]); + channel->setColor(ColorChooser::getPalette(ColorChooser::Palette::Mixer)[fastRand(48)]); Engine::getSong()->setModified(); update(); } diff --git a/src/gui/clips/ClipView.cpp b/src/gui/clips/ClipView.cpp index 37ee4c29d..6bc0e28d5 100644 --- a/src/gui/clips/ClipView.cpp +++ b/src/gui/clips/ClipView.cpp @@ -40,6 +40,7 @@ #include "embed.h" #include "GuiApplication.h" #include "KeyboardShortcuts.h" +#include "lmms_math.h" #include "MidiClipView.h" #include "PatternClip.h" #include "PatternStore.h" @@ -353,7 +354,7 @@ void ClipView::selectColor() void ClipView::randomizeColor() { - setColor(ColorChooser::getPalette(ColorChooser::Palette::Mixer)[std::rand() % 48]); + setColor(ColorChooser::getPalette(ColorChooser::Palette::Mixer)[fastRand(48)]); } void ClipView::resetColor() diff --git a/src/gui/tracks/TrackOperationsWidget.cpp b/src/gui/tracks/TrackOperationsWidget.cpp index 458877701..16c0ca3e4 100644 --- a/src/gui/tracks/TrackOperationsWidget.cpp +++ b/src/gui/tracks/TrackOperationsWidget.cpp @@ -41,6 +41,7 @@ #include "embed.h" #include "Engine.h" #include "InstrumentTrackView.h" +#include "lmms_math.h" #include "KeyboardShortcuts.h" #include "Song.h" #include "StringPairDrag.h" @@ -270,7 +271,7 @@ void TrackOperationsWidget::resetTrackColor() void TrackOperationsWidget::randomizeTrackColor() { - QColor buffer = ColorChooser::getPalette( ColorChooser::Palette::Track )[ rand() % 48 ]; + QColor buffer = ColorChooser::getPalette(ColorChooser::Palette::Track)[fastRand(48)]; auto track = m_trackView->getTrack(); track->addJournalCheckPoint(); track->setColor(buffer);