justasample/Source/Components/FxChain.cpp

211 lines
7.6 KiB
C++
Raw Normal View History

2026-07-23 23:40:48 +02:00
/*
==============================================================================
FxChain.cpp
Created: 5 Jan 2024 3:26:37pm
Author: binya
==============================================================================
*/
#include <JuceHeader.h>
#include "FxChain.h"
void FxChainShadows::resized()
{
int innerShadowOffset = int(0.001f * getWidth());
innerShadow.setOffset({ 0, innerShadowOffset }, 0);
innerShadow.setOffset({ 0, -innerShadowOffset }, 1);
dragShadow.setOffset({ innerShadowOffset, innerShadowOffset });
}
void FxChainShadows::paint(juce::Graphics& g)
{
juce::Path innerShadowPath;
innerShadowPath.addRectangle(getLocalBounds());
innerShadow.render(g, innerShadowPath);
auto parent = dynamic_cast<FxChain*>(getParentComponent());
if (parent->isChainDragging())
{
juce::Path dragShadowPath;
dragShadowPath.addRectangle(parent->getDragComp()->getBounds());
dragShadow.render(g, dragShadowPath);
}
}
void FxChainShadows::lookAndFeelChanged()
{
auto colors = getTheme();
innerShadow.setColor(colors.slate.withAlpha(0.25f), 0);
innerShadow.setColor(colors.slate.withAlpha(0.25f), 1);
dragShadow.setColor(colors.slate.withAlpha(0.125f), 0);
}
FxChain::FxChain(JustaSampleAudioProcessor& processor) :
reverbDisplay(processor.APVTS()),
distortionDisplay(processor.APVTS(), int(processor.getSampleRate())),
eqDisplay(processor.APVTS(), int(processor.getSampleRate())),
chorusDisplay(processor.APVTS(), int(processor.getSampleRate())),
reverbModule(this, processor.APVTS(), "Reverb", PluginParameters::REVERB, PluginParameters::REVERB_ENABLED, PluginParameters::REVERB_MIX, reverbDisplay),
distortionModule(this, processor.APVTS(), "Distortion", PluginParameters::DISTORTION, PluginParameters::DISTORTION_ENABLED, PluginParameters::DISTORTION_MIX, distortionDisplay),
eqModule(this, processor.APVTS(), "Equalizer", PluginParameters::EQ, PluginParameters::EQ_ENABLED, eqDisplay),
chorusModule(this, processor.APVTS(), "Chorus", PluginParameters::CHORUS, PluginParameters::CHORUS_ENABLED, PluginParameters::CHORUS_MIX, chorusDisplay),
fxPermAttachment(*processor.APVTS().getParameter(PluginParameters::FX_PERM), [&](float newValue) { moduleOrder = PluginParameters::paramToPerm(int(newValue)); oldVal = int(newValue); resized(); }, &processor.getUndoManager())
{
reverbModule.addRotary(PluginParameters::REVERB_SIZE, "Size", { 11.4f, 82.f }, 87.f);
reverbModule.addRotary(PluginParameters::REVERB_DAMPING, "Damping", { 108.4f, 52.f }, 87.f);
reverbModule.addRotary(PluginParameters::REVERB_PREDELAY, "Delay", { 208.f, 82.f }, 87.f, PluginParameters::TIME_UNIT);
reverbModule.addRotary(PluginParameters::REVERB_LOWS, "Lows", { 302.f, 52.f }, 87.f);
reverbModule.addRotary(PluginParameters::REVERB_HIGHS, "Highs", { 399.4f, 82.f }, 87.f);
addAndMakeVisible(reverbModule);
distortionModule.addRotary(PluginParameters::DISTORTION_DENSITY, "Density", { 99.f, 46.f }, 110.f);
distortionModule.addRotary(PluginParameters::DISTORTION_HIGHPASS, "Highpass", { 289.f, 46.f }, 110.f);
addAndMakeVisible(distortionModule);
eqModule.addRotary(PluginParameters::EQ_LOW_GAIN, "Lows", { 44.5f, 46.f }, 110.f, PluginParameters::VOLUME_UNIT);
eqModule.addRotary(PluginParameters::EQ_MID_GAIN, "Mids", { 194.f, 46.f }, 110.f, PluginParameters::VOLUME_UNIT);
eqModule.addRotary(PluginParameters::EQ_HIGH_GAIN, "Highs", { 344.f, 46.f }, 110.f, PluginParameters::VOLUME_UNIT);
addAndMakeVisible(eqModule);
chorusModule.addRotary(PluginParameters::CHORUS_RATE, "Rate", { 40.f, 82.f }, 87.f, PluginParameters::FREQUENCY_UNIT);
chorusModule.addRotary(PluginParameters::CHORUS_DEPTH, "Depth", { 150.f, 52.f }, 87.f);
chorusModule.addRotary(PluginParameters::CHORUS_CENTER_DELAY, "Delay", { 260.6f, 82.f }, 87.f, PluginParameters::TIME_UNIT);
chorusModule.addRotary(PluginParameters::CHORUS_FEEDBACK, "Feedback", { 371.f, 52.f }, 87.f);
addAndMakeVisible(chorusModule);
shadows.setInterceptsMouseClicks(false, false);
addAndMakeVisible(shadows);
fxPermAttachment.sendInitialUpdate();
addMouseListener(this, true);
}
void FxChain::paint(juce::Graphics& g)
{
auto colors = getTheme();
g.setColour(colors.slate);
auto bounds = getLocalBounds();
auto dividerWidth = int(std::ceil(getWidth() * Layout::fxChainDivider));
auto moduleWidth = int(std::round((bounds.getWidth() - 3 * dividerWidth) / 4.f));
for (size_t i = 0; i < moduleOrder.size() - 1; i++)
{
bounds.removeFromLeft(moduleWidth);
auto divider = bounds.removeFromLeft(dividerWidth);
g.fillRect(divider);
}
}
void FxChain::resized()
{
auto bounds = getLocalBounds();
auto dividerWidth = int(std::ceil(getWidth() * Layout::fxChainDivider));
auto moduleWidth = int(std::round((bounds.getWidth() - 3 * dividerWidth) / 4.f));
for (const auto& fxType : moduleOrder)
{
auto& module = getModule(fxType);
auto moduleBounds = bounds.removeFromLeft(moduleWidth);
bounds.removeFromLeft(dividerWidth);
if (!(dragging && &module == dragComp))
module.setBounds(moduleBounds.toNearestInt());
}
shadows.setBounds(getLocalBounds());
if (dragging)
{
auto dragCompBounds = dragComp->getBounds();
dragCompBounds.setPosition(juce::jlimit<int>(0, getWidth() - dragComp->getWidth(), mouseX + dragOffset), 0);
dragComp->setBounds(dragCompBounds);
repaint();
}
}
void FxChain::mouseDrag(const juce::MouseEvent& event)
{
if (!dragging)
return;
auto localEvent = event.getEventRelativeTo(this);
mouseX = localEvent.x;
auto dragCompBounds = dragComp->getBounds();
dragCompBounds.setPosition(juce::jlimit<int>(0, getWidth() - dragComp->getWidth(), mouseX + dragOffset), 0);
// See if the chain's module order needs to be updated
auto bounds = getLocalBounds();
auto moduleWidth = bounds.getWidth() / 4;
for (int i = 0; i < 4; i++)
{
auto moduleBounds = bounds.removeFromLeft(moduleWidth);
if (i != dragCompIndex && moduleBounds.getX() <= dragCompBounds.getCentreX() && dragCompBounds.getCentreX() <= moduleBounds.getRight())
{
auto fxType = moduleOrder[i];
moduleOrder[i] = moduleOrder[dragCompIndex];
moduleOrder[dragCompIndex] = fxType;
dragCompIndex = i;
}
}
resized();
}
void FxChain::dragStarted(Component* comp, const juce::MouseEvent& event)
{
dragging = true;
dragComp = comp;
dragTarget = dynamic_cast<FxModule*>(comp)->getEffectType();
for (int i = 0; i < 4; i++)
if (&getModule(moduleOrder[i]) == dragComp)
dragCompIndex = i;
shadows.toFront(true);
dragComp->toFront(true);
mouseX = dragComp->getX();
dragOffset = dragComp->getX() - event.getEventRelativeTo(this).x;
}
void FxChain::dragEnded()
{
dragging = false;
int newVal = permToParam(moduleOrder);
if (newVal != oldVal)
fxPermAttachment.setValueAsCompleteGesture(float(newVal));
dragComp->toBehind(&shadows);
resized();
repaint();
}
void FxChain::enablementChanged()
{
reverbModule.setEnabled(isEnabled());
distortionModule.setEnabled(isEnabled());
eqModule.setEnabled(isEnabled());
chorusModule.setEnabled(isEnabled());
}
FxModule& FxChain::getModule(PluginParameters::FxTypes type)
{
switch (type)
{
case PluginParameters::REVERB:
return reverbModule;
case PluginParameters::DISTORTION:
return distortionModule;
case PluginParameters::EQ:
return eqModule;
case PluginParameters::CHORUS:
default:
return chorusModule;
}
}