diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt index 4f139f8b3..e12783bab 100644 --- a/plugins/CMakeLists.txt +++ b/plugins/CMakeLists.txt @@ -49,6 +49,7 @@ IF("${PLUGIN_LIST}" STREQUAL "") carlarack CrossoverEQ Delay + Disintegrator DualFilter dynamics_processor Eq diff --git a/plugins/Disintegrator/CMakeLists.txt b/plugins/Disintegrator/CMakeLists.txt new file mode 100644 index 000000000..7642f8138 --- /dev/null +++ b/plugins/Disintegrator/CMakeLists.txt @@ -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) diff --git a/plugins/Disintegrator/Disintegrator.cpp b/plugins/Disintegrator/Disintegrator.cpp new file mode 100644 index 000000000..6531f9468 --- /dev/null +++ b/plugins/Disintegrator/Disintegrator.cpp @@ -0,0 +1,279 @@ +/* + * Disintegrator.cpp + * + * Copyright (c) 2019 Lost Robot + * + * 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 "embed.h" +#include "lmms_math.h" +#include "plugin_export.h" + +extern "C" +{ + +Plugin::Descriptor PLUGIN_EXPORT disintegrator_plugin_descriptor = +{ + STRINGIFY(PLUGIN_NAME), + "Disintegrator", + QT_TRANSLATE_NOOP("pluginBrowser", "A delay modulation effect for creating very aggressive digital distortion."), + "Lost Robot ", + 0x0100, + Plugin::Effect, + new PluginPixmapLoader("logo"), + NULL, + NULL +} ; + +} + + + +DisintegratorEffect::DisintegratorEffect(Model* parent, const Descriptor::SubPluginFeatures::Key* key) : + Effect(&disintegrator_plugin_descriptor, parent, key), + m_disintegratorControls(this) +{ + for (int a = 0; a < 200; ++a) + { + for (int b = 0; b < 2; ++b) + { + m_inBuf[b].push_back(0); + } + } +} + + + + +DisintegratorEffect::~DisintegratorEffect() +{ +} + + + + +bool DisintegratorEffect::processAudioBuffer(sampleFrame* buf, const fpp_t frames) +{ + if (!isEnabled() || !isRunning ()) + { + return false; + } + + double outSum = 0.0; + const float d = dryLevel(); + const float w = wetLevel(); + + const ValueBuffer * lowCutBuf = m_disintegratorControls.m_lowCutModel.valueBuffer(); + const ValueBuffer * highCutBuf = m_disintegratorControls.m_highCutModel.valueBuffer(); + const ValueBuffer * amountBuf = m_disintegratorControls.m_amountModel.valueBuffer(); + const ValueBuffer * typeBuf = m_disintegratorControls.m_typeModel.valueBuffer(); + const ValueBuffer * freqBuf = m_disintegratorControls.m_lowCutModel.valueBuffer(); + + sample_rate_t sample_rate = Engine::mixer()->processingSampleRate(); + + for (fpp_t f = 0; f < frames; ++f) + { + const float lowCut = lowCutBuf ? lowCutBuf->value(f) : m_disintegratorControls.m_lowCutModel.value(); + const float highCut = highCutBuf ? highCutBuf->value(f) : m_disintegratorControls.m_highCutModel.value(); + const float amount = amountBuf ? amountBuf->value(f) : m_disintegratorControls.m_amountModel.value(); + const int type = typeBuf ? typeBuf->value(f) : m_disintegratorControls.m_typeModel.value(); + const float freq = freqBuf ? freqBuf->value(f) : m_disintegratorControls.m_freqModel.value(); + + outSum += buf[f][0]*buf[f][0] + buf[f][1]*buf[f][1]; + + sample_t s[2] = {buf[f][0], buf[f][1]}; + + ++m_inBufLoc; + if (m_inBufLoc >= 200) + { + m_inBufLoc = 0; + } + + m_inBuf[0][m_inBufLoc] = s[0]; + m_inBuf[1][m_inBufLoc] = s[1]; + + float newInBufLoc[2] = {0, 0}; + float newInBufLocFrac[2] = {0, 0}; + switch (type) + { + case 0:// Mono Noise + { + newInBufLoc[0] = fast_rand() / (float)FAST_RAND_MAX; + + calcHighpassFilter(newInBufLoc[0], newInBufLoc[0], 0, lowCut, 0.707, sample_rate); + calcLowpassFilter(newInBufLoc[0], newInBufLoc[0], 0, highCut, 0.707, sample_rate); + + newInBufLoc[0] = realfmod(m_inBufLoc - newInBufLoc[0] * amount, 200); + newInBufLoc[1] = newInBufLoc[0]; + + newInBufLocFrac[0] = fmod(newInBufLoc[0], 1); + newInBufLocFrac[1] = newInBufLocFrac[0]; + + break; + } + case 1:// Stereo Noise + { + newInBufLoc[0] = fast_rand() / (float)FAST_RAND_MAX; + newInBufLoc[1] = fast_rand() / (float)FAST_RAND_MAX; + + calcHighpassFilter(newInBufLoc[0], newInBufLoc[0], 0, lowCut, 0.707, sample_rate); + calcHighpassFilter(newInBufLoc[1], newInBufLoc[1], 1, lowCut, 0.707, sample_rate); + calcLowpassFilter(newInBufLoc[0], newInBufLoc[0], 0, highCut, 0.707, sample_rate); + calcLowpassFilter(newInBufLoc[1], newInBufLoc[1], 1, highCut, 0.707, sample_rate); + + newInBufLoc[0] = realfmod(m_inBufLoc - newInBufLoc[0] * amount, 200); + newInBufLoc[1] = realfmod(m_inBufLoc - newInBufLoc[1] * amount, 200); + + newInBufLocFrac[0] = fmod(newInBufLoc[0], 1); + newInBufLocFrac[1] = fmod(newInBufLoc[1], 1); + + break; + } + case 2:// Sine Wave + { + m_sineLoc = fmod(m_sineLoc + (freq / (float)sample_rate * F_2PI), F_2PI); + + newInBufLoc[0] = (sin(m_sineLoc) + 1) * 0.5f; + + newInBufLoc[0] = realfmod(m_inBufLoc - newInBufLoc[0] * amount, 200); + newInBufLoc[1] = newInBufLoc[0]; + + newInBufLocFrac[0] = fmod(newInBufLoc[0], 1); + newInBufLocFrac[1] = newInBufLocFrac[0]; + + break; + } + } + + for (int b = 0; b < 2; ++b) + { + if (fmod(newInBufLoc[b], 1) == 0) + { + s[b] = m_inBuf[b][newInBufLoc[b]]; + } + else + { + if (newInBufLoc[b] < 199) + { + s[b] = m_inBuf[b][floor(newInBufLoc[b])] * (1 - newInBufLocFrac[b]) + m_inBuf[b][ceil(newInBufLoc[b])] * newInBufLocFrac[b]; + } + else + { + s[b] = m_inBuf[b][199] * (1 - newInBufLocFrac[b]) + m_inBuf[b][0] * newInBufLocFrac[b]; + } + } + } + + buf[f][0] = d * buf[f][0] + w * s[0]; + buf[f][1] = d * buf[f][1] + w * s[1]; + } + + checkGate(outSum / frames); + + return isRunning(); +} + + + +inline void DisintegratorEffect::calcLowpassFilter(sample_t &outSamp, sample_t inSamp, int which, float lpCutoff, float resonance, sample_rate_t Fs) +{ + if (m_prevLPCutoff[which] != lpCutoff) + { + m_prevLPCutoff[which] = lpCutoff; + const float w0 = D_2PI * lpCutoff / Fs; + const float tempCosW0 = cos(w0); + const float alpha = sin(w0) / 0.3535f; + + m_LPa0 = 1 + alpha; + m_LPb0 = (1 - tempCosW0) * 0.5f; + m_LPb1 = 1 - tempCosW0; + m_LPa1 = -(2 * tempCosW0); + m_LPa2 = 1 - alpha; + } + + m_filtLPY[which][0] = (m_LPb0 * (inSamp + m_filtLPX[which][2]) + m_LPb1 * m_filtLPX[which][1] - m_LPa1 * m_filtLPY[which][1] - m_LPa2 * m_filtLPY[which][2]) / m_LPa0; + + m_filtLPX[which][2] = m_filtLPX[which][1]; + m_filtLPX[which][1] = inSamp; + m_filtLPY[which][2] = m_filtLPY[which][1]; + m_filtLPY[which][1] = m_filtLPY[which][0]; + + outSamp = m_filtLPY[which][0]; +} + + + +inline void DisintegratorEffect::calcHighpassFilter(sample_t &outSamp, sample_t inSamp, int which, float hpCutoff, float resonance, sample_rate_t Fs) +{ + if (m_prevHPCutoff[which] != hpCutoff) + { + m_prevHPCutoff[which] = hpCutoff; + const float w0 = D_2PI * hpCutoff / Fs; + const float tempCosW0 = cos(w0); + const float alpha = sin(w0) / 0.3535f; + + m_HPa0 = 1 + alpha; + m_HPb0 = (1 + tempCosW0) * 0.5f; + m_HPb1 = -(1 + tempCosW0); + m_HPa1 = -2 * tempCosW0; + m_HPa2 = 1 - alpha; + } + + m_filtHPY[which][0] = (m_HPb0 * (inSamp + m_filtHPX[which][2]) + m_HPb1 * m_filtHPX[which][1] - m_HPa1 * m_filtHPY[which][1] - m_HPa2 * m_filtHPY[which][2]) / m_HPa0; + + m_filtHPX[which][2] = m_filtHPX[which][1]; + m_filtHPX[which][1] = inSamp; + m_filtHPY[which][2] = m_filtHPY[which][1]; + m_filtHPY[which][1] = m_filtHPY[which][0]; + + outSamp = m_filtHPY[which][0]; +} + + + +// Takes input of original Hz and the number of cents to detune it by, and returns the detuned result in Hz. +inline float DisintegratorEffect::detuneWithOctaves(float pitchValue, float detuneValue) +{ + return pitchValue * std::exp2(detuneValue); +} + + + +// Handles negative values properly, unlike fmod. +inline float DisintegratorEffect::realfmod(float k, float n) +{ + return ((k = fmod(k,n)) < 0) ? k+n : k; +} + + + +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(data)); +} + +} + diff --git a/plugins/Disintegrator/Disintegrator.h b/plugins/Disintegrator/Disintegrator.h new file mode 100644 index 000000000..a206e4304 --- /dev/null +++ b/plugins/Disintegrator/Disintegrator.h @@ -0,0 +1,84 @@ +/* + * Disintegrator.h + * + * Copyright (c) 2019 Lost Robot + * + * 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 "Effect.h" +#include "ValueBuffer.h" + +class DisintegratorEffect : public Effect +{ +public: + DisintegratorEffect(Model* parent, const Descriptor::SubPluginFeatures::Key* key); + virtual ~DisintegratorEffect(); + virtual bool processAudioBuffer(sampleFrame* buf, const fpp_t frames); + + virtual EffectControls* controls() + { + return &m_disintegratorControls; + } + + inline float realfmod(float k, float n); + inline float detuneWithOctaves(float pitchValue, float detuneValue); + + inline void calcLowpassFilter(sample_t &outSamp, sample_t inSamp, int which, float lpCutoff, float resonance, sample_rate_t Fs); + inline void calcHighpassFilter(sample_t &outSamp, sample_t inSamp, int which, float lpCutoff, float resonance, sample_rate_t Fs); + + float m_filtLPX[2][3] = {{0}};// [filter number][samples back in time] + float m_filtLPY[2][3] = {{0}};// [filter number][samples back in time] + float m_prevLPCutoff[2] = {0}; + + float m_LPa0; + float m_LPb0; + float m_LPb1; + float m_LPa1; + float m_LPa2; + + float m_filtHPX[2][3] = {{0}};// [filter number][samples back in time] + float m_filtHPY[2][3] = {{0}};// [filter number][samples back in time] + float m_prevHPCutoff[2] = {0}; + + float m_HPa0; + float m_HPb0; + float m_HPb1; + float m_HPa1; + float m_HPa2; + +private: + DisintegratorControls m_disintegratorControls; + + std::vector m_inBuf[2]; + int m_inBufLoc = 0; + + float m_sineLoc = 0; + + friend class DisintegratorControls; + +} ; + +#endif diff --git a/plugins/Disintegrator/DisintegratorControlDialog.cpp b/plugins/Disintegrator/DisintegratorControlDialog.cpp new file mode 100644 index 000000000..a680f3c33 --- /dev/null +++ b/plugins/Disintegrator/DisintegratorControlDialog.cpp @@ -0,0 +1,97 @@ +/* + * DisintegratorControlDialog.cpp + * + * Copyright (c) 2019 Lost Robot + * + * 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 + +#include "DisintegratorControlDialog.h" +#include "DisintegratorControls.h" + +#include "embed.h" +#include "gui_templates.h" + + + +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(knobBright_26, 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(knobBright_26, 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(knobBright_26, 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:"), " samples"); + + m_typeBox = new ComboBox(this); + m_typeBox->setGeometry(1000, 5, 149, 22); + m_typeBox->setFont(pointSize<8>(m_typeBox->font())); + m_typeBox->move(14, 65); + m_typeBox->setModel(&m_controls->m_typeModel); + + m_freqKnob = new Knob(knobBright_26, 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 +} + + + +void DisintegratorControlDialog::updateKnobVisibility() +{ + if (m_controls->m_typeModel.value() == 2) + { + m_lowCutKnob->hide(); + m_highCutKnob->hide(); + m_freqKnob->show(); + } + else + { + m_lowCutKnob->show(); + m_highCutKnob->show(); + m_freqKnob->hide(); + } +} diff --git a/plugins/Disintegrator/DisintegratorControlDialog.h b/plugins/Disintegrator/DisintegratorControlDialog.h new file mode 100644 index 000000000..2c9938318 --- /dev/null +++ b/plugins/Disintegrator/DisintegratorControlDialog.h @@ -0,0 +1,60 @@ +/* + * DisintegratorControlDialog.h + * + * Copyright (c) 2019 Lost Robot + * + * 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 "ComboBox.h" +#include "EffectControlDialog.h" +#include "Knob.h" + + +class DisintegratorControls; + + +class DisintegratorControlDialog : public EffectControlDialog +{ + Q_OBJECT +public: + DisintegratorControlDialog(DisintegratorControls* controls); + DisintegratorControls * m_controls; + + virtual ~DisintegratorControlDialog() + { + } + +private slots: + void updateKnobVisibility(); + +private: + Knob * m_lowCutKnob; + Knob * m_highCutKnob; + Knob * m_amountKnob; + ComboBox * m_typeBox; + Knob * m_freqKnob; + + friend class DisintegratorControls; +}; + +#endif diff --git a/plugins/Disintegrator/DisintegratorControls.cpp b/plugins/Disintegrator/DisintegratorControls.cpp new file mode 100644 index 000000000..547b962b3 --- /dev/null +++ b/plugins/Disintegrator/DisintegratorControls.cpp @@ -0,0 +1,73 @@ +/* + * DisintegratorControls.cpp + * + * Copyright (c) 2019 Lost Robot + * + * 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 + +#include "DisintegratorControls.h" +#include "Disintegrator.h" + +#include "Engine.h" +#include "Song.h" + + +DisintegratorControls::DisintegratorControls(DisintegratorEffect* effect) : + EffectControls(effect), + m_effect(effect), + m_lowCutModel(2.0f, 2.0f, 21050.0f, 0.01f, this, tr("Low Cut")), + m_highCutModel(21050.0f, 2.0f, 21050.0f, 0.01f, this, tr("High Cut")), + m_amountModel(30.0f, 0.0f, 200.0f, 0.01f, this, tr("Amount")), + m_typeModel(this, tr("Type")), + m_freqModel(100.0f, 2.0f, 21050.0f, 0.01f, this, tr("Frequency")) +{ + 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")); +} + + +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"); +} diff --git a/plugins/Disintegrator/DisintegratorControls.h b/plugins/Disintegrator/DisintegratorControls.h new file mode 100644 index 000000000..c8611cf92 --- /dev/null +++ b/plugins/Disintegrator/DisintegratorControls.h @@ -0,0 +1,79 @@ +/* + * DisintegratorControls.h + * + * Copyright (c) 2019 Lost Robot + * + * 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 "ComboBox.h" +#include "EffectControls.h" +#include "Knob.h" + + +class DisintegratorEffect; + + +class DisintegratorControls : public EffectControls +{ + Q_OBJECT +public: + DisintegratorControls(DisintegratorEffect* effect); + virtual ~DisintegratorControls() + { + } + + virtual void saveSettings(QDomDocument & _doc, QDomElement & _parent); + virtual void loadSettings(const QDomElement & _this); + inline virtual QString nodeName() const + { + return "DisintegratorControls"; + } + + virtual int controlCount() + { + return 5; + } + + virtual EffectControlDialog* createView() + { + m_effectView = new DisintegratorControlDialog(this); + return m_effectView; + } + +private: + DisintegratorEffect* m_effect; + DisintegratorControlDialog * m_effectView; + + FloatModel m_lowCutModel; + FloatModel m_highCutModel; + FloatModel m_amountModel; + ComboBoxModel m_typeModel; + FloatModel m_freqModel; + + friend class DisintegratorControlDialog; + friend class DisintegratorEffect; +} ; + +#endif diff --git a/plugins/Disintegrator/OLD 1/CMakeLists.txt b/plugins/Disintegrator/OLD 1/CMakeLists.txt new file mode 100644 index 000000000..7642f8138 --- /dev/null +++ b/plugins/Disintegrator/OLD 1/CMakeLists.txt @@ -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) diff --git a/plugins/Disintegrator/OLD 1/Disintegrator.cpp b/plugins/Disintegrator/OLD 1/Disintegrator.cpp new file mode 100644 index 000000000..1f4139dc9 --- /dev/null +++ b/plugins/Disintegrator/OLD 1/Disintegrator.cpp @@ -0,0 +1,245 @@ +/* + * Disintegrator.cpp + * + * Copyright (c) 2019 Lost Robot + * + * 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 "embed.h" +#include "plugin_export.h" +#include "lmms_math.h" + +extern "C" +{ + +Plugin::Descriptor PLUGIN_EXPORT disintegrator_plugin_descriptor = +{ + STRINGIFY( PLUGIN_NAME ), + "Disintegrator", + QT_TRANSLATE_NOOP( "pluginBrowser", "A plugin generated by Lost Robot's LMMS Development Package. This is your plugin description. You should change this." ), + "Lost Robot ", + 0x0100, + Plugin::Effect, + new PluginPixmapLoader("logo"), + NULL, + NULL +} ; + +} + + + +DisintegratorEffect::DisintegratorEffect( Model* parent, const Descriptor::SubPluginFeatures::Key* key ) : + Effect( &disintegrator_plugin_descriptor, parent, key ), + m_disintegratorControls( this ) +{ + for( int a = 0; a < 100; ++a ) + { + for( int b = 0; b < 2; ++b ) + { + inBuf[b].push_back(0); + } + } +} + + + + +DisintegratorEffect::~DisintegratorEffect() +{ +} + + + + +bool DisintegratorEffect::processAudioBuffer( sampleFrame* buf, const fpp_t frames ) +{ + if( !isEnabled() || !isRunning () ) + { + return( false ); + } + + double outSum = 0.0; + const float d = dryLevel(); + const float w = wetLevel(); + + // ==TAG== MAKEVALUEBUFFERS ==TAG== // + const ValueBuffer * volBuf = m_disintegratorControls.m_volumeModel.valueBuffer(); + const ValueBuffer * panBuf = m_disintegratorControls.m_panModel.valueBuffer(); + const ValueBuffer * leftBuf = m_disintegratorControls.m_leftModel.valueBuffer(); + const ValueBuffer * rightBuf = m_disintegratorControls.m_rightModel.valueBuffer(); + // ==TAG== ENDMAKEVALUEBUFFERS ==TAG== // + + for( fpp_t f = 0; f < frames; ++f ) + { + // ==TAG== EVALUATEVALUEBUFFERS ==TAG== // + const float vol = volBuf ? volBuf->value( f ) : m_disintegratorControls.m_volumeModel.value(); + const float pan = panBuf ? panBuf->value( f ) : m_disintegratorControls.m_panModel.value(); + const float left = leftBuf ? leftBuf->value( f ) : m_disintegratorControls.m_leftModel.value(); + const float right = rightBuf ? rightBuf->value( f ) : m_disintegratorControls.m_rightModel.value(); + // ==TAG== ENDEVALUATEVALUEBUFFERS ==TAG== // + + outSum += buf[f][0]*buf[f][0] + buf[f][1]*buf[f][1]; + + sample_t s[2] = { buf[f][0], buf[f][1] }; + + ++inBufLoc; + if( inBufLoc >= 100 ) + { + inBufLoc = 0; + } + + inBuf[0][inBufLoc] = s[0]; + inBuf[1][inBufLoc] = s[1]; + + float newInBufLoc[2]; + newInBufLoc[0] = fast_rand() / (float)FAST_RAND_MAX; + newInBufLoc[1] = fast_rand() / (float)FAST_RAND_MAX; + + calcHighpassFilter( newInBufLoc[0], newInBufLoc[0], 0, vol, 0.707, Engine::mixer()->processingSampleRate() ); + calcHighpassFilter( newInBufLoc[1], newInBufLoc[1], 1, vol, 0.707, Engine::mixer()->processingSampleRate() ); + calcLowpassFilter( newInBufLoc[0], newInBufLoc[0], 0, pan, 0.707, Engine::mixer()->processingSampleRate() ); + calcLowpassFilter( newInBufLoc[1], newInBufLoc[1], 1, pan, 0.707, Engine::mixer()->processingSampleRate() ); + + newInBufLoc[0] = realfmod(inBufLoc - newInBufLoc[0] * left, 100); + newInBufLoc[1] = realfmod(inBufLoc - newInBufLoc[1] * left, 100); + + float newInBufLocFrac[2]; + newInBufLocFrac[0] = fmod(newInBufLoc[0], 1); + newInBufLocFrac[1] = fmod(newInBufLoc[1], 1); + + if( newInBufLoc[0] < 99 ) + { + s[0] = inBuf[0][floor(newInBufLoc[0])] * (1 - newInBufLocFrac[0]) + inBuf[0][ceil(newInBufLoc[0])] * newInBufLocFrac[0]; + } + else + { + s[0] = inBuf[0][99] * (1 - newInBufLocFrac[0]) + inBuf[0][0] * newInBufLocFrac[0]; + } + + if( newInBufLoc[1] < 99 ) + { + s[1] = inBuf[1][floor(newInBufLoc[1])] * (1 - newInBufLocFrac[1]) + inBuf[1][ceil(newInBufLoc[1])] * newInBufLocFrac[1]; + } + else + { + s[1] = inBuf[1][99] * (1 - newInBufLocFrac[1]) + inBuf[1][0] * newInBufLocFrac[1]; + } + + buf[f][0] = d * buf[f][0] + w * s[0]; + buf[f][1] = d * buf[f][1] + w * s[1]; + } + + checkGate( outSum / frames ); + + return isRunning(); +} + + + +inline void DisintegratorEffect::calcLowpassFilter( sample_t &outSamp, sample_t inSamp, int which, float lpCutoff, float resonance, sample_rate_t Fs ) +{ + const float m_w0 = D_2PI * lpCutoff / Fs; + + const float m_tempCosW0 = cos(m_w0); + const float m_alpha = sin(m_w0) / ( resonance / 2.f ); + const float m_b0 = (1 - m_tempCosW0) * 0.5f; + const float m_b1 = 1 - m_tempCosW0; + const float m_b2 = m_b0; + const float m_a0 = 1 + m_alpha; + const float m_a1 = -2 * m_tempCosW0; + const float m_a2 = 1 - m_alpha; + + const float m_temp1 = m_b0/m_a0; + const float m_temp2 = m_b1/m_a0; + const float m_temp3 = m_b2/m_a0; + const float m_temp4 = m_a1/m_a0; + const float m_temp5 = m_a2/m_a0; + filtLPY[which][0] = m_temp1*inSamp + m_temp2*filtLPX[which][1] + m_temp3*filtLPX[which][2] - m_temp4*filtLPY[which][1] - m_temp5*filtLPY[which][2]; + + filtLPX[which][2] = filtLPX[which][1]; + filtLPX[which][1] = inSamp; + filtLPY[which][2] = filtLPY[which][1]; + filtLPY[which][1] = filtLPY[which][0]; + + outSamp = filtLPY[which][0]; +} + + + +inline void DisintegratorEffect::calcHighpassFilter( sample_t &outSamp, sample_t inSamp, int which, float hpCutoff, float resonance, sample_rate_t Fs ) +{ + const float m_w0 = D_2PI * hpCutoff / Fs; + + const float m_tempCosW0 = cos(m_w0); + const float m_alpha = sin(m_w0) / ( resonance / 2.f ); + const float m_b0 = (1 + m_tempCosW0) * 0.5f; + const float m_b1 = -(1 + m_tempCosW0); + const float m_b2 = m_b0; + const float m_a0 = 1 + m_alpha; + const float m_a1 = -2 * m_tempCosW0; + const float m_a2 = 1 - m_alpha; + + const float m_temp1 = m_b0/m_a0; + const float m_temp2 = m_b1/m_a0; + const float m_temp3 = m_b2/m_a0; + const float m_temp4 = m_a1/m_a0; + const float m_temp5 = m_a2/m_a0; + filtHPY[which][0] = m_temp1*inSamp + m_temp2*filtHPX[which][1] + m_temp3*filtHPX[which][2] - m_temp4*filtHPY[which][1] - m_temp5*filtHPY[which][2]; + + filtHPX[which][2] = filtHPX[which][1]; + filtHPX[which][1] = inSamp; + filtHPY[which][2] = filtHPY[which][1]; + filtHPY[which][1] = filtHPY[which][0]; + + outSamp = filtHPY[which][0]; +} + + + +// Takes input of original Hz and the number of cents to detune it by, and returns the detuned result in Hz. +inline float DisintegratorEffect::detuneWithOctaves(float pitchValue, float detuneValue) +{ + return pitchValue * std::exp2(detuneValue); +} + + + +// Handles negative values properly, unlike fmod. +inline float DisintegratorEffect::realfmod(float k, float n) +{ + return ((k = fmod(k,n)) < 0) ? k+n : k; +} + + + +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( data ) ); +} + +} + diff --git a/plugins/Disintegrator/OLD 1/Disintegrator.h b/plugins/Disintegrator/OLD 1/Disintegrator.h new file mode 100644 index 000000000..80b1ee3cc --- /dev/null +++ b/plugins/Disintegrator/OLD 1/Disintegrator.h @@ -0,0 +1,67 @@ +/* + * Disintegrator.h + * + * Copyright (c) 2019 Lost Robot + * + * 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 "Effect.h" +#include "DisintegratorControls.h" +#include "ValueBuffer.h" + +class DisintegratorEffect : public Effect +{ +public: + DisintegratorEffect( Model* parent, const Descriptor::SubPluginFeatures::Key* key ); + virtual ~DisintegratorEffect(); + virtual bool processAudioBuffer( sampleFrame* buf, const fpp_t frames ); + + virtual EffectControls* controls() + { + return &m_disintegratorControls; + } + + inline float realfmod(float k, float n); + inline float detuneWithOctaves(float pitchValue, float detuneValue); + + inline void calcLowpassFilter( sample_t &outSamp, sample_t inSamp, int which, float lpCutoff, float resonance, sample_rate_t Fs ); + inline void calcHighpassFilter( sample_t &outSamp, sample_t inSamp, int which, float lpCutoff, float resonance, sample_rate_t Fs ); + + float filtLPX[2][3] = {0};// [filter number][samples back in time] + float filtLPY[2][3] = {0};// [filter number][samples back in time] + + float filtHPX[2][3] = {0};// [filter number][samples back in time] + float filtHPY[2][3] = {0};// [filter number][samples back in time] + +private: + DisintegratorControls m_disintegratorControls; + + std::vector inBuf[2]; + int inBufLoc = 0; + + friend class DisintegratorControls; + +} ; + +#endif diff --git a/plugins/Disintegrator/OLD 1/DisintegratorControlDialog.cpp b/plugins/Disintegrator/OLD 1/DisintegratorControlDialog.cpp new file mode 100644 index 000000000..3dbc63c8a --- /dev/null +++ b/plugins/Disintegrator/OLD 1/DisintegratorControlDialog.cpp @@ -0,0 +1,70 @@ +/* + * DisintegratorControlDialog.cpp + * + * Copyright (c) 2019 Lost Robot + * + * 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 + +#include "DisintegratorControlDialog.h" +#include "DisintegratorControls.h" +#include "embed.h" + + + +DisintegratorControlDialog::DisintegratorControlDialog( DisintegratorControls* controls ) : + EffectControlDialog( controls ) +{ + setAutoFillBackground( true ); + QPalette pal; + pal.setBrush( backgroundRole(), PLUGIN_NAME::getIconPixmap( "artwork" ) ); + setPalette( pal ); + setFixedSize( 100, 110 ); + + // ==TAG== INITIALIZEWIDGETS ==TAG== // + Knob * volumeKnob = new Knob( knobBright_26, this); + volumeKnob -> move( 16, 10 ); + volumeKnob -> setVolumeKnob( true ); + volumeKnob->setModel( &controls->m_volumeModel ); + volumeKnob->setLabel( tr( "VOL" ) ); + volumeKnob->setHintText( tr( "Volume:" ) , "%" ); + + Knob * panKnob = new Knob( knobBright_26, this); + panKnob -> move( 57, 10 ); + panKnob->setModel( &controls->m_panModel ); + panKnob->setLabel( tr( "PAN" ) ); + panKnob->setHintText( tr( "Panning:" ) , "" ); + + Knob * leftKnob = new Knob( knobBright_26, this); + leftKnob -> move( 16, 65 ); + leftKnob -> setVolumeKnob( true ); + leftKnob->setModel( &controls->m_leftModel ); + leftKnob->setLabel( tr( "LEFT" ) ); + leftKnob->setHintText( tr( "Left gain:" ) , "%" ); + + Knob * rightKnob = new Knob( knobBright_26, this); + rightKnob -> move( 57, 65 ); + rightKnob -> setVolumeKnob( true ); + rightKnob->setModel( &controls->m_rightModel ); + rightKnob->setLabel( tr( "RIGHT" ) ); + rightKnob->setHintText( tr( "Right gain:" ) , "%" ); + // ==TAG== ENDINITIALIZEWIDGETS ==TAG== // +} diff --git a/plugins/Disintegrator/OLD 1/DisintegratorControlDialog.h b/plugins/Disintegrator/OLD 1/DisintegratorControlDialog.h new file mode 100644 index 000000000..89d270130 --- /dev/null +++ b/plugins/Disintegrator/OLD 1/DisintegratorControlDialog.h @@ -0,0 +1,45 @@ +/* + * DisintegratorControlDialog.h + * + * Copyright (c) 2019 Lost Robot + * + * 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" + + +class DisintegratorControls; + + +class DisintegratorControlDialog : public EffectControlDialog +{ + Q_OBJECT +public: + DisintegratorControlDialog( DisintegratorControls* controls ); + virtual ~DisintegratorControlDialog() + { + } + +} ; + +#endif diff --git a/plugins/Disintegrator/OLD 1/DisintegratorControls.cpp b/plugins/Disintegrator/OLD 1/DisintegratorControls.cpp new file mode 100644 index 000000000..47fc5d295 --- /dev/null +++ b/plugins/Disintegrator/OLD 1/DisintegratorControls.cpp @@ -0,0 +1,69 @@ +/* + * DisintegratorControls.cpp + * + * Copyright (c) 2019 Lost Robot + * + * 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 + +#include "DisintegratorControls.h" +#include "Disintegrator.h" +#include "Engine.h" +#include "Song.h" + + +DisintegratorControls::DisintegratorControls( DisintegratorEffect* effect ) : + EffectControls( effect ), + m_effect( effect ), + // ==TAG== INITIALIZEMODELS ==TAG== // + m_volumeModel( 20.0f, 20.0f, 21050.0f, 0.001f, this, tr( "Volume" ) ), + m_panModel( 20.0f, 20.0f, 21050.0f, 0.001f, this, tr( "Panning" ) ), + m_leftModel( 50.0f, 0.0f, 100.0f, 0.001f, this, tr( "Left gain" ) ), + m_rightModel( 100.0f, 0.0f, 200.0f, 0.1f, this, tr( "Right gain" ) ) + // ==TAG== ENDINITIALIZEMODELS ==TAG== // +{ +} + + +void DisintegratorControls::saveSettings( QDomDocument& doc, QDomElement& _this ) +{ + // ==TAG== SAVESETTINGS ==TAG== // + m_volumeModel.saveSettings( doc, _this, "volume" ); + m_panModel.saveSettings( doc, _this, "pan" ); + m_leftModel.saveSettings( doc, _this, "left" ); + m_rightModel.saveSettings( doc, _this, "right" ); + // ==TAG== ENDSAVESETTINGS ==TAG== // +} + + + +void DisintegratorControls::loadSettings( const QDomElement& _this ) +{ + // ==TAG== LOADSETTINGS ==TAG== // + m_volumeModel.loadSettings( _this, "volume" ); + m_panModel.loadSettings( _this, "pan" ); + m_leftModel.loadSettings( _this, "left" ); + m_rightModel.loadSettings( _this, "right" ); + // ==TAG== ENDLOADSETTINGS ==TAG== // +} + + diff --git a/plugins/Disintegrator/OLD 1/DisintegratorControls.h b/plugins/Disintegrator/OLD 1/DisintegratorControls.h new file mode 100644 index 000000000..39f7f5b26 --- /dev/null +++ b/plugins/Disintegrator/OLD 1/DisintegratorControls.h @@ -0,0 +1,78 @@ +/* + * DisintegratorControls.h + * + * Copyright (c) 2019 Lost Robot + * + * 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 "EffectControls.h" +#include "DisintegratorControlDialog.h" +#include "Knob.h" + + +class DisintegratorEffect; + + +class DisintegratorControls : public EffectControls +{ + Q_OBJECT +public: + DisintegratorControls( DisintegratorEffect* effect ); + virtual ~DisintegratorControls() + { + } + + virtual void saveSettings( QDomDocument & _doc, QDomElement & _parent ); + virtual void loadSettings( const QDomElement & _this ); + inline virtual QString nodeName() const + { + return "DisintegratorControls"; + } + + virtual int controlCount() + { + // ==TAG== CONTROLCOUNT ==TAG== // + return 4; + } + + virtual EffectControlDialog* createView() + { + return new DisintegratorControlDialog( this ); + } + +private: + DisintegratorEffect* m_effect; + + // ==TAG== DEFINEMODELS ==TAG== // + FloatModel m_volumeModel; + FloatModel m_panModel; + FloatModel m_leftModel; + FloatModel m_rightModel; + // ==TAG== ENDDEFINEMODELS ==TAG== // + + friend class DisintegratorControlDialog; + friend class DisintegratorEffect; + +} ; + +#endif diff --git a/plugins/Disintegrator/OLD 1/artwork.png b/plugins/Disintegrator/OLD 1/artwork.png new file mode 100644 index 000000000..5598b32db Binary files /dev/null and b/plugins/Disintegrator/OLD 1/artwork.png differ diff --git a/plugins/Disintegrator/OLD 1/logo.png b/plugins/Disintegrator/OLD 1/logo.png new file mode 100644 index 000000000..9340da708 Binary files /dev/null and b/plugins/Disintegrator/OLD 1/logo.png differ diff --git a/plugins/Disintegrator/artwork.png b/plugins/Disintegrator/artwork.png new file mode 100644 index 000000000..5598b32db Binary files /dev/null and b/plugins/Disintegrator/artwork.png differ diff --git a/plugins/Disintegrator/logo.png b/plugins/Disintegrator/logo.png new file mode 100644 index 000000000..9340da708 Binary files /dev/null and b/plugins/Disintegrator/logo.png differ