iPlug 2: IPlugParameter.cpp Source File

1

2

3

4

5

6

7

8

9

10

16#include <cstdio>

17#include <algorithm>

18

21

22using namespace iplug;

23

24#pragma mark - Shape

25

27{

28 return param.mMin + value * (param.mMax - param.mMin);

29}

30

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

52{

53 return param.GetMin() + std::pow(value, mShape) * (param.GetMax() - param.GetMin());

54}

55

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

73{

74 return std::exp(mAdd + value * mMul);

75}

76

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

97

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 {

111

112 va_list args;

113 va_start(args, listItems);

114 for (auto i = 1; i < nEnums; ++i)

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 {

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

145

146

147 strcpy(mName, name);

148 strcpy(mLabel, label);

149 strcpy(mParamGroup, group);

150

151

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, false, middleCisC);

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

241 {

242 double val;

245 }

246}

247

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{

265

266 if (mDisplayFunction != nullptr)

267 {

268 mDisplayFunction(value, str);

269 return;

270 }

271

272 if (withDisplayText)

273 {

275

276 if (CStringHasContents(displayText))

277 {

278 str.Set(displayText, MAX_PARAM_DISPLAY_LEN);

279 return;

280 }

281 }

282

283 double displayValue = value;

284

286 displayValue = -displayValue;

287

288

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 }

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

308{

309 return mName;

310}

311

313{

314 return (CStringHasContents(GetDisplayText(static_cast<int>(mValue.load())))) ? "" : mLabel;

315}

316

318{

319 return mParamGroup;

320}

321

323{

324 return mDisplayTexts.GetSize();

325}

326

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

338{

339 DisplayText* pDT = mDisplayTexts.Get()+idx;

340 if (pValue) *pValue = pDT->mValue;

341 return pDT->mText;

342}

343

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

359{

360 double v = 0.;

362

363 if (mapped)

365

366 if (!mapped && Type() != kTypeEnum && Type() != kTypeBool)

367 {

368 v = atof(str);

369

371 v = -v;

372

374 mapped = true;

375 }

376

377 return v;

378}

379

381{

382 lo = mMin;

383 hi = mMax;

384}

385

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{

421}

422

424{

426 return IParam::EShapeIDs::kShapeLinear;

428 return IParam::EShapeIDs::kShapePowCurve;

430 return IParam::EShapeIDs::kShapeExponential;

431 else

432 return IParam::EShapeIDs::kShapeUnknown;

433}

434

436{

438 return pShapePowCurve->mShape;

439 else

440 return 0.0;

441}

442

IPlug logging a.k.a tracing functionality.

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.

EShapeIDs

IDs for the shapes.

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.

double GetShapeValue() const

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.

EShapeIDs GetShapeID() const

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)

Converts a MIDI pitch number to a human-readable note name.

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.

PowCurve parameter shaping.

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.