Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
108 commits
Select commit Hold shift + click to select a range
99e74a4
Update PluginList.cmake
ewanp2025 Dec 12, 2025
d8db6bc
Create CMakeLists.txt
ewanp2025 Dec 12, 2025
f5eb091
Create Visualiser.cpp
ewanp2025 Dec 12, 2025
b2afbb6
Create Visualiser.h
ewanp2025 Dec 12, 2025
9e1911e
Create CMakeLists.txt
ewanp2025 Dec 12, 2025
1443f0c
Create artwork.svg
ewanp2025 Dec 12, 2025
7759cf2
Create TransferFunction.cpp
ewanp2025 Dec 12, 2025
fc150ed
Create TransferFunction.h
ewanp2025 Dec 12, 2025
7bd02b5
Create TransferFunctionControlDialog.cpp
ewanp2025 Dec 12, 2025
967ddbd
Create TransferFunctionControlDialog.h
ewanp2025 Dec 12, 2025
c5c975c
Create TransferFunctionLogic.h
ewanp2025 Dec 12, 2025
c427cbd
Create TransferFunctionControls.cpp
ewanp2025 Dec 12, 2025
ad61d67
Create TransferFunctionControls.h
ewanp2025 Dec 12, 2025
1a8890a
Update TransferFunctionControls.cpp
ewanp2025 Dec 12, 2025
0f02ba8
Update TransferFunction.h
ewanp2025 Dec 12, 2025
d13c721
Update TransferFunction.cpp
ewanp2025 Dec 12, 2025
192ce63
Update TransferFunctionControls.h
ewanp2025 Dec 12, 2025
cd5920a
Update TransferFunctionLogic.h
ewanp2025 Dec 12, 2025
c73993a
Update artwork.svg
ewanp2025 Dec 12, 2025
f346ced
Update Visualiser.cpp
ewanp2025 Dec 12, 2025
e757a98
Update Visualiser.h
ewanp2025 Dec 12, 2025
5681c5f
Update TransferFunction.cpp
ewanp2025 Dec 12, 2025
79850cc
Update TransferFunction.h
ewanp2025 Dec 12, 2025
a6e2ef9
Update TransferFunctionControlDialog.cpp
ewanp2025 Dec 12, 2025
2c8d151
Update TransferFunctionControlDialog.h
ewanp2025 Dec 12, 2025
4cfc1a9
Update TransferFunctionControls.cpp
ewanp2025 Dec 12, 2025
b3a95b5
Update TransferFunctionControls.h
ewanp2025 Dec 12, 2025
d14df63
Update TransferFunctionLogic.h
ewanp2025 Dec 12, 2025
14d1b0c
Update artwork.svg
ewanp2025 Dec 12, 2025
2662d6f
Update Visualiser.cpp
ewanp2025 Dec 12, 2025
79abb97
Update Visualiser.h
ewanp2025 Dec 12, 2025
6f3d733
Update Visualiser.h
ewanp2025 Dec 12, 2025
be6adb8
Update TransferFunction.cpp
ewanp2025 Dec 16, 2025
74e885c
Update TransferFunction.h
ewanp2025 Dec 16, 2025
8aef05b
Update TransferFunctionControlDialog.cpp
ewanp2025 Dec 16, 2025
37a54ad
Update TransferFunctionControlDialog.h
ewanp2025 Dec 16, 2025
3a5452d
Update TransferFunctionControls.cpp
ewanp2025 Dec 16, 2025
ea8ef56
Update TransferFunctionControls.h
ewanp2025 Dec 16, 2025
4965801
Update TransferFunctionLogic.h
ewanp2025 Dec 16, 2025
41709ad
Update TransferFunction.cpp
ewanp2025 Dec 16, 2025
2866931
Update TransferFunctionControlDialog.cpp
ewanp2025 Dec 16, 2025
48e328e
Update TransferFunctionLogic.h
ewanp2025 Dec 16, 2025
90ba663
Add Windows build workflow for LMMS
ewanp2025 Dec 17, 2025
a060346
Add full Windows build workflow for LMMS
ewanp2025 Dec 17, 2025
2ca1f33
Update windows-build.yml
ewanp2025 Dec 17, 2025
04f7b41
Update windows-build.yml
ewanp2025 Dec 17, 2025
adc21e3
Update windows-build.yml
ewanp2025 Dec 17, 2025
da9e31e
Update windows-build.yml
ewanp2025 Dec 17, 2025
18b25df
Update Visualiser.cpp
ewanp2025 Dec 17, 2025
5a93cf4
Update windows-build.yml
ewanp2025 Dec 17, 2025
88dc36c
Update Visualiser.cpp
ewanp2025 Dec 17, 2025
2cc31d9
Fixed Namespace to comply for build check
ewanp2025 Dec 17, 2025
999c275
Changed Namespace to comply with build check
ewanp2025 Dec 17, 2025
5127d9e
Change namespace to comply with build check
ewanp2025 Dec 17, 2025
26ef724
Update windows-build.yml
ewanp2025 Dec 17, 2025
f6c4b88
Update TransferFunction.cpp
ewanp2025 Dec 17, 2025
0a0f42c
Update windows-build.yml
ewanp2025 Dec 17, 2025
75c4cc6
Update windows-build.yml
ewanp2025 Dec 17, 2025
823ecf1
Removed Space
ewanp2025 Dec 17, 2025
4ff443b
Update PluginList.cmake
ewanp2025 Dec 17, 2025
abeec67
Fixed to also compile under GitHub
ewanp2025 Dec 17, 2025
f8e07cb
Update windows-build.yml
ewanp2025 Dec 17, 2025
afcc092
Fixed to compile under Github
ewanp2025 Dec 17, 2025
aead096
Trying to delete
ewanp2025 Dec 17, 2025
ba8855f
Update Visualiser.h
ewanp2025 Dec 17, 2025
f00b9e5
Update Visualiser.cpp
ewanp2025 Dec 17, 2025
d2bdb29
Compiles on Ubuntu, but not GitHub, last try then sleep
ewanp2025 Dec 17, 2025
945dce5
Compiles on Ubuntu but not Github, last try then sleep
ewanp2025 Dec 17, 2025
dbaf288
Update Visualiser.cpp
ewanp2025 Dec 18, 2025
b722bae
Update Visualiser.cpp
ewanp2025 Dec 18, 2025
8e9ca17
Update Visualiser.cpp
ewanp2025 Dec 18, 2025
d3b53f0
Update Visualiser.cpp
ewanp2025 Dec 18, 2025
0a11d28
Create CMakeLists.txt
ewanp2025 Dec 18, 2025
ee58204
Add
ewanp2025 Dec 18, 2025
f269ad5
Update PluginList.cmake
ewanp2025 Dec 18, 2025
ba47b56
Update StepGate.h
ewanp2025 Dec 18, 2025
d05d408
Update StepGate.cpp
ewanp2025 Dec 18, 2025
b1991da
Update StepGateControlDialog.cpp
ewanp2025 Dec 18, 2025
88b85ab
Update StepGateControlDialog.h
ewanp2025 Dec 18, 2025
616e3dc
Update StepGateControls.cpp
ewanp2025 Dec 18, 2025
642b23b
Update StepGateControls.h
ewanp2025 Dec 18, 2025
f40c579
Update StepGateControls.h
ewanp2025 Dec 18, 2025
fe4c1bd
Update StepGate.cpp
ewanp2025 Dec 18, 2025
23e1d92
Update StepGateControlDialog.cpp
ewanp2025 Dec 18, 2025
a5da671
Update StepGateControlDialog.h
ewanp2025 Dec 18, 2025
f82c255
Update StepGateControls.cpp
ewanp2025 Dec 18, 2025
1e111fb
Update CMakeLists.txt
ewanp2025 Dec 18, 2025
e00875f
Update StepGate.h
ewanp2025 Dec 18, 2025
18a38ed
Update StepGate.cpp
ewanp2025 Dec 18, 2025
4046919
Create CMakeLists.txt
ewanp2025 Dec 19, 2025
b0eb123
Update CMakeLists.txt
ewanp2025 Dec 19, 2025
1d1f5be
Delete plugins/MasteringSuite directory
ewanp2025 Dec 19, 2025
c08a3e1
Update CMakeLists.txt
ewanp2025 Dec 19, 2025
edf5f34
Create CMakeLists.txt
ewanp2025 Dec 21, 2025
1ab723f
Files
ewanp2025 Dec 21, 2025
1b4a2ef
add
ewanp2025 Dec 21, 2025
312b14d
Update WaveScanner.cpp
ewanp2025 Dec 21, 2025
5602e0f
Delete plugins/WaveScanner directory
ewanp2025 Dec 21, 2025
fa37c59
Update CMakeLists.txt
ewanp2025 Dec 21, 2025
002d594
Create CMakeLists.txt
ewanp2025 Jan 7, 2026
1b84816
Create ModularOne.cpp
ewanp2025 Jan 7, 2026
c82a907
Create ModularOne.h
ewanp2025 Jan 7, 2026
e19109d
Add files via upload
ewanp2025 Jan 7, 2026
c2517f9
Update PluginList.cmake
ewanp2025 Jan 7, 2026
d332c66
Update ModularOne.cpp
ewanp2025 Jan 7, 2026
31df357
Update ModularOne.h
ewanp2025 Jan 7, 2026
17650c3
Delete plugins/ModularOne directory
ewanp2025 Jan 7, 2026
2127d88
Update PluginList.cmake
ewanp2025 Jan 7, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/windows-build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@

3 changes: 3 additions & 0 deletions cmake/modules/PluginList.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -64,17 +64,20 @@ SET(LMMS_PLUGIN_LIST
SlewDistortion
SlicerT
SpectrumAnalyzer
StepGate
StereoEnhancer
StereoMatrix
Stk
TapTempo
TransferFunction
VstBase
Vestige
VstEffect
Watsyn
WaveShaper
Vectorscope
Vibed
Visualiser
Xpressive
ZynAddSubFx
)
Expand Down
3 changes: 3 additions & 0 deletions plugins/StepGate/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
INCLUDE(BuildPlugin)

BUILD_PLUGIN(StepGate StepGate.cpp StepGateControls.cpp StepGateControlDialog.cpp MOCFILES StepGateControls.h StepGateControlDialog.h )
168 changes: 168 additions & 0 deletions plugins/StepGate/StepGate.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
#include "StepGate.h"
#include "embed.h"
#include "plugin_export.h"
#include "Engine.h"
#include "AudioEngine.h"
#include "Song.h"
#include <cmath>
namespace lmms
{
extern "C" {
Plugin::Descriptor PLUGIN_EXPORT StepGate_plugin_descriptor = {
QT_STRINGIFY(PLUGIN_NAME),
"StepGate",
QT_TRANSLATE_NOOP("PluginBrowser", "16-Step On Off Gate"),
"Ewan Pettigrew",
0x0100,
Plugin::Type::Effect,
new PixmapLoader("lmms-plugin-logo"),
nullptr,
nullptr,
};
}
// =============================================================
// Constructor
// =============================================================
StepGateEffect::StepGateEffect(Model* parent,
const Descriptor::SubPluginFeatures::Key* key)
: Effect(&StepGate_plugin_descriptor, parent, key),
m_controls(this),
m_phase(0.0),
m_currentGain(0.0f)
{
}
// =============================================================
// Initialize delay buffer when needed
// =============================================================
void StepGateEffect::initDelayBuffer(float sampleRate)
{
float maxDelaySeconds = 2.0f;
m_delayBufferSize = (int)(maxDelaySeconds * sampleRate);
m_delayBufferL.assign(m_delayBufferSize, 0.0f);
m_delayBufferR.assign(m_delayBufferSize, 0.0f);
m_delayWritePos = 0;
}
// =============================================================
// Circular buffer reader helper
// =============================================================
float StepGateEffect::readDelaySample(const std::vector<float>& buf, int pos, int bufferSize)
{
if(pos < 0) pos += bufferSize;
if(pos >= bufferSize) pos -= bufferSize;
return buf[pos];
}
// =============================================================
// MAIN DSP — Process Audio
// =============================================================
Effect::ProcessStatus StepGateEffect::processImpl(SampleFrame* buf,
const fpp_t frames)
{
// -------------------------
// Host timing
// -------------------------
float bpm = Engine::getSong()->getTempo();
float rate = Engine::audioEngine()->baseSampleRate();
// Init delay buffer if needed
if(m_delayBufferSize == 0)
initDelayBuffer(rate);
float speed = m_controls.m_speedModel.value();
float smoothAmount = m_controls.m_smoothModel.value();
float swingAmount = m_controls.m_swingModel.value();
// Delay controls
int delayIndex = (int)m_controls.m_delayTimeModel.value(); // 0..3
float feedback = m_controls.m_feedbackModel.value();
float wet = m_controls.m_wetModel.value();
float dry = 1.0f - wet;
// tempo-synced delay table
// Values in beats:
// 1/16 = 0.25 beats
// 1/8 = 0.5 beats
// 3/16 = 0.75 beats
// 1/4 = 1.0 beats
static const float delayBeatValues[4] =
{
0.25f,
0.50f,
0.75f,
1.00f
};
float delayBeats = delayBeatValues[delayIndex];
float delaySeconds = (60.0f / bpm) * delayBeats;
int delaySamples = (int)(delaySeconds * rate);
if(delaySamples >= m_delayBufferSize)
delaySamples = m_delayBufferSize - 1;
// -------------------------
// Timing for gate
// -------------------------
double samplesPerBar = (240.0 * rate) / bpm;
double samplesPerStep = (samplesPerBar / 16.0) / speed;
double swingOffset = samplesPerStep * swingAmount * 0.75;
float inertia = smoothAmount * 0.995f;
// -------------------------
// Compute current step index ONCE per block for LED
// -------------------------
double pairLength = samplesPerStep * 2.0;
double positionInPair = fmod(m_phase, pairLength);
int pairIndex = (int)(m_phase / pairLength);
double swingThreshold = samplesPerStep + swingOffset;
int stepIndexInPair =
(positionInPair < swingThreshold) ? 0 : 1;
int blockStepIndex = (pairIndex * 2) + stepIndexInPair;
blockStepIndex %= 16;
m_controls.setRunIndex(blockStepIndex);
// -------------------------
// MAIN AUDIO LOOP
// -------------------------
for (fpp_t i = 0; i < frames; ++i)
{
// recalc pair position per sample
double positionInPair_i = fmod(m_phase, pairLength);
int pairIndex_i = (int)(m_phase / pairLength);
int stepIndexInPair_i =
(positionInPair_i < swingThreshold) ? 0 : 1;
int stepIndex = (pairIndex_i * 2) + stepIndexInPair_i;
stepIndex %= 16;
bool isOpen = m_controls.getCurrentStep(stepIndex);
float target = isOpen ? 1.f : 0.f;
// smoothing
if (smoothAmount < 0.001f)
m_currentGain = target;
else
m_currentGain =
(m_currentGain * inertia) + (target * (1.f - inertia));
// apply gate
float inL = buf[i][0] * m_currentGain;
float inR = buf[i][1] * m_currentGain;
// ---- Delay DSP ----
int readPos = m_delayWritePos - delaySamples;
if(readPos < 0) readPos += m_delayBufferSize;
float delayedL = readDelaySample(m_delayBufferL, readPos, m_delayBufferSize);
float delayedR = readDelaySample(m_delayBufferR, readPos, m_delayBufferSize);
// write new sample into circular buffer
float fbL = delayedL * feedback;
float fbR = delayedR * feedback;
m_delayBufferL[m_delayWritePos] = inL + fbL;
m_delayBufferR[m_delayWritePos] = inR + fbR;
// increment write pos
m_delayWritePos++;
if(m_delayWritePos >= m_delayBufferSize)
m_delayWritePos = 0;
// output mix
buf[i][0] = (inL * dry) + (delayedL * wet);
buf[i][1] = (inR * dry) + (delayedR * wet);
// advance gate phase
m_phase += 1.0;
if (m_phase >= samplesPerBar)
m_phase -= samplesPerBar;
}
return Effect::ProcessStatus::Continue;
}
extern "C" {
PLUGIN_EXPORT Plugin* lmms_plugin_main(Model* parent, void* data)
{
return new StepGateEffect(
parent,
static_cast<const Plugin::Descriptor::SubPluginFeatures::Key*>(data));
}
}
} // namespace lmms
34 changes: 34 additions & 0 deletions plugins/StepGate/StepGate.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
#ifndef LMMS_STEPGATE_H
#define LMMS_STEPGATE_H
#include "Effect.h"
#include "StepGateControls.h"
#include <vector>
namespace lmms
{
class StepGateEffect : public Effect
{
public:
StepGateEffect(Model* parent, const Descriptor::SubPluginFeatures::Key* key);
~StepGateEffect() override = default;
ProcessStatus processImpl(SampleFrame* buf, const fpp_t frames) override;
EffectControls* controls() override { return &m_controls; }
private:
StepGateControls m_controls;
// Gate DSP
double m_phase;
float m_currentGain;
// -------------------------
// Delay DSP
// -------------------------
float m_prevFeedback = 0.0f;
float m_prevWet = 0.0f;
int m_delayBufferSize = 0;
int m_delayWritePos = 0;
std::vector<float> m_delayBufferL;
std::vector<float> m_delayBufferR;
void initDelayBuffer(float sampleRate);
float readDelaySample(const std::vector<float>& buf, int readPos, int bufferSize);
friend class StepGateControls;
};
} // namespace lmms
#endif // LMMS_STEPGATE_H
161 changes: 161 additions & 0 deletions plugins/StepGate/StepGateControlDialog.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
#include "StepGateControlDialog.h"
#include "StepGateControls.h"
#include "Knob.h"
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QPushButton>
#include <QLabel>
#include <QVariant>
namespace lmms
{
namespace gui
{
StepGateControlDialog::StepGateControlDialog(StepGateControls* controls) :
EffectControlDialog(controls),
m_controls(controls)
{
setMinimumWidth(700);
setMinimumHeight(260);
setWindowTitle("StepGate - Trance Gate + Delay");
// MAIN LAYOUT: Vertical Stack
// Row 1: Knobs
// Row 2: Buttons
QVBoxLayout* mainLayout = new QVBoxLayout(this);
mainLayout->setSpacing(20);
mainLayout->setContentsMargins(20, 20, 20, 20);
// ------------------------------------------------------------
// TOP ROW: KNOBS (Horizontal Layout)
// ------------------------------------------------------------
QHBoxLayout* knobLayout = new QHBoxLayout();
knobLayout->setSpacing(15);
mainLayout->addLayout(knobLayout);
// Pattern (A–D)
Knob* patKnob = new Knob(KnobType::Bright26, "Pattern", this);
patKnob->setModel(&m_controls->m_patternModel);
patKnob->setHintText("Pattern", "Select Pattern A–D");
knobLayout->addWidget(patKnob, 0, Qt::AlignCenter);
// Speed
Knob* speedKnob = new Knob(KnobType::Bright26, "Speed", this);
speedKnob->setModel(&m_controls->m_speedModel);
speedKnob->setHintText("Speed", "Pattern Speed (0.5x, 1x, 2x, 4x)");
knobLayout->addWidget(speedKnob, 0, Qt::AlignCenter);
// Smooth
Knob* smoothKnob = new Knob(KnobType::Bright26, "Smooth", this);
smoothKnob->setModel(&m_controls->m_smoothModel);
smoothKnob->setHintText("Smooth", "Gate Smoothing");
knobLayout->addWidget(smoothKnob, 0, Qt::AlignCenter);
// Swing
Knob* swingKnob = new Knob(KnobType::Bright26, "Swing", this);
swingKnob->setModel(&m_controls->m_swingModel);
swingKnob->setHintText("Swing", "Rhythmic Swing");
knobLayout->addWidget(swingKnob, 0, Qt::AlignCenter);
// Delay Time
Knob* delayTimeKnob = new Knob(KnobType::Bright26, "Delay", this);
delayTimeKnob->setModel(&m_controls->m_delayTimeModel);
delayTimeKnob->setHintText("Delay Time", "1/16, 1/8, 3/16, 1/4");
knobLayout->addWidget(delayTimeKnob, 0, Qt::AlignCenter);
// Feedback
Knob* feedbackKnob = new Knob(KnobType::Bright26, "Feedback", this);
feedbackKnob->setModel(&m_controls->m_feedbackModel);
feedbackKnob->setHintText("Feedback", "Delay Feedback");
knobLayout->addWidget(feedbackKnob, 0, Qt::AlignCenter);
// Wet
Knob* wetKnob = new Knob(KnobType::Bright26, "Wet", this);
wetKnob->setModel(&m_controls->m_wetModel);
wetKnob->setHintText("Wet", "Delay Wet Mix");
knobLayout->addWidget(wetKnob, 0, Qt::AlignCenter);
// Center knobs if window is wide
knobLayout->addStretch();
knobLayout->insertStretch(0);
// ------------------------------------------------------------
// GATE BUTTON GRID (Horizontal Layout)
// ------------------------------------------------------------
QHBoxLayout* buttonLayout = new QHBoxLayout();
buttonLayout->setSpacing(6);
mainLayout->addLayout(buttonLayout);
for(int i = 0; i < 16; ++i)
{
QPushButton* btn = new QPushButton(QString::number(i + 1), this);
btn->setCheckable(true);
btn->setFixedSize(32, 42);
btn->setProperty("stepIndex", QVariant(i));
// default styles
btn->setStyleSheet(
"QPushButton { background-color:#800000; color:#fff; "
"border:1px solid #400; border-radius:3px; }"
"QPushButton:hover { background-color:#aa0000; }"
"QPushButton:checked { background-color:#00FF00; color:#000; "
"font-weight:bold; border:1px solid #0A0; }"
"QPushButton:checked:hover { background-color:#55FF55; }"
);
connect(btn, &QPushButton::clicked,
this, &StepGateControlDialog::onButtonClicked);
m_stepButtons.push_back(btn);
buttonLayout->addWidget(btn);
}
// SIGNAL CONNECTIONS
connect(m_controls, &StepGateControls::stepsChanged,
this, &StepGateControlDialog::updateButtonsFromModel);
connect(&m_controls->m_patternModel, &FloatModel::dataChanged,
this, &StepGateControlDialog::updateButtonsFromModel);
connect(m_controls, &StepGateControls::runIndexChanged,
this, &StepGateControlDialog::onRunIndexChanged);
updateButtonsFromModel();
}
void StepGateControlDialog::onButtonClicked()
{
QPushButton* btn = qobject_cast<QPushButton*>(sender());
if(!btn) return;
int idx = btn->property("stepIndex").toInt();
int pat = (int)m_controls->m_patternModel.value();
m_controls->setStep(pat, idx, btn->isChecked());
}
void StepGateControlDialog::updateButtonsFromModel()
{
int pat = (int)m_controls->m_patternModel.value();
for(int i = 0; i < 16; ++i)
{
m_stepButtons[i]->blockSignals(true);
m_stepButtons[i]->setChecked(m_controls->getStep(pat, i));
m_stepButtons[i]->blockSignals(false);
}
}
void StepGateControlDialog::onRunIndexChanged(int index)
{
for(int i = 0; i < 16; ++i)
{
if(i == index)
{
// ALWAYS VISIBLE LED
m_stepButtons[i]->setStyleSheet(
"QPushButton { "
"background-color:#00BFFF; "
"color:#000; "
"border:3px solid #FFFFFF; "
"border-radius:3px; "
"font-weight:bold; "
"} "
);
}
else
{
// normal appearance
if(m_stepButtons[i]->isChecked())
{
m_stepButtons[i]->setStyleSheet(
"QPushButton { background-color:#00FF00; color:#000; "
"border:1px solid #0A0; border-radius:3px; }"
);
}
else
{
m_stepButtons[i]->setStyleSheet(
"QPushButton { background-color:#800000; color:#fff; "
"border:1px solid #400; border-radius:3px; }"
);
}
}
}
}
} // namespace gui
} // namespace lmms
Loading