You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

689 lines
20KB

  1. /*
  2. Copyright (C) 2017 Xenakios
  3. This program is free software; you can redistribute it and/or modify
  4. it under the terms of version 3 of the GNU General Public License
  5. as published by the Free Software Foundation.
  6. This program is distributed in the hope that it will be useful,
  7. but WITHOUT ANY WARRANTY; without even the implied warranty of
  8. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  9. GNU General Public License (version 3) for more details.
  10. www.gnu.org/licenses
  11. */
  12. #pragma once
  13. #include <vector>
  14. #include <algorithm>
  15. #include <random>
  16. #include "../JuceLibraryCode/JuceHeader.h"
  17. #include "PS_Source/globals.h"
  18. struct envelope_point
  19. {
  20. envelope_point()
  21. : pt_x(0.0), pt_y(0.0), ShapeParam1(0.5), ShapeParam2(0.5) {}
  22. envelope_point(double x, double y, double p1=0.5, double p2=0.5)
  23. : pt_x(x), pt_y(y),ShapeParam1(p1),ShapeParam2(p2) {}
  24. double pt_x;
  25. double pt_y;
  26. int Shape = 0;
  27. double ShapeParam1;
  28. double ShapeParam2;
  29. int Status = 0;
  30. size_t get_hash() const
  31. {
  32. size_t seed = 0;
  33. seed ^= std::hash<double>()(pt_x) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
  34. seed ^= std::hash<double>()(pt_y) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
  35. seed ^= std::hash<int>()(Shape) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
  36. seed ^= std::hash<double>()(ShapeParam1) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
  37. seed ^= std::hash<double>()(ShapeParam2) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
  38. return seed;
  39. }
  40. };
  41. inline bool operator<(const envelope_point& a, const envelope_point& b)
  42. {
  43. return a.pt_x<b.pt_x;
  44. }
  45. template<typename T>
  46. inline void appendToMemoryBlock(MemoryBlock& mb, T x)
  47. {
  48. T temp(x);
  49. mb.append((void*)&temp, sizeof(temp));
  50. }
  51. struct grid_entry
  52. {
  53. grid_entry(double v) : m_value(v) {}
  54. double m_value=0.0;
  55. bool m_foo=false;
  56. };
  57. inline double grid_value(const grid_entry& ge)
  58. {
  59. return ge.m_value;
  60. }
  61. inline bool operator<(const grid_entry& a, const grid_entry& b)
  62. {
  63. return a.m_value<b.m_value;
  64. }
  65. using grid_t=std::vector<grid_entry>;
  66. //#define BEZIER_EXPERIMENT
  67. inline double get_shaped_value(double x, int, double p1, double)
  68. {
  69. #ifndef BEZIER_EXPERIMENT
  70. if (p1<0.5)
  71. {
  72. double foo=1.0-(p1*2.0);
  73. return 1.0-pow(1.0-x,1.0+foo*4.0);
  74. }
  75. double foo=(p1-0.5)*2.0;
  76. return pow(x,1.0+foo*4.0);
  77. #else
  78. /*
  79. double pt0=-2.0*p1;
  80. double pt1=2.0*p2;
  81. double pt2=1.0;
  82. return pow(1-x,2.0)*pt0+2*(1-x)*x*pt1+pow(x,2)*pt2;
  83. */
  84. if (p2<=0.5)
  85. {
  86. if (p1<0.5)
  87. {
  88. double foo=1.0-(p1*2.0);
  89. return 1.0-pow(1.0-x,1.0+foo*4.0);
  90. }
  91. double foo=(p1-0.5)*2.0;
  92. return pow(x,1.0+foo*4.0);
  93. } else
  94. {
  95. if (p1<0.5)
  96. {
  97. if (x<0.5)
  98. {
  99. x*=2.0;
  100. p1*=2.0;
  101. return 0.5*pow(x,p1*4.0);
  102. } else
  103. {
  104. x-=0.5;
  105. x*=2.0;
  106. p1*=2.0;
  107. return 1.0-0.5*pow(1.0-x,p1*4.0);
  108. }
  109. } else
  110. {
  111. if (x<0.5)
  112. {
  113. x*=2.0;
  114. p1-=0.5;
  115. p1*=2.0;
  116. return 0.5-0.5*pow(1.0-x,p1*4.0);
  117. } else
  118. {
  119. x-=0.5;
  120. x*=2.0;
  121. p1-=0.5;
  122. p1*=2.0;
  123. return 0.5+0.5*pow(x,p1*4.0);
  124. }
  125. }
  126. }
  127. return x;
  128. #endif
  129. }
  130. using nodes_t=std::vector<envelope_point>;
  131. inline double GetInterpolatedEnvelopeValue(const nodes_t& m_nodes, double atime, double m_defvalue=0.5)
  132. {
  133. int maxnodeind=(int)m_nodes.size()-1;
  134. if (m_nodes.size()==0) return m_defvalue;
  135. if (m_nodes.size()==1) return m_nodes[0].pt_y;
  136. if (atime<=m_nodes[0].pt_x)
  137. return m_nodes[0].pt_y;
  138. if (atime>m_nodes[maxnodeind].pt_x)
  139. return m_nodes[maxnodeind].pt_y;
  140. const envelope_point to_search(atime,0.0);
  141. //to_search.Time=atime;
  142. auto it=std::lower_bound(m_nodes.begin(),m_nodes.end(),to_search,
  143. [](const envelope_point& a, const envelope_point& b)
  144. { return a.pt_x<b.pt_x; } );
  145. if (it==m_nodes.end())
  146. {
  147. return m_defvalue;
  148. }
  149. --it; // lower_bound has returned iterator to point one too far
  150. double t1=it->pt_x;
  151. double v1=it->pt_y;
  152. double p1=it->ShapeParam1;
  153. double p2=it->ShapeParam2;
  154. ++it; // next envelope point
  155. double tdelta=it->pt_x-t1;
  156. if (tdelta<0.00001)
  157. tdelta=0.00001;
  158. double vdelta=it->pt_y-v1;
  159. return v1+vdelta*get_shaped_value(((1.0/tdelta*(atime-t1))),0,p1,p2);
  160. }
  161. inline double interpolate_foo(double atime,double t0, double v0, double t1, double v1, double p1, double p2)
  162. {
  163. double tdelta=t1-t0;
  164. if (tdelta<0.00001)
  165. tdelta=0.00001;
  166. double vdelta=v1-v0;
  167. return v0+vdelta*get_shaped_value(((1.0/tdelta*(atime-t0))),0,p1,p2);
  168. }
  169. class breakpoint_envelope
  170. {
  171. public:
  172. breakpoint_envelope() : m_name("Untitled")
  173. {
  174. m_randbuf.resize(1024);
  175. }
  176. breakpoint_envelope(String name, double minv=0.0, double maxv=1.0)
  177. : m_minvalue(minv), m_maxvalue(maxv), m_name(name)
  178. {
  179. m_defshape=0;
  180. //m_color=RGB(0,255,255);
  181. m_defvalue=0.5;
  182. m_updateopinprogress=false;
  183. m_value_grid={0.0,0.25,0.5,0.75,1.0};
  184. m_randbuf.resize(1024);
  185. }
  186. std::unique_ptr<breakpoint_envelope> duplicate()
  187. {
  188. auto result = std::make_unique<breakpoint_envelope>();
  189. result->m_nodes = m_nodes;
  190. result->m_randbuf = m_randbuf;
  191. result->m_transform_wrap_x = m_transform_wrap_x;
  192. result->m_transform_x_shift = m_transform_x_shift;
  193. return result;
  194. }
  195. void SetName(String Name) { m_name=Name; }
  196. const String& GetName() const { return m_name; }
  197. double GetDefValue() const { return m_defvalue; }
  198. void SetDefValue(double value) { m_defvalue=value; }
  199. int GetDefShape() const { return m_defshape; }
  200. ValueTree saveState(Identifier id) const
  201. {
  202. ValueTree result(id);
  203. for (int i = 0; i < m_nodes.size(); ++i)
  204. {
  205. ValueTree pt_tree("pt");
  206. storeToTreeProperties(pt_tree, nullptr,
  207. "x", m_nodes[i].pt_x, "y", m_nodes[i].pt_y, "p1", m_nodes[i].ShapeParam1, "p2", m_nodes[i].ShapeParam2);
  208. result.addChild(pt_tree, -1, nullptr);
  209. }
  210. result.setProperty("wrapxtransform", m_transform_wrap_x, nullptr);
  211. result.setProperty("yrandlerp", m_transform_y_random_linear_interpolation, nullptr);
  212. return result;
  213. }
  214. void restoreState(ValueTree state)
  215. {
  216. if (state.isValid()==false)
  217. return;
  218. m_transform_wrap_x = state.getProperty("wrapxtransform", false);
  219. m_transform_y_random_linear_interpolation = state.getProperty("yrandlerp", false);
  220. int numnodes = state.getNumChildren();
  221. if (numnodes > 0)
  222. {
  223. m_nodes.clear();
  224. for (int i = 0; i < numnodes; ++i)
  225. {
  226. ValueTree pt_tree = state.getChild(i);
  227. double x, y = 0.0;
  228. double p1, p2 = 0.5;
  229. getFromTreeProperties(pt_tree, "x", x, "y", y, "p1", p1, "p2", p2);
  230. m_nodes.emplace_back(x, y, p1,p2);
  231. }
  232. SortNodes();
  233. }
  234. }
  235. MD5 getHash() const
  236. {
  237. MemoryBlock mb;
  238. for (int i = 0; i < m_nodes.size(); ++i)
  239. {
  240. appendToMemoryBlock(mb, m_nodes[i].pt_x);
  241. appendToMemoryBlock(mb, m_nodes[i].pt_y);
  242. appendToMemoryBlock(mb, m_nodes[i].ShapeParam1);
  243. appendToMemoryBlock(mb, m_nodes[i].ShapeParam2);
  244. }
  245. return MD5(mb);
  246. }
  247. int GetNumPoints() const { return (int)m_nodes.size(); }
  248. void SetDefShape(int value) { m_defshape=value; }
  249. double getNodeLeftBound(int index, double margin=0.01) const noexcept
  250. {
  251. if (m_nodes.size() == 0)
  252. return 0.0;
  253. if (index == 0)
  254. return 0.0;
  255. return m_nodes[index - 1].pt_x + margin;
  256. }
  257. double getNodeRightBound(int index, double margin = 0.01) const noexcept
  258. {
  259. if (m_nodes.size() == 0)
  260. return 1.0;
  261. if (index == m_nodes.size()-1)
  262. return 1.0;
  263. return m_nodes[index + 1].pt_x - margin;
  264. }
  265. const std::vector<envelope_point>& get_all_nodes() const { return m_nodes; }
  266. void set_all_nodes(nodes_t nds) { m_nodes=std::move(nds); }
  267. void set_reset_nodes(const std::vector<envelope_point>& nodes, bool convertvalues=false)
  268. {
  269. if (convertvalues==false)
  270. m_reset_nodes=nodes;
  271. else
  272. {
  273. if (scaled_to_normalized_func)
  274. {
  275. m_nodes.clear();
  276. for (int i=0;i<nodes.size();++i)
  277. {
  278. envelope_point node=nodes[i];
  279. node.pt_y=scaled_to_normalized_func(node.pt_y);
  280. m_nodes.push_back(node);
  281. }
  282. }
  283. }
  284. }
  285. void ResetEnvelope()
  286. {
  287. m_nodes=m_reset_nodes;
  288. m_playoffset=0.0;
  289. }
  290. Colour GetColor() const
  291. {
  292. return m_colour;
  293. }
  294. void SetColor(Colour colour)
  295. {
  296. m_colour=colour;
  297. }
  298. void BeginUpdate() // used for doing larger update operations, so can avoid needlessly sorting etc
  299. {
  300. m_updateopinprogress=true;
  301. }
  302. void EndUpdate()
  303. {
  304. m_updateopinprogress=false;
  305. SortNodes();
  306. }
  307. void AddNode(envelope_point newnode)
  308. {
  309. m_nodes.push_back(newnode);
  310. if (!m_updateopinprogress)
  311. SortNodes();
  312. }
  313. void ClearAllNodes()
  314. {
  315. m_nodes.clear();
  316. }
  317. void DeleteNode(int indx)
  318. {
  319. if (indx<0 || indx>m_nodes.size()-1)
  320. return;
  321. m_nodes.erase(m_nodes.begin()+indx);
  322. }
  323. void delete_nodes_in_time_range(double t0, double t1)
  324. {
  325. m_nodes.erase(std::remove_if(std::begin(m_nodes),
  326. std::end(m_nodes),
  327. [t0,t1](const envelope_point& a) { return a.pt_x>=t0 && a.pt_x<=t1; } ),
  328. std::end(m_nodes) );
  329. }
  330. template<typename F>
  331. void removePointsConditionally(F predicate)
  332. {
  333. m_nodes.erase(std::remove_if(m_nodes.begin(), m_nodes.end(), predicate), m_nodes.end());
  334. }
  335. envelope_point& GetNodeAtIndex(int indx)
  336. {
  337. if (m_nodes.size()==0)
  338. {
  339. throw(std::length_error("Empty envelope accessed"));
  340. }
  341. if (indx<0)
  342. indx=0;
  343. if (indx>=(int)m_nodes.size())
  344. indx=(int)m_nodes.size()-1;
  345. return m_nodes[indx];
  346. }
  347. const envelope_point& GetNodeAtIndex(int indx) const
  348. {
  349. if (m_nodes.size()==0)
  350. {
  351. throw(std::length_error("Empty envelope accessed"));
  352. }
  353. if (indx<0)
  354. indx=0;
  355. if (indx>=(int)m_nodes.size())
  356. indx=(int)m_nodes.size()-1;
  357. return m_nodes[indx];
  358. }
  359. void SetNodeStatus(int indx, int nstatus)
  360. {
  361. int i=indx;
  362. if (indx<0) i=0;
  363. if (indx>(int)m_nodes.size()-1) i=(int)m_nodes.size()-1;
  364. m_nodes[i].Status=nstatus;
  365. }
  366. void SetNode(int indx, envelope_point anode)
  367. {
  368. int i=indx;
  369. if (indx<0) i=0;
  370. if (indx>(int)m_nodes.size()-1) i=(int)m_nodes.size()-1;
  371. m_nodes[i]=anode;
  372. }
  373. void SetNodeTimeValue(int indx,bool setTime,bool setValue,double atime,double avalue)
  374. {
  375. int i=indx;
  376. if (indx<0) i=0;
  377. if (indx>(int)m_nodes.size()-1) i=(int)m_nodes.size()-1;
  378. if (setTime) m_nodes[i].pt_x=atime;
  379. if (setValue) m_nodes[i].pt_y=avalue;
  380. }
  381. double GetInterpolatedEnvelopeValue(double atime) const
  382. {
  383. double t0=0.0;
  384. double t1=0.0;
  385. double v0=0.0;
  386. double v1=0.0;
  387. double p1=0.0;
  388. double p2=0.0;
  389. const int maxnodeind=(int)m_nodes.size()-1;
  390. if (m_nodes.size()==0)
  391. return m_defvalue;
  392. if (m_nodes.size()==1)
  393. return m_nodes[0].pt_y;
  394. if (atime<=m_nodes[0].pt_x)
  395. {
  396. #ifdef INTERPOLATING_ENVELOPE_BORDERS
  397. t1=m_nodes[0].Time;
  398. t0=0.0-(1.0-m_nodes[maxnodeind].Time);
  399. v0=m_nodes[maxnodeind].Value;
  400. p1=m_nodes[maxnodeind].ShapeParam1;
  401. p2=m_nodes[maxnodeind].ShapeParam2;
  402. v1=m_nodes[0].Value;
  403. return interpolate_foo(atime,t0,v0,t1,v1,p1,p2);
  404. #else
  405. return m_nodes[0].pt_y;
  406. #endif
  407. }
  408. if (atime>m_nodes[maxnodeind].pt_x)
  409. {
  410. #ifdef INTERPOLATING_ENVELOPE_BORDERS
  411. t0=m_nodes[maxnodeind].Time;
  412. t1=1.0+(m_nodes[0].Time);
  413. v0=m_nodes[maxnodeind].Value;
  414. v1=m_nodes[0].Value;
  415. p1=m_nodes[maxnodeind].ShapeParam1;
  416. p2=m_nodes[maxnodeind].ShapeParam2;
  417. return interpolate_foo(atime,t0,v0,t1,v1,p1,p2);
  418. #else
  419. return m_nodes.back().pt_y;
  420. #endif
  421. }
  422. const envelope_point to_search(atime,0.0);
  423. //to_search.Time=atime;
  424. auto it=std::lower_bound(m_nodes.begin(),m_nodes.end(),to_search,
  425. [](const envelope_point& a, const envelope_point& b)
  426. { return a.pt_x<b.pt_x; } );
  427. if (it==m_nodes.end())
  428. {
  429. return m_defvalue;
  430. }
  431. --it; // lower_bound has returned iterator to point one too far
  432. t0=it->pt_x;
  433. v0=it->pt_y;
  434. p1=it->ShapeParam1;
  435. p2=it->ShapeParam2;
  436. ++it; // next envelope point
  437. t1=it->pt_x;
  438. v1=it->pt_y;
  439. return interpolate_foo(atime,t0,v0,t1,v1,p1,p2);
  440. }
  441. bool IsSorted() const
  442. {
  443. return std::is_sorted(m_nodes.begin(), m_nodes.end(), []
  444. (const envelope_point& lhs, const envelope_point& rhs)
  445. {
  446. return lhs.pt_x<rhs.pt_x;
  447. });
  448. }
  449. void SortNodes()
  450. {
  451. stable_sort(m_nodes.begin(),m_nodes.end(),
  452. [](const envelope_point& a, const envelope_point& b){ return a.pt_x<b.pt_x; } );
  453. }
  454. double minimum_value() const { return m_minvalue; }
  455. double maximum_value() const { return m_maxvalue; }
  456. void set_minimum_value(double v) { m_minvalue=v; }
  457. void set_maximum_value(double v) { m_maxvalue=v; }
  458. std::function<double(double)> normalized_to_scaled_func;
  459. std::function<double(double)> scaled_to_normalized_func;
  460. void beginRelativeTransformation()
  461. {
  462. m_old_nodes=m_nodes;
  463. }
  464. void endRelativeTransformation()
  465. {
  466. m_old_nodes.clear();
  467. }
  468. nodes_t& getRelativeTransformBaseNodes()
  469. {
  470. return m_old_nodes;
  471. }
  472. template<typename F>
  473. inline void performRelativeTransformation(F&& f)
  474. {
  475. for (int i = 0; i < m_old_nodes.size(); ++i)
  476. {
  477. envelope_point node = m_old_nodes[i];
  478. f(i, node);
  479. node.ShapeParam1 = jlimit(0.0, 1.0, node.ShapeParam1);
  480. m_nodes[i] = node;
  481. }
  482. }
  483. void adjustEnvelopeSegmentValues(int index, double amount)
  484. {
  485. if (index >= m_old_nodes.size())
  486. {
  487. m_nodes.back().pt_y = jlimit(0.0,1.0,m_old_nodes.back().pt_y+amount);
  488. return;
  489. }
  490. m_nodes[index].pt_y = jlimit(0.0, 1.0, m_old_nodes[index].pt_y + amount);
  491. m_nodes[index+1].pt_y = jlimit(0.0, 1.0, m_old_nodes[index+1].pt_y + amount);
  492. }
  493. const nodes_t& repeater_nodes() const
  494. {
  495. return m_repeater_nodes;
  496. }
  497. void store_repeater_nodes()
  498. {
  499. m_repeater_nodes.clear();
  500. for (int i=0;i<m_nodes.size();++i)
  501. {
  502. if (m_nodes[i].pt_x>=m_playoffset && m_nodes[i].pt_x<=m_playoffset+1.0)
  503. {
  504. envelope_point temp=m_nodes[i];
  505. temp.pt_x-=m_playoffset;
  506. m_repeater_nodes.push_back(temp);
  507. }
  508. }
  509. }
  510. double get_play_offset() const { return m_playoffset; }
  511. //void set_play_offset(double x) { m_playoffset=bound_value(m_mintime,x,m_maxtime); }
  512. //time_range get_play_offset_range() const { return std::make_pair(m_mintime,m_maxtime); }
  513. const grid_t& get_value_grid() const { return m_value_grid; }
  514. void set_value_grid(grid_t g) { m_value_grid=std::move(g); }
  515. template<typename F>
  516. void manipulate(F&& f)
  517. {
  518. nodes_t backup=m_nodes;
  519. if (f(backup)==true)
  520. {
  521. std::swap(backup,m_nodes);
  522. SortNodes();
  523. }
  524. }
  525. template<typename F0, typename F1>
  526. inline void resamplePointToLinearSegments(int point_index,double /*xmin*/, double /*xmax*/, double /*ymin*/, double /*ymax*/,
  527. F0&& handlesegmentfunc, F1&& numsegmentsfunc)
  528. {
  529. if (m_nodes.size() == 0)
  530. return;
  531. envelope_point pt0 = GetNodeAtIndex(point_index);
  532. envelope_point pt1 = GetNodeAtIndex(point_index+1);
  533. double xdiff = pt1.pt_x - pt0.pt_x;
  534. if (xdiff > 0.0)
  535. {
  536. int numsegments = numsegmentsfunc(xdiff);
  537. for (int j=0;j<numsegments;++j)
  538. {
  539. double cb_x0 = pt0.pt_x + xdiff / (numsegments)*j;
  540. double cb_y0 = GetInterpolatedEnvelopeValue(cb_x0);
  541. double cb_x1 = pt0.pt_x + xdiff / (numsegments)*(j+1);
  542. double cb_y1 = GetInterpolatedEnvelopeValue(cb_x1);
  543. handlesegmentfunc(cb_x0, cb_y0,cb_x1,cb_y1);
  544. }
  545. }
  546. }
  547. double m_transform_x_shift = 0.0;
  548. double m_transform_y_shift = 0.0;
  549. double m_transform_y_scale = 1.0;
  550. double m_transform_y_sinus = 0.0;
  551. double m_transform_y_sinus_freq = 8.0;
  552. double m_transform_y_tilt = 0.0;
  553. double m_transform_y_random_amount = 0.0;
  554. double m_transform_y_random_rate = 2.0;
  555. bool m_transform_y_random_linear_interpolation = false;
  556. int m_transform_y_random_bands = 32;
  557. bool m_transform_wrap_x = false;
  558. double m_min_pt_value = 0.0;
  559. double m_max_pt_value = 0.0;
  560. inline double getTransformedValue(double x)
  561. {
  562. if (isTransformed() == false)
  563. return GetInterpolatedEnvelopeValue(x);
  564. double temp = x-m_transform_x_shift;
  565. if (m_transform_wrap_x == true)
  566. {
  567. temp = fmod(x - m_transform_x_shift, 1.0);
  568. if (temp < 0.0)
  569. temp += 1.0;
  570. }
  571. double v = GetInterpolatedEnvelopeValue(temp);
  572. double center_v = m_minvalue + (m_maxvalue - m_minvalue) / 2.0;
  573. double diff = center_v - v;
  574. double scaled = center_v - m_transform_y_scale * diff;
  575. double shifted = scaled + m_transform_y_shift;
  576. if (m_transform_y_sinus>0.0)
  577. shifted+=m_transform_y_sinus * sin(2*c_PI*(x-m_transform_x_shift)*m_transform_y_sinus_freq);
  578. double tiltline = m_transform_y_tilt-(2.0*m_transform_y_tilt*x);
  579. double tilted = shifted+tiltline;
  580. if (m_transform_y_random_amount > 0.0)
  581. {
  582. if (m_transform_y_random_linear_interpolation == false)
  583. {
  584. int tableindex = jlimit<int>(0, m_randbuf.size() - 1, floor(x * (m_transform_y_random_bands)));
  585. double randamt = jmap(m_randbuf[tableindex], 0.0, 1.0, -m_transform_y_random_amount, m_transform_y_random_amount);
  586. tilted += randamt;
  587. }
  588. else
  589. {
  590. double fracindex = x * m_transform_y_random_bands;
  591. int tableindex0 = jlimit<int>(0, m_randbuf.size() - 1, floor(fracindex));
  592. int tableindex1 = tableindex0 + 1;
  593. double y0 = m_randbuf[tableindex0];
  594. double y1 = m_randbuf[tableindex1];
  595. double interpolated = y0 + (y1 - y0)*fractpart(fracindex);
  596. double randamt = jmap(interpolated, 0.0, 1.0, -m_transform_y_random_amount, m_transform_y_random_amount);
  597. tilted += randamt;
  598. }
  599. }
  600. return jlimit(0.0,1.0,tilted);
  601. }
  602. bool isTransformed() const
  603. {
  604. return m_transform_x_shift != 0.0 || m_transform_y_shift != 0.0
  605. || m_transform_y_scale!=1.0 || m_transform_y_sinus!=0.0 || m_transform_y_tilt!=0.0
  606. || m_transform_y_random_amount>0.0;
  607. }
  608. void updateMinMaxValues()
  609. {
  610. double minv = 1.0;
  611. double maxv = 0.0;
  612. for (auto& e : m_nodes)
  613. {
  614. minv = std::min(minv, e.pt_y);
  615. maxv = std::max(maxv, e.pt_y);
  616. }
  617. m_minvalue = minv;
  618. m_maxvalue = maxv;
  619. }
  620. void updateRandomState()
  621. {
  622. //Logger::writeToLog("updating envelope random state");
  623. std::uniform_real_distribution<double> dist(0.0,1.0);
  624. for (int i = 0; i < m_transform_y_random_bands+1; ++i)
  625. m_randbuf[i] = dist(m_randgen);
  626. }
  627. private:
  628. nodes_t m_nodes;
  629. double m_playoffset=0.0;
  630. double m_minvalue=0.0;
  631. double m_maxvalue=1.0;
  632. double m_mintime=-2.0;
  633. double m_maxtime=2.0;
  634. int m_defshape;
  635. Colour m_colour;
  636. String m_name;
  637. bool m_updateopinprogress;
  638. double m_defvalue; // "neutral" value to be used for resets and stuff
  639. nodes_t m_reset_nodes;
  640. nodes_t m_old_nodes;
  641. nodes_t m_repeater_nodes;
  642. grid_t m_value_grid;
  643. std::mt19937 m_randgen;
  644. std::vector<double> m_randbuf;
  645. JUCE_LEAK_DETECTOR(breakpoint_envelope)
  646. };
  647. template<typename F, typename... Args>
  648. inline double derivative(const F& f, double x, const Args&... func_args)
  649. {
  650. const double epsilon = std::numeric_limits<double>::epsilon() * 100;
  651. //const double epsilon=0.000001;
  652. return (f(x + epsilon, func_args...) - f(x, func_args...)) / epsilon;
  653. }
  654. using shared_envelope = std::shared_ptr<breakpoint_envelope>;