1 /************************** BEGIN ValueConverter.h **************************/
2 /************************************************************************
3  FAUST Architecture File
4  Copyright (C) 2003-2017 GRAME, Centre National de Creation Musicale
5  ---------------------------------------------------------------------
6  This Architecture section is free software; you can redistribute it
7  and/or modify it under the terms of the GNU General Public License
8  as published by the Free Software Foundation; either version 3 of
9  the License, or (at your option) any later version.
10 
11  This program is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  GNU General Public License for more details.
15 
16  You should have received a copy of the GNU General Public License
17  along with this program; If not, see <http://www.gnu.org/licenses/>.
18 
19  EXCEPTION : As a special exception, you may create a larger work
20  that contains this FAUST architecture section and distribute
21  that work under terms of your choice, so long as this FAUST
22  architecture section is not modified.
23  ************************************************************************/
24 
25 #ifndef __ValueConverter__
26 #define __ValueConverter__
27 
28 /***************************************************************************************
29  ValueConverter.h
30  (GRAME, Copyright 2015-2019)
31 
32  Set of conversion objects used to map user interface values (for example a gui slider
33  delivering values between 0 and 1) to faust values (for example a vslider between
34  20 and 20000) using a log scale.
35 
36  -- Utilities
37 
38  Range(lo,hi) : clip a value x between lo and hi
39  Interpolator(lo,hi,v1,v2) : Maps a value x between lo and hi to a value y between v1 and v2
40  Interpolator3pt(lo,mi,hi,v1,vm,v2) : Map values between lo mid hi to values between v1 vm v2
41 
42  -- Value Converters
43 
44  ValueConverter::ui2faust(x)
45  ValueConverter::faust2ui(x)
46 
47  -- ValueConverters used for sliders depending of the scale
48 
49  LinearValueConverter(umin, umax, fmin, fmax)
50  LinearValueConverter2(lo, mi, hi, v1, vm, v2) using 2 segments
51  LogValueConverter(umin, umax, fmin, fmax)
52  ExpValueConverter(umin, umax, fmin, fmax)
53 
54  -- ValueConverters used for accelerometers based on 3 points
55 
56  AccUpConverter(amin, amid, amax, fmin, fmid, fmax)        -- curve 0
57  AccDownConverter(amin, amid, amax, fmin, fmid, fmax)      -- curve 1
58  AccUpDownConverter(amin, amid, amax, fmin, fmid, fmax)    -- curve 2
59  AccDownUpConverter(amin, amid, amax, fmin, fmid, fmax)    -- curve 3
60 
61  -- lists of ZoneControl are used to implement accelerometers metadata for each axes
62 
63  ZoneControl(zone, valueConverter) : a zone with an accelerometer data converter
64 
65  -- ZoneReader are used to implement screencolor metadata
66 
67  ZoneReader(zone, valueConverter) : a zone with a data converter
68 
69 ****************************************************************************************/
70 
71 #include <float.h>
72 #include <algorithm>    // std::max
73 #include <cmath>
74 #include <vector>
75 #include <assert.h>
76 
77 //--------------------------------------------------------------------------------------
78 // Interpolator(lo,hi,v1,v2)
79 // Maps a value x between lo and hi to a value y between v1 and v2
80 // y = v1 + (x-lo)/(hi-lo)*(v2-v1)
81 // y = v1 + (x-lo) * coef           with coef = (v2-v1)/(hi-lo)
82 // y = v1 + x*coef - lo*coef
83 // y = v1 - lo*coef + x*coef
84 // y = offset + x*coef              with offset = v1 - lo*coef
85 //--------------------------------------------------------------------------------------
86 class Interpolator
87 {
88     private:
89 
90         //--------------------------------------------------------------------------------------
91         // Range(lo,hi) clip a value between lo and hi
92         //--------------------------------------------------------------------------------------
93         struct Range
94         {
95             double fLo;
96             double fHi;
97 
RangeRange98             Range(double x, double y) : fLo(std::min<double>(x,y)), fHi(std::max<double>(x,y)) {}
operatorRange99             double operator()(double x) { return (x<fLo) ? fLo : (x>fHi) ? fHi : x; }
100         };
101 
102 
103         Range fRange;
104         double fCoef;
105         double fOffset;
106 
107     public:
108 
Interpolator(double lo,double hi,double v1,double v2)109         Interpolator(double lo, double hi, double v1, double v2) : fRange(lo,hi)
110         {
111             if (hi != lo) {
112                 // regular case
113                 fCoef = (v2-v1)/(hi-lo);
114                 fOffset = v1 - lo*fCoef;
115             } else {
116                 // degenerate case, avoids division by zero
117                 fCoef = 0;
118                 fOffset = (v1+v2)/2;
119             }
120         }
operator()121         double operator()(double v)
122         {
123             double x = fRange(v);
124             return  fOffset + x*fCoef;
125         }
126 
getLowHigh(double & amin,double & amax)127         void getLowHigh(double& amin, double& amax)
128         {
129             amin = fRange.fLo;
130             amax = fRange.fHi;
131         }
132 };
133 
134 //--------------------------------------------------------------------------------------
135 // Interpolator3pt(lo,mi,hi,v1,vm,v2)
136 // Map values between lo mid hi to values between v1 vm v2
137 //--------------------------------------------------------------------------------------
138 class Interpolator3pt
139 {
140 
141     private:
142 
143         Interpolator fSegment1;
144         Interpolator fSegment2;
145         double fMid;
146 
147     public:
148 
Interpolator3pt(double lo,double mi,double hi,double v1,double vm,double v2)149         Interpolator3pt(double lo, double mi, double hi, double v1, double vm, double v2) :
150             fSegment1(lo, mi, v1, vm),
151             fSegment2(mi, hi, vm, v2),
152             fMid(mi) {}
operator()153         double operator()(double x) { return  (x < fMid) ? fSegment1(x) : fSegment2(x); }
154 
getMappingValues(double & amin,double & amid,double & amax)155         void getMappingValues(double& amin, double& amid, double& amax)
156         {
157             fSegment1.getLowHigh(amin, amid);
158             fSegment2.getLowHigh(amid, amax);
159         }
160 };
161 
162 //--------------------------------------------------------------------------------------
163 // Abstract ValueConverter class. Converts values between UI and Faust representations
164 //--------------------------------------------------------------------------------------
165 class ValueConverter // Identity by default
166 {
167 
168     public:
169 
~ValueConverter()170         virtual ~ValueConverter() {}
ui2faust(double x)171         virtual double ui2faust(double x) { return x; };
faust2ui(double x)172         virtual double faust2ui(double x) { return x; };
173 };
174 
175 //--------------------------------------------------------------------------------------
176 // A converter than can be updated
177 //--------------------------------------------------------------------------------------
178 
179 class UpdatableValueConverter : public ValueConverter {
180 
181     protected:
182 
183         bool fActive;
184 
185     public:
186 
UpdatableValueConverter()187         UpdatableValueConverter():fActive(true)
188         {}
~UpdatableValueConverter()189         virtual ~UpdatableValueConverter()
190         {}
191 
192         virtual void setMappingValues(double amin, double amid, double amax, double min, double init, double max) = 0;
193         virtual void getMappingValues(double& amin, double& amid, double& amax) = 0;
194 
setActive(bool on_off)195         void setActive(bool on_off) { fActive = on_off; }
getActive()196         bool getActive() { return fActive; }
197 
198 };
199 
200 //--------------------------------------------------------------------------------------
201 // Linear conversion between ui and Faust values
202 //--------------------------------------------------------------------------------------
203 class LinearValueConverter : public ValueConverter
204 {
205 
206     private:
207 
208         Interpolator fUI2F;
209         Interpolator fF2UI;
210 
211     public:
212 
LinearValueConverter(double umin,double umax,double fmin,double fmax)213         LinearValueConverter(double umin, double umax, double fmin, double fmax) :
214             fUI2F(umin,umax,fmin,fmax), fF2UI(fmin,fmax,umin,umax)
215         {}
216 
LinearValueConverter()217         LinearValueConverter() : fUI2F(0.,0.,0.,0.), fF2UI(0.,0.,0.,0.)
218         {}
ui2faust(double x)219         virtual double ui2faust(double x) { return fUI2F(x); }
faust2ui(double x)220         virtual double faust2ui(double x) { return fF2UI(x); }
221 
222 };
223 
224 //--------------------------------------------------------------------------------------
225 // Two segments linear conversion between ui and Faust values
226 //--------------------------------------------------------------------------------------
227 class LinearValueConverter2 : public UpdatableValueConverter
228 {
229 
230     private:
231 
232         Interpolator3pt fUI2F;
233         Interpolator3pt fF2UI;
234 
235     public:
236 
LinearValueConverter2(double amin,double amid,double amax,double min,double init,double max)237         LinearValueConverter2(double amin, double amid, double amax, double min, double init, double max) :
238             fUI2F(amin, amid, amax, min, init, max), fF2UI(min, init, max, amin, amid, amax)
239         {}
240 
LinearValueConverter2()241         LinearValueConverter2() : fUI2F(0.,0.,0.,0.,0.,0.), fF2UI(0.,0.,0.,0.,0.,0.)
242         {}
243 
ui2faust(double x)244         virtual double ui2faust(double x) { return fUI2F(x); }
faust2ui(double x)245         virtual double faust2ui(double x) { return fF2UI(x); }
246 
setMappingValues(double amin,double amid,double amax,double min,double init,double max)247         virtual void setMappingValues(double amin, double amid, double amax, double min, double init, double max)
248         {
249             fUI2F = Interpolator3pt(amin, amid, amax, min, init, max);
250             fF2UI = Interpolator3pt(min, init, max, amin, amid, amax);
251         }
252 
getMappingValues(double & amin,double & amid,double & amax)253         virtual void getMappingValues(double& amin, double& amid, double& amax)
254         {
255             fUI2F.getMappingValues(amin, amid, amax);
256         }
257 
258 };
259 
260 //--------------------------------------------------------------------------------------
261 // Logarithmic conversion between ui and Faust values
262 //--------------------------------------------------------------------------------------
263 class LogValueConverter : public LinearValueConverter
264 {
265 
266     public:
267 
LogValueConverter(double umin,double umax,double fmin,double fmax)268         LogValueConverter(double umin, double umax, double fmin, double fmax) :
269             LinearValueConverter(umin, umax, std::log(std::max<double>(DBL_MIN, fmin)), std::log(std::max<double>(DBL_MIN, fmax)))
270         {}
271 
ui2faust(double x)272         virtual double ui2faust(double x) { return std::exp(LinearValueConverter::ui2faust(x)); }
faust2ui(double x)273         virtual double faust2ui(double x) { return LinearValueConverter::faust2ui(std::log(std::max<double>(x, DBL_MIN))); }
274 
275 };
276 
277 //--------------------------------------------------------------------------------------
278 // Exponential conversion between ui and Faust values
279 //--------------------------------------------------------------------------------------
280 class ExpValueConverter : public LinearValueConverter
281 {
282 
283     public:
284 
ExpValueConverter(double umin,double umax,double fmin,double fmax)285         ExpValueConverter(double umin, double umax, double fmin, double fmax) :
286             LinearValueConverter(umin, umax, std::min<double>(DBL_MAX, std::exp(fmin)), std::min<double>(DBL_MAX, std::exp(fmax)))
287         {}
288 
ui2faust(double x)289         virtual double ui2faust(double x) { return std::log(LinearValueConverter::ui2faust(x)); }
faust2ui(double x)290         virtual double faust2ui(double x) { return LinearValueConverter::faust2ui(std::min<double>(DBL_MAX, std::exp(x))); }
291 
292 };
293 
294 //--------------------------------------------------------------------------------------
295 // Convert accelerometer or gyroscope values to Faust values
296 // Using an Up curve (curve 0)
297 //--------------------------------------------------------------------------------------
298 class AccUpConverter : public UpdatableValueConverter
299 {
300 
301     private:
302 
303         Interpolator3pt fA2F;
304         Interpolator3pt fF2A;
305 
306     public:
307 
AccUpConverter(double amin,double amid,double amax,double fmin,double fmid,double fmax)308         AccUpConverter(double amin, double amid, double amax, double fmin, double fmid, double fmax) :
309             fA2F(amin,amid,amax,fmin,fmid,fmax),
310             fF2A(fmin,fmid,fmax,amin,amid,amax)
311         {}
312 
ui2faust(double x)313         virtual double ui2faust(double x) { return fA2F(x); }
faust2ui(double x)314         virtual double faust2ui(double x) { return fF2A(x); }
315 
setMappingValues(double amin,double amid,double amax,double fmin,double fmid,double fmax)316         virtual void setMappingValues(double amin, double amid, double amax, double fmin, double fmid, double fmax)
317         {
318             //__android_log_print(ANDROID_LOG_ERROR, "Faust", "AccUpConverter update %f %f %f %f %f %f", amin,amid,amax,fmin,fmid,fmax);
319             fA2F = Interpolator3pt(amin, amid, amax, fmin, fmid, fmax);
320             fF2A = Interpolator3pt(fmin, fmid, fmax, amin, amid, amax);
321         }
322 
getMappingValues(double & amin,double & amid,double & amax)323         virtual void getMappingValues(double& amin, double& amid, double& amax)
324         {
325             fA2F.getMappingValues(amin, amid, amax);
326         }
327 
328 };
329 
330 //--------------------------------------------------------------------------------------
331 // Convert accelerometer or gyroscope values to Faust values
332 // Using a Down curve (curve 1)
333 //--------------------------------------------------------------------------------------
334 class AccDownConverter : public UpdatableValueConverter
335 {
336 
337     private:
338 
339         Interpolator3pt	fA2F;
340         Interpolator3pt	fF2A;
341 
342     public:
343 
AccDownConverter(double amin,double amid,double amax,double fmin,double fmid,double fmax)344         AccDownConverter(double amin, double amid, double amax, double fmin, double fmid, double fmax) :
345             fA2F(amin,amid,amax,fmax,fmid,fmin),
346             fF2A(fmin,fmid,fmax,amax,amid,amin)
347         {}
348 
ui2faust(double x)349         virtual double ui2faust(double x) { return fA2F(x); }
faust2ui(double x)350         virtual double faust2ui(double x) { return fF2A(x); }
351 
setMappingValues(double amin,double amid,double amax,double fmin,double fmid,double fmax)352         virtual void setMappingValues(double amin, double amid, double amax, double fmin, double fmid, double fmax)
353         {
354              //__android_log_print(ANDROID_LOG_ERROR, "Faust", "AccDownConverter update %f %f %f %f %f %f", amin,amid,amax,fmin,fmid,fmax);
355             fA2F = Interpolator3pt(amin, amid, amax, fmax, fmid, fmin);
356             fF2A = Interpolator3pt(fmin, fmid, fmax, amax, amid, amin);
357         }
358 
getMappingValues(double & amin,double & amid,double & amax)359         virtual void getMappingValues(double& amin, double& amid, double& amax)
360         {
361             fA2F.getMappingValues(amin, amid, amax);
362         }
363 };
364 
365 //--------------------------------------------------------------------------------------
366 // Convert accelerometer or gyroscope values to Faust values
367 // Using an Up-Down curve (curve 2)
368 //--------------------------------------------------------------------------------------
369 class AccUpDownConverter : public UpdatableValueConverter
370 {
371 
372     private:
373 
374         Interpolator3pt	fA2F;
375         Interpolator fF2A;
376 
377     public:
378 
AccUpDownConverter(double amin,double amid,double amax,double fmin,double fmid,double fmax)379         AccUpDownConverter(double amin, double amid, double amax, double fmin, double fmid, double fmax) :
380             fA2F(amin,amid,amax,fmin,fmax,fmin),
381             fF2A(fmin,fmax,amin,amax)				// Special, pseudo inverse of a non monotonic function
382         {}
383 
ui2faust(double x)384         virtual double ui2faust(double x) { return fA2F(x); }
faust2ui(double x)385         virtual double faust2ui(double x) { return fF2A(x); }
386 
setMappingValues(double amin,double amid,double amax,double fmin,double fmid,double fmax)387         virtual void setMappingValues(double amin, double amid, double amax, double fmin, double fmid, double fmax)
388         {
389             //__android_log_print(ANDROID_LOG_ERROR, "Faust", "AccUpDownConverter update %f %f %f %f %f %f", amin,amid,amax,fmin,fmid,fmax);
390             fA2F = Interpolator3pt(amin, amid, amax, fmin, fmax, fmin);
391             fF2A = Interpolator(fmin, fmax, amin, amax);
392         }
393 
getMappingValues(double & amin,double & amid,double & amax)394         virtual void getMappingValues(double& amin, double& amid, double& amax)
395         {
396             fA2F.getMappingValues(amin, amid, amax);
397         }
398 };
399 
400 //--------------------------------------------------------------------------------------
401 // Convert accelerometer or gyroscope values to Faust values
402 // Using a Down-Up curve (curve 3)
403 //--------------------------------------------------------------------------------------
404 class AccDownUpConverter : public UpdatableValueConverter
405 {
406 
407     private:
408 
409         Interpolator3pt	fA2F;
410         Interpolator fF2A;
411 
412     public:
413 
AccDownUpConverter(double amin,double amid,double amax,double fmin,double fmid,double fmax)414         AccDownUpConverter(double amin, double amid, double amax, double fmin, double fmid, double fmax) :
415             fA2F(amin,amid,amax,fmax,fmin,fmax),
416             fF2A(fmin,fmax,amin,amax)				// Special, pseudo inverse of a non monotonic function
417         {}
418 
ui2faust(double x)419         virtual double ui2faust(double x) { return fA2F(x); }
faust2ui(double x)420         virtual double faust2ui(double x) { return fF2A(x); }
421 
setMappingValues(double amin,double amid,double amax,double fmin,double fmid,double fmax)422         virtual void setMappingValues(double amin, double amid, double amax, double fmin, double fmid, double fmax)
423         {
424             //__android_log_print(ANDROID_LOG_ERROR, "Faust", "AccDownUpConverter update %f %f %f %f %f %f", amin,amid,amax,fmin,fmid,fmax);
425             fA2F = Interpolator3pt(amin, amid, amax, fmax, fmin, fmax);
426             fF2A = Interpolator(fmin, fmax, amin, amax);
427         }
428 
getMappingValues(double & amin,double & amid,double & amax)429         virtual void getMappingValues(double& amin, double& amid, double& amax)
430         {
431             fA2F.getMappingValues(amin, amid, amax);
432         }
433 };
434 
435 //--------------------------------------------------------------------------------------
436 // Base class for ZoneControl
437 //--------------------------------------------------------------------------------------
438 class ZoneControl
439 {
440 
441     protected:
442 
443         FAUSTFLOAT*	fZone;
444 
445     public:
446 
ZoneControl(FAUSTFLOAT * zone)447         ZoneControl(FAUSTFLOAT* zone) : fZone(zone) {}
~ZoneControl()448         virtual ~ZoneControl() {}
449 
update(double v)450         virtual void update(double v) const {}
451 
setMappingValues(int curve,double amin,double amid,double amax,double min,double init,double max)452         virtual void setMappingValues(int curve, double amin, double amid, double amax, double min, double init, double max) {}
getMappingValues(double & amin,double & amid,double & amax)453         virtual void getMappingValues(double& amin, double& amid, double& amax) {}
454 
getZone()455         FAUSTFLOAT* getZone() { return fZone; }
456 
setActive(bool on_off)457         virtual void setActive(bool on_off) {}
getActive()458         virtual bool getActive() { return false; }
459 
getCurve()460         virtual int getCurve() { return -1; }
461 
462 };
463 
464 //--------------------------------------------------------------------------------------
465 //  Useful to implement accelerometers metadata as a list of ZoneControl for each axes
466 //--------------------------------------------------------------------------------------
467 class ConverterZoneControl : public ZoneControl
468 {
469 
470     protected:
471 
472         ValueConverter* fValueConverter;
473 
474     public:
475 
ConverterZoneControl(FAUSTFLOAT * zone,ValueConverter * converter)476         ConverterZoneControl(FAUSTFLOAT* zone, ValueConverter* converter) : ZoneControl(zone), fValueConverter(converter) {}
~ConverterZoneControl()477         virtual ~ConverterZoneControl() { delete fValueConverter; } // Assuming fValueConverter is not kept elsewhere...
478 
update(double v)479         virtual void update(double v) const { *fZone = fValueConverter->ui2faust(v); }
480 
getConverter()481         ValueConverter* getConverter() { return fValueConverter; }
482 
483 };
484 
485 //--------------------------------------------------------------------------------------
486 // Association of a zone and a four value converter, each one for each possible curve.
487 // Useful to implement accelerometers metadata as a list of ZoneControl for each axes
488 //--------------------------------------------------------------------------------------
489 class CurveZoneControl : public ZoneControl
490 {
491 
492     private:
493 
494         std::vector<UpdatableValueConverter*> fValueConverters;
495         int fCurve;
496 
497     public:
498 
CurveZoneControl(FAUSTFLOAT * zone,int curve,double amin,double amid,double amax,double min,double init,double max)499         CurveZoneControl(FAUSTFLOAT* zone, int curve, double amin, double amid, double amax, double min, double init, double max) : ZoneControl(zone), fCurve(0)
500         {
501             assert(curve >= 0 && curve <= 3);
502             fValueConverters.push_back(new AccUpConverter(amin, amid, amax, min, init, max));
503             fValueConverters.push_back(new AccDownConverter(amin, amid, amax, min, init, max));
504             fValueConverters.push_back(new AccUpDownConverter(amin, amid, amax, min, init, max));
505             fValueConverters.push_back(new AccDownUpConverter(amin, amid, amax, min, init, max));
506             fCurve = curve;
507         }
~CurveZoneControl()508         virtual ~CurveZoneControl()
509         {
510             std::vector<UpdatableValueConverter*>::iterator it;
511             for (it = fValueConverters.begin(); it != fValueConverters.end(); it++) {
512                 delete(*it);
513             }
514         }
update(double v)515         void update(double v) const { if (fValueConverters[fCurve]->getActive()) *fZone = fValueConverters[fCurve]->ui2faust(v); }
516 
setMappingValues(int curve,double amin,double amid,double amax,double min,double init,double max)517         void setMappingValues(int curve, double amin, double amid, double amax, double min, double init, double max)
518         {
519             fValueConverters[curve]->setMappingValues(amin, amid, amax, min, init, max);
520             fCurve = curve;
521         }
522 
getMappingValues(double & amin,double & amid,double & amax)523         void getMappingValues(double& amin, double& amid, double& amax)
524         {
525             fValueConverters[fCurve]->getMappingValues(amin, amid, amax);
526         }
527 
setActive(bool on_off)528         void setActive(bool on_off)
529         {
530             std::vector<UpdatableValueConverter*>::iterator it;
531             for (it = fValueConverters.begin(); it != fValueConverters.end(); it++) {
532                 (*it)->setActive(on_off);
533             }
534         }
535 
getCurve()536         int getCurve() { return fCurve; }
537 };
538 
539 class ZoneReader
540 {
541 
542     private:
543 
544         FAUSTFLOAT* fZone;
545         Interpolator fInterpolator;
546 
547     public:
548 
ZoneReader(FAUSTFLOAT * zone,double lo,double hi)549         ZoneReader(FAUSTFLOAT* zone, double lo, double hi) : fZone(zone), fInterpolator(lo, hi, 0, 255) {}
550 
~ZoneReader()551         virtual ~ZoneReader() {}
552 
getValue()553         int getValue()
554         {
555             return (fZone != nullptr) ? int(fInterpolator(*fZone)) : 127;
556         }
557 
558 };
559 
560 #endif
561 /**************************  END  ValueConverter.h **************************/
562