OpenShot Library | libopenshot-audio  0.1.9
juce_NormalisableRange.h
1 
2 /** @weakgroup juce_core-maths
3  * @{
4  */
5 /*
6  ==============================================================================
7 
8  This file is part of the JUCE library.
9  Copyright (c) 2017 - ROLI Ltd.
10 
11  JUCE is an open source library subject to commercial or open-source
12  licensing.
13 
14  The code included in this file is provided under the terms of the ISC license
15  http://www.isc.org/downloads/software-support-policy/isc-license. Permission
16  To use, copy, modify, and/or distribute this software for any purpose with or
17  without fee is hereby granted provided that the above copyright notice and
18  this permission notice appear in all copies.
19 
20  JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
21  EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
22  DISCLAIMED.
23 
24  ==============================================================================
25 */
26 
27 namespace juce
28 {
29 
30 //==============================================================================
31 /**
32  Represents a mapping between an arbitrary range of values and a
33  normalised 0->1 range.
34 
35  The properties of the mapping also include an optional snapping interval
36  and skew-factor.
37 
38  @see Range
39 
40  @tags{Core}
41 */
42 template <typename ValueType>
44 {
45 public:
46  /** Creates a continuous range that performs a dummy mapping. */
47  NormalisableRange() = default;
48 
49  NormalisableRange (const NormalisableRange&) = default;
50  NormalisableRange& operator= (const NormalisableRange&) = default;
51 
52  // VS2013 can't default move constructors
54  : start (other.start), end (other.end),
55  interval (other.interval), skew (other.skew),
56  symmetricSkew (other.symmetricSkew),
57  convertFrom0To1Function (std::move (other.convertFrom0To1Function)),
58  convertTo0To1Function (std::move (other.convertTo0To1Function)),
59  snapToLegalValueFunction (std::move (other.snapToLegalValueFunction))
60  {
61  }
62 
63  // VS2013 can't default move assignments
64  NormalisableRange& operator= (NormalisableRange&& other)
65  {
66  start = other.start;
67  end = other.end;
68  interval = other.interval;
69  skew = other.skew;
70  symmetricSkew = other.symmetricSkew;
71  convertFrom0To1Function = std::move (other.convertFrom0To1Function);
72  convertTo0To1Function = std::move (other.convertTo0To1Function);
73  snapToLegalValueFunction = std::move (other.snapToLegalValueFunction);
74 
75  return *this;
76  }
77 
78  /** Creates a NormalisableRange with a given range, interval and skew factor. */
79  NormalisableRange (ValueType rangeStart,
80  ValueType rangeEnd,
81  ValueType intervalValue,
82  ValueType skewFactor,
83  bool useSymmetricSkew = false) noexcept
84  : start (rangeStart), end (rangeEnd), interval (intervalValue),
85  skew (skewFactor), symmetricSkew (useSymmetricSkew)
86  {
87  checkInvariants();
88  }
89 
90  /** Creates a NormalisableRange with a given range, continuous interval, but a dummy skew-factor. */
91  NormalisableRange (ValueType rangeStart,
92  ValueType rangeEnd) noexcept
93  : start (rangeStart), end (rangeEnd)
94  {
95  checkInvariants();
96  }
97 
98  /** Creates a NormalisableRange with a given range and interval, but a dummy skew-factor. */
99  NormalisableRange (ValueType rangeStart,
100  ValueType rangeEnd,
101  ValueType intervalValue) noexcept
102  : start (rangeStart), end (rangeEnd), interval (intervalValue)
103  {
104  checkInvariants();
105  }
106 
107  /** Creates a NormalisableRange with a given range, continuous interval, but a dummy skew-factor. */
109  : NormalisableRange (range.getStart(), range.getEnd())
110  {
111  }
112 
113  /** Creates a NormalisableRange with a given range and interval, but a dummy skew-factor. */
114  NormalisableRange (Range<ValueType> range, ValueType intervalValue) noexcept
115  : NormalisableRange (range.getStart(), range.getEnd(), intervalValue)
116  {
117  }
118 
119  /** Creates a NormalisableRange with a given range and an injective mapping function.
120 
121  @param rangeStart The minimum value in the range.
122  @param rangeEnd The maximum value in the range.
123  @param convertFrom0To1Func A function which uses the current start and end of this NormalisableRange
124  and produces a mapped value from a normalised value.
125  @param convertTo0To1Func A function which uses the current start and end of this NormalisableRange
126  and produces a normalised value from a mapped value.
127  @param snapToLegalValueFunc A function which uses the current start and end of this NormalisableRange
128  to take a mapped value and snap it to the nearest legal value.
129  */
130  NormalisableRange (ValueType rangeStart,
131  ValueType rangeEnd,
132  std::function<ValueType (ValueType currentRangeStart, ValueType currentRangeEnd, ValueType normalisedValue)> convertFrom0To1Func,
133  std::function<ValueType (ValueType currentRangeStart, ValueType currentRangeEnd, ValueType mappedValue)> convertTo0To1Func,
134  std::function<ValueType (ValueType currentRangeStart, ValueType currentRangeEnd, ValueType valueToSnap)> snapToLegalValueFunc = nullptr) noexcept
135  : start (rangeStart),
136  end (rangeEnd),
137  convertFrom0To1Function (convertFrom0To1Func),
138  convertTo0To1Function (convertTo0To1Func),
139  snapToLegalValueFunction (snapToLegalValueFunc)
140  {
141  checkInvariants();
142  }
143 
144  /** Uses the properties of this mapping to convert a non-normalised value to
145  its 0->1 representation.
146  */
147  ValueType convertTo0to1 (ValueType v) const noexcept
148  {
149  if (convertTo0To1Function != nullptr)
150  return clampTo0To1 (convertTo0To1Function (start, end, v));
151 
152  auto proportion = clampTo0To1 ((v - start) / (end - start));
153 
154  if (skew == static_cast<ValueType> (1))
155  return proportion;
156 
157  if (! symmetricSkew)
158  return std::pow (proportion, skew);
159 
160  auto distanceFromMiddle = static_cast<ValueType> (2) * proportion - static_cast<ValueType> (1);
161 
162  return (static_cast<ValueType> (1) + std::pow (std::abs (distanceFromMiddle), skew)
163  * (distanceFromMiddle < ValueType() ? static_cast<ValueType> (-1)
164  : static_cast<ValueType> (1)))
165  / static_cast<ValueType> (2);
166  }
167 
168  /** Uses the properties of this mapping to convert a normalised 0->1 value to
169  its full-range representation.
170  */
171  ValueType convertFrom0to1 (ValueType proportion) const noexcept
172  {
173  proportion = clampTo0To1 (proportion);
174 
175  if (convertFrom0To1Function != nullptr)
176  return convertFrom0To1Function (start, end, proportion);
177 
178  if (! symmetricSkew)
179  {
180  if (skew != static_cast<ValueType> (1) && proportion > ValueType())
181  proportion = std::exp (std::log (proportion) / skew);
182 
183  return start + (end - start) * proportion;
184  }
185 
186  auto distanceFromMiddle = static_cast<ValueType> (2) * proportion - static_cast<ValueType> (1);
187 
188  if (skew != static_cast<ValueType> (1) && distanceFromMiddle != static_cast<ValueType> (0))
189  distanceFromMiddle = std::exp (std::log (std::abs (distanceFromMiddle)) / skew)
190  * (distanceFromMiddle < ValueType() ? static_cast<ValueType> (-1)
191  : static_cast<ValueType> (1));
192 
193  return start + (end - start) / static_cast<ValueType> (2) * (static_cast<ValueType> (1) + distanceFromMiddle);
194  }
195 
196  /** Takes a non-normalised value and snaps it based on either the interval property of
197  this NormalisedRange or the lambda function supplied to the constructor.
198  */
199  ValueType snapToLegalValue (ValueType v) const noexcept
200  {
201  if (snapToLegalValueFunction != nullptr)
202  return snapToLegalValueFunction (start, end, v);
203 
204  if (interval > ValueType())
205  v = start + interval * std::floor ((v - start) / interval + static_cast<ValueType> (0.5));
206 
207  return (v <= start || end <= start) ? start : (v >= end ? end : v);
208  }
209 
210  /** Returns the extent of the normalisable range. */
211  Range<ValueType> getRange() const noexcept { return { start, end }; }
212 
213  /** Given a value which is between the start and end points, this sets the skew
214  such that convertFrom0to1 (0.5) will return this value.
215 
216  If you have used lambda functions for convertFrom0to1Func and convertFrom0to1Func in the
217  constructor of this class then the skew value is ignored.
218 
219  @param centrePointValue this must be greater than the start of the range and less than the end.
220  */
221  void setSkewForCentre (ValueType centrePointValue) noexcept
222  {
223  jassert (centrePointValue > start);
224  jassert (centrePointValue < end);
225 
226  symmetricSkew = false;
227  skew = std::log (static_cast<ValueType> (0.5)) / std::log ((centrePointValue - start) / (end - start));
228  checkInvariants();
229  }
230 
231  /** The minimum value of the non-normalised range. */
232  ValueType start = 0;
233 
234  /** The maximum value of the non-normalised range. */
235  ValueType end = 1;
236 
237  /** The snapping interval that should be used (for a non-normalised value). Use 0 for a
238  continuous range.
239 
240  If you have used a lambda function for snapToLegalValueFunction in the constructor of
241  this class then the interval is ignored.
242  */
243  ValueType interval = 0;
244 
245  /** An optional skew factor that alters the way values are distribute across the range.
246 
247  The skew factor lets you skew the mapping logarithmically so that larger or smaller
248  values are given a larger proportion of the available space.
249 
250  A factor of 1.0 has no skewing effect at all. If the factor is < 1.0, the lower end
251  of the range will fill more of the slider's length; if the factor is > 1.0, the upper
252  end of the range will be expanded.
253 
254  If you have used lambda functions for convertFrom0to1Func and convertFrom0to1Func in the
255  constructor of this class then the skew value is ignored.
256  */
257  ValueType skew = 1;
258 
259  /** If true, the skew factor applies from the middle of the slider to each of its ends. */
260  bool symmetricSkew = false;
261 
262 private:
263  void checkInvariants() const
264  {
265  jassert (end > start);
266  jassert (interval >= ValueType());
267  jassert (skew > ValueType());
268  }
269 
270  static ValueType clampTo0To1 (ValueType value)
271  {
272  auto clampedValue = jlimit (static_cast<ValueType> (0), static_cast<ValueType> (1), value);
273 
274  // If you hit this assertion then either your normalisation function is not working
275  // correctly or your input is out of the expected bounds.
276  jassert (clampedValue == value);
277 
278  return clampedValue;
279  }
280 
281  using ConversionFunction = std::function<ValueType(ValueType, ValueType, ValueType)>;
282 
283  ConversionFunction convertFrom0To1Function = {},
284  convertTo0To1Function = {},
285  snapToLegalValueFunction = {};
286 };
287 
288 } // namespace juce
289 
290 /** @}*/
Range< ValueType > getRange() const noexcept
Returns the extent of the normalisable range.
void setSkewForCentre(ValueType centrePointValue) noexcept
Given a value which is between the start and end points, this sets the skew such that convertFrom0to1...
NormalisableRange(Range< ValueType > range) noexcept
Creates a NormalisableRange with a given range, continuous interval, but a dummy skew-factor.
ValueType start
The minimum value of the non-normalised range.
NormalisableRange(ValueType rangeStart, ValueType rangeEnd, ValueType intervalValue) noexcept
Creates a NormalisableRange with a given range and interval, but a dummy skew-factor.
ValueType convertTo0to1(ValueType v) const noexcept
Uses the properties of this mapping to convert a non-normalised value to its 0->1 representation...
ValueType skew
An optional skew factor that alters the way values are distribute across the range.
bool symmetricSkew
If true, the skew factor applies from the middle of the slider to each of its ends.
ValueType snapToLegalValue(ValueType v) const noexcept
Takes a non-normalised value and snaps it based on either the interval property of this NormalisedRan...
Represents a mapping between an arbitrary range of values and a normalised 0->1 range.
NormalisableRange(ValueType rangeStart, ValueType rangeEnd, std::function< ValueType(ValueType currentRangeStart, ValueType currentRangeEnd, ValueType normalisedValue)> convertFrom0To1Func, std::function< ValueType(ValueType currentRangeStart, ValueType currentRangeEnd, ValueType mappedValue)> convertTo0To1Func, std::function< ValueType(ValueType currentRangeStart, ValueType currentRangeEnd, ValueType valueToSnap)> snapToLegalValueFunc=nullptr) noexcept
Creates a NormalisableRange with a given range and an injective mapping function. ...
NormalisableRange(Range< ValueType > range, ValueType intervalValue) noexcept
Creates a NormalisableRange with a given range and interval, but a dummy skew-factor.
ValueType convertFrom0to1(ValueType proportion) const noexcept
Uses the properties of this mapping to convert a normalised 0->1 value to its full-range representati...
NormalisableRange(ValueType rangeStart, ValueType rangeEnd) noexcept
Creates a NormalisableRange with a given range, continuous interval, but a dummy skew-factor.
ValueType interval
The snapping interval that should be used (for a non-normalised value).
NormalisableRange(ValueType rangeStart, ValueType rangeEnd, ValueType intervalValue, ValueType skewFactor, bool useSymmetricSkew=false) noexcept
Creates a NormalisableRange with a given range, interval and skew factor.
ValueType end
The maximum value of the non-normalised range.
NormalisableRange()=default
Creates a continuous range that performs a dummy mapping.
A general-purpose range object, that simply represents any linear range with a start and end point...
Definition: juce_Range.h:43