OpenShot Library | libopenshot-audio 0.2.0
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
27namespace 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*/
42template <typename ValueType>
44{
45public:
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),
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
262private:
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/** @}*/
Represents a mapping between an arbitrary range of values and a normalised 0->1 range.
ValueType skew
An optional skew factor that alters the way values are distribute across the range.
ValueType end
The maximum value of the non-normalised 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...
NormalisableRange()=default
Creates a continuous range that performs a dummy mapping.
ValueType start
The minimum value of the non-normalised range.
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.
void setSkewForCentre(ValueType centrePointValue) noexcept
Given a value which is between the start and end points, this sets the skew such that convertFrom0to1...
NormalisableRange(ValueType rangeStart, ValueType rangeEnd, ValueType intervalValue) noexcept
Creates a NormalisableRange with a given range and interval, but a dummy skew-factor.
Range< ValueType > getRange() const noexcept
Returns the extent of the normalisable range.
ValueType interval
The snapping interval that should be used (for a non-normalised value).
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, ValueType intervalValue, ValueType skewFactor, bool useSymmetricSkew=false) noexcept
Creates a NormalisableRange with a given range, interval and 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.
NormalisableRange(Range< ValueType > range) noexcept
Creates a NormalisableRange with a given range, continuous interval, but a dummy skew-factor.
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.
A general-purpose range object, that simply represents any linear range with a start and end point.
Definition juce_Range.h:44