Skip to content

Commit

Permalink
fixes #6354: Sample and Hold for LFO Controller (#6850)
Browse files Browse the repository at this point in the history
* 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 <[email protected]>
Co-authored-by: saker <[email protected]>
  • Loading branch information
3 people authored Sep 12, 2023
1 parent 296d573 commit b64912c
Show file tree
Hide file tree
Showing 4 changed files with 50 additions and 4 deletions.
1 change: 1 addition & 0 deletions include/DataFile.h
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ class LMMS_EXPORT DataFile : public QDomDocument
void upgrade_defaultTripleOscillatorHQ();
void upgrade_mixerRename();
void upgrade_bbTcoRename();
void upgrade_sampleAndHold();

// List of all upgrade methods
static const std::vector<UpgradeMethod> UPGRADE_METHODS;
Expand Down
1 change: 1 addition & 0 deletions include/LfoController.h
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ public slots:
sample_t (*m_sampleFunction)( const float );

private:
float m_heldSample;
SampleBuffer * m_userDefSampleBuffer;

protected slots:
Expand Down
18 changes: 18 additions & 0 deletions src/core/DataFile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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
Expand Down
34 changes: 30 additions & 4 deletions src/core/LfoController.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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++;
Expand All @@ -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;
}

Expand Down

0 comments on commit b64912c

Please sign in to comment.