fixes #6354: Sample and Hold for LFO Controller (#6850)

* fixes #6354: Sample and Hold for LFO Controller

LFO controller's "white noise" wave shape didn't respect the frequency knob at all, so
Sample-and-Hold was added to extend the functionality of the LFO Controller with this
random waveshape. The original functionallity can still be accessed by setting the
FREQ knob to minimum (0.01)

---------

Co-authored-by: Kevin Zander <veratil@gmail.com>
Co-authored-by: saker <sakertooth@gmail.com>
This commit is contained in:
consolegrl
2023-09-12 14:35:54 -04:00
committed by GitHub
parent 296d5736c8
commit b64912cd57
4 changed files with 50 additions and 4 deletions

View File

@@ -126,6 +126,7 @@ private:
void upgrade_defaultTripleOscillatorHQ();
void upgrade_mixerRename();
void upgrade_bbTcoRename();
void upgrade_sampleAndHold();
// List of all upgrade methods
static const std::vector<UpgradeMethod> UPGRADE_METHODS;

View File

@@ -86,6 +86,7 @@ protected:
sample_t (*m_sampleFunction)( const float );
private:
float m_heldSample;
SampleBuffer * m_userDefSampleBuffer;
protected slots:

View File

@@ -79,6 +79,7 @@ const std::vector<DataFile::UpgradeMethod> DataFile::UPGRADE_METHODS = {
&DataFile::upgrade_automationNodes , &DataFile::upgrade_extendedNoteRange,
&DataFile::upgrade_defaultTripleOscillatorHQ,
&DataFile::upgrade_mixerRename , &DataFile::upgrade_bbTcoRename,
&DataFile::upgrade_sampleAndHold ,
};
// Vector of all versions that have upgrade routines.
@@ -1762,6 +1763,23 @@ void DataFile::upgrade_bbTcoRename()
}
// Set LFO speed to 0.01 on projects made before sample-and-hold PR
void DataFile::upgrade_sampleAndHold()
{
QDomNodeList elements = elementsByTagName("lfocontroller");
for (int i = 0; i < elements.length(); ++i)
{
if (elements.item(i).isNull()) { continue; }
auto e = elements.item(i).toElement();
// Correct old random wave LFO speeds
if (e.attribute("wave").toInt() == 6)
{
e.setAttribute("speed",0.01f);
}
}
}
void DataFile::upgrade()
{
// Runs all necessary upgrade methods

View File

@@ -88,6 +88,7 @@ void LfoController::updateValueBuffer()
{
m_phaseOffset = m_phaseModel.value() / 360.0;
float phase = m_currentPhase + m_phaseOffset;
float phasePrev = 0.0f;
// roll phase up until we're in sync with period counter
m_bufferLastUpdated++;
@@ -102,20 +103,45 @@ void LfoController::updateValueBuffer()
ValueBuffer *amountBuffer = m_amountModel.valueBuffer();
int amountInc = amountBuffer ? 1 : 0;
float *amountPtr = amountBuffer ? &(amountBuffer->values()[ 0 ] ) : &amount;
Oscillator::WaveShape waveshape = static_cast<Oscillator::WaveShape>(m_waveModel.value());
for( float& f : m_valueBuffer )
{
const float currentSample = m_sampleFunction != nullptr
? m_sampleFunction( phase )
: m_userDefSampleBuffer->userWaveSample( phase );
float currentSample = 0;
switch (waveshape)
{
case Oscillator::WaveShape::WhiteNoise:
{
if (absFraction(phase) < absFraction(phasePrev))
{
// Resample when phase period has completed
m_heldSample = m_sampleFunction(phase);
}
currentSample = m_heldSample;
break;
}
case Oscillator::WaveShape::UserDefined:
{
currentSample = m_userDefSampleBuffer->userWaveSample(phase);
break;
}
default:
{
if (m_sampleFunction != nullptr)
{
currentSample = m_sampleFunction(phase);
}
}
}
f = std::clamp(m_baseModel.value() + (*amountPtr * currentSample / 2.0f), 0.0f, 1.0f);
phasePrev = phase;
phase += 1.0 / m_duration;
amountPtr += amountInc;
}
m_currentPhase = absFraction( phase - m_phaseOffset );
m_currentPhase = absFraction(phase - m_phaseOffset);
m_bufferLastUpdated = s_periods;
}