OpenShot Library | OpenShotAudio  0.2.2
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;
52  NormalisableRange& operator= (NormalisableRange&&) = default;
53 
54  /** Creates a NormalisableRange with a given range, interval and skew factor. */
55  NormalisableRange (ValueType rangeStart,
56  ValueType rangeEnd,
57  ValueType intervalValue,
58  ValueType skewFactor,
59  bool useSymmetricSkew = false) noexcept
60  : start (rangeStart), end (rangeEnd), interval (intervalValue),
61  skew (skewFactor), symmetricSkew (useSymmetricSkew)
62  {
63  checkInvariants();
64  }
65 
66  /** Creates a NormalisableRange with a given range, continuous interval, but a dummy skew-factor. */
67  NormalisableRange (ValueType rangeStart,
68  ValueType rangeEnd) noexcept
69  : start (rangeStart), end (rangeEnd)
70  {
71  checkInvariants();
72  }
73 
74  /** Creates a NormalisableRange with a given range and interval, but a dummy skew-factor. */
75  NormalisableRange (ValueType rangeStart,
76  ValueType rangeEnd,
77  ValueType intervalValue) noexcept
78  : start (rangeStart), end (rangeEnd), interval (intervalValue)
79  {
80  checkInvariants();
81  }
82 
83  /** Creates a NormalisableRange with a given range, continuous interval, but a dummy skew-factor. */
85  : NormalisableRange (range.getStart(), range.getEnd())
86  {
87  }
88 
89  /** Creates a NormalisableRange with a given range and interval, but a dummy skew-factor. */
90  NormalisableRange (Range<ValueType> range, ValueType intervalValue) noexcept
91  : NormalisableRange (range.getStart(), range.getEnd(), intervalValue)
92  {
93  }
94 
95  /** A function object which can remap a value in some way based on the start and end of a range. */
96  using ValueRemapFunction = std::function<ValueType(ValueType rangeStart,
97  ValueType rangeEnd,
98  ValueType valueToRemap)>;
99 
100  /** Creates a NormalisableRange with a given range and an injective mapping function.
101 
102  @param rangeStart The minimum value in the range.
103  @param rangeEnd The maximum value in the range.
104  @param convertFrom0To1Func A function which uses the current start and end of this NormalisableRange
105  and produces a mapped value from a normalised value.
106  @param convertTo0To1Func A function which uses the current start and end of this NormalisableRange
107  and produces a normalised value from a mapped value.
108  @param snapToLegalValueFunc A function which uses the current start and end of this NormalisableRange
109  to take a mapped value and snap it to the nearest legal value.
110  */
111  NormalisableRange (ValueType rangeStart,
112  ValueType rangeEnd,
113  ValueRemapFunction convertFrom0To1Func,
114  ValueRemapFunction convertTo0To1Func,
115  ValueRemapFunction snapToLegalValueFunc = {}) noexcept
116  : start (rangeStart),
117  end (rangeEnd),
118  convertFrom0To1Function (std::move (convertFrom0To1Func)),
119  convertTo0To1Function (std::move (convertTo0To1Func)),
120  snapToLegalValueFunction (std::move (snapToLegalValueFunc))
121  {
122  checkInvariants();
123  }
124 
125  /** Uses the properties of this mapping to convert a non-normalised value to
126  its 0->1 representation.
127  */
128  ValueType convertTo0to1 (ValueType v) const noexcept
129  {
130  if (convertTo0To1Function != nullptr)
131  return clampTo0To1 (convertTo0To1Function (start, end, v));
132 
133  auto proportion = clampTo0To1 ((v - start) / (end - start));
134 
135  if (skew == static_cast<ValueType> (1))
136  return proportion;
137 
138  if (! symmetricSkew)
139  return std::pow (proportion, skew);
140 
141  auto distanceFromMiddle = static_cast<ValueType> (2) * proportion - static_cast<ValueType> (1);
142 
143  return (static_cast<ValueType> (1) + std::pow (std::abs (distanceFromMiddle), skew)
144  * (distanceFromMiddle < ValueType() ? static_cast<ValueType> (-1)
145  : static_cast<ValueType> (1)))
146  / static_cast<ValueType> (2);
147  }
148 
149  /** Uses the properties of this mapping to convert a normalised 0->1 value to
150  its full-range representation.
151  */
152  ValueType convertFrom0to1 (ValueType proportion) const noexcept
153  {
154  proportion = clampTo0To1 (proportion);
155 
156  if (convertFrom0To1Function != nullptr)
157  return convertFrom0To1Function (start, end, proportion);
158 
159  if (! symmetricSkew)
160  {
161  if (skew != static_cast<ValueType> (1) && proportion > ValueType())
162  proportion = std::exp (std::log (proportion) / skew);
163 
164  return start + (end - start) * proportion;
165  }
166 
167  auto distanceFromMiddle = static_cast<ValueType> (2) * proportion - static_cast<ValueType> (1);
168 
169  if (skew != static_cast<ValueType> (1) && distanceFromMiddle != static_cast<ValueType> (0))
170  distanceFromMiddle = std::exp (std::log (std::abs (distanceFromMiddle)) / skew)
171  * (distanceFromMiddle < ValueType() ? static_cast<ValueType> (-1)
172  : static_cast<ValueType> (1));
173 
174  return start + (end - start) / static_cast<ValueType> (2) * (static_cast<ValueType> (1) + distanceFromMiddle);
175  }
176 
177  /** Takes a non-normalised value and snaps it based on either the interval property of
178  this NormalisableRange or the lambda function supplied to the constructor.
179  */
180  ValueType snapToLegalValue (ValueType v) const noexcept
181  {
182  if (snapToLegalValueFunction != nullptr)
183  return snapToLegalValueFunction (start, end, v);
184 
185  if (interval > ValueType())
186  v = start + interval * std::floor ((v - start) / interval + static_cast<ValueType> (0.5));
187 
188  return (v <= start || end <= start) ? start : (v >= end ? end : v);
189  }
190 
191  /** Returns the extent of the normalisable range. */
192  Range<ValueType> getRange() const noexcept { return { start, end }; }
193 
194  /** Given a value which is between the start and end points, this sets the skew
195  such that convertFrom0to1 (0.5) will return this value.
196 
197  If you have used lambda functions for convertFrom0to1Func and convertFrom0to1Func in the
198  constructor of this class then the skew value is ignored.
199 
200  @param centrePointValue this must be greater than the start of the range and less than the end.
201  */
202  void setSkewForCentre (ValueType centrePointValue) noexcept
203  {
204  jassert (centrePointValue > start);
205  jassert (centrePointValue < end);
206 
207  symmetricSkew = false;
208  skew = std::log (static_cast<ValueType> (0.5)) / std::log ((centrePointValue - start) / (end - start));
209  checkInvariants();
210  }
211 
212  /** The minimum value of the non-normalised range. */
213  ValueType start = 0;
214 
215  /** The maximum value of the non-normalised range. */
216  ValueType end = 1;
217 
218  /** The snapping interval that should be used (for a non-normalised value). Use 0 for a
219  continuous range.
220 
221  If you have used a lambda function for snapToLegalValueFunction in the constructor of
222  this class then the interval is ignored.
223  */
224  ValueType interval = 0;
225 
226  /** An optional skew factor that alters the way values are distribute across the range.
227 
228  The skew factor lets you skew the mapping logarithmically so that larger or smaller
229  values are given a larger proportion of the available space.
230 
231  A factor of 1.0 has no skewing effect at all. If the factor is < 1.0, the lower end
232  of the range will fill more of the slider's length; if the factor is > 1.0, the upper
233  end of the range will be expanded.
234 
235  If you have used lambda functions for convertFrom0to1Func and convertFrom0to1Func in the
236  constructor of this class then the skew value is ignored.
237  */
238  ValueType skew = 1;
239 
240  /** If true, the skew factor applies from the middle of the slider to each of its ends. */
241  bool symmetricSkew = false;
242 
243 private:
244  void checkInvariants() const
245  {
246  jassert (end > start);
247  jassert (interval >= ValueType());
248  jassert (skew > ValueType());
249  }
250 
251  static ValueType clampTo0To1 (ValueType value)
252  {
253  auto clampedValue = jlimit (static_cast<ValueType> (0), static_cast<ValueType> (1), value);
254 
255  // If you hit this assertion then either your normalisation function is not working
256  // correctly or your input is out of the expected bounds.
257  jassert (clampedValue == value);
258 
259  return clampedValue;
260  }
261 
262  ValueRemapFunction convertFrom0To1Function, convertTo0To1Function, snapToLegalValueFunction;
263 };
264 
265 } // namespace juce
266 
267 /** @}*/
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 NormalisableR...
Represents a mapping between an arbitrary range of values and a normalised 0->1 range.
std::function< ValueType(ValueType rangeStart, ValueType rangeEnd, ValueType valueToRemap)> ValueRemapFunction
A function object which can remap a value in some way based on the start and end of a range...
NormalisableRange(Range< ValueType > range, ValueType intervalValue) noexcept
Creates a NormalisableRange with a given range and interval, but a dummy skew-factor.
NormalisableRange(ValueType rangeStart, ValueType rangeEnd, ValueRemapFunction convertFrom0To1Func, ValueRemapFunction convertTo0To1Func, ValueRemapFunction snapToLegalValueFunc={}) noexcept
Creates a NormalisableRange with a given range and an injective mapping function. ...
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