iPlug2 - C++ Audio Plug-in Framework
Loading...
Searching...
No Matches
IPlugParameter.cpp
Go to the documentation of this file.
1/*
2 ==============================================================================
3
4 This file is part of the iPlug 2 library. Copyright (C) the iPlug 2 developers.
5
6 See LICENSE.txt for more info.
7
8 ==============================================================================
9*/
10
16#include <cstdio>
17#include <algorithm>
18
19#include "IPlugParameter.h"
20#include "IPlugLogger.h"
21
22using namespace iplug;
23
24#pragma mark - Shape
25
26double IParam::ShapeLinear::NormalizedToValue(double value, const IParam& param) const
27{
28 return param.mMin + value * (param.mMax - param.mMin);
29}
30
31double IParam::ShapeLinear::ValueToNormalized(double value, const IParam& param) const
32{
33 return (value - param.mMin) / (param.mMax - param.mMin);
34}
35
36IParam::ShapePowCurve::ShapePowCurve(double shape)
37: mShape(shape)
38{
39}
40
42{
43 if (mShape > 2.5) return kDisplayCubeRoot;
44 if (mShape > 1.5) return kDisplaySquareRoot;
45 if (mShape < (2.0 / 5.0)) return kDisplayCubed;
46 if (mShape < (2.0 / 3.0)) return kDisplaySquared;
47
48 return IParam::kDisplayLinear;
49}
50
51double IParam::ShapePowCurve::NormalizedToValue(double value, const IParam& param) const
52{
53 return param.GetMin() + std::pow(value, mShape) * (param.GetMax() - param.GetMin());
54}
55
56double IParam::ShapePowCurve::ValueToNormalized(double value, const IParam& param) const
57{
58 return std::pow((value - param.GetMin()) / (param.GetMax() - param.GetMin()), 1.0 / mShape);
59}
60
62{
63 double min = param.GetMin();
64
65 if(min <= 0.)
66 min = 0.00000001;
67
68 mAdd = std::log(min);
69 mMul = std::log(param.GetMax() / min);
70}
71
72double IParam::ShapeExp::NormalizedToValue(double value, const IParam& param) const
73{
74 return std::exp(mAdd + value * mMul);
75}
76
77double IParam::ShapeExp::ValueToNormalized(double value, const IParam& param) const
78{
79 return (std::log(value) - mAdd) / mMul;
80}
81
82#pragma mark -
83
84IParam::IParam()
85{
86 mShape = std::make_unique<ShapeLinear>();
87 memset(mName, 0, MAX_PARAM_NAME_LEN * sizeof(char));
88 memset(mLabel, 0, MAX_PARAM_LABEL_LEN * sizeof(char));
89 memset(mParamGroup, 0, MAX_PARAM_LABEL_LEN * sizeof(char));
90};
91
92void IParam::InitBool(const char* name, bool defaultVal, const char* label, int flags, const char* group, const char* offText, const char* onText)
93{
94 if (mType == kTypeNone) mType = kTypeBool;
95
96 InitEnum(name, (defaultVal ? 1 : 0), 2, label, flags | kFlagStepped, group);
97
98 SetDisplayText(0, offText);
99 SetDisplayText(1, onText);
100}
101
102void IParam::InitEnum(const char* name, int defaultVal, int nEnums, const char* label, int flags, const char* group, const char* listItems, ...)
103{
104 if (mType == kTypeNone) mType = kTypeEnum;
105
106 InitInt(name, defaultVal, 0, nEnums - 1, label, flags | kFlagStepped, group);
107
108 if(listItems)
109 {
110 SetDisplayText(0, listItems);
111
112 va_list args;
113 va_start(args, listItems);
114 for (auto i = 1; i < nEnums; ++i)
115 SetDisplayText(i, va_arg(args, const char*));
116 va_end(args);
117 }
118}
119
120void IParam::InitEnum(const char* name, int defaultVal, const std::initializer_list<const char*>& listItems, int flags, const char* group)
121{
122 if (mType == kTypeNone) mType = kTypeEnum;
123
124 InitInt(name, defaultVal, 0, static_cast<int>(listItems.size()) - 1, "", flags | kFlagStepped, group);
125
126 int idx = 0;
127 for (auto& item : listItems)
128 {
129 SetDisplayText(idx++, item);
130 }
131}
132
133void IParam::InitInt(const char* name, int defaultVal, int minVal, int maxVal, const char* label, int flags, const char* group)
134{
135 if (mType == kTypeNone) mType = kTypeInt;
136
137 InitDouble(name, (double) defaultVal, (double) minVal, (double) maxVal, 1.0, label, flags | kFlagStepped, group);
138}
139
140void IParam::InitDouble(const char* name, double defaultVal, double minVal, double maxVal, double step, const char* label, int flags, const char* group, const Shape& shape, EParamUnit unit, DisplayFunc displayFunc)
141{
142 if (mType == kTypeNone) mType = kTypeDouble;
143
144// assert(CStringHasContents(mName) && "Parameter already initialised!");
145// assert(CStringHasContents(name) && "Parameter must be given a name!");
146
147 strcpy(mName, name);
148 strcpy(mLabel, label);
149 strcpy(mParamGroup, group);
150
151 // N.B. apply stepping and constraints to the default value (and store the result)
152 mMin = minVal;
153 mMax = std::max(maxVal, minVal + step);
154 mStep = step;
155 mDefault = defaultVal;
156 mUnit = unit;
157 mFlags = flags;
158 mDisplayFunction = displayFunc;
159
160 Set(defaultVal);
161
162 for (mDisplayPrecision = 0;
163 mDisplayPrecision < MAX_PARAM_DISPLAY_PRECISION && step != floor(step);
164 ++mDisplayPrecision, step *= 10.0)
165 {
166 ;
167 }
168
169 mShape = std::unique_ptr<Shape>(shape.Clone());
170 mShape->Init(*this);
171}
172
173void IParam::InitFrequency(const char *name, double defaultVal, double minVal, double maxVal, double step, int flags, const char *group)
174{
175 InitDouble(name, defaultVal, minVal, maxVal, step, "Hz", flags, group, ShapeExp(), kUnitFrequency);
176}
177
178void IParam::InitSeconds(const char *name, double defaultVal, double minVal, double maxVal, double step, int flags, const char *group)
179{
180 InitDouble(name, defaultVal, minVal, maxVal, step, "Seconds", flags, group, ShapeLinear(), kUnitSeconds);
181}
182
183void IParam::InitMilliseconds(const char *name, double defaultVal, double minVal, double maxVal, int flags, const char *group)
184{
185 InitDouble(name, defaultVal, minVal, maxVal, 1, "ms", flags, group, ShapeLinear(), kUnitMilliseconds);
186}
187
188void IParam::InitPitch(const char *name, int defaultVal, int minVal, int maxVal, int flags, const char *group, bool middleCisC)
189{
190 InitEnum(name, defaultVal, (maxVal - minVal) + 1, "", flags, group);
191 WDL_String displayText;
192 for (auto i = minVal; i <= maxVal; i++)
193 {
194 MidiNoteName(i, displayText, /*cents*/false, middleCisC);
195 SetDisplayText(i - minVal, displayText.Get());
196 }
197}
198
199void IParam::InitGain(const char *name, double defaultVal, double minVal, double maxVal, double step, int flags, const char *group)
200{
201 InitDouble(name, defaultVal, minVal, maxVal, step, "dB", flags, group, ShapeLinear(), kUnitDB);
202}
203
204void IParam::InitPercentage(const char *name, double defaultVal, double minVal, double maxVal, int flags, const char *group)
205{
206 InitDouble(name, defaultVal, minVal, maxVal, 1, "%", flags, group, ShapeLinear(), kUnitPercentage);
207}
208
209void IParam::InitAngleDegrees(const char *name, double defaultVal, double minVal, double maxVal, int flags, const char *group)
210{
211 InitDouble(name, defaultVal, minVal, maxVal, 1, "degrees", flags, group, ShapeLinear(), kUnitDegrees);
212}
213
214void IParam::Init(const IParam& p, const char* searchStr, const char* replaceStr, const char* newGroup)
215{
216 if (mType == kTypeNone) mType = p.Type();
217
218 WDL_String str(p.mName);
219 WDL_String group(p.mParamGroup);
220
221 if (CStringHasContents(searchStr))
222 {
223 char* pos = strstr(str.Get(), searchStr);
224
225 if(pos)
226 {
227 int insertionPos = static_cast<int>(str.Get() - pos);
228 str.DeleteSub(insertionPos, static_cast<int>(strlen(searchStr)));
229 str.Insert(replaceStr, insertionPos);
230 }
231 }
232
233 if (CStringHasContents(newGroup))
234 {
235 group.Set(newGroup);
236 }
237
238 InitDouble(str.Get(), p.mDefault, p.mMin, p.mMax, p.mStep, p.mLabel, p.mFlags, group.Get(), *p.mShape, p.mUnit, p.mDisplayFunction);
239
240 for (auto i=0; i<p.NDisplayTexts(); i++)
241 {
242 double val;
243 const char* str = p.GetDisplayTextAtIdx(i, &val);
244 SetDisplayText(val, str);
245 }
246}
247
248void IParam::SetDisplayText(double value, const char* str)
249{
250 int n = mDisplayTexts.GetSize();
251 mDisplayTexts.Resize(n + 1);
252 DisplayText* pDT = mDisplayTexts.Get() + n;
253 pDT->mValue = value;
254 strcpy(pDT->mText, str);
255}
256
258{
259 mDisplayPrecision = precision;
260}
261
262void IParam::GetDisplay(double value, bool normalized, WDL_String& str, bool withDisplayText) const
263{
264 if (normalized) value = FromNormalized(value);
265
266 if (mDisplayFunction != nullptr)
267 {
268 mDisplayFunction(value, str);
269 return;
270 }
271
272 if (withDisplayText)
273 {
274 const char* displayText = GetDisplayText(value);
275
276 if (CStringHasContents(displayText))
277 {
278 str.Set(displayText, MAX_PARAM_DISPLAY_LEN);
279 return;
280 }
281 }
282
283 double displayValue = value;
284
285 if (mFlags & kFlagNegateDisplay)
286 displayValue = -displayValue;
287
288 // Squash all zeros to positive
289 if (!displayValue) displayValue = 0.0;
290
291 if (mDisplayPrecision == 0)
292 {
293 str.SetFormatted(MAX_PARAM_DISPLAY_LEN, "%d", static_cast<int>(round(displayValue)));
294 }
295 else if ((mFlags & kFlagSignDisplay) && displayValue)
296 {
297 char fmt[16];
298 snprintf(fmt, 16, "%%+.%df", mDisplayPrecision);
299 str.SetFormatted(MAX_PARAM_DISPLAY_LEN, fmt, displayValue);
300 }
301 else
302 {
303 str.SetFormatted(MAX_PARAM_DISPLAY_LEN, "%.*f", mDisplayPrecision, displayValue);
304 }
305}
306
307const char* IParam::GetName() const
308{
309 return mName;
310}
311
312const char* IParam::GetLabel() const
313{
314 return (CStringHasContents(GetDisplayText(static_cast<int>(mValue.load())))) ? "" : mLabel;
315}
316
317const char* IParam::GetGroup() const
318{
319 return mParamGroup;
320}
321
323{
324 return mDisplayTexts.GetSize();
325}
326
327const char* IParam::GetDisplayText(double value) const
328{
329 int n = mDisplayTexts.GetSize();
330 for (DisplayText* pDT = mDisplayTexts.Get(); n; --n, ++pDT)
331 {
332 if (value == pDT->mValue) return pDT->mText;
333 }
334 return "";
335}
336
337const char* IParam::GetDisplayTextAtIdx(int idx, double* pValue) const
338{
339 DisplayText* pDT = mDisplayTexts.Get()+idx;
340 if (pValue) *pValue = pDT->mValue;
341 return pDT->mText;
342}
343
344bool IParam::MapDisplayText(const char* str, double* pValue) const
345{
346 int n = mDisplayTexts.GetSize();
347 for (DisplayText* pDT = mDisplayTexts.Get(); n; --n, ++pDT)
348 {
349 if (!strcmp(str, pDT->mText))
350 {
351 *pValue = pDT->mValue;
352 return true;
353 }
354 }
355 return false;
356}
357
358double IParam::StringToValue(const char* str) const
359{
360 double v = 0.;
361 bool mapped = (bool) NDisplayTexts();
362
363 if (mapped)
364 mapped = MapDisplayText(str, &v);
365
366 if (!mapped && Type() != kTypeEnum && Type() != kTypeBool)
367 {
368 v = atof(str);
369
370 if (mFlags & kFlagNegateDisplay)
371 v = -v;
372
373 v = Constrain(v);
374 mapped = true;
375 }
376
377 return v;
378}
379
380void IParam::GetBounds(double& lo, double& hi) const
381{
382 lo = mMin;
383 hi = mMax;
384}
385
386void IParam::GetJSON(WDL_String& json, int idx) const
387{
388 json.AppendFormatted(8192, "{");
389 json.AppendFormatted(8192, "\"id\":%i, ", idx);
390 json.AppendFormatted(8192, "\"name\":\"%s\", ", GetName());
391 switch (Type())
392 {
393 case IParam::kTypeNone:
394 break;
395 case IParam::kTypeBool:
396 json.AppendFormatted(8192, "\"type\":\"%s\", ", "bool");
397 break;
398 case IParam::kTypeInt:
399 json.AppendFormatted(8192, "\"type\":\"%s\", ", "int");
400 break;
401 case IParam::kTypeEnum:
402 json.AppendFormatted(8192, "\"type\":\"%s\", ", "enum");
403 break;
404 case IParam::kTypeDouble:
405 json.AppendFormatted(8192, "\"type\":\"%s\", ", "float");
406 break;
407 default:
408 break;
409 }
410 json.AppendFormatted(8192, "\"min\":%f, ", GetMin());
411 json.AppendFormatted(8192, "\"max\":%f, ", GetMax());
412 json.AppendFormatted(8192, "\"default\":%f, ", GetDefault());
413 json.AppendFormatted(8192, "\"display_type\":%i, ", mShape->GetDisplayType());
414 json.AppendFormatted(8192, "\"rate\":\"control\"");
415 json.AppendFormatted(8192, "}");
416}
417
419{
420 DBGMSG("%s %f", GetName(), Value());
421}
IPlug logging a.k.a tracing functionality.
IPlug's parameter class.
double GetDefault(bool normalized=false) const
Returns the parameter's default value.
void InitGain(const char *name, double defaultVal=0., double minVal=-70., double maxVal=24., double step=0.5, int flags=0, const char *group="")
Initialize the parameter as gain (units in decibels)
void InitAngleDegrees(const char *name, double defaultVal=0., double minVal=0., double maxVal=360., int flags=0, const char *group="")
Initialize the parameter as angle in degrees.
EParamType Type() const
Get the parameter's type.
void InitPercentage(const char *name, double defaultVal=0., double minVal=0., double maxVal=100., int flags=0, const char *group="")
Initialize the parameter as percentage.
@ kFlagSignDisplay
Indicates that the parameter should be displayed as a signed value.
@ kFlagStepped
Indicates that the parameter is stepped
@ kFlagNegateDisplay
Indicates that the parameter should be displayed as a negative value.
void InitEnum(const char *name, int defaultValue, int nEnums, const char *label="", int flags=0, const char *group="", const char *listItems=0,...)
Initialize the parameter as an enumerated list.
void GetDisplay(WDL_String &display, bool withDisplayText=true) const
Get the current textual display for the current parameter value.
double GetMin() const
Returns the parameter's minimum value.
void InitDouble(const char *name, double defaultVal, double minVal, double maxVal, double step, const char *label="", int flags=0, const char *group="", const Shape &shape=ShapeLinear(), EParamUnit unit=kUnitCustom, DisplayFunc displayFunc=nullptr)
Initialize the parameter as double.
void Init(const IParam &p, const char *searchStr="", const char *replaceStr="", const char *newGroup="")
Initialize the parameter based on another parameter, replacing a CString in the name.
void GetBounds(double &lo, double &hi) const
Get the minimum and maximum real value of the parameter's range in one method call.
void Set(double value)
Sets the parameter value.
const char * GetLabel() const
Returns the parameter's label.
void SetDisplayText(double value, const char *str)
Set some text to display for a particular value, e.g.
std::function< void(double, WDL_String &)> DisplayFunc
DisplayFunc allows custom parameter display functions, defined by a lambda matching this signature.
double StringToValue(const char *str) const
Convert a textual representation of the parameter value to a double (real value)
bool MapDisplayText(const char *str, double *pValue) const
Get the value of a particular display text.
void InitFrequency(const char *name, double defaultVal=1000., double minVal=0.1, double maxVal=10000., double step=0.1, int flags=0, const char *group="")
Initialize the parameter as frequency.
EParamUnit
Used by AudioUnit plugins to determine the appearance of parameters, based on the kind of data they r...
const char * GetName() const
Returns the parameter's name.
void InitSeconds(const char *name, double defaultVal=1., double minVal=0., double maxVal=10., double step=0.1, int flags=0, const char *group="")
Initialize the parameter as seconds.
double FromNormalized(double normalizedValue) const
Convert a normalized value to real value for this parameter.
void PrintDetails() const
Helper to print the parameter details to debug console in debug builds.
const char * GetDisplayTextAtIdx(int idx, double *pValue=nullptr) const
Get the display text at a particular index.
double Constrain(double value) const
Constrains the input value between mMin and mMax and apply stepping if relevant.
const char * GetDisplayText(double value) const
Get the display text for a particular value.
const char * GetGroup() const
Returns the parameter's group.
void InitMilliseconds(const char *name, double defaultVal=1., double minVal=0., double maxVal=100., int flags=0, const char *group="")
Initialize the parameter as milliseconds.
void SetDisplayPrecision(int precision)
Set the parameters display precision.
EDisplayType
Used by AudioUnit plugins to determine the mapping of parameters.
void InitPitch(const char *name, int defaultVal=60, int minVal=0, int maxVal=128, int flags=0, const char *group="", bool middleCisC4=false)
Initialize the parameter as pitch.
double Value() const
Gets a readable value of the parameter.
int NDisplayTexts() const
Get the number of display texts for the parameter.
double GetMax() const
Returns the parameter's maximum value.
void InitBool(const char *name, bool defaultValue, const char *label="", int flags=0, const char *group="", const char *offText="off", const char *onText="on")
Initialize the parameter as boolean.
void InitInt(const char *name, int defaultValue, int minVal, int maxVal, const char *label="", int flags=0, const char *group="")
Initialize the parameter as integer.
void GetJSON(WDL_String &json, int idx) const
Get a JSON description of the parameter.
static void MidiNoteName(double midiPitch, WDL_String &noteName, bool cents=false, bool middleCisC4=false)
Exponential parameter shaping.
void Init(const IParam &param) override
Initializes the shape instance.
double NormalizedToValue(double value, const IParam &param) const override
Returns the real value from a normalized input, based on an IParam's settings.
double ValueToNormalized(double value, const IParam &param) const override
Returns the normalized value from a real value, based on an IParam's settings.
Base struct for parameter shaping.
virtual Shape * Clone() const =0
Linear parameter shaping.
double ValueToNormalized(double value, const IParam &param) const override
Returns the normalized value from a real value, based on an IParam's settings.
double NormalizedToValue(double value, const IParam &param) const override
Returns the real value from a normalized input, based on an IParam's settings.
IParam::EDisplayType GetDisplayType() const override
double ValueToNormalized(double value, const IParam &param) const override
Returns the normalized value from a real value, based on an IParam's settings.
double NormalizedToValue(double value, const IParam &param) const override
Returns the real value from a normalized input, based on an IParam's settings.