Compare commits

...

26 Commits

Author SHA1 Message Date
Your Name
c39da2f8cc vibefix disintegrator
Some checks failed
build / linux-arm64 (push) Has been cancelled
build / macos-arm64 (push) Has been cancelled
build / macos-x86_64 (push) Has been cancelled
build / mingw64 (push) Has been cancelled
checks / scripted-checks (push) Has been cancelled
build / linux-x86_64 (push) Has been cancelled
build / msvc-x64 (push) Has been cancelled
checks / shellcheck (push) Has been cancelled
build / windows-arm64 (push) Has been cancelled
checks / yamllint (push) Has been cancelled
2026-03-15 04:50:00 +01:00
Your Name
bec763a179 Merge branch 'disintegrator' 2026-03-15 03:20:19 +01:00
Robert Daniel Black
88ea50dd3e Optimize 2020-12-27 20:10:19 -07:00
Robert Daniel Black
5384c5d286 Fix more stuff 2020-12-27 20:05:58 -07:00
Robert Daniel Black
5665902ce0 Fix Amount knob units 2020-12-27 11:59:32 -07:00
Robert Daniel Black
1235e419d3 Fix stuff 2020-12-27 11:21:51 -07:00
Hyunjin Song
fa0f436683 Apply suggestions from code review 2020-12-10 13:18:48 +09:00
root
ee0420a67f Make effect work correctly with sample rate changes 2020-04-19 08:21:23 -06:00
root
7e231b8b2d Remove newline in untouched file 2020-04-18 14:50:16 -06:00
root
624b2f24df Put some duplicate code into for loops 2020-04-18 14:48:29 -06:00
root
89f05018c3 Resolve code/style reviews 2020-04-18 14:43:26 -06:00
Lost Robot
06024b85e7 Fix knob ranges 2019-11-23 18:06:03 -07:00
Lost Robot
d2cb54f6e6 Hippity hoppity squash and merge hides this probably 2019-11-23 17:45:19 -07:00
Lost Robot
ee442e8fdc Merge branch 'master' into disintegrator 2019-11-23 17:40:28 -07:00
root
02b9a2e6d6 Minor CPU boost I missed 2019-09-03 21:12:45 -06:00
root
4556151c03 Clip modulator at 0db for self-modulation mode 2019-08-30 12:00:45 -06:00
root
6b09fce36d Add self-modulation mode 2019-08-30 11:31:26 -06:00
root
328c7654ab Increase buffer size to correct amount 2019-08-30 10:23:30 -06:00
root
5a4670eac2 Changed filters to use BasicFilters.h, fixed crashing bug (caused by last commit). 2019-08-30 07:34:36 -06:00
root
6a44a51b5a Resolve code/style reviews 2019-08-29 21:08:52 -06:00
root
2fce224480 Added comments, removed unnecessary detuneWithOctaves function. 2019-08-29 20:44:49 -06:00
root
a630f32f21 Add Disintegrator effect 2019-08-29 19:59:24 -06:00
root
e83d44a56e Add Disintegrator effect 2019-08-29 19:59:03 -06:00
Lost Robot
a332d471c9 Merge pull request #12 from LMMS/master
Master
2019-08-29 19:47:29 -06:00
Lost Robot
0bb50a8604 Merge pull request #11 from LMMS/master
Master
2019-08-07 08:29:09 -06:00
Lost Robot
7f1c954f5a Merge pull request #8 from LMMS/master
Master
2019-06-21 15:09:34 -06:00
10 changed files with 658 additions and 0 deletions

View File

@@ -34,6 +34,7 @@ SET(LMMS_PLUGIN_LIST
CrossoverEQ
Delay
Dispersion
Disintegrator
DualFilter
DynamicsProcessor
Eq

View File

@@ -0,0 +1,3 @@
INCLUDE(BuildPlugin)
BUILD_PLUGIN(disintegrator Disintegrator.cpp DisintegratorControls.cpp DisintegratorControlDialog.cpp MOCFILES DisintegratorControls.h DisintegratorControlDialog.h EMBEDDED_RESOURCES artwork.png logo.png)

View File

@@ -0,0 +1,237 @@
/*
* Disintegrator.cpp
*
* Copyright (c) 2019 Lost Robot <r94231@gmail.com>
*
* This file is part of LMMS - https://lmms.io
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program (see COPYING); if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA.
*
*/
#include "Disintegrator.h"
#include "Engine.h"
#include "embed.h"
#include "lmms_math.h"
#include "plugin_export.h"
#include <numbers>
namespace lmms
{
extern "C"
{
Plugin::Descriptor PLUGIN_EXPORT disintegrator_plugin_descriptor =
{
LMMS_STRINGIFY(PLUGIN_NAME),
"Disintegrator",
QT_TRANSLATE_NOOP("PluginBrowser", "A delay modulation effect for very aggressive digital distortion."),
"Lost Robot <r94231@gmail.com>",
0x0100,
Plugin::Type::Effect,
new PixmapLoader("logo"),
nullptr,
nullptr
} ;
}
DisintegratorEffect::DisintegratorEffect(Model* parent, const Descriptor::SubPluginFeatures::Key* key) :
Effect(&disintegrator_plugin_descriptor, parent, key),
m_disintegratorControls(this),
m_needsUpdate(true)
{
sampleRateChanged();
}
void DisintegratorEffect::sampleRateChanged()
{
m_sampleRate = Engine::audioEngine()->outputSampleRate();
m_2PiOverSR = 2.0f * std::numbers::pi_v<float> / m_sampleRate;
m_lp = new BasicFilters<2>(Engine::audioEngine()->outputSampleRate());
m_hp = new BasicFilters<2>(Engine::audioEngine()->outputSampleRate());
m_lp->setFilterType(BasicFilters<2>::FilterType::LowPass);
m_hp->setFilterType(BasicFilters<2>::FilterType::HiPass);
m_needsUpdate = true;
m_bufferSize = m_sampleRate * 0.01f + 1.f;
for (int i = 0; i < 2; ++i)
{
m_inBuf[i].resize(m_bufferSize);
}
}
Effect::ProcessStatus DisintegratorEffect::processImpl(SampleFrame* buf, const fpp_t frames)
{
const float d = dryLevel();
const float w = wetLevel();
const ValueBuffer * amountBuf = m_disintegratorControls.m_amountModel.valueBuffer();
const ValueBuffer * typeBuf = m_disintegratorControls.m_typeModel.valueBuffer();
const ValueBuffer * freqBuf = m_disintegratorControls.m_lowCutModel.valueBuffer();
// Update filters
if(m_needsUpdate || m_disintegratorControls.m_highCutModel.isValueChanged())
{
m_lp->calcFilterCoeffs(m_disintegratorControls.m_highCutModel.value(), 0.5);
}
if(m_needsUpdate || m_disintegratorControls.m_lowCutModel.isValueChanged())
{
m_hp->calcFilterCoeffs(m_disintegratorControls.m_lowCutModel.value(), 0.5);
}
m_needsUpdate = false;
for (fpp_t f = 0; f < frames; ++f)
{
const float amount = (amountBuf ? amountBuf->value(f) : m_disintegratorControls.m_amountModel.value()) * 0.001f * m_sampleRate;
const int type = typeBuf ? typeBuf->value(f) : m_disintegratorControls.m_typeModel.value();
const float freq = freqBuf ? freqBuf->value(f) : m_disintegratorControls.m_freqModel.value();
sample_t s[2] = {buf[f][0], buf[f][1]};
// Increment buffer read point
++m_inBufLoc;
if (m_inBufLoc >= m_bufferSize)
{
m_inBufLoc = 0;
}
// Write dry input to buffer
m_inBuf[0][m_inBufLoc] = s[0];
m_inBuf[1][m_inBufLoc] = s[1];
float newInBufLoc[2] = {0, 0};
float newInBufLocFrac[2] = {0, 0};
// Generate white noise or sine wave, apply filters, subtract the
// result from the buffer read point and store in a variable.
SampleFrame delayModInput;
switch (type)
{
case 0://Mono Noise
{
delayModInput[0] = fastRand(2.0f) - 1.0f;
delayModInput[1] = delayModInput[0];
break;
}
case 1://Stereo Noise
{
delayModInput[0] = fastRand(2.0f) - 1.0f;
delayModInput[1] = fastRand(2.0f) - 1.0f;
break;
}
case 2://Sine Wave
{
m_sineLoc = fmod(m_sineLoc + (freq * m_2PiOverSR), 2.0f * std::numbers::pi_v<float>);
delayModInput[0] = sin(m_sineLoc);
delayModInput[1] = delayModInput[0];
break;
}
case 3:// Self-Modulation
{
delayModInput[0] = qBound(-1.f, s[0], 1.f);
delayModInput[1] = qBound(-1.f, s[1], 1.f);
break;
}
}
for (int i = 0; i < 2; ++i)
{
newInBufLoc[i] = delayModInput[i];
if (type != 2)// Sine mode doesn't use filters
{
newInBufLoc[i] = m_hp->update(newInBufLoc[i], i);
newInBufLoc[i] = m_lp->update(newInBufLoc[i], i);
}
newInBufLoc[i] = (newInBufLoc[i] + 1) * 0.5f;
newInBufLoc[i] = realfmod(m_inBufLoc - newInBufLoc[i] * amount, m_bufferSize);
// Distance between samples
newInBufLocFrac[i] = fmod(newInBufLoc[i], 1);
}
for (int i = 0; i < 2; ++i)
{
if (newInBufLocFrac[i] == 0)
{
s[i] = m_inBuf[i][newInBufLoc[i]];
}
else
{
if (newInBufLoc[i] < m_bufferSize - 1)
{
s[i] = m_inBuf[i][floor(newInBufLoc[i])] * (1 - newInBufLocFrac[i]) + m_inBuf[i][ceil(newInBufLoc[i])] * newInBufLocFrac[i];
}
else// For when the interpolation wraps around to the beginning of the buffer
{
s[i] = m_inBuf[i][m_bufferSize - 1] * (1 - newInBufLocFrac[i]) + m_inBuf[i][0] * newInBufLocFrac[i];
}
}
}
buf[f][0] = d * buf[f][0] + w * s[0];
buf[f][1] = d * buf[f][1] + w * s[1];
}
return ProcessStatus::ContinueIfNotQuiet;
}
// Handles negative values properly, unlike fmod.
inline float DisintegratorEffect::realfmod(float k, float n)
{
float r = fmod(k, n);
return r < 0 ? r + n : r;
}
void DisintegratorEffect::clearFilterHistories()
{
m_lp->clearHistory();
m_hp->clearHistory();
}
extern "C"
{
// necessary for getting instance out of shared lib
PLUGIN_EXPORT Plugin * lmms_plugin_main(Model* parent, void* data)
{
return new DisintegratorEffect(parent, static_cast<const Plugin::Descriptor::SubPluginFeatures::Key *>(data));
}
}
} // namespace lmms

View File

@@ -0,0 +1,78 @@
/*
* Disintegrator.h
*
* Copyright (c) 2019 Lost Robot <r94231@gmail.com>
*
* This file is part of LMMS - https://lmms.io
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program (see COPYING); if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA.
*
*/
#ifndef DISINTEGRATOR_H
#define DISINTEGRATOR_H
#include "DisintegratorControls.h"
#include "BasicFilters.h"
#include "Effect.h"
#include "ValueBuffer.h"
namespace lmms
{
class DisintegratorEffect : public Effect
{
public:
DisintegratorEffect(Model* parent, const Descriptor::SubPluginFeatures::Key* key);
ProcessStatus processImpl(SampleFrame* buf, const fpp_t frames) override;
EffectControls* controls() override
{
return &m_disintegratorControls;
}
void sampleRateChanged();
inline float realfmod(float k, float n);
void clearFilterHistories();
private:
DisintegratorControls m_disintegratorControls;
std::vector<float> m_inBuf[2];
int m_inBufLoc = 0;
float m_sineLoc = 0;
BasicFilters<2> * m_lp;
BasicFilters<2> * m_hp;
bool m_needsUpdate;
float m_sampleRate;
float m_2PiOverSR;
float m_sampleRateMult;
int m_bufferSize = 500;
friend class DisintegratorControls;
} ;
} // namespace lmms
#endif

View File

@@ -0,0 +1,103 @@
/*
* DisintegratorControlDialog.cpp
*
* Copyright (c) 2019 Lost Robot <r94231@gmail.com>
*
* This file is part of LMMS - https://lmms.io
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program (see COPYING); if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA.
*
*/
#include <QLayout>
#include "DisintegratorControlDialog.h"
#include "DisintegratorControls.h"
#include "ComboBox.h"
#include "embed.h"
#include "Knob.h"
namespace lmms::gui
{
DisintegratorControlDialog::DisintegratorControlDialog(DisintegratorControls* controls) :
EffectControlDialog(controls),
m_controls(controls)
{
setAutoFillBackground(true);
QPalette pal;
pal.setBrush(backgroundRole(), PLUGIN_NAME::getIconPixmap("artwork"));
setPalette(pal);
setFixedSize(179, 97);
m_lowCutKnob = new Knob(KnobType::Bright26, this);
m_lowCutKnob -> move(70, 10);
m_lowCutKnob->setModel(&m_controls->m_lowCutModel);
m_lowCutKnob->setLabel(tr("LOW CUT"));
m_lowCutKnob->setHintText(tr("Low Cut:"), " Hz");
m_highCutKnob = new Knob(KnobType::Bright26, this);
m_highCutKnob -> move(125, 10);
m_highCutKnob->setModel(&m_controls->m_highCutModel);
m_highCutKnob->setLabel(tr("HIGH CUT"));
m_highCutKnob->setHintText(tr("High Cut:"), " Hz");
m_amountKnob = new Knob(KnobType::Bright26, this);
m_amountKnob -> move(15, 10);
m_amountKnob -> setVolumeKnob(true);
m_amountKnob->setModel(&m_controls->m_amountModel);
m_amountKnob->setLabel(tr("AMOUNT"));
m_amountKnob->setHintText(tr("Amount:"), " ms");
m_typeBox = new ComboBox(this);
m_typeBox->setGeometry(1000, 5, 149, 22);
QFont f = m_typeBox->font();
f.setPointSize(8);
m_typeBox->setFont(f);
m_typeBox->move(14, 65);
m_typeBox->setModel(&m_controls->m_typeModel);
m_freqKnob = new Knob(KnobType::Bright26, this);
m_freqKnob -> move(132, 10);
m_freqKnob->setModel(&m_controls->m_freqModel);
m_freqKnob->setLabel(tr("FREQ"));
m_freqKnob->setHintText(tr("Frequency:"), " Hz");
connect(&m_controls->m_typeModel, SIGNAL(dataChanged()), this, SLOT(updateKnobVisibility()));
emit m_controls->m_typeModel.dataChanged();// Needed to update knobs when view is opened
}
/* Switches between the lowcut/highcut and
frequency knobs depending on the modulation type. */
void DisintegratorControlDialog::updateKnobVisibility()
{
if (m_controls->m_typeModel.value() == 2)// Sine Mode
{
m_lowCutKnob->hide();
m_highCutKnob->hide();
m_freqKnob->show();
}
else
{
m_lowCutKnob->show();
m_highCutKnob->show();
m_freqKnob->hide();
}
}
} // namespace lmms::gui

View File

@@ -0,0 +1,65 @@
/*
* DisintegratorControlDialog.h
*
* Copyright (c) 2019 Lost Robot <r94231@gmail.com>
*
* This file is part of LMMS - https://lmms.io
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program (see COPYING); if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA.
*
*/
#ifndef DISINTEGRATOR_CONTROL_DIALOG_H
#define DISINTEGRATOR_CONTROL_DIALOG_H
#include "EffectControlDialog.h"
namespace lmms
{
class DisintegratorControls;
namespace gui
{
class ComboBox;
class Knob;
class DisintegratorControlDialog : public EffectControlDialog
{
Q_OBJECT
public:
DisintegratorControlDialog(DisintegratorControls* controls);
DisintegratorControls * m_controls;
private slots:
void updateKnobVisibility();
private:
Knob * m_lowCutKnob;
Knob * m_highCutKnob;
Knob * m_amountKnob;
ComboBox * m_typeBox;
Knob * m_freqKnob;
friend class DisintegratorControls;
};
} // namespace gui
} // namespace lmms
#endif

View File

@@ -0,0 +1,91 @@
/*
* DisintegratorControls.cpp
*
* Copyright (c) 2019 Lost Robot <r94231@gmail.com>
*
* This file is part of LMMS - https://lmms.io
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program (see COPYING); if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA.
*
*/
#include <QDomElement>
#include "DisintegratorControls.h"
#include "Disintegrator.h"
#include "Engine.h"
#include "Song.h"
namespace lmms
{
DisintegratorControls::DisintegratorControls(DisintegratorEffect* effect) :
EffectControls(effect),
m_effect(effect),
m_lowCutModel(20.0f, 20.0f, 20000.0f, 0.01f, this, tr("Low Cut Frequency")),
m_highCutModel(20000.0f, 20.0f, 20000.0f, 0.01f, this, tr("High Cut Frequency")),
m_amountModel(1.6f, 0.0f, 10.0f, 0.001f, this, tr("Amount")),
m_typeModel(this, tr("Type")),
m_freqModel(100.0f, 1.0f, 21050.0f, 0.01f, this, tr("Frequency"))
{
// All of these are much easier to tweak when logarithmic
m_lowCutModel.setScaleLogarithmic(true);
m_highCutModel.setScaleLogarithmic(true);
m_amountModel.setScaleLogarithmic(true);
m_freqModel.setScaleLogarithmic(true);
m_typeModel.addItem(tr("Mono Noise"));
m_typeModel.addItem(tr("Stereo Noise"));
m_typeModel.addItem(tr("Sine Wave"));
m_typeModel.addItem(tr("Self-Modulation"));
connect(Engine::audioEngine(), SIGNAL(sampleRateChanged()), this, SLOT(sampleRateChanged()));
}
void DisintegratorControls::saveSettings(QDomDocument& doc, QDomElement& _this)
{
m_lowCutModel.saveSettings(doc, _this, "lowCut");
m_highCutModel.saveSettings(doc, _this, "highCut");
m_amountModel.saveSettings(doc, _this, "amount");
m_typeModel.saveSettings(doc, _this, "type");
m_freqModel.saveSettings(doc, _this, "freq");
}
void DisintegratorControls::loadSettings(const QDomElement& _this)
{
m_lowCutModel.loadSettings(_this, "lowCut");
m_highCutModel.loadSettings(_this, "highCut");
m_amountModel.loadSettings(_this, "amount");
m_typeModel.loadSettings(_this, "type");
m_freqModel.loadSettings(_this, "freq");
m_effect->m_needsUpdate = true;
m_effect->clearFilterHistories();
}
void DisintegratorControls::sampleRateChanged()
{
m_effect->sampleRateChanged();
}
} // namespace lmms

View File

@@ -0,0 +1,80 @@
/*
* DisintegratorControls.h
*
* Copyright (c) 2019 Lost Robot <r94231@gmail.com>
*
* This file is part of LMMS - https://lmms.io
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program (see COPYING); if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA.
*
*/
#ifndef DISINTEGRATOR_CONTROLS_H
#define DISINTEGRATOR_CONTROLS_H
#include "DisintegratorControlDialog.h"
#include "ComboBoxModel.h"
#include "EffectControls.h"
namespace lmms
{
class DisintegratorEffect;
class DisintegratorControls : public EffectControls
{
Q_OBJECT
public:
DisintegratorControls(DisintegratorEffect* effect);
void saveSettings(QDomDocument & _doc, QDomElement & _parent) override;
void loadSettings(const QDomElement & _this) override;
inline QString nodeName() const override
{
return "DisintegratorControls";
}
int controlCount() override
{
return 5;
}
gui::EffectControlDialog* createView() override
{
return new gui::DisintegratorControlDialog(this);
}
private slots:
void sampleRateChanged();
private:
DisintegratorEffect* m_effect;
FloatModel m_lowCutModel;
FloatModel m_highCutModel;
FloatModel m_amountModel;
ComboBoxModel m_typeModel;
FloatModel m_freqModel;
friend class gui::DisintegratorControlDialog;
friend class DisintegratorEffect;
} ;
} // namespace lmms
#endif

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 774 B