Jamba C++ API  5.1.1
ParamConverters.h
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2018-2020 pongasoft
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5  * use this file except in compliance with the License. You may obtain a copy of
6  * the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13  * License for the specific language governing permissions and limitations under
14  * the License.
15  *
16  * @author Yan Pujante
17  */
18 #pragma once
19 
20 #include <pongasoft/Utils/Misc.h>
21 #include <pongasoft/VST/Types.h>
23 
24 #include <pluginterfaces/vst/vsttypes.h>
25 #include <pluginterfaces/vst/ivstparameterchanges.h>
26 #include <pluginterfaces/base/ustring.h>
27 #include <base/source/fstring.h>
28 #include <pluginterfaces/base/ftypes.h>
29 
30 #include <cmath>
31 #include <algorithm>
32 #include <memory>
33 #include <string>
34 #include <array>
35 #include <vector>
36 #include <map>
37 #include <type_traits>
39 
40 namespace pongasoft::VST {
41 
42 using namespace Steinberg;
43 using namespace Steinberg::Vst;
44 
52 template<typename T>
54 {
55 public:
56  using ParamType = T;
57  virtual int32 getStepCount() const { return 0; }
58  virtual ParamValue normalize(ParamType const &iValue) const = 0;
59  virtual ParamType denormalize(ParamValue iNormalizedValue) const = 0;
60  virtual void toString(ParamType const &iValue, String128 iString, int32 iPrecision) const { }
61  virtual std::string toString(ParamType const &iValue, int32 iPrecision) const
62  {
63  String128 s;
64  s[0] = 0;
65  toString(iValue, s, iPrecision);
66  return VstUtils::toUT8String(s);
67  }
68 };
69 
73 class RawParamConverter : public IParamConverter<ParamValue>
74 {
75 public:
76 
78 
79  inline ParamValue normalize(ParamValue const &iValue) const override
80  {
81  return Utils::clamp(iValue, 0.0, 1.0);
82  }
83 
84  inline ParamValue denormalize(ParamValue iNormalizedValue) const override
85  {
86  return Utils::clamp(iNormalizedValue, 0.0, 1.0);
87  }
88 
89  inline void toString(ParamValue const &iValue, String128 oString, int32 iPrecision) const override
90  {
91  staticToString(iValue, oString, iPrecision);
92  }
93 
94  static inline void staticToString(ParamValue const &iValue, String128 oString, int32 iPrecision)
95  {
96  Steinberg::UString wrapper(oString, str16BufferSize(String128));
97  if(!wrapper.printFloat(iValue, iPrecision))
98  oString[0] = 0;
99  }
100 };
101 
108 {
109 public:
111 
112  explicit BooleanParamConverter(VstString16 iFalseString = STR16("Off"),
113  VstString16 iTrueString = STR16("On")) :
114  fFalseString{std::move(iFalseString)},
115  fTrueString{std::move(iTrueString)}
116  {}
117 
118  inline int32 getStepCount() const override { return 1; }
119 
120  inline ParamValue normalize(bool const &iValue) const override
121  {
122  return iValue ? 1.0 : 0;
123  }
124 
125  inline bool denormalize(ParamValue iNormalizedValue) const override
126  {
127  return toBoolean(iNormalizedValue);
128  }
129 
130  inline void toString(bool const &iValue, String128 oString, int32 /* iPrecision */) const override
131  {
132  Steinberg::UString wrapper(oString, str16BufferSize(String128));
133  if(iValue)
134  wrapper.assign(fTrueString.c_str());
135  else
136  wrapper.assign(fFalseString.c_str());
137  }
138 
142  inline static bool toBoolean(ParamValue iNormalizedValue) { return iNormalizedValue >= 0.5; }
143 
144 protected:
147 };
148 
152 using Percent = double;
153 
158 class PercentParamConverter : public IParamConverter<Percent>
159 {
160 public:
161 
163 
164  inline ParamValue normalize(double const &iValue) const override
165  {
166  return Utils::clamp(iValue, 0.0, 1.0);
167  }
168 
169  inline double denormalize(ParamValue iNormalizedValue) const override
170  {
171  return Utils::clamp(iNormalizedValue, 0.0, 1.0);
172  }
173 
174  inline void toString(ParamType const &iValue, String128 oString, int32 iPrecision) const override
175  {
176  Steinberg::UString wrapper(oString, str16BufferSize (String128));
177  wrapper.printFloat(iValue * 100, iPrecision);
178  wrapper.append(STR16("%"));
179  }
180 };
181 
186 static inline ParamValue convertDiscreteValueToNormalizedValue(int32 iStepCount, int32 iDiscreteValue)
187 {
188  auto value = Utils::clamp<int32, int32>(iDiscreteValue, 0, iStepCount);
189  if(value == 0)
190  return value;
191  else
192  return value / static_cast<ParamValue>(iStepCount);
193 }
194 
199 static inline int32 convertNormalizedValueToDiscreteValue(int32 iStepCount, ParamValue iNormalizedValue)
200 {
201  // ParamValue must remain within its bounds
202  auto value = Utils::clamp(iNormalizedValue, 0.0, 1.0);
203  auto discreteValue = std::floor(std::min(static_cast<ParamValue>(iStepCount), value * (iStepCount + 1)));
204  return static_cast<int32>(discreteValue);
205 }
206 
217 static inline int32 computeNextDiscreteValue(int32 iValue, int32 iStepCount, int32 iIncrement, bool iWrap)
218 {
219  // no increment, noop
220  if(iIncrement == 0)
221  return iValue;
222 
223  if(iStepCount > 0)
224  {
225  auto discreteValue = iValue + iIncrement;
226 
227  // handles wrapping
228  if(iWrap)
229  {
230  if(iIncrement > 0)
231  {
232  while(discreteValue > iStepCount)
233  discreteValue -= iStepCount + 1;
234  }
235  else
236  {
237  while(discreteValue < 0)
238  discreteValue += iStepCount + 1;
239  }
240  }
241  else
242  {
243  // no wrapping => simply clamp the value to the range
244  discreteValue = Utils::clamp(discreteValue, Utils::ZERO_INT32, iStepCount);
245  }
246 
247  return discreteValue;
248  }
249  else
250  {
251  return iValue;
252  }
253 }
254 
260 template<int32 StepCount, typename IntType = int32>
262 {
263 public:
264  using ParamType = IntType;
265 
267 
270  using ConstructorType = std::array<VstString16, StepCount + 1> const &;
271 
272  // Constructor - you can provide an offset for the toString conversion (ex: counting from 1 instead of 0)
273  explicit DiscreteValueParamConverter(IntType iToStringOffset = 0) : fToStringOffset{iToStringOffset} {}
274 
275  // Constructor with printf style format where the parameter (%d) will be (value + offset)
276  explicit DiscreteValueParamConverter(VstString16 iFormat, IntType iToStringOffset = 0) :
277  fToStringOffset{iToStringOffset}, fFormat{std::move(iFormat)} {}
278 
279  // Constructor with all values defined
280  explicit DiscreteValueParamConverter(ConstructorType iToStringValues) :
281  fToStringValues(iToStringValues.cbegin(), iToStringValues.cend()) {}
282 
283  inline int32 getStepCount() const override { return StepCount; }
284 
285  inline ParamValue normalize(ParamType const &iDiscreteValue) const override
286  {
287  return convertDiscreteValueToNormalizedValue(StepCount, static_cast<int32>(iDiscreteValue));
288  }
289 
290  inline ParamType denormalize(ParamValue iNormalizedValue) const override
291  {
292  return static_cast<ParamType>(convertNormalizedValueToDiscreteValue(StepCount, iNormalizedValue));
293  }
294 
295  // toString
296  void toString(ParamType const &iValue, String128 oString, int32 /* iPrecision */) const override
297  {
298  Steinberg::UString wrapper(oString, str16BufferSize (String128));
299  if(!fFormat.empty())
300  {
301  String s;
302  s.printf(fFormat.c_str(), iValue + fToStringOffset);
303  wrapper.assign(s.text());
304  }
305  else
306  {
307  if(fToStringValues.empty())
308  {
309  if(!wrapper.printInt(iValue + fToStringOffset))
310  oString[0] = 0;
311  }
312  else
313  {
314  wrapper.assign(fToStringValues[iValue].c_str());
315  }
316  }
317  }
318 
319 private:
320  IntType fToStringOffset{};
321  VstString16 fFormat{};
322  std::vector<VstString16> fToStringValues{};
323 };
324 
351 template<typename T, class Compare = std::less<T>>
353 {
354 public:
357  using TMap = std::map<T, std::tuple<VstString16, ParamValue, int32>, Compare>;
358 
361  using TList = std::vector<T>;
362 
365  using ConstructorType = std::initializer_list<std::pair<const T, VstString16>> const &;
366 
367  using ParamType = T;
368 
370 
375  {
376  auto stepCount = static_cast<int32>(iInitList.size() - 1);
377 
378  // by definition, a discrete parameter has a step count > 0
379  DCHECK_F(stepCount > 0);
380 
381  int32 i = 0;
382  for(auto &pair : iInitList)
383  {
384  auto paramValue = convertDiscreteValueToNormalizedValue(stepCount, i);
385  fMap[pair.first] = std::make_tuple(pair.second, paramValue, i);
386  fList.emplace_back(pair.first);
387  i++;
388  }
389 
390  // sanity check... if not the same size it means that 2 entries in the list were the same!
391  DCHECK_F(fList.size() == fMap.size());
392  }
393 
394  // getStepCount
395  inline int32 getStepCount() const override { return static_cast<int32>(fMap.size() - 1); }
396 
397  // normalize
398  inline ParamValue normalize(ParamType const &iValue) const override
399  {
400  auto iter = fMap.find(iValue);
401  if(iter != fMap.cend())
402  return std::get<1>(iter->second);
403  else
404  {
405  DLOG_F(WARNING, "could not normalize value...");
406  return 0;
407  }
408  }
409 
410  // denormalize
411  inline ParamType denormalize(ParamValue iNormalizedValue) const override
412  {
413  auto index = convertNormalizedValueToDiscreteValue(getStepCount(), iNormalizedValue);
414  return fList[index];
415  }
416 
417  // toString
418  void toString(ParamType const &iValue, String128 oString, int32 iPrecision) const override
419  {
420  auto iter = fMap.find(iValue);
421  if(iter != fMap.cend())
422  {
423  Steinberg::UString wrapper(oString, str16BufferSize (String128));
424  wrapper.assign(std::get<0>(iter->second).c_str());
425  }
426  else
427  oString[0] = 0;
428  }
429 
430 private:
431  TMap fMap{};
432  TList fList{};
433 };
434 
440 template<typename Enum, Enum MaxValue>
442 {
443 public:
444  using ParamType = Enum;
445 
446  using IntType = std::underlying_type_t<Enum>;
447 
449 
452  using ConstructorType = std::array<VstString16, MaxValue + 1> const &;
453 
454  // Constructor - you can provide an offset for the toString conversion (ex: counting from 1 instead of 0)
455  explicit EnumParamConverter(IntType iToStringOffset = 0) : fConverter{iToStringOffset} {}
456 
457  // Constructor with printf style format where the parameter (%d) will be (value + offset)
458  explicit EnumParamConverter(VstString16 iFormat, IntType iToStringOffset = 0) : fConverter{std::move(iFormat), iToStringOffset} {}
459 
460  // Constructor with all values defined
461  explicit EnumParamConverter(ConstructorType iToStringValues) : fConverter{iToStringValues} {}
462 
463  // getStepCount
464  inline int32 getStepCount() const override { return MaxValue; }
465 
466  // normalize
467  inline ParamValue normalize(ParamType const &iDiscreteValue) const override
468  {
469  return fConverter.normalize(static_cast<IntType>(iDiscreteValue));
470  }
471 
472  // denormalize
473  inline ParamType denormalize(ParamValue iNormalizedValue) const override
474  {
475  return static_cast<Enum>(fConverter.denormalize(iNormalizedValue));
476  }
477 
478  // toString
479  void toString(ParamType const &iValue, String128 oString, int32 iPrecision) const override
480  {
481  fConverter.toString(static_cast<IntType>(iValue), oString, iPrecision);
482  }
483 
484 private:
486 };
487 
488 
489 }
int32 getStepCount() const override
Definition: ParamConverters.h:283
static T clamp(const U &iValue, const T &iLower, const T &iUpper)
Make sure that the value remains within its bounds.
Definition: Misc.h:33
void toString(ParamType const &iValue, String128 oString, int32 iPrecision) const override
Definition: ParamConverters.h:418
virtual void toString(ParamType const &iValue, String128 iString, int32 iPrecision) const
Definition: ParamConverters.h:60
std::initializer_list< std::pair< const T, VstString16 > > const & ConstructorType
Defines the type for the constructor argument.
Definition: ParamConverters.h:365
double denormalize(ParamValue iNormalizedValue) const override
Definition: ParamConverters.h:169
std::vector< T > TList
Defines the mapping: discrete value [0, stepCount] to T.
Definition: ParamConverters.h:361
int32 getStepCount() const override
Definition: ParamConverters.h:118
constexpr auto ZERO_INT32
Definition: Constants.h:24
DiscreteValueParamConverter(ConstructorType iToStringValues)
Definition: ParamConverters.h:280
Enum ParamType
Definition: ParamConverters.h:56
void toString(ParamType const &iValue, String128 oString, int32 iPrecision) const override
Definition: ParamConverters.h:479
std::underlying_type_t< Enum > IntType
Definition: ParamConverters.h:446
DiscreteValueParamConverter(VstString16 iFormat, IntType iToStringOffset=0)
Definition: ParamConverters.h:276
EnumParamConverter(ConstructorType iToStringValues)
Definition: ParamConverters.h:461
std::array< VstString16, MaxValue+1 > const & ConstructorType
Defines the type for the constructor argument.
Definition: ParamConverters.h:452
std::array< VstString16, StepCount+1 > const & ConstructorType
Defines the type for the constructor argument.
Definition: ParamConverters.h:270
DiscreteValueParamConverter(IntType iToStringOffset=0)
Definition: ParamConverters.h:273
DiscreteTypeParamConverter(ConstructorType iInitList)
This constructor will be called this way when initializing a vst or jmb parameter:
Definition: ParamConverters.h:374
void toString(bool const &iValue, String128 oString, int32) const override
Definition: ParamConverters.h:130
This converters maps a list of values of type T to discrete values.
Definition: ParamConverters.h:352
This parameter is just a no-op wrapper to the ParamValue to adapt it to the use of the ParamConverter...
Definition: ParamConverters.h:73
ParamValue normalize(ParamValue const &iValue) const override
Definition: ParamConverters.h:79
ParamValue normalize(double const &iValue) const override
Definition: ParamConverters.h:164
int32 getStepCount() const override
Definition: ParamConverters.h:395
A trivial percent converter.
Definition: ParamConverters.h:158
static void staticToString(ParamValue const &iValue, String128 oString, int32 iPrecision)
Definition: ParamConverters.h:94
ParamValue normalize(ParamType const &iDiscreteValue) const override
Definition: ParamConverters.h:467
EnumParamConverter(VstString16 iFormat, IntType iToStringOffset=0)
Definition: ParamConverters.h:458
ParamType denormalize(ParamValue iNormalizedValue) const override
Definition: ParamConverters.h:411
double Percent
Percent type represented by a double.
Definition: ParamConverters.h:152
void toString(ParamValue const &iValue, String128 oString, int32 iPrecision) const override
Definition: ParamConverters.h:89
std::basic_string< Steinberg::char16 > VstString16
Strings made of char16 characters are represented by the native C++11 type std::basic_string<Steinber...
Definition: Types.h:43
ParamValue normalize(bool const &iValue) const override
Definition: ParamConverters.h:120
ParamValue normalize(ParamType const &iValue) const override
Definition: ParamConverters.h:398
static bool toBoolean(ParamValue iNormalizedValue)
Converts a normalized value to a boolean according to the rule: false for [0.0, 0....
Definition: ParamConverters.h:142
int32 getStepCount() const override
Definition: ParamConverters.h:464
static ParamValue convertDiscreteValueToNormalizedValue(int32 iStepCount, int32 iDiscreteValue)
Implements the algorithm described in the VST documentation on how to interpret a discrete value into...
Definition: ParamConverters.h:186
VstString16 fTrueString
Definition: ParamConverters.h:146
bool denormalize(ParamValue iNormalizedValue) const override
Definition: ParamConverters.h:125
void toString(ParamType const &iValue, String128 oString, int32 iPrecision) const override
Definition: ParamConverters.h:174
Manages the very common case when a param represents a boolean value.
Definition: ParamConverters.h:107
static int32 convertNormalizedValueToDiscreteValue(int32 iStepCount, ParamValue iNormalizedValue)
Implements the algorithm described in the VST documentation on how to interpret a normalized value as...
Definition: ParamConverters.h:199
ParamType denormalize(ParamValue iNormalizedValue) const override
Definition: ParamConverters.h:473
A converter to deal with a discrete value which has StepCount steps.
Definition: ParamConverters.h:261
ParamValue denormalize(ParamValue iNormalizedValue) const override
Definition: ParamConverters.h:84
virtual int32 getStepCount() const
Definition: ParamConverters.h:57
Enum ParamType
Definition: ParamConverters.h:444
VstString16 fFalseString
Definition: ParamConverters.h:145
EnumParamConverter(IntType iToStringOffset=0)
Definition: ParamConverters.h:455
ParamType denormalize(ParamValue iNormalizedValue) const override
Definition: ParamConverters.h:290
DiscreteValueParamConverter< MaxValue, IntType > fConverter
Definition: ParamConverters.h:485
std::map< T, std::tuple< VstString16, ParamValue, int32 >, Compare > TMap
Maintains the map of possible values of T (defined in constructor)
Definition: ParamConverters.h:357
Definition: Clock.h:23
virtual std::string toString(ParamType const &iValue, int32 iPrecision) const
Definition: ParamConverters.h:61
BooleanParamConverter(VstString16 iFalseString=STR16("Off"), VstString16 iTrueString=STR16("On"))
Definition: ParamConverters.h:112
static int32 computeNextDiscreteValue(int32 iValue, int32 iStepCount, int32 iIncrement, bool iWrap)
Implements a standard behavior for what it means to increment (resp.
Definition: ParamConverters.h:217
A converter to deal with an enum (assumes that the enum is contiguous, starts at 0 and that MaxValue ...
Definition: ParamConverters.h:441
std::string toUT8String(VstString16 const &iString)
Converts a VstString16 to a regular std::string that is properly utf-8 encoded.
Definition: Utils.h:34
void toString(ParamType const &iValue, String128 oString, int32) const override
Definition: ParamConverters.h:296
ParamValue normalize(ParamType const &iDiscreteValue) const override
Definition: ParamConverters.h:285
A vst parameter is represented by a ParamValue type which is a double in the range [0,...
Definition: ParamConverters.h:53