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