Skip to content

Instantly share code, notes, and snippets.

@olilarkin
Last active April 7, 2022 21:50
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save olilarkin/3b461d27fd7a1c8b8882e1d561820b68 to your computer and use it in GitHub Desktop.
Save olilarkin/3b461d27fd7a1c8b8882e1d561820b68 to your computer and use it in GitHub Desktop.
IPlug 2 XY Pad - control with 2 params
#include "IPlugXY.h"
#include "IPlug_include_in_plug_src.h"
#include "IControls.h"
#if IPLUG_EDITOR
class IXYPad : public IControl
{
private:
IPlugXY& mPlug;
ILayerPtr mLayer;
public:
IXYPad(IPlugXY& dlg, IRECT r)
: IControl(r)
, mPlug(dlg)
{
}
void Draw(IGraphics& g) override
{
float xpos = mX * mRECT.W();
float ypos = mY * mRECT.H();
g.DrawVerticalLine(mHandleColor, mRECT, mX);
g.DrawHorizontalLine(mHandleColor, mRECT, mY);
g.FillCircle(mHandleColor, xpos, ypos, mHandleRadius);
}
void OnMouseDown(float x, float y, const IMouseMod& mod) override
{
mPlug.BeginParamGestureFromXY(GetTag());
mHandleColor = COLOR_BLACK;
OnMouseDrag(x, y, 0., 0., mod);
}
void OnMouseUp(float x, float y, const IMouseMod& mod) override
{
mPlug.EndParamGestureFromXY(GetTag());
mHandleColor = COLOR_WHITE;
SetDirty(false);
}
void OnMouseDrag(float x, float y, float dX, float dY, const IMouseMod& mod) override
{
mRECT.Constrain(x, y);
mX = (x - mRECT.L) / mRECT.W();
mY = 1.f-((y - mRECT.T) / mRECT.H());
SetDirty(true);
}
void SetDirty(bool triggerAction) override
{
//mValue = Clip(mValue, mClampLo, mClampHi);
mDirty = true;
if (triggerAction)
mPlug.SetParamGestureFromXY(GetTag(), mX, mY);
}
void SetValsFromPlug(double x, double y)
{
mX = x;
mY = y;
SetDirty(false);
}
private:
int mParamX = -1;
int mParamY = -1;
float mHandleRadius = 10.;
float mX = 0.f;
float mY = 0.f;
IColor mHandleColor = COLOR_BLACK;
};
#endif
IPlugXY::IPlugXY(IPlugInstanceInfo instanceInfo)
: IPLUG_CTOR(kNumParams, kNumPrograms, instanceInfo)
{
GetParam(kParamLeftX)->InitDouble("X1", 100., 0., 100.0, 0.01, "%");
GetParam(kParamLeftY)->InitDouble("Y1", 100., 0., 100.0, 0.01, "%");
GetParam(kParamRightX)->InitDouble("X2", 100., 0., 100.0, 0.01, "%");
GetParam(kParamRightY)->InitDouble("Y2", 100., 0., 100.0, 0.01, "%");
GetParam(kParamLink)->InitBool("link", false);
#if IPLUG_EDITOR // All UI methods and member variables should be within an IPLUG_EDITOR guard, should you want distributed UI
mMakeGraphicsFunc = [&]() {
return MakeGraphics(*this, PLUG_WIDTH, PLUG_HEIGHT, PLUG_FPS, 1.);
};
mLayoutFunc = [&](IGraphics* pGraphics) {
pGraphics->AttachCornerResizer(kUIResizerScale, false);
pGraphics->AttachPanelBackground(COLOR_GRAY);
pGraphics->LoadFont(ROBOTTO_FN);
const IRECT b = pGraphics->GetBounds();
pGraphics->AttachControl(new IXYPad(*this, b.GetGridCell(0, 2, 2)), kXYControl1Tag);
pGraphics->AttachControl(new IXYPad(*this, b.GetGridCell(1, 2, 2)), kXYControl2Tag);
pGraphics->AttachControl(new IVKnobControl(b.GetGridCell(2, 2, 2).FracRectHorizontal(0.5), kParamLeftX), kKnobX1);
pGraphics->AttachControl(new IVKnobControl(b.GetGridCell(2, 2, 2).FracRectHorizontal(0.5, true), kParamLeftY), kKnobY1);
pGraphics->AttachControl(new IVKnobControl(b.GetGridCell(3, 2, 2).FracRectHorizontal(0.5), kParamRightX), kKnobX2);
pGraphics->AttachControl(new IVKnobControl(b.GetGridCell(3, 2, 2).FracRectHorizontal(0.5, true), kParamRightY), kKnobY2);
pGraphics->AttachControl(new IVSwitchControl(b.GetCentredInside(30), kParamLink));
pGraphics->GetControlWithTag(kKnobX1)->SetActionFunction(std::bind(&IPlugXY::UpdateXYs, this, std::placeholders::_1));
pGraphics->GetControlWithTag(kKnobY1)->SetActionFunction(std::bind(&IPlugXY::UpdateXYs, this, std::placeholders::_1));
pGraphics->GetControlWithTag(kKnobX2)->SetActionFunction(std::bind(&IPlugXY::UpdateXYs, this, std::placeholders::_1));
pGraphics->GetControlWithTag(kKnobY2)->SetActionFunction(std::bind(&IPlugXY::UpdateXYs, this, std::placeholders::_1));
};
#endif
}
#if IPLUG_EDITOR
void IPlugXY::BeginParamGestureFromXY(int tag)
{
if(GetParam(kParamLink)->Bool() || tag == kXYControl1Tag)
{
BeginInformHostOfParamChangeFromUI(kParamLeftX);
BeginInformHostOfParamChangeFromUI(kParamLeftY);
}
if(GetParam(kParamLink)->Bool() || tag == kXYControl2Tag)
{
BeginInformHostOfParamChangeFromUI(kParamRightX);
BeginInformHostOfParamChangeFromUI(kParamRightY);
}
}
void IPlugXY::SetParamGestureFromXY(int tag, double x, double y)
{
if(GetParam(kParamLink)->Bool() || tag == kXYControl1Tag)
{
SetParameterValue(kParamLeftX, x);
SetParameterValue(kParamLeftY, y);
}
if(GetParam(kParamLink)->Bool() || tag == kXYControl2Tag)
{
SetParameterValue(kParamRightX, x);
SetParameterValue(kParamRightY, y);
}
if(GetParam(kParamLink)->Bool())
{
if(tag == kXYControl1Tag)
dynamic_cast<IXYPad*>(GetUI()->GetControlWithTag(kXYControl2Tag))->SetValsFromPlug(x, y);
else
dynamic_cast<IXYPad*>(GetUI()->GetControlWithTag(kXYControl1Tag))->SetValsFromPlug(x, y);
}
UpdateKnobs();
}
void IPlugXY::EndParamGestureFromXY(int tag)
{
if(GetParam(kParamLink)->Bool() || tag == kXYControl1Tag)
{
EndInformHostOfParamChangeFromUI(kParamLeftX);
EndInformHostOfParamChangeFromUI(kParamLeftY);
}
if(GetParam(kParamLink)->Bool() || tag == kXYControl2Tag)
{
EndInformHostOfParamChangeFromUI(kParamRightX);
EndInformHostOfParamChangeFromUI(kParamRightY);
}
}
void IPlugXY::UpdateKnobs()
{
GetUI()->GetControlWithTag(kKnobX1)->SetValueFromDelegate(GetParam(kParamLeftX)->GetNormalized());
GetUI()->GetControlWithTag(kKnobY1)->SetValueFromDelegate(GetParam(kParamLeftY)->GetNormalized());
GetUI()->GetControlWithTag(kKnobX2)->SetValueFromDelegate(GetParam(kParamRightX)->GetNormalized());
GetUI()->GetControlWithTag(kKnobY2)->SetValueFromDelegate(GetParam(kParamRightY)->GetNormalized());
}
void IPlugXY::UpdateXYs(IControl* pCaller)
{
if(pCaller->GetTag() == kKnobX1 || pCaller->GetTag() == kKnobY1)
{
const double vx = GetParam(kParamLeftX)->GetNormalized();
const double vy = GetParam(kParamLeftY)->GetNormalized();
dynamic_cast<IXYPad*>(GetUI()->GetControlWithTag(kXYControl1Tag))->SetValsFromPlug(vx, vy);
if(GetParam(kParamLink)->Bool())
{
SetParameterValue(kParamRightX, vx);
SetParameterValue(kParamRightY, vy);
dynamic_cast<IXYPad*>(GetUI()->GetControlWithTag(kXYControl2Tag))->SetValsFromPlug(vx, vy);
GetUI()->GetControlWithTag(kKnobX2)->SetValueFromDelegate(vx);
GetUI()->GetControlWithTag(kKnobY2)->SetValueFromDelegate(vy);
}
}
if(pCaller->GetTag() == kKnobX2 || pCaller->GetTag() == kKnobY2)
{
const double vx = GetParam(kParamRightX)->GetNormalized();
const double vy = GetParam(kParamRightY)->GetNormalized();
dynamic_cast<IXYPad*>(GetUI()->GetControlWithTag(kXYControl2Tag))->SetValsFromPlug(vx, vy);
if(GetParam(kParamLink)->Bool())
{
SetParameterValue(kParamLeftX, vx);
SetParameterValue(kParamLeftY, vy);
dynamic_cast<IXYPad*>(GetUI()->GetControlWithTag(kXYControl1Tag))->SetValsFromPlug(vx, vy);
GetUI()->GetControlWithTag(kKnobX1)->SetValueFromDelegate(vx);
GetUI()->GetControlWithTag(kKnobY1)->SetValueFromDelegate(vy);
}
}
}
void IPlugXY::OnParamChangeUI(int paramIdx, EParamSource src)
{
if(GetUI() && src != kUI)
{
switch (paramIdx)
{
case kParamLeftX:
case kParamLeftY:
{
const double vx = GetParam(kParamLeftX)->GetNormalized();
const double vy = GetParam(kParamLeftY)->GetNormalized();
if(GetParam(kParamLink)->Bool())
{
dynamic_cast<IXYPad*>(GetUI()->GetControlWithTag(kXYControl2Tag))->SetValsFromPlug(vx, vy);
GetUI()->GetControlWithTag(kKnobX2)->SetValueFromDelegate(vx);
GetUI()->GetControlWithTag(kKnobY2)->SetValueFromDelegate(vy);
}
dynamic_cast<IXYPad*>(GetUI()->GetControlWithTag(kXYControl1Tag))->SetValsFromPlug(vx, vy);
break;
}
case kParamRightX:
case kParamRightY:
{
const double vx = GetParam(kParamRightX)->GetNormalized();
const double vy = GetParam(kParamRightY)->GetNormalized();
if(GetParam(kParamLink)->Bool())
{
dynamic_cast<IXYPad*>(GetUI()->GetControlWithTag(kXYControl1Tag))->SetValsFromPlug(vx, vy);
GetUI()->GetControlWithTag(kKnobX1)->SetValueFromDelegate(vx);
GetUI()->GetControlWithTag(kKnobY1)->SetValueFromDelegate(vy);
}
dynamic_cast<IXYPad*>(GetUI()->GetControlWithTag(kXYControl2Tag))->SetValsFromPlug(vx, vy);
break;
}
default:
break;
}
}
}
#endif
#if IPLUG_DSP
void IPlugXY::ProcessBlock(sample** inputs, sample** outputs, int nFrames)
{
const double gainX = GetParam(kParamLeftX)->Value() / 100.;
const double gainY = GetParam(kParamLeftY)->Value() / 100.;
for (int s = 0; s < nFrames; s++) {
outputs[0][s] = inputs[0][s] * gainX;
outputs[1][s] = inputs[1][s] * gainY;
}
}
#endif
#pragma once
#include "IPlug_include_in_plug_hdr.h"
const int kNumPrograms = 1;
enum EParams
{
kParamLeftX = 0,
kParamLeftY,
kParamRightX,
kParamRightY,
kParamLink,
kNumParams
};
enum ECtrlTags
{
kXYControl1Tag = 0,
kXYControl2Tag,
kKnobX1,
kKnobY1,
kKnobX2,
kKnobY2
};
class IPlugXY : public IPlug
{
public:
IPlugXY(IPlugInstanceInfo instanceInfo);
#if IPLUG_EDITOR
void OnParamChangeUI(int paramIdx, EParamSource src) override;
void BeginParamGestureFromXY(int tag);
void SetParamGestureFromXY(int tag, double x, double y);
void EndParamGestureFromXY(int tag);
void UpdateKnobs();
void UpdateXYs(IControl* pCaller);
#endif
#if IPLUG_DSP // All DSP methods and member variables should be within an IPLUG_DSP guard, should you want distributed UI
void ProcessBlock(sample** inputs, sample** outputs, int nFrames) override;
#endif
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment