LOMM (upward/downward multiband compressor) (#6925)
@@ -41,6 +41,7 @@ SET(LMMS_PLUGIN_LIST
|
||||
HydrogenImport
|
||||
LadspaBrowser
|
||||
LadspaEffect
|
||||
LOMM
|
||||
Lv2Effect
|
||||
Lv2Instrument
|
||||
Lb302
|
||||
|
||||
BIN
data/themes/classic/lcd_11green.png
Normal file
|
After Width: | Height: | Size: 10 KiB |
BIN
data/themes/classic/lcd_11green_dot.png
Normal file
|
After Width: | Height: | Size: 5.8 KiB |
BIN
data/themes/default/lcd_11green.png
Normal file
|
After Width: | Height: | Size: 10 KiB |
BIN
data/themes/default/lcd_11green_dot.png
Normal file
|
After Width: | Height: | Size: 5.8 KiB |
@@ -157,6 +157,11 @@ public:
|
||||
{
|
||||
m_noRun = _state;
|
||||
}
|
||||
|
||||
inline TempoSyncKnobModel* autoQuitModel()
|
||||
{
|
||||
return &m_autoQuitModel;
|
||||
}
|
||||
|
||||
EffectChain * effectChain() const
|
||||
{
|
||||
|
||||
3
plugins/LOMM/CMakeLists.txt
Normal file
@@ -0,0 +1,3 @@
|
||||
INCLUDE(BuildPlugin)
|
||||
|
||||
BUILD_PLUGIN(lomm LOMM.cpp LOMMControls.cpp LOMMControlDialog.cpp MOCFILES LOMM.h LOMMControls.h LOMMControlDialog.h EMBEDDED_RESOURCES *.png)
|
||||
444
plugins/LOMM/LOMM.cpp
Normal file
@@ -0,0 +1,444 @@
|
||||
/*
|
||||
* LOMM.cpp
|
||||
*
|
||||
* Copyright (c) 2023 Lost Robot <r94231/at/gmail/dot/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 "LOMM.h"
|
||||
|
||||
#include "embed.h"
|
||||
#include "plugin_export.h"
|
||||
|
||||
namespace lmms
|
||||
{
|
||||
|
||||
extern "C"
|
||||
{
|
||||
Plugin::Descriptor PLUGIN_EXPORT lomm_plugin_descriptor =
|
||||
{
|
||||
LMMS_STRINGIFY(PLUGIN_NAME),
|
||||
"LOMM",
|
||||
QT_TRANSLATE_NOOP("PluginBrowser", "Upwards/downwards multiband compression plugin powered by the eldritch elder god LOMMUS."),
|
||||
"Lost Robot <r94231/at/gmail/dot/com>",
|
||||
0x0100,
|
||||
Plugin::Type::Effect,
|
||||
new PluginPixmapLoader("logo"),
|
||||
nullptr,
|
||||
nullptr
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
LOMMEffect::LOMMEffect(Model* parent, const Descriptor::SubPluginFeatures::Key* key) :
|
||||
Effect(&lomm_plugin_descriptor, parent, key),
|
||||
m_lommControls(this),
|
||||
m_sampleRate(Engine::audioEngine()->processingSampleRate()),
|
||||
m_lp1(m_sampleRate),
|
||||
m_lp2(m_sampleRate),
|
||||
m_hp1(m_sampleRate),
|
||||
m_hp2(m_sampleRate),
|
||||
m_needsUpdate(true),
|
||||
m_coeffPrecalc(-0.05),
|
||||
m_crestTimeConst(0.999),
|
||||
m_lookWrite(0),
|
||||
m_lookBufLength(2)
|
||||
{
|
||||
autoQuitModel()->setValue(autoQuitModel()->maxValue());
|
||||
|
||||
m_yL[0][0] = m_yL[0][1] = LOMM_MIN_FLOOR;
|
||||
m_yL[1][0] = m_yL[1][1] = LOMM_MIN_FLOOR;
|
||||
m_yL[2][0] = m_yL[2][1] = LOMM_MIN_FLOOR;
|
||||
|
||||
connect(Engine::audioEngine(), SIGNAL(sampleRateChanged()), this, SLOT(changeSampleRate()));
|
||||
emit changeSampleRate();
|
||||
}
|
||||
|
||||
void LOMMEffect::changeSampleRate()
|
||||
{
|
||||
m_sampleRate = Engine::audioEngine()->processingSampleRate();
|
||||
m_lp1.setSampleRate(m_sampleRate);
|
||||
m_lp2.setSampleRate(m_sampleRate);
|
||||
m_hp1.setSampleRate(m_sampleRate);
|
||||
m_hp2.setSampleRate(m_sampleRate);
|
||||
|
||||
m_coeffPrecalc = -2.2f / (m_sampleRate * 0.001f);
|
||||
m_needsUpdate = true;
|
||||
|
||||
m_crestTimeConst = exp(-1.f / (0.2f * m_sampleRate));
|
||||
|
||||
m_lookBufLength = std::ceil((LOMM_MAX_LOOKAHEAD / 1000.f) * m_sampleRate) + 2;
|
||||
for (int i = 0; i < 2; ++i)
|
||||
{
|
||||
for (int j = 0; j < 3; ++j)
|
||||
{
|
||||
m_inLookBuf[j][i].resize(m_lookBufLength);
|
||||
m_scLookBuf[j][i].resize(m_lookBufLength, LOMM_MIN_FLOOR);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LOMMEffect::clearFilterHistories()
|
||||
{
|
||||
m_lp1.clearHistory();
|
||||
m_lp2.clearHistory();
|
||||
m_hp1.clearHistory();
|
||||
m_hp2.clearHistory();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
bool LOMMEffect::processAudioBuffer(sampleFrame* buf, const fpp_t frames)
|
||||
{
|
||||
if (!isEnabled() || !isRunning())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_needsUpdate || m_lommControls.m_split1Model.isValueChanged())
|
||||
{
|
||||
m_lp1.setLowpass(m_lommControls.m_split1Model.value());
|
||||
m_hp1.setHighpass(m_lommControls.m_split1Model.value());
|
||||
}
|
||||
if (m_needsUpdate || m_lommControls.m_split2Model.isValueChanged())
|
||||
{
|
||||
m_lp2.setLowpass(m_lommControls.m_split2Model.value());
|
||||
m_hp2.setHighpass(m_lommControls.m_split2Model.value());
|
||||
}
|
||||
m_needsUpdate = false;
|
||||
|
||||
float outSum = 0.f;
|
||||
const float d = dryLevel();
|
||||
const float w = wetLevel();
|
||||
|
||||
const float depth = m_lommControls.m_depthModel.value();
|
||||
const float time = m_lommControls.m_timeModel.value();
|
||||
const float inVol = dbfsToAmp(m_lommControls.m_inVolModel.value());
|
||||
const float outVol = dbfsToAmp(m_lommControls.m_outVolModel.value());
|
||||
const float upward = m_lommControls.m_upwardModel.value();
|
||||
const float downward = m_lommControls.m_downwardModel.value();
|
||||
const bool split1Enabled = m_lommControls.m_split1EnabledModel.value();
|
||||
const bool split2Enabled = m_lommControls.m_split2EnabledModel.value();
|
||||
const bool band1Enabled = m_lommControls.m_band1EnabledModel.value();
|
||||
const bool band2Enabled = m_lommControls.m_band2EnabledModel.value();
|
||||
const bool band3Enabled = m_lommControls.m_band3EnabledModel.value();
|
||||
const float inHigh = dbfsToAmp(m_lommControls.m_inHighModel.value());
|
||||
const float inMid = dbfsToAmp(m_lommControls.m_inMidModel.value());
|
||||
const float inLow = dbfsToAmp(m_lommControls.m_inLowModel.value());
|
||||
float inBandVol[3] = {inHigh, inMid, inLow};
|
||||
const float outHigh = dbfsToAmp(m_lommControls.m_outHighModel.value());
|
||||
const float outMid = dbfsToAmp(m_lommControls.m_outMidModel.value());
|
||||
const float outLow = dbfsToAmp(m_lommControls.m_outLowModel.value());
|
||||
float outBandVol[3] = {outHigh, outMid, outLow};
|
||||
const float aThreshH = m_lommControls.m_aThreshHModel.value();
|
||||
const float aThreshM = m_lommControls.m_aThreshMModel.value();
|
||||
const float aThreshL = m_lommControls.m_aThreshLModel.value();
|
||||
float aThresh[3] = {aThreshH, aThreshM, aThreshL};
|
||||
const float aRatioH = m_lommControls.m_aRatioHModel.value();
|
||||
const float aRatioM = m_lommControls.m_aRatioMModel.value();
|
||||
const float aRatioL = m_lommControls.m_aRatioLModel.value();
|
||||
float aRatio[3] = {1.f / aRatioH, 1.f / aRatioM, 1.f / aRatioL};
|
||||
const float bThreshH = m_lommControls.m_bThreshHModel.value();
|
||||
const float bThreshM = m_lommControls.m_bThreshMModel.value();
|
||||
const float bThreshL = m_lommControls.m_bThreshLModel.value();
|
||||
float bThresh[3] = {bThreshH, bThreshM, bThreshL};
|
||||
const float bRatioH = m_lommControls.m_bRatioHModel.value();
|
||||
const float bRatioM = m_lommControls.m_bRatioMModel.value();
|
||||
const float bRatioL = m_lommControls.m_bRatioLModel.value();
|
||||
float bRatio[3] = {1.f / bRatioH, 1.f / bRatioM, 1.f / bRatioL};
|
||||
const float atkH = m_lommControls.m_atkHModel.value() * time;
|
||||
const float atkM = m_lommControls.m_atkMModel.value() * time;
|
||||
const float atkL = m_lommControls.m_atkLModel.value() * time;
|
||||
const float atkCoefH = msToCoeff(atkH);
|
||||
const float atkCoefM = msToCoeff(atkM);
|
||||
const float atkCoefL = msToCoeff(atkL);
|
||||
float atk[3] = {atkH, atkM, atkL};
|
||||
float atkCoef[3] = {atkCoefH, atkCoefM, atkCoefL};
|
||||
const float relH = m_lommControls.m_relHModel.value() * time;
|
||||
const float relM = m_lommControls.m_relMModel.value() * time;
|
||||
const float relL = m_lommControls.m_relLModel.value() * time;
|
||||
const float relCoefH = msToCoeff(relH);
|
||||
const float relCoefM = msToCoeff(relM);
|
||||
const float relCoefL = msToCoeff(relL);
|
||||
float rel[3] = {relH, relM, relL};
|
||||
float relCoef[3] = {relCoefH, relCoefM, relCoefL};
|
||||
const float rmsTime = m_lommControls.m_rmsTimeModel.value();
|
||||
const float rmsTimeConst = (rmsTime == 0) ? 0 : exp(-1.f / (rmsTime * 0.001f * m_sampleRate));
|
||||
const float knee = m_lommControls.m_kneeModel.value() * 0.5f;
|
||||
const float range = m_lommControls.m_rangeModel.value();
|
||||
const float rangeAmp = dbfsToAmp(range);
|
||||
const float balance = m_lommControls.m_balanceModel.value();
|
||||
const float balanceAmpTemp = dbfsToAmp(balance);
|
||||
const float balanceAmp[2] = {1.f / balanceAmpTemp, balanceAmpTemp};
|
||||
const bool depthScaling = m_lommControls.m_depthScalingModel.value();
|
||||
const bool stereoLink = m_lommControls.m_stereoLinkModel.value();
|
||||
const float autoTime = m_lommControls.m_autoTimeModel.value() * m_lommControls.m_autoTimeModel.value();
|
||||
const float mix = m_lommControls.m_mixModel.value();
|
||||
const bool midside = m_lommControls.m_midsideModel.value();
|
||||
const bool lookaheadEnable = m_lommControls.m_lookaheadEnableModel.value();
|
||||
const int lookahead = std::ceil((m_lommControls.m_lookaheadModel.value() / 1000.f) * m_sampleRate);
|
||||
const bool feedback = m_lommControls.m_feedbackModel.value() && !lookaheadEnable;
|
||||
const bool lowSideUpwardSuppress = m_lommControls.m_lowSideUpwardSuppressModel.value() && midside;
|
||||
|
||||
for (fpp_t f = 0; f < frames; ++f)
|
||||
{
|
||||
std::array<sample_t, 2> s = {buf[f][0], buf[f][1]};
|
||||
|
||||
// Convert left/right to mid/side. Side channel is intentionally made
|
||||
// to be 6 dB louder to bring it into volume ranges comparable to the mid channel.
|
||||
if (midside)
|
||||
{
|
||||
float tempS0 = s[0];
|
||||
s[0] = (s[0] + s[1]) * 0.5f;
|
||||
s[1] = tempS0 - s[1];
|
||||
}
|
||||
|
||||
std::array<std::array<float, 2>, 3> bands = {{}};
|
||||
std::array<std::array<float, 2>, 3> bandsDry = {{}};
|
||||
|
||||
for (int i = 0; i < 2; ++i)// Channels
|
||||
{
|
||||
// These values are for the Auto time knob. Higher crest factor allows for faster attack/release.
|
||||
float inSquared = s[i] * s[i];
|
||||
m_crestPeakVal[i] = std::max(std::max(LOMM_MIN_FLOOR, inSquared), m_crestTimeConst * m_crestPeakVal[i] + (1 - m_crestTimeConst) * (inSquared));
|
||||
m_crestRmsVal[i] = std::max(LOMM_MIN_FLOOR, m_crestTimeConst * m_crestRmsVal[i] + ((1 - m_crestTimeConst) * (inSquared)));
|
||||
m_crestFactorVal[i] = m_crestPeakVal[i] / m_crestRmsVal[i];
|
||||
float crestFactorValTemp = ((m_crestFactorVal[i] - LOMM_AUTO_TIME_ADJUST) * autoTime) + LOMM_AUTO_TIME_ADJUST;
|
||||
|
||||
// Crossover filters
|
||||
bands[0][i] = m_hp1.update(s[i], i);
|
||||
bands[1][i] = m_hp2.update(m_lp1.update(s[i], i), i);
|
||||
bands[2][i] = m_lp2.update(s[i], i);
|
||||
|
||||
if (!split1Enabled)
|
||||
{
|
||||
bands[1][i] += bands[0][i];
|
||||
bands[0][i] = 0;
|
||||
}
|
||||
if (!split2Enabled)
|
||||
{
|
||||
bands[1][i] += bands[2][i];
|
||||
bands[2][i] = 0;
|
||||
}
|
||||
|
||||
// Mute disabled bands
|
||||
bands[0][i] *= band1Enabled;
|
||||
bands[1][i] *= band2Enabled;
|
||||
bands[2][i] *= band3Enabled;
|
||||
|
||||
std::array<float, 3> detect = {0, 0, 0};
|
||||
for (int j = 0; j < 3; ++j)// Bands
|
||||
{
|
||||
bandsDry[j][i] = bands[j][i];
|
||||
|
||||
if (feedback && !lookaheadEnable)
|
||||
{
|
||||
bands[j][i] = m_prevOut[j][i];
|
||||
}
|
||||
|
||||
bands[j][i] *= inBandVol[j] * inVol * balanceAmp[i];
|
||||
|
||||
if (rmsTime > 0)// RMS
|
||||
{
|
||||
m_rms[j][i] = rmsTimeConst * m_rms[j][i] + ((1 - rmsTimeConst) * (bands[j][i] * bands[j][i]));
|
||||
detect[j] = std::max(LOMM_MIN_FLOOR, std::sqrt(m_rms[j][i]));
|
||||
}
|
||||
else// Peak
|
||||
{
|
||||
detect[j] = std::max(LOMM_MIN_FLOOR, std::abs(bands[j][i]));
|
||||
}
|
||||
|
||||
if (detect[j] > m_yL[j][i])// Attack phase
|
||||
{
|
||||
// Calculate attack value depending on crest factor
|
||||
const float currentAttack = autoTime
|
||||
? msToCoeff(LOMM_AUTO_TIME_ADJUST * atk[j] / crestFactorValTemp)
|
||||
: atkCoef[j];
|
||||
|
||||
m_yL[j][i] = m_yL[j][i] * currentAttack + (1 - currentAttack) * detect[j];
|
||||
}
|
||||
else// Release phase
|
||||
{
|
||||
// Calculate release value depending on crest factor
|
||||
const float currentRelease = autoTime
|
||||
? msToCoeff(LOMM_AUTO_TIME_ADJUST * rel[j] / crestFactorValTemp)
|
||||
: relCoef[j];
|
||||
|
||||
m_yL[j][i] = m_yL[j][i] * currentRelease + (1 - currentRelease) * detect[j];
|
||||
}
|
||||
|
||||
m_yL[j][i] = std::max(LOMM_MIN_FLOOR, m_yL[j][i]);
|
||||
|
||||
float yAmp = m_yL[j][i];
|
||||
if (lookaheadEnable)
|
||||
{
|
||||
float temp = yAmp;
|
||||
// Lookahead is calculated by picking the largest value between
|
||||
// the current sidechain signal and the delayed sidechain signal.
|
||||
yAmp = std::max(m_scLookBuf[j][i][m_lookWrite], m_scLookBuf[j][i][(m_lookWrite + m_lookBufLength - lookahead) % m_lookBufLength]);
|
||||
m_scLookBuf[j][i][m_lookWrite] = temp;
|
||||
}
|
||||
|
||||
const float yDbfs = ampToDbfs(yAmp);
|
||||
|
||||
float aboveGain = 0;
|
||||
float belowGain = 0;
|
||||
|
||||
// Downward compression
|
||||
if (yDbfs - aThresh[j] < -knee)// Below knee
|
||||
{
|
||||
aboveGain = yDbfs;
|
||||
}
|
||||
else if (yDbfs - aThresh[j] < knee)// Within knee
|
||||
{
|
||||
const float temp = yDbfs - aThresh[j] + knee;
|
||||
aboveGain = yDbfs + (aRatio[j] - 1) * temp * temp / (4 * knee);
|
||||
}
|
||||
else// Above knee
|
||||
{
|
||||
aboveGain = aThresh[j] + (yDbfs - aThresh[j]) * aRatio[j];
|
||||
}
|
||||
if (aboveGain < yDbfs)
|
||||
{
|
||||
if (downward * depth <= 1)
|
||||
{
|
||||
aboveGain = linearInterpolate(yDbfs, aboveGain, downward * depth);
|
||||
}
|
||||
else
|
||||
{
|
||||
aboveGain = linearInterpolate(aboveGain, aThresh[j], downward * depth - 1);
|
||||
}
|
||||
}
|
||||
|
||||
// Upward compression
|
||||
if (yDbfs - bThresh[j] > knee)// Above knee
|
||||
{
|
||||
belowGain = yDbfs;
|
||||
}
|
||||
else if (bThresh[j] - yDbfs < knee)// Within knee
|
||||
{
|
||||
const float temp = bThresh[j] - yDbfs + knee;
|
||||
belowGain = yDbfs + (1 - bRatio[j]) * temp * temp / (4 * knee);
|
||||
}
|
||||
else// Below knee
|
||||
{
|
||||
belowGain = bThresh[j] + (yDbfs - bThresh[j]) * bRatio[j];
|
||||
}
|
||||
if (belowGain > yDbfs)
|
||||
{
|
||||
if (upward * depth <= 1)
|
||||
{
|
||||
belowGain = linearInterpolate(yDbfs, belowGain, upward * depth);
|
||||
}
|
||||
else
|
||||
{
|
||||
belowGain = linearInterpolate(belowGain, bThresh[j], upward * depth - 1);
|
||||
}
|
||||
}
|
||||
|
||||
m_displayIn[j][i] = yDbfs;
|
||||
m_gainResult[j][i] = (dbfsToAmp(aboveGain) / yAmp) * (dbfsToAmp(belowGain) / yAmp);
|
||||
if (lowSideUpwardSuppress && m_gainResult[j][i] > 1 && j == 2 && i == 1) //undo upward compression if low side band
|
||||
{
|
||||
m_gainResult[j][i] = 1;
|
||||
}
|
||||
m_gainResult[j][i] = std::min(m_gainResult[j][i], rangeAmp);
|
||||
m_displayOut[j][i] = ampToDbfs(std::max(LOMM_MIN_FLOOR, yAmp * m_gainResult[j][i]));
|
||||
|
||||
// Apply the same gain reduction to both channels if stereo link is enabled.
|
||||
if (stereoLink && i == 1)
|
||||
{
|
||||
if (m_gainResult[j][1] < m_gainResult[j][0])
|
||||
{
|
||||
m_gainResult[j][0] = m_gainResult[j][1];
|
||||
m_displayOut[j][0] = m_displayIn[j][0] - (m_displayIn[j][1] - m_displayOut[j][1]);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_gainResult[j][1] = m_gainResult[j][0];
|
||||
m_displayOut[j][1] = m_displayIn[j][1] - (m_displayIn[j][0] - m_displayOut[j][0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < 2; ++i)// Channels
|
||||
{
|
||||
for (int j = 0; j < 3; ++j)// Bands
|
||||
{
|
||||
if (lookaheadEnable)
|
||||
{
|
||||
float temp = bands[j][i];
|
||||
bands[j][i] = m_inLookBuf[j][i][m_lookWrite];
|
||||
m_inLookBuf[j][i][m_lookWrite] = temp;
|
||||
bandsDry[j][i] = bands[j][i];
|
||||
}
|
||||
else if (feedback)
|
||||
{
|
||||
bands[j][i] = bandsDry[j][i] * inBandVol[j] * inVol * balanceAmp[i];
|
||||
}
|
||||
|
||||
// Apply gain reduction
|
||||
bands[j][i] *= m_gainResult[j][i];
|
||||
|
||||
// Store for Feedback
|
||||
m_prevOut[j][i] = bands[j][i];
|
||||
|
||||
bands[j][i] *= outBandVol[j];
|
||||
|
||||
bands[j][i] = linearInterpolate(bandsDry[j][i], bands[j][i], mix);
|
||||
}
|
||||
|
||||
s[i] = bands[0][i] + bands[1][i] + bands[2][i];
|
||||
|
||||
s[i] *= linearInterpolate(1.f, outVol, mix * (depthScaling ? depth : 1));
|
||||
}
|
||||
|
||||
// Convert mid/side back to left/right.
|
||||
// Note that the side channel was intentionally made to be 6 dB louder prior to compression.
|
||||
if (midside)
|
||||
{
|
||||
float tempS0 = s[0];
|
||||
s[0] = s[0] + (s[1] * 0.5f);
|
||||
s[1] = tempS0 - (s[1] * 0.5f);
|
||||
}
|
||||
|
||||
if (--m_lookWrite < 0) { m_lookWrite = m_lookBufLength - 1; }
|
||||
|
||||
buf[f][0] = d * buf[f][0] + w * s[0];
|
||||
buf[f][1] = d * buf[f][1] + w * s[1];
|
||||
outSum += buf[f][0] + buf[f][1];
|
||||
}
|
||||
|
||||
checkGate(outSum / frames);
|
||||
return isRunning();
|
||||
}
|
||||
|
||||
extern "C"
|
||||
{
|
||||
// necessary for getting instance out of shared lib
|
||||
PLUGIN_EXPORT Plugin * lmms_plugin_main(Model* parent, void* data)
|
||||
{
|
||||
return new LOMMEffect(parent, static_cast<const Plugin::Descriptor::SubPluginFeatures::Key *>(data));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace lmms
|
||||
106
plugins/LOMM/LOMM.h
Normal file
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
* LOMM.h
|
||||
*
|
||||
* Copyright (c) 2023 Lost Robot <r94231/at/gmail/dot/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 LMMS_LOMM_H
|
||||
#define LMMS_LOMM_H
|
||||
|
||||
#include "LOMMControls.h"
|
||||
#include "Effect.h"
|
||||
|
||||
#include "BasicFilters.h"
|
||||
#include "lmms_math.h"
|
||||
|
||||
namespace lmms
|
||||
{
|
||||
|
||||
constexpr inline float LOMM_MIN_FLOOR = 0.00012589;// -72 dBFS
|
||||
constexpr inline float LOMM_MAX_LOOKAHEAD = 20.f;
|
||||
constexpr inline float LOMM_AUTO_TIME_ADJUST = 5.f;
|
||||
|
||||
class LOMMEffect : public Effect
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
LOMMEffect(Model* parent, const Descriptor::SubPluginFeatures::Key* key);
|
||||
~LOMMEffect() override = default;
|
||||
bool processAudioBuffer(sampleFrame* buf, const fpp_t frames) override;
|
||||
|
||||
EffectControls* controls() override
|
||||
{
|
||||
return &m_lommControls;
|
||||
}
|
||||
|
||||
void clearFilterHistories();
|
||||
|
||||
inline float msToCoeff(float ms)
|
||||
{
|
||||
return (ms == 0) ? 0 : exp(m_coeffPrecalc / ms);
|
||||
}
|
||||
|
||||
private slots:
|
||||
void changeSampleRate();
|
||||
|
||||
private:
|
||||
LOMMControls m_lommControls;
|
||||
|
||||
float m_sampleRate;
|
||||
|
||||
StereoLinkwitzRiley m_lp1;
|
||||
StereoLinkwitzRiley m_lp2;
|
||||
|
||||
StereoLinkwitzRiley m_hp1;
|
||||
StereoLinkwitzRiley m_hp2;
|
||||
|
||||
bool m_needsUpdate;
|
||||
float m_coeffPrecalc;
|
||||
|
||||
std::array<std::array<float, 2>, 3> m_yL;
|
||||
std::array<std::array<float, 2>, 3> m_rms;
|
||||
std::array<std::array<float, 2>, 3> m_gainResult;
|
||||
|
||||
std::array<std::array<float, 2>, 3> m_displayIn;
|
||||
std::array<std::array<float, 2>, 3> m_displayOut;
|
||||
|
||||
std::array<float, 2> m_crestPeakVal;
|
||||
std::array<float, 2> m_crestRmsVal;
|
||||
std::array<float, 2> m_crestFactorVal;
|
||||
float m_crestTimeConst = 0.0f;
|
||||
|
||||
std::array<std::array<float, 2>, 3> m_prevOut;
|
||||
|
||||
std::array<std::array<std::vector<float>, 2>, 3> m_inLookBuf;
|
||||
std::array<std::array<std::vector<float>, 2>, 3> m_scLookBuf;
|
||||
|
||||
int m_lookWrite = 0;
|
||||
int m_lookBufLength = 0;
|
||||
|
||||
friend class LOMMControls;
|
||||
friend class gui::LOMMControlDialog;
|
||||
};
|
||||
|
||||
|
||||
} // namespace lmms
|
||||
|
||||
#endif // LMMS_LOMM_H
|
||||
275
plugins/LOMM/LOMMControlDialog.cpp
Normal file
@@ -0,0 +1,275 @@
|
||||
/*
|
||||
* LOMMControlDialog.cpp
|
||||
*
|
||||
* Copyright (c) 2023 Lost Robot <r94231/at/gmail/dot/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 "LOMM.h"
|
||||
#include "LOMMControlDialog.h"
|
||||
#include "LOMMControls.h"
|
||||
|
||||
|
||||
namespace lmms::gui
|
||||
{
|
||||
|
||||
LOMMControlDialog::LOMMControlDialog(LOMMControls* controls) :
|
||||
EffectControlDialog(controls),
|
||||
m_controls(controls)
|
||||
{
|
||||
setAutoFillBackground(true);
|
||||
QPalette pal;
|
||||
pal.setBrush(backgroundRole(), PLUGIN_NAME::getIconPixmap("artwork"));
|
||||
setPalette(pal);
|
||||
setFixedSize(400, 256);
|
||||
|
||||
createKnob(KnobType::Bright26, this, 10, 4, &controls->m_depthModel, tr("Depth:"), "", tr("Compression amount for all bands"));
|
||||
createKnob(KnobType::Bright26, this, 10, 41, &controls->m_timeModel, tr("Time:"), "", tr("Attack/release scaling for all bands"));
|
||||
createKnob(KnobType::Bright26, this, 10, 220, &controls->m_inVolModel, tr("Input Volume:"), " dB", tr("Input volume"));
|
||||
createKnob(KnobType::Bright26, this, 363, 220, &controls->m_outVolModel, tr("Output Volume:"), " dB", tr("Output volume"));
|
||||
createKnob(KnobType::Bright26, this, 10, 179, &controls->m_upwardModel, tr("Upward Depth:"), "", tr("Upward compression amount for all bands"));
|
||||
createKnob(KnobType::Bright26, this, 363, 179, &controls->m_downwardModel, tr("Downward Depth:"), "", tr("Downward compression amount for all bands"));
|
||||
|
||||
createLcdFloatSpinBox(5, 2, "11green", tr("High/Mid Crossover"), this, 352, 76, &controls->m_split1Model, tr("High/Mid Crossover"));
|
||||
createLcdFloatSpinBox(5, 2, "11green", tr("Mid/Low Crossover"), this, 352, 156, &controls->m_split2Model, tr("Mid/Low Crossover"));
|
||||
|
||||
createPixmapButton(tr("High/mid band split"), this, 369, 104, &controls->m_split1EnabledModel, "crossover_led_green", "crossover_led_off", tr("High/mid band split"));
|
||||
createPixmapButton(tr("Mid/low band split"), this, 369, 126, &controls->m_split2EnabledModel, "crossover_led_green", "crossover_led_off", tr("Mid/low band split"));
|
||||
|
||||
createPixmapButton(tr("Enable High Band"), this, 143, 66, &controls->m_band1EnabledModel, "high_band_active", "high_band_inactive", tr("Enable High Band"));
|
||||
createPixmapButton(tr("Enable Mid Band"), this, 143, 146, &controls->m_band2EnabledModel, "mid_band_active", "mid_band_inactive", tr("Enable Mid Band"));
|
||||
createPixmapButton(tr("Enable Low Band"), this, 143, 226, &controls->m_band3EnabledModel, "low_band_active", "low_band_inactive", tr("Enable Low Band"));
|
||||
|
||||
createKnob(KnobType::Bright26, this, 53, 43, &controls->m_inHighModel, tr("High Input Volume:"), " dB", tr("Input volume for high band"));
|
||||
createKnob(KnobType::Bright26, this, 53, 123, &controls->m_inMidModel, tr("Mid Input Volume:"), " dB", tr("Input volume for mid band"));
|
||||
createKnob(KnobType::Bright26, this, 53, 203, &controls->m_inLowModel, tr("Low Input Volume:"), " dB", tr("Input volume for low band"));
|
||||
createKnob(KnobType::Bright26, this, 320, 43, &controls->m_outHighModel, tr("High Output Volume:"), " dB", tr("Output volume for high band"));
|
||||
createKnob(KnobType::Bright26, this, 320, 123, &controls->m_outMidModel, tr("Mid Output Volume:"), " dB", tr("Output volume for mid band"));
|
||||
createKnob(KnobType::Bright26, this, 320, 203, &controls->m_outLowModel, tr("Low Output Volume:"), " dB", tr("Output volume for low band"));
|
||||
|
||||
createLcdFloatSpinBox(3, 3, "11green", tr("Above Threshold High"), this, 300, 13, &controls->m_aThreshHModel, tr("Downward compression threshold for high band"));
|
||||
createLcdFloatSpinBox(3, 3, "11green", tr("Above Threshold Mid"), this, 300, 93, &controls->m_aThreshMModel, tr("Downward compression threshold for mid band"));
|
||||
createLcdFloatSpinBox(3, 3, "11green", tr("Above Threshold Low"), this, 300, 173, &controls->m_aThreshLModel, tr("Downward compression threshold for low band"));
|
||||
createLcdFloatSpinBox(2, 2, "11green", tr("Above Ratio High"), this, 284, 44, &controls->m_aRatioHModel, tr("Downward compression ratio for high band"));
|
||||
createLcdFloatSpinBox(2, 2, "11green", tr("Above Ratio Mid"), this, 284, 124, &controls->m_aRatioMModel, tr("Downward compression ratio for mid band"));
|
||||
createLcdFloatSpinBox(2, 2, "11green", tr("Above Ratio Low"), this, 284, 204, &controls->m_aRatioLModel, tr("Downward compression ratio for low band"));
|
||||
|
||||
createLcdFloatSpinBox(3, 3, "11green", tr("Below Threshold High"), this, 59, 13, &controls->m_bThreshHModel, tr("Upward compression threshold for high band"));
|
||||
createLcdFloatSpinBox(3, 3, "11green", tr("Below Threshold Mid"), this, 59, 93, &controls->m_bThreshMModel, tr("Upward compression threshold for mid band"));
|
||||
createLcdFloatSpinBox(3, 3, "11green", tr("Below Threshold Low"), this, 59, 173, &controls->m_bThreshLModel, tr("Upward compression threshold for low band"));
|
||||
createLcdFloatSpinBox(2, 2, "11green", tr("Below Ratio High"), this, 87, 44, &controls->m_bRatioHModel, tr("Upward compression ratio for high band"));
|
||||
createLcdFloatSpinBox(2, 2, "11green", tr("Below Ratio Mid"), this, 87, 124, &controls->m_bRatioMModel, tr("Upward compression ratio for mid band"));
|
||||
createLcdFloatSpinBox(2, 2, "11green", tr("Below Ratio Low"), this, 87, 204, &controls->m_bRatioLModel, tr("Upward compression ratio for low band"));
|
||||
|
||||
createKnob(KnobType::Small17, this, 120, 61, &controls->m_atkHModel, tr("Attack High:"), " ms", tr("Attack time for high band"));
|
||||
createKnob(KnobType::Small17, this, 120, 141, &controls->m_atkMModel, tr("Attack Mid:"), " ms", tr("Attack time for mid band"));
|
||||
createKnob(KnobType::Small17, this, 120, 221, &controls->m_atkLModel, tr("Attack Low:"), " ms", tr("Attack time for low band"));
|
||||
createKnob(KnobType::Small17, this, 261, 61, &controls->m_relHModel, tr("Release High:"), " ms", tr("Release time for high band"));
|
||||
createKnob(KnobType::Small17, this, 261, 141, &controls->m_relMModel, tr("Release Mid:"), " ms", tr("Release time for mid band"));
|
||||
createKnob(KnobType::Small17, this, 261, 221, &controls->m_relLModel, tr("Release Low:"), " ms", tr("Release time for low band"));
|
||||
|
||||
createKnob(KnobType::Small17, this, 380, 42, &controls->m_rmsTimeModel, tr("RMS Time:"), " ms", tr("RMS size for sidechain signal (set to 0 for Peak mode)"));
|
||||
createKnob(KnobType::Small17, this, 356, 42, &controls->m_kneeModel, tr("Knee:"), " dB", tr("Knee size for all compressors"));
|
||||
createKnob(KnobType::Small17, this, 24, 146, &controls->m_rangeModel, tr("Range:"), " dB", tr("Maximum gain increase for all bands"));
|
||||
createKnob(KnobType::Small17, this, 13, 114, &controls->m_balanceModel, tr("Balance:"), " dB", tr("Bias input volume towards one channel"));
|
||||
|
||||
createPixmapButton(tr("Scale output volume with Depth"), this, 51, 0, &controls->m_depthScalingModel, "depthScaling_active", "depthScaling_inactive",
|
||||
tr("Scale output volume with Depth parameter"));
|
||||
createPixmapButton(tr("Stereo Link"), this, 52, 237, &controls->m_stereoLinkModel, "stereoLink_active", "stereoLink_inactive",
|
||||
tr("Apply same gain change to both channels"));
|
||||
|
||||
createKnob(KnobType::Small17, this, 24, 80, &controls->m_autoTimeModel, tr("Auto Time:"), "", tr("Speed up attack and release times when transients occur"));
|
||||
createKnob(KnobType::Bright26, this, 363, 4, &controls->m_mixModel, tr("Mix:"), "", tr("Wet/Dry of all bands"));
|
||||
|
||||
m_feedbackButton = createPixmapButton(tr("Feedback"), this, 317, 238, &controls->m_feedbackModel, "feedback_active", "feedback_inactive",
|
||||
tr("Use output as sidechain signal instead of input"));
|
||||
createPixmapButton(tr("Mid/Side"), this, 285, 238, &controls->m_midsideModel, "midside_active", "midside_inactive", tr("Compress mid/side channels instead of left/right"));
|
||||
m_lowSideUpwardSuppressButton = createPixmapButton(tr("Suppress upward compression for side band"), this, 106, 180, &controls->m_lowSideUpwardSuppressModel,
|
||||
"lowSideUpwardSuppress_active", "lowSideUpwardSuppress_inactive", tr("Suppress upward compression for side band"));
|
||||
createPixmapButton(tr("Lookahead"), this, 147, 0, &controls->m_lookaheadEnableModel, "lookahead_active", "lookahead_inactive",
|
||||
tr(("Enable lookahead with fixed " + std::to_string(int(LOMM_MAX_LOOKAHEAD)) + " ms latency").c_str()));
|
||||
createLcdFloatSpinBox(2, 2, "11green", tr("Lookahead"), this, 214, 2, &controls->m_lookaheadModel, tr("Lookahead length"));
|
||||
|
||||
PixmapButton* initButton = createPixmapButton(tr("Clear all parameters"), this, 84, 237, nullptr, "init_active", "init_inactive", tr("Clear all parameters"));
|
||||
|
||||
connect(initButton, SIGNAL(clicked()), m_controls, SLOT(resetAllParameters()));
|
||||
connect(&controls->m_lookaheadEnableModel, SIGNAL(dataChanged()), this, SLOT(updateFeedbackVisibility()));
|
||||
connect(&controls->m_midsideModel, SIGNAL(dataChanged()), this, SLOT(updateLowSideUpwardSuppressVisibility()));
|
||||
connect(getGUI()->mainWindow(), SIGNAL(periodicUpdate()), this, SLOT(updateDisplay()));
|
||||
|
||||
emit updateFeedbackVisibility();
|
||||
emit updateLowSideUpwardSuppressVisibility();
|
||||
}
|
||||
|
||||
void LOMMControlDialog::updateFeedbackVisibility()
|
||||
{
|
||||
m_feedbackButton->setVisible(!m_controls->m_lookaheadEnableModel.value());
|
||||
}
|
||||
|
||||
void LOMMControlDialog::updateLowSideUpwardSuppressVisibility()
|
||||
{
|
||||
m_lowSideUpwardSuppressButton->setVisible(m_controls->m_midsideModel.value());
|
||||
}
|
||||
|
||||
void LOMMControlDialog::updateDisplay()
|
||||
{
|
||||
update();
|
||||
}
|
||||
|
||||
void LOMMControlDialog::paintEvent(QPaintEvent *event)
|
||||
{
|
||||
if (!isVisible()) { return; }
|
||||
|
||||
QPainter p;
|
||||
p.begin(this);
|
||||
|
||||
// Draw threshold lines
|
||||
QColor aColor(255, 255, 0, 31);
|
||||
QColor bColor(255, 0, 0, 31);
|
||||
QPen aPen(QColor(255, 255, 0, 255), 1);
|
||||
QPen bPen(QColor(255, 0, 0, 255), 1);
|
||||
int thresholdsX[] = {dbfsToX(m_controls->m_aThreshHModel.value()),
|
||||
dbfsToX(m_controls->m_aThreshMModel.value()),
|
||||
dbfsToX(m_controls->m_aThreshLModel.value()),
|
||||
dbfsToX(m_controls->m_bThreshHModel.value()),
|
||||
dbfsToX(m_controls->m_bThreshMModel.value()),
|
||||
dbfsToX(m_controls->m_bThreshLModel.value())};
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
p.setPen(aPen);
|
||||
p.fillRect(thresholdsX[i], LOMM_DISPLAY_Y[2 * i], LOMM_DISPLAY_X + LOMM_DISPLAY_WIDTH - thresholdsX[i], LOMM_DISPLAY_Y[2 * i + 1] + LOMM_DISPLAY_HEIGHT - LOMM_DISPLAY_Y[2 * i], aColor);
|
||||
p.drawLine(thresholdsX[i], LOMM_DISPLAY_Y[2 * i], thresholdsX[i], LOMM_DISPLAY_Y[2 * i + 1] + LOMM_DISPLAY_HEIGHT);
|
||||
|
||||
p.setPen(bPen);
|
||||
p.fillRect(LOMM_DISPLAY_X, LOMM_DISPLAY_Y[2 * i], thresholdsX[i + 3] - LOMM_DISPLAY_X, LOMM_DISPLAY_Y[2 * i + 1] + LOMM_DISPLAY_HEIGHT - LOMM_DISPLAY_Y[2 * i], bColor);
|
||||
p.drawLine(thresholdsX[i + 3], LOMM_DISPLAY_Y[2 * i], thresholdsX[i + 3], LOMM_DISPLAY_Y[2 * i + 1] + LOMM_DISPLAY_HEIGHT);
|
||||
}
|
||||
|
||||
QPen inputPen(QColor(200, 200, 200, 80), 1);
|
||||
QPen outputPen(QColor(255, 255, 255, 255), 1);
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
// Draw input lines
|
||||
p.setPen(inputPen);
|
||||
int inL = dbfsToX(m_controls->m_effect->m_displayIn[i][0]);
|
||||
p.drawLine(inL, LOMM_DISPLAY_Y[2 * i] + 4, inL, LOMM_DISPLAY_Y[2 * i] + LOMM_DISPLAY_HEIGHT);
|
||||
int inR = dbfsToX(m_controls->m_effect->m_displayIn[i][1]);
|
||||
p.drawLine(inR, LOMM_DISPLAY_Y[2 * i + 1], inR, LOMM_DISPLAY_Y[2 * i + 1] + LOMM_DISPLAY_HEIGHT - 4);
|
||||
|
||||
// Draw output lines
|
||||
p.setPen(outputPen);
|
||||
int outL = dbfsToX(m_controls->m_effect->m_displayOut[i][0]);
|
||||
p.drawLine(outL, LOMM_DISPLAY_Y[2 * i], outL, LOMM_DISPLAY_Y[2 * i] + LOMM_DISPLAY_HEIGHT);
|
||||
int outR = dbfsToX(m_controls->m_effect->m_displayOut[i][1]);
|
||||
p.drawLine(outR, LOMM_DISPLAY_Y[2 * i + 1], outR, LOMM_DISPLAY_Y[2 * i + 1] + LOMM_DISPLAY_HEIGHT);
|
||||
}
|
||||
|
||||
p.end();
|
||||
}
|
||||
|
||||
int LOMMControlDialog::dbfsToX(float dbfs)
|
||||
{
|
||||
float returnX = (dbfs - LOMM_DISPLAY_MIN) / (LOMM_DISPLAY_MAX - LOMM_DISPLAY_MIN);
|
||||
returnX = qBound(LOMM_DISPLAY_X, LOMM_DISPLAY_X + returnX * LOMM_DISPLAY_WIDTH, LOMM_DISPLAY_X + LOMM_DISPLAY_WIDTH);
|
||||
return returnX;
|
||||
}
|
||||
|
||||
float LOMMControlDialog::xToDbfs(int x)
|
||||
{
|
||||
float xNorm = static_cast<float>(x - LOMM_DISPLAY_X) / LOMM_DISPLAY_WIDTH;
|
||||
float dbfs = xNorm * (LOMM_DISPLAY_MAX - LOMM_DISPLAY_MIN) + LOMM_DISPLAY_MIN;
|
||||
return dbfs;
|
||||
}
|
||||
|
||||
void LOMMControlDialog::mousePressEvent(QMouseEvent* event)
|
||||
{
|
||||
if ((event->button() == Qt::LeftButton || event->button() == Qt::MiddleButton) && !(event->modifiers() & (Qt::ControlModifier | Qt::ShiftModifier)))
|
||||
{
|
||||
const QPoint& p = event->pos();
|
||||
|
||||
if (LOMM_DISPLAY_X - 10 <= p.x() && p.x() <= LOMM_DISPLAY_X + LOMM_DISPLAY_WIDTH + 10)
|
||||
{
|
||||
FloatModel* aThresh[] = {&m_controls->m_aThreshHModel, &m_controls->m_aThreshMModel, &m_controls->m_aThreshLModel};
|
||||
FloatModel* bThresh[] = {&m_controls->m_bThreshHModel, &m_controls->m_bThreshMModel, &m_controls->m_bThreshLModel};
|
||||
|
||||
for (int i = 0; i < 3; ++i)
|
||||
{
|
||||
if (LOMM_DISPLAY_Y[i * 2] <= p.y() && p.y() <= LOMM_DISPLAY_Y[i * 2 + 1] + LOMM_DISPLAY_HEIGHT)
|
||||
{
|
||||
int behavior = (p.x() < dbfsToX(bThresh[i]->value())) ? 0 : (p.x() > dbfsToX(aThresh[i]->value())) ? 1 : 2;
|
||||
if (event->button() == Qt::MiddleButton)
|
||||
{
|
||||
if (behavior == 0 || behavior == 2) {bThresh[i]->reset();}
|
||||
if (behavior == 1 || behavior == 2) {aThresh[i]->reset();}
|
||||
return;
|
||||
}
|
||||
|
||||
m_bandDrag = i;
|
||||
m_lastMousePos = p;
|
||||
m_buttonPressed = true;
|
||||
|
||||
m_dragType = behavior;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LOMMControlDialog::mouseMoveEvent(QMouseEvent * event)
|
||||
{
|
||||
if (m_buttonPressed && event->pos() != m_lastMousePos)
|
||||
{
|
||||
const float distance = event->pos().x() - m_lastMousePos.x();
|
||||
float dbDistance = distance * LOMM_DISPLAY_DB_PER_PIXEL;
|
||||
m_lastMousePos = event->pos();
|
||||
|
||||
FloatModel* aModel[] = {&m_controls->m_aThreshHModel, &m_controls->m_aThreshMModel, &m_controls->m_aThreshLModel};
|
||||
FloatModel* bModel[] = {&m_controls->m_bThreshHModel, &m_controls->m_bThreshMModel, &m_controls->m_bThreshLModel};
|
||||
|
||||
float bVal = bModel[m_bandDrag]->value();
|
||||
float aVal = aModel[m_bandDrag]->value();
|
||||
if (m_dragType == 0)
|
||||
{
|
||||
bModel[m_bandDrag]->setValue(bVal + dbDistance);
|
||||
}
|
||||
else if (m_dragType == 1)
|
||||
{
|
||||
aModel[m_bandDrag]->setValue(aVal + dbDistance);
|
||||
}
|
||||
else
|
||||
{
|
||||
dbDistance = qBound(bModel[m_bandDrag]->minValue(), bVal + dbDistance, bModel[m_bandDrag]->maxValue()) - bVal;
|
||||
dbDistance = qBound(aModel[m_bandDrag]->minValue(), aVal + dbDistance, aModel[m_bandDrag]->maxValue()) - aVal;
|
||||
bModel[m_bandDrag]->setValue(bVal + dbDistance);
|
||||
aModel[m_bandDrag]->setValue(aVal + dbDistance);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LOMMControlDialog::mouseReleaseEvent(QMouseEvent* event)
|
||||
{
|
||||
if (event && event->button() == Qt::LeftButton)
|
||||
{
|
||||
m_buttonPressed = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} // namespace lmms::gui
|
||||
129
plugins/LOMM/LOMMControlDialog.h
Normal file
@@ -0,0 +1,129 @@
|
||||
/*
|
||||
* LOMMControlDialog.h
|
||||
*
|
||||
* Copyright (c) 2023 Lost Robot <r94231/at/gmail/dot/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 LMMS_GUI_LOMM_CONTROL_DIALOG_H
|
||||
#define LMMS_GUI_LOMM_CONTROL_DIALOG_H
|
||||
|
||||
#include "EffectControlDialog.h"
|
||||
|
||||
#include <QMouseEvent>
|
||||
#include <QPainter>
|
||||
|
||||
#include "embed.h"
|
||||
#include "GuiApplication.h"
|
||||
#include "Knob.h"
|
||||
#include "LcdFloatSpinBox.h"
|
||||
#include "LcdSpinBox.h"
|
||||
#include "LedCheckBox.h"
|
||||
#include "MainWindow.h"
|
||||
#include "PixmapButton.h"
|
||||
|
||||
namespace lmms
|
||||
{
|
||||
|
||||
inline constexpr float LOMM_DISPLAY_MIN = -72;
|
||||
inline constexpr float LOMM_DISPLAY_MAX = 0;
|
||||
inline constexpr float LOMM_DISPLAY_X = 125;
|
||||
inline constexpr float LOMM_DISPLAY_Y[6] = {24, 41, 106, 123, 186, 203};
|
||||
inline constexpr float LOMM_DISPLAY_WIDTH = 150;
|
||||
inline constexpr float LOMM_DISPLAY_HEIGHT = 13;
|
||||
inline constexpr float LOMM_DISPLAY_DB_PER_PIXEL = (LOMM_DISPLAY_MAX - LOMM_DISPLAY_MIN) / LOMM_DISPLAY_WIDTH;
|
||||
|
||||
class LOMMControls;
|
||||
|
||||
|
||||
namespace gui
|
||||
{
|
||||
|
||||
class LOMMControlDialog : public EffectControlDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
LOMMControlDialog(LOMMControls* controls);
|
||||
~LOMMControlDialog() override = default;
|
||||
|
||||
int dbfsToX(float dbfs);
|
||||
float xToDbfs(int x);
|
||||
|
||||
Knob* createKnob(KnobType knobType, QWidget* parent, int x, int y, FloatModel* model, const QString& hintText, const QString& unit, const QString& toolTip)
|
||||
{
|
||||
Knob* knob = new Knob(knobType, parent);
|
||||
knob->move(x, y);
|
||||
knob->setModel(model);
|
||||
knob->setHintText(hintText, unit);
|
||||
knob->setToolTip(toolTip);
|
||||
return knob;
|
||||
}
|
||||
|
||||
LcdFloatSpinBox* createLcdFloatSpinBox(int integerDigits, int decimalDigits, const QString& color, const QString& unit, QWidget* parent, int x, int y, FloatModel* model, const QString& toolTip)
|
||||
{
|
||||
LcdFloatSpinBox* spinBox = new LcdFloatSpinBox(integerDigits, decimalDigits, color, unit, parent);
|
||||
spinBox->move(x, y);
|
||||
spinBox->setModel(model);
|
||||
spinBox->setSeamless(true, true);
|
||||
spinBox->setToolTip(toolTip);
|
||||
return spinBox;
|
||||
}
|
||||
|
||||
PixmapButton* createPixmapButton(const QString& text, QWidget* parent, int x, int y, BoolModel* model, const QString& activeIcon, const QString& inactiveIcon, const QString& tooltip)
|
||||
{
|
||||
PixmapButton* button = new PixmapButton(parent, text);
|
||||
button->move(x, y);
|
||||
button->setCheckable(true);
|
||||
if (model) { button->setModel(model); }
|
||||
button->setActiveGraphic(PLUGIN_NAME::getIconPixmap(activeIcon));
|
||||
button->setInactiveGraphic(PLUGIN_NAME::getIconPixmap(inactiveIcon));
|
||||
button->setToolTip(tooltip);
|
||||
return button;
|
||||
}
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *event) override;
|
||||
void mousePressEvent(QMouseEvent* event) override;
|
||||
void mouseReleaseEvent(QMouseEvent* event) override;
|
||||
void mouseMoveEvent(QMouseEvent* event) override;
|
||||
|
||||
private:
|
||||
LOMMControls* m_controls;
|
||||
|
||||
QPoint m_lastMousePos;
|
||||
bool m_buttonPressed = false;
|
||||
int m_bandDrag = 0;
|
||||
int m_dragType = -1;
|
||||
|
||||
PixmapButton* m_feedbackButton;
|
||||
PixmapButton* m_lowSideUpwardSuppressButton;
|
||||
|
||||
private slots:
|
||||
void updateFeedbackVisibility();
|
||||
void updateLowSideUpwardSuppressVisibility();
|
||||
void updateDisplay();
|
||||
};
|
||||
|
||||
|
||||
} // namespace gui
|
||||
|
||||
} // namespace lmms
|
||||
|
||||
#endif // LMMS_GUI_LOMM_CONTROL_DIALOG_H
|
||||
277
plugins/LOMM/LOMMControls.cpp
Normal file
@@ -0,0 +1,277 @@
|
||||
/*
|
||||
* LOMMControls.cpp
|
||||
*
|
||||
* Copyright (c) 2023 Lost Robot <r94231/at/gmail/dot/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 "LOMMControls.h"
|
||||
#include "LOMM.h"
|
||||
|
||||
#include <QDomElement>
|
||||
#include <QMessageBox>
|
||||
|
||||
namespace lmms
|
||||
{
|
||||
|
||||
LOMMControls::LOMMControls(LOMMEffect* effect) :
|
||||
EffectControls(effect),
|
||||
m_effect(effect),
|
||||
m_depthModel(0.4, 0, 1, 0.00001, this, tr("Depth")),
|
||||
m_timeModel(1, 0, 10, 0.00001, this, tr("Time")),
|
||||
m_inVolModel(0, -48, 48, 0.00001, this, tr("Input Volume")),
|
||||
m_outVolModel(8, -48, 48, 0.00001, this, tr("Output Volume")),
|
||||
m_upwardModel(1, 0, 2, 0.00001, this, tr("Upward Depth")),
|
||||
m_downwardModel(1, 0, 2, 0.00001, this, tr("Downward Depth")),
|
||||
m_split1Model(2500, 20, 20000, 0.01, this, tr("High/Mid Split")),
|
||||
m_split2Model(88.3, 20, 20000, 0.01, this, tr("Mid/Low Split")),
|
||||
m_split1EnabledModel(true, this, tr("Enable High/Mid Split")),
|
||||
m_split2EnabledModel(true, this, tr("Enable Mid/Low Split")),
|
||||
m_band1EnabledModel(true, this, tr("Enable High Band")),
|
||||
m_band2EnabledModel(true, this, tr("Enable Mid Band")),
|
||||
m_band3EnabledModel(true, this, tr("Enable Low Band")),
|
||||
m_inHighModel(0, -48, 48, 0.00001, this, tr("High Input Volume")),
|
||||
m_inMidModel(0, -48, 48, 0.00001, this, tr("Mid Input Volume")),
|
||||
m_inLowModel(0, -48, 48, 0.00001, this, tr("Low Input Volume")),
|
||||
m_outHighModel(4.6, -48, 48, 0.00001, this, tr("High Output Volume")),
|
||||
m_outMidModel(0.0, -48, 48, 0.00001, this, tr("Mid Output Volume")),
|
||||
m_outLowModel(4.6, -48, 48, 0.00001, this, tr("Low Output Volume")),
|
||||
m_aThreshHModel(-30.3, LOMM_DISPLAY_MIN, LOMM_DISPLAY_MAX, 0.001, this, tr("Above Threshold High")),
|
||||
m_aThreshMModel(-25.0, LOMM_DISPLAY_MIN, LOMM_DISPLAY_MAX, 0.001, this, tr("Above Threshold Mid")),
|
||||
m_aThreshLModel(-28.6, LOMM_DISPLAY_MIN, LOMM_DISPLAY_MAX, 0.001, this, tr("Above Threshold Low")),
|
||||
m_aRatioHModel(99.99, 1, 99.99, 0.01, this, tr("Above Ratio High")),
|
||||
m_aRatioMModel(66.7, 1, 99.99, 0.01, this, tr("Above Ratio Mid")),
|
||||
m_aRatioLModel(66.7, 1, 99.99, 0.01, this, tr("Above Ratio Low")),
|
||||
m_bThreshHModel(-35.6, LOMM_DISPLAY_MIN, LOMM_DISPLAY_MAX, 0.001, this, tr("Below Threshold High")),
|
||||
m_bThreshMModel(-36.6, LOMM_DISPLAY_MIN, LOMM_DISPLAY_MAX, 0.001, this, tr("Below Threshold Mid")),
|
||||
m_bThreshLModel(-35.6, LOMM_DISPLAY_MIN, LOMM_DISPLAY_MAX, 0.001, this, tr("Below Threshold Low")),
|
||||
m_bRatioHModel(4.17, 1, 99.99, 0.01, this, tr("Below Ratio High")),
|
||||
m_bRatioMModel(4.17, 1, 99.99, 0.01, this, tr("Below Ratio Mid")),
|
||||
m_bRatioLModel(4.17, 1, 99.99, 0.01, this, tr("Below Ratio Low")),
|
||||
m_atkHModel(13.5, 0, 1000, 0.001, this, tr("Attack High")),
|
||||
m_atkMModel(22.4, 0, 1000, 0.001, this, tr("Attack Mid")),
|
||||
m_atkLModel(47.8, 0, 1000, 0.001, this, tr("Attack Low")),
|
||||
m_relHModel(132, 0, 1000, 0.001, this, tr("Release High")),
|
||||
m_relMModel(282, 0, 1000, 0.001, this, tr("Release Mid")),
|
||||
m_relLModel(282, 0, 1000, 0.001, this, tr("Release Low")),
|
||||
m_rmsTimeModel(10, 0, 500, 0.001, this, tr("RMS Time")),
|
||||
m_kneeModel(6, 0, 36, 0.00001, this, tr("Knee")),
|
||||
m_rangeModel(36, 0, 96, 0.00001, this, tr("Range")),
|
||||
m_balanceModel(0, -18, 18, 0.00001, this, tr("Balance")),
|
||||
m_depthScalingModel(true, this, tr("Scale output volume with Depth")),
|
||||
m_stereoLinkModel(false, this, tr("Stereo Link")),
|
||||
m_autoTimeModel(0, 0, 1, 0.00001, this, tr("Auto Time")),
|
||||
m_mixModel(1, 0, 1, 0.00001, this, tr("Mix")),
|
||||
m_feedbackModel(false, this, tr("Feedback")),
|
||||
m_midsideModel(false, this, tr("Mid/Side")),
|
||||
m_lookaheadEnableModel(false, this, tr("Lookahead")),
|
||||
m_lookaheadModel(0.f, 0.f, LOMM_MAX_LOOKAHEAD, 0.01, this, tr("Lookahead Length")),
|
||||
m_lowSideUpwardSuppressModel(false, this, tr("Suppress upward compression for side band"))
|
||||
{
|
||||
auto models = {&m_timeModel, &m_inVolModel, &m_outVolModel, &m_inHighModel, &m_inMidModel,
|
||||
&m_inLowModel, &m_outHighModel, &m_outMidModel, &m_outLowModel, &m_aRatioHModel,
|
||||
&m_aRatioMModel, &m_aRatioLModel, &m_bRatioHModel, &m_bRatioMModel, &m_bRatioLModel,
|
||||
&m_atkHModel, &m_atkMModel, &m_atkLModel, &m_relHModel, &m_relMModel, &m_relLModel,
|
||||
&m_rmsTimeModel, &m_balanceModel};
|
||||
for (auto model : models) { model->setScaleLogarithmic(true); }
|
||||
}
|
||||
|
||||
|
||||
void LOMMControls::resetAllParameters()
|
||||
{
|
||||
int choice = QMessageBox::question(m_view, "Clear Plugin Settings", "Are you sure you want to clear all parameters?\n(This wipes LOMM to a clean slate, not the default preset.)", QMessageBox::Yes | QMessageBox::No);
|
||||
if (choice != QMessageBox::Yes) { return; }
|
||||
|
||||
// give the user a chance to beg LMMS for forgiveness
|
||||
addJournalCheckPoint();
|
||||
|
||||
// This plugin's normal default values are fairly close to what they'd want in most applications.
|
||||
// The Init button is there so the user can start from a clean slate instead.
|
||||
// These are those values.
|
||||
setInitAndReset(m_depthModel, 1);
|
||||
setInitAndReset(m_timeModel, 1);
|
||||
setInitAndReset(m_inVolModel, 0);
|
||||
setInitAndReset(m_outVolModel, 0);
|
||||
setInitAndReset(m_upwardModel, 1);
|
||||
setInitAndReset(m_downwardModel, 1);
|
||||
setInitAndReset(m_split1Model, 2500);
|
||||
setInitAndReset(m_split2Model, 88);
|
||||
setInitAndReset(m_split1EnabledModel, true);
|
||||
setInitAndReset(m_split2EnabledModel, true);
|
||||
setInitAndReset(m_band1EnabledModel, true);
|
||||
setInitAndReset(m_band2EnabledModel, true);
|
||||
setInitAndReset(m_band3EnabledModel, true);
|
||||
setInitAndReset(m_inHighModel, 0);
|
||||
setInitAndReset(m_inMidModel, 0);
|
||||
setInitAndReset(m_inLowModel, 0);
|
||||
setInitAndReset(m_outHighModel, 0);
|
||||
setInitAndReset(m_outMidModel, 0);
|
||||
setInitAndReset(m_outLowModel, 0);
|
||||
setInitAndReset(m_aThreshHModel, m_aThreshHModel.maxValue());
|
||||
setInitAndReset(m_aThreshMModel, m_aThreshMModel.maxValue());
|
||||
setInitAndReset(m_aThreshLModel, m_aThreshLModel.maxValue());
|
||||
setInitAndReset(m_aRatioHModel, 1);
|
||||
setInitAndReset(m_aRatioMModel, 1);
|
||||
setInitAndReset(m_aRatioLModel, 1);
|
||||
setInitAndReset(m_bThreshHModel, m_bThreshHModel.minValue());
|
||||
setInitAndReset(m_bThreshMModel, m_bThreshMModel.minValue());
|
||||
setInitAndReset(m_bThreshLModel, m_bThreshLModel.minValue());
|
||||
setInitAndReset(m_bRatioHModel, 1);
|
||||
setInitAndReset(m_bRatioMModel, 1);
|
||||
setInitAndReset(m_bRatioLModel, 1);
|
||||
setInitAndReset(m_atkHModel, 13.5);
|
||||
setInitAndReset(m_atkMModel, 22.4);
|
||||
setInitAndReset(m_atkLModel, 47.8);
|
||||
setInitAndReset(m_relHModel, 132);
|
||||
setInitAndReset(m_relMModel, 282);
|
||||
setInitAndReset(m_relLModel, 282);
|
||||
setInitAndReset(m_rmsTimeModel, 10);
|
||||
setInitAndReset(m_kneeModel, 6);
|
||||
setInitAndReset(m_rangeModel, 36);
|
||||
setInitAndReset(m_balanceModel, 0);
|
||||
setInitAndReset(m_depthScalingModel, true);
|
||||
setInitAndReset(m_stereoLinkModel, false);
|
||||
setInitAndReset(m_autoTimeModel, 0);
|
||||
setInitAndReset(m_mixModel, 1);
|
||||
setInitAndReset(m_feedbackModel, false);
|
||||
setInitAndReset(m_midsideModel, false);
|
||||
setInitAndReset(m_lookaheadEnableModel, false);
|
||||
setInitAndReset(m_lookaheadModel, 0.f);
|
||||
setInitAndReset(m_lowSideUpwardSuppressModel, false);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void LOMMControls::loadSettings(const QDomElement& parent)
|
||||
{
|
||||
m_depthModel.loadSettings(parent, "depth");
|
||||
m_timeModel.loadSettings(parent, "time");
|
||||
m_inVolModel.loadSettings(parent, "inVol");
|
||||
m_outVolModel.loadSettings(parent, "outVol");
|
||||
m_upwardModel.loadSettings(parent, "upward");
|
||||
m_downwardModel.loadSettings(parent, "downward");
|
||||
m_split1Model.loadSettings(parent, "split1");
|
||||
m_split2Model.loadSettings(parent, "split2");
|
||||
m_split1EnabledModel.loadSettings(parent, "split1Enabled");
|
||||
m_split2EnabledModel.loadSettings(parent, "split2Enabled");
|
||||
m_band1EnabledModel.loadSettings(parent, "band1Enabled");
|
||||
m_band2EnabledModel.loadSettings(parent, "band2Enabled");
|
||||
m_band3EnabledModel.loadSettings(parent, "band3Enabled");
|
||||
m_inHighModel.loadSettings(parent, "inHigh");
|
||||
m_inMidModel.loadSettings(parent, "inMid");
|
||||
m_inLowModel.loadSettings(parent, "inLow");
|
||||
m_outHighModel.loadSettings(parent, "outHigh");
|
||||
m_outMidModel.loadSettings(parent, "outMid");
|
||||
m_outLowModel.loadSettings(parent, "outLow");
|
||||
m_aThreshHModel.loadSettings(parent, "aThreshH");
|
||||
m_aThreshMModel.loadSettings(parent, "aThreshM");
|
||||
m_aThreshLModel.loadSettings(parent, "aThreshL");
|
||||
m_aRatioHModel.loadSettings(parent, "aRatioH");
|
||||
m_aRatioMModel.loadSettings(parent, "aRatioM");
|
||||
m_aRatioLModel.loadSettings(parent, "aRatioL");
|
||||
m_bThreshHModel.loadSettings(parent, "bThreshH");
|
||||
m_bThreshMModel.loadSettings(parent, "bThreshM");
|
||||
m_bThreshLModel.loadSettings(parent, "bThreshL");
|
||||
m_bRatioHModel.loadSettings(parent, "bRatioH");
|
||||
m_bRatioMModel.loadSettings(parent, "bRatioM");
|
||||
m_bRatioLModel.loadSettings(parent, "bRatioL");
|
||||
m_atkHModel.loadSettings(parent, "atkH");
|
||||
m_atkMModel.loadSettings(parent, "atkM");
|
||||
m_atkLModel.loadSettings(parent, "atkL");
|
||||
m_relHModel.loadSettings(parent, "relH");
|
||||
m_relMModel.loadSettings(parent, "relM");
|
||||
m_relLModel.loadSettings(parent, "relL");
|
||||
m_rmsTimeModel.loadSettings(parent, "rmsTime");
|
||||
m_kneeModel.loadSettings(parent, "knee");
|
||||
m_rangeModel.loadSettings(parent, "range");
|
||||
m_balanceModel.loadSettings(parent, "balance");
|
||||
m_depthScalingModel.loadSettings(parent, "depthScaling");
|
||||
m_stereoLinkModel.loadSettings(parent, "stereoLink");
|
||||
m_autoTimeModel.loadSettings(parent, "autoTime");
|
||||
m_mixModel.loadSettings(parent, "mix");
|
||||
m_feedbackModel.loadSettings(parent, "feedback");
|
||||
m_midsideModel.loadSettings(parent, "midside");
|
||||
m_lookaheadEnableModel.loadSettings(parent, "lookaheadEnable");
|
||||
m_lookaheadModel.loadSettings(parent, "lookahead");
|
||||
m_lowSideUpwardSuppressModel.loadSettings(parent, "lowSideUpwardSuppress");
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void LOMMControls::saveSettings(QDomDocument& doc, QDomElement& parent)
|
||||
{
|
||||
m_depthModel.saveSettings(doc, parent, "depth");
|
||||
m_timeModel.saveSettings(doc, parent, "time");
|
||||
m_inVolModel.saveSettings(doc, parent, "inVol");
|
||||
m_outVolModel.saveSettings(doc, parent, "outVol");
|
||||
m_upwardModel.saveSettings(doc, parent, "upward");
|
||||
m_downwardModel.saveSettings(doc, parent, "downward");
|
||||
m_split1Model.saveSettings(doc, parent, "split1");
|
||||
m_split2Model.saveSettings(doc, parent, "split2");
|
||||
m_split1EnabledModel.saveSettings(doc, parent, "split1Enabled");
|
||||
m_split2EnabledModel.saveSettings(doc, parent, "split2Enabled");
|
||||
m_band1EnabledModel.saveSettings(doc, parent, "band1Enabled");
|
||||
m_band2EnabledModel.saveSettings(doc, parent, "band2Enabled");
|
||||
m_band3EnabledModel.saveSettings(doc, parent, "band3Enabled");
|
||||
m_inHighModel.saveSettings(doc, parent, "inHigh");
|
||||
m_inMidModel.saveSettings(doc, parent, "inMid");
|
||||
m_inLowModel.saveSettings(doc, parent, "inLow");
|
||||
m_outHighModel.saveSettings(doc, parent, "outHigh");
|
||||
m_outMidModel.saveSettings(doc, parent, "outMid");
|
||||
m_outLowModel.saveSettings(doc, parent, "outLow");
|
||||
m_aThreshHModel.saveSettings(doc, parent, "aThreshH");
|
||||
m_aThreshMModel.saveSettings(doc, parent, "aThreshM");
|
||||
m_aThreshLModel.saveSettings(doc, parent, "aThreshL");
|
||||
m_aRatioHModel.saveSettings(doc, parent, "aRatioH");
|
||||
m_aRatioMModel.saveSettings(doc, parent, "aRatioM");
|
||||
m_aRatioLModel.saveSettings(doc, parent, "aRatioL");
|
||||
m_bThreshHModel.saveSettings(doc, parent, "bThreshH");
|
||||
m_bThreshMModel.saveSettings(doc, parent, "bThreshM");
|
||||
m_bThreshLModel.saveSettings(doc, parent, "bThreshL");
|
||||
m_bRatioHModel.saveSettings(doc, parent, "bRatioH");
|
||||
m_bRatioMModel.saveSettings(doc, parent, "bRatioM");
|
||||
m_bRatioLModel.saveSettings(doc, parent, "bRatioL");
|
||||
m_atkHModel.saveSettings(doc, parent, "atkH");
|
||||
m_atkMModel.saveSettings(doc, parent, "atkM");
|
||||
m_atkLModel.saveSettings(doc, parent, "atkL");
|
||||
m_relHModel.saveSettings(doc, parent, "relH");
|
||||
m_relMModel.saveSettings(doc, parent, "relM");
|
||||
m_relLModel.saveSettings(doc, parent, "relL");
|
||||
m_rmsTimeModel.saveSettings(doc, parent, "rmsTime");
|
||||
m_kneeModel.saveSettings(doc, parent, "knee");
|
||||
m_rangeModel.saveSettings(doc, parent, "range");
|
||||
m_balanceModel.saveSettings(doc, parent, "balance");
|
||||
m_depthScalingModel.saveSettings(doc, parent, "depthScaling");
|
||||
m_stereoLinkModel.saveSettings(doc, parent, "stereoLink");
|
||||
m_autoTimeModel.saveSettings(doc, parent, "autoTime");
|
||||
m_mixModel.saveSettings(doc, parent, "mix");
|
||||
m_feedbackModel.saveSettings(doc, parent, "feedback");
|
||||
m_midsideModel.saveSettings(doc, parent, "midside");
|
||||
m_lookaheadEnableModel.saveSettings(doc, parent, "lookaheadEnable");
|
||||
m_lookaheadModel.saveSettings(doc, parent, "lookahead");
|
||||
m_lowSideUpwardSuppressModel.saveSettings(doc, parent, "lowSideUpwardSuppress");
|
||||
}
|
||||
|
||||
|
||||
} // namespace lmms
|
||||
|
||||
|
||||
136
plugins/LOMM/LOMMControls.h
Normal file
@@ -0,0 +1,136 @@
|
||||
/*
|
||||
* LOMMControls.h
|
||||
*
|
||||
* Copyright (c) 2023 Lost Robot <r94231/at/gmail/dot/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 LMMS_LOMM_CONTROLS_H
|
||||
#define LMMS_LOMM_CONTROLS_H
|
||||
|
||||
#include "LOMMControlDialog.h"
|
||||
#include "EffectControls.h"
|
||||
|
||||
namespace lmms
|
||||
{
|
||||
class LOMMEffect;
|
||||
|
||||
namespace gui
|
||||
{
|
||||
class LOMMControlDialog;
|
||||
}
|
||||
|
||||
class LOMMControls : public EffectControls
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
LOMMControls(LOMMEffect* effect);
|
||||
~LOMMControls() override = default;
|
||||
|
||||
void saveSettings(QDomDocument & doc, QDomElement & parent) override;
|
||||
void loadSettings(const QDomElement & parent) override;
|
||||
inline QString nodeName() const override
|
||||
{
|
||||
return "LOMMControls";
|
||||
}
|
||||
|
||||
int controlCount() override
|
||||
{
|
||||
return 49;
|
||||
}
|
||||
|
||||
gui::EffectControlDialog* createView() override
|
||||
{
|
||||
m_view = new gui::LOMMControlDialog(this);
|
||||
return m_view;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void setInitAndReset(AutomatableModel& model, T initValue)
|
||||
{
|
||||
model.setInitValue(initValue);
|
||||
model.reset();
|
||||
}
|
||||
|
||||
public slots:
|
||||
void resetAllParameters();
|
||||
|
||||
private:
|
||||
LOMMEffect* m_effect;
|
||||
gui::LOMMControlDialog* m_view;
|
||||
|
||||
FloatModel m_depthModel;
|
||||
FloatModel m_timeModel;
|
||||
FloatModel m_inVolModel;
|
||||
FloatModel m_outVolModel;
|
||||
FloatModel m_upwardModel;
|
||||
FloatModel m_downwardModel;
|
||||
FloatModel m_split1Model;
|
||||
FloatModel m_split2Model;
|
||||
BoolModel m_split1EnabledModel;
|
||||
BoolModel m_split2EnabledModel;
|
||||
BoolModel m_band1EnabledModel;
|
||||
BoolModel m_band2EnabledModel;
|
||||
BoolModel m_band3EnabledModel;
|
||||
FloatModel m_inHighModel;
|
||||
FloatModel m_inMidModel;
|
||||
FloatModel m_inLowModel;
|
||||
FloatModel m_outHighModel;
|
||||
FloatModel m_outMidModel;
|
||||
FloatModel m_outLowModel;
|
||||
FloatModel m_aThreshHModel;
|
||||
FloatModel m_aThreshMModel;
|
||||
FloatModel m_aThreshLModel;
|
||||
FloatModel m_aRatioHModel;
|
||||
FloatModel m_aRatioMModel;
|
||||
FloatModel m_aRatioLModel;
|
||||
FloatModel m_bThreshHModel;
|
||||
FloatModel m_bThreshMModel;
|
||||
FloatModel m_bThreshLModel;
|
||||
FloatModel m_bRatioHModel;
|
||||
FloatModel m_bRatioMModel;
|
||||
FloatModel m_bRatioLModel;
|
||||
FloatModel m_atkHModel;
|
||||
FloatModel m_atkMModel;
|
||||
FloatModel m_atkLModel;
|
||||
FloatModel m_relHModel;
|
||||
FloatModel m_relMModel;
|
||||
FloatModel m_relLModel;
|
||||
FloatModel m_rmsTimeModel;
|
||||
FloatModel m_kneeModel;
|
||||
FloatModel m_rangeModel;
|
||||
FloatModel m_balanceModel;
|
||||
BoolModel m_depthScalingModel;
|
||||
BoolModel m_stereoLinkModel;
|
||||
FloatModel m_autoTimeModel;
|
||||
FloatModel m_mixModel;
|
||||
BoolModel m_feedbackModel;
|
||||
BoolModel m_midsideModel;
|
||||
BoolModel m_lookaheadEnableModel;
|
||||
FloatModel m_lookaheadModel;
|
||||
BoolModel m_lowSideUpwardSuppressModel;
|
||||
|
||||
friend class gui::LOMMControlDialog;
|
||||
friend class LOMMEffect;
|
||||
};
|
||||
|
||||
} // namespace lmms
|
||||
|
||||
#endif // LMMS_LOMM_CONTROLS_H
|
||||
BIN
plugins/LOMM/artwork.png
Normal file
|
After Width: | Height: | Size: 68 KiB |
BIN
plugins/LOMM/crossover_led_green.png
Normal file
|
After Width: | Height: | Size: 290 B |
BIN
plugins/LOMM/crossover_led_off.png
Normal file
|
After Width: | Height: | Size: 6.5 KiB |
BIN
plugins/LOMM/depthScaling_active.png
Normal file
|
After Width: | Height: | Size: 867 B |
BIN
plugins/LOMM/depthScaling_inactive.png
Normal file
|
After Width: | Height: | Size: 886 B |
BIN
plugins/LOMM/feedback_active.png
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
plugins/LOMM/feedback_inactive.png
Normal file
|
After Width: | Height: | Size: 8.7 KiB |
BIN
plugins/LOMM/high_band_active.png
Normal file
|
After Width: | Height: | Size: 8.6 KiB |
BIN
plugins/LOMM/high_band_inactive.png
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
plugins/LOMM/init_active.png
Normal file
|
After Width: | Height: | Size: 1.2 KiB |
BIN
plugins/LOMM/init_inactive.png
Normal file
|
After Width: | Height: | Size: 1.2 KiB |
BIN
plugins/LOMM/logo.png
Normal file
|
After Width: | Height: | Size: 774 B |
BIN
plugins/LOMM/lookahead_active.png
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
BIN
plugins/LOMM/lookahead_inactive.png
Normal file
|
After Width: | Height: | Size: 1.0 KiB |
BIN
plugins/LOMM/lowSideUpwardSuppress_active.png
Normal file
|
After Width: | Height: | Size: 972 B |
BIN
plugins/LOMM/lowSideUpwardSuppress_inactive.png
Normal file
|
After Width: | Height: | Size: 4.6 KiB |
BIN
plugins/LOMM/low_band_active.png
Normal file
|
After Width: | Height: | Size: 8.6 KiB |
BIN
plugins/LOMM/low_band_inactive.png
Normal file
|
After Width: | Height: | Size: 1.7 KiB |
BIN
plugins/LOMM/mid_band_active.png
Normal file
|
After Width: | Height: | Size: 8.6 KiB |
BIN
plugins/LOMM/mid_band_inactive.png
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
plugins/LOMM/midside_active.png
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
plugins/LOMM/midside_inactive.png
Normal file
|
After Width: | Height: | Size: 9.0 KiB |
BIN
plugins/LOMM/split1Enabled_active.png
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
plugins/LOMM/split1Enabled_inactive.png
Normal file
|
After Width: | Height: | Size: 1.0 KiB |
BIN
plugins/LOMM/split2Enabled_active.png
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
plugins/LOMM/split2Enabled_inactive.png
Normal file
|
After Width: | Height: | Size: 1.0 KiB |
BIN
plugins/LOMM/stereoLink_active.png
Normal file
|
After Width: | Height: | Size: 1.0 KiB |
BIN
plugins/LOMM/stereoLink_inactive.png
Normal file
|
After Width: | Height: | Size: 1.0 KiB |