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.

683 lines
20KB

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