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.

593 lines
17KB

  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 "../JuceLibraryCode/JuceHeader.h"
  19. #include "PS_Source/globals.h"
  20. struct envelope_node
  21. {
  22. envelope_node()
  23. : Time(0.0), Value(0.0), ShapeParam1(0.5), ShapeParam2(0.5) {}
  24. envelope_node(double x, double y, double p1=0.5, double p2=0.5)
  25. : Time(x), Value(y),ShapeParam1(p1),ShapeParam2(p2) {}
  26. double Time;
  27. double Value;
  28. int Shape = 0;
  29. double ShapeParam1;
  30. double ShapeParam2;
  31. int Status = 0;
  32. size_t get_hash() const
  33. {
  34. size_t seed = 0;
  35. seed ^= std::hash<double>()(Time) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
  36. seed ^= std::hash<double>()(Value) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
  37. seed ^= std::hash<int>()(Shape) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
  38. seed ^= std::hash<double>()(ShapeParam1) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
  39. seed ^= std::hash<double>()(ShapeParam2) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
  40. return seed;
  41. }
  42. };
  43. inline bool operator<(const envelope_node& a, const envelope_node& b)
  44. {
  45. return a.Time<b.Time;
  46. }
  47. template<typename T>
  48. inline void appendToMemoryBlock(MemoryBlock& mb, T x)
  49. {
  50. T temp(x);
  51. mb.append((void*)&temp, sizeof(temp));
  52. }
  53. struct grid_entry
  54. {
  55. grid_entry(double v) : m_value(v) {}
  56. double m_value=0.0;
  57. bool m_foo=false;
  58. };
  59. inline double grid_value(const grid_entry& ge)
  60. {
  61. return ge.m_value;
  62. }
  63. inline bool operator<(const grid_entry& a, const grid_entry& b)
  64. {
  65. return a.m_value<b.m_value;
  66. }
  67. using grid_t=std::vector<grid_entry>;
  68. //#define BEZIER_EXPERIMENT
  69. inline double get_shaped_value(double x, int, double p1, double)
  70. {
  71. #ifndef BEZIER_EXPERIMENT
  72. if (p1<0.5)
  73. {
  74. double foo=1.0-(p1*2.0);
  75. return 1.0-pow(1.0-x,1.0+foo*4.0);
  76. }
  77. double foo=(p1-0.5)*2.0;
  78. return pow(x,1.0+foo*4.0);
  79. #else
  80. /*
  81. double pt0=-2.0*p1;
  82. double pt1=2.0*p2;
  83. double pt2=1.0;
  84. return pow(1-x,2.0)*pt0+2*(1-x)*x*pt1+pow(x,2)*pt2;
  85. */
  86. if (p2<=0.5)
  87. {
  88. if (p1<0.5)
  89. {
  90. double foo=1.0-(p1*2.0);
  91. return 1.0-pow(1.0-x,1.0+foo*4.0);
  92. }
  93. double foo=(p1-0.5)*2.0;
  94. return pow(x,1.0+foo*4.0);
  95. } else
  96. {
  97. if (p1<0.5)
  98. {
  99. if (x<0.5)
  100. {
  101. x*=2.0;
  102. p1*=2.0;
  103. return 0.5*pow(x,p1*4.0);
  104. } else
  105. {
  106. x-=0.5;
  107. x*=2.0;
  108. p1*=2.0;
  109. return 1.0-0.5*pow(1.0-x,p1*4.0);
  110. }
  111. } else
  112. {
  113. if (x<0.5)
  114. {
  115. x*=2.0;
  116. p1-=0.5;
  117. p1*=2.0;
  118. return 0.5-0.5*pow(1.0-x,p1*4.0);
  119. } else
  120. {
  121. x-=0.5;
  122. x*=2.0;
  123. p1-=0.5;
  124. p1*=2.0;
  125. return 0.5+0.5*pow(x,p1*4.0);
  126. }
  127. }
  128. }
  129. return x;
  130. #endif
  131. }
  132. using nodes_t=std::vector<envelope_node>;
  133. inline double GetInterpolatedNodeValue(const nodes_t& m_nodes, double atime, double m_defvalue=0.5)
  134. {
  135. int maxnodeind=(int)m_nodes.size()-1;
  136. if (m_nodes.size()==0) return m_defvalue;
  137. if (m_nodes.size()==1) return m_nodes[0].Value;
  138. if (atime<=m_nodes[0].Time)
  139. return m_nodes[0].Value;
  140. if (atime>m_nodes[maxnodeind].Time)
  141. return m_nodes[maxnodeind].Value;
  142. const envelope_node to_search(atime,0.0);
  143. //to_search.Time=atime;
  144. auto it=std::lower_bound(m_nodes.begin(),m_nodes.end(),to_search,
  145. [](const envelope_node& a, const envelope_node& b)
  146. { return a.Time<b.Time; } );
  147. if (it==m_nodes.end())
  148. {
  149. return m_defvalue;
  150. }
  151. --it; // lower_bound has returned iterator to point one too far
  152. double t1=it->Time;
  153. double v1=it->Value;
  154. double p1=it->ShapeParam1;
  155. double p2=it->ShapeParam2;
  156. ++it; // next envelope point
  157. double tdelta=it->Time-t1;
  158. if (tdelta<0.00001)
  159. tdelta=0.00001;
  160. double vdelta=it->Value-v1;
  161. return v1+vdelta*get_shaped_value(((1.0/tdelta*(atime-t1))),0,p1,p2);
  162. }
  163. inline double interpolate_foo(double atime,double t0, double v0, double t1, double v1, double p1, double p2)
  164. {
  165. double tdelta=t1-t0;
  166. if (tdelta<0.00001)
  167. tdelta=0.00001;
  168. double vdelta=v1-v0;
  169. return v0+vdelta*get_shaped_value(((1.0/tdelta*(atime-t0))),0,p1,p2);
  170. }
  171. class breakpoint_envelope
  172. {
  173. public:
  174. breakpoint_envelope() : m_name("Untitled") {}
  175. breakpoint_envelope(String name, double minv=0.0, double maxv=1.0)
  176. : m_minvalue(minv), m_maxvalue(maxv), m_name(name)
  177. {
  178. m_defshape=0;
  179. //m_color=RGB(0,255,255);
  180. m_defvalue=0.5;
  181. m_updateopinprogress=false;
  182. m_value_grid={0.0,0.25,0.5,0.75,1.0};
  183. }
  184. void SetName(String Name) { m_name=Name; }
  185. const String& GetName() const { return m_name; }
  186. double GetDefValue() { return m_defvalue; }
  187. void SetDefValue(double value) { m_defvalue=value; }
  188. int GetDefShape() { return m_defshape; }
  189. ValueTree saveState(Identifier id)
  190. {
  191. ValueTree result(id);
  192. for (int i = 0; i < m_nodes.size(); ++i)
  193. {
  194. ValueTree pt_tree("pt");
  195. storeToTreeProperties(pt_tree, nullptr,
  196. "x", m_nodes[i].Time, "y", m_nodes[i].Value, "p1", m_nodes[i].ShapeParam1, "p2", m_nodes[i].ShapeParam2);
  197. result.addChild(pt_tree, -1, nullptr);
  198. }
  199. return result;
  200. }
  201. void restoreState(ValueTree state)
  202. {
  203. if (state.isValid()==false)
  204. return;
  205. int numnodes = state.getNumChildren();
  206. if (numnodes > 0)
  207. {
  208. m_nodes.clear();
  209. for (int i = 0; i < numnodes; ++i)
  210. {
  211. ValueTree pt_tree = state.getChild(i);
  212. double x, y = 0.0;
  213. double p1, p2 = 0.5;
  214. getFromTreeProperties(pt_tree, "x", x, "y", y, "p1", p1, "p2", p2);
  215. m_nodes.emplace_back(x, y, p1,p2);
  216. }
  217. SortNodes();
  218. }
  219. }
  220. MD5 getHash() const
  221. {
  222. MemoryBlock mb;
  223. for (int i = 0; i < m_nodes.size(); ++i)
  224. {
  225. appendToMemoryBlock(mb, m_nodes[i].Time);
  226. appendToMemoryBlock(mb, m_nodes[i].Value);
  227. appendToMemoryBlock(mb, m_nodes[i].ShapeParam1);
  228. appendToMemoryBlock(mb, m_nodes[i].ShapeParam2);
  229. }
  230. return MD5(mb);
  231. }
  232. int GetNumNodes() const { return (int)m_nodes.size(); }
  233. void SetDefShape(int value) { m_defshape=value; }
  234. double getNodeLeftBound(int index, double margin=0.01) const noexcept
  235. {
  236. if (m_nodes.size() == 0)
  237. return 0.0;
  238. if (index == 0)
  239. return 0.0;
  240. return m_nodes[index - 1].Time + margin;
  241. }
  242. double getNodeRightBound(int index, double margin = 0.01) const noexcept
  243. {
  244. if (m_nodes.size() == 0)
  245. return 1.0;
  246. if (index == m_nodes.size()-1)
  247. return 1.0;
  248. return m_nodes[index + 1].Time - margin;
  249. }
  250. const std::vector<envelope_node>& get_all_nodes() const { return m_nodes; }
  251. void set_all_nodes(nodes_t nds) { m_nodes=std::move(nds); }
  252. void set_reset_nodes(const std::vector<envelope_node>& nodes, bool convertvalues=false)
  253. {
  254. if (convertvalues==false)
  255. m_reset_nodes=nodes;
  256. else
  257. {
  258. if (scaled_to_normalized_func)
  259. {
  260. m_nodes.clear();
  261. for (int i=0;i<nodes.size();++i)
  262. {
  263. envelope_node node=nodes[i];
  264. node.Value=scaled_to_normalized_func(node.Value);
  265. m_nodes.push_back(node);
  266. }
  267. }
  268. }
  269. }
  270. void ResetEnvelope()
  271. {
  272. m_nodes=m_reset_nodes;
  273. m_playoffset=0.0;
  274. }
  275. Colour GetColor()
  276. {
  277. return m_colour;
  278. }
  279. void SetColor(Colour colour)
  280. {
  281. m_colour=colour;
  282. }
  283. void BeginUpdate() // used for doing larger update operations, so can avoid needlessly sorting etc
  284. {
  285. m_updateopinprogress=true;
  286. }
  287. void EndUpdate()
  288. {
  289. m_updateopinprogress=false;
  290. SortNodes();
  291. }
  292. void AddNode(envelope_node newnode)
  293. {
  294. m_nodes.push_back(newnode);
  295. if (!m_updateopinprogress)
  296. SortNodes();
  297. }
  298. void ClearAllNodes()
  299. {
  300. m_nodes.clear();
  301. }
  302. void DeleteNode(int indx)
  303. {
  304. if (indx<0 || indx>m_nodes.size()-1)
  305. return;
  306. m_nodes.erase(m_nodes.begin()+indx);
  307. }
  308. void delete_nodes_in_time_range(double t0, double t1)
  309. {
  310. m_nodes.erase(std::remove_if(std::begin(m_nodes),
  311. std::end(m_nodes),
  312. [t0,t1](const envelope_node& a) { return a.Time>=t0 && a.Time<=t1; } ),
  313. std::end(m_nodes) );
  314. }
  315. template<typename F>
  316. void removePointsConditionally(F predicate)
  317. {
  318. m_nodes.erase(std::remove_if(m_nodes.begin(), m_nodes.end(), predicate), m_nodes.end());
  319. }
  320. envelope_node& GetNodeAtIndex(int indx)
  321. {
  322. if (m_nodes.size()==0)
  323. {
  324. throw(std::length_error("Empty envelope accessed"));
  325. }
  326. if (indx<0)
  327. indx=0;
  328. if (indx>=(int)m_nodes.size())
  329. indx=(int)m_nodes.size()-1;
  330. return m_nodes[indx];
  331. }
  332. const envelope_node& GetNodeAtIndex(int indx) const
  333. {
  334. if (m_nodes.size()==0)
  335. {
  336. throw(std::length_error("Empty envelope accessed"));
  337. }
  338. if (indx<0)
  339. indx=0;
  340. if (indx>=(int)m_nodes.size())
  341. indx=(int)m_nodes.size()-1;
  342. return m_nodes[indx];
  343. }
  344. void SetNodeStatus(int indx, int nstatus)
  345. {
  346. int i=indx;
  347. if (indx<0) i=0;
  348. if (indx>(int)m_nodes.size()-1) i=(int)m_nodes.size()-1;
  349. m_nodes[i].Status=nstatus;
  350. }
  351. void SetNode(int indx, envelope_node anode)
  352. {
  353. int i=indx;
  354. if (indx<0) i=0;
  355. if (indx>(int)m_nodes.size()-1) i=(int)m_nodes.size()-1;
  356. m_nodes[i]=anode;
  357. }
  358. void SetNodeTimeValue(int indx,bool setTime,bool setValue,double atime,double avalue)
  359. {
  360. int i=indx;
  361. if (indx<0) i=0;
  362. if (indx>(int)m_nodes.size()-1) i=(int)m_nodes.size()-1;
  363. if (setTime) m_nodes[i].Time=atime;
  364. if (setValue) m_nodes[i].Value=avalue;
  365. }
  366. double GetInterpolatedNodeValue(double atime)
  367. {
  368. double t0=0.0;
  369. double t1=0.0;
  370. double v0=0.0;
  371. double v1=0.0;
  372. double p1=0.0;
  373. double p2=0.0;
  374. const int maxnodeind=(int)m_nodes.size()-1;
  375. if (m_nodes.size()==0)
  376. return m_defvalue;
  377. if (m_nodes.size()==1)
  378. return m_nodes[0].Value;
  379. if (atime<=m_nodes[0].Time)
  380. {
  381. #ifdef INTERPOLATING_ENVELOPE_BORDERS
  382. t1=m_nodes[0].Time;
  383. t0=0.0-(1.0-m_nodes[maxnodeind].Time);
  384. v0=m_nodes[maxnodeind].Value;
  385. p1=m_nodes[maxnodeind].ShapeParam1;
  386. p2=m_nodes[maxnodeind].ShapeParam2;
  387. v1=m_nodes[0].Value;
  388. return interpolate_foo(atime,t0,v0,t1,v1,p1,p2);
  389. #else
  390. return m_nodes[0].Value;
  391. #endif
  392. }
  393. if (atime>m_nodes[maxnodeind].Time)
  394. {
  395. #ifdef INTERPOLATING_ENVELOPE_BORDERS
  396. t0=m_nodes[maxnodeind].Time;
  397. t1=1.0+(m_nodes[0].Time);
  398. v0=m_nodes[maxnodeind].Value;
  399. v1=m_nodes[0].Value;
  400. p1=m_nodes[maxnodeind].ShapeParam1;
  401. p2=m_nodes[maxnodeind].ShapeParam2;
  402. return interpolate_foo(atime,t0,v0,t1,v1,p1,p2);
  403. #else
  404. return m_nodes.back().Value;
  405. #endif
  406. }
  407. const envelope_node to_search(atime,0.0);
  408. //to_search.Time=atime;
  409. auto it=std::lower_bound(m_nodes.begin(),m_nodes.end(),to_search,
  410. [](const envelope_node& a, const envelope_node& b)
  411. { return a.Time<b.Time; } );
  412. if (it==m_nodes.end())
  413. {
  414. return m_defvalue;
  415. }
  416. --it; // lower_bound has returned iterator to point one too far
  417. t0=it->Time;
  418. v0=it->Value;
  419. p1=it->ShapeParam1;
  420. p2=it->ShapeParam2;
  421. ++it; // next envelope point
  422. t1=it->Time;
  423. v1=it->Value;
  424. return interpolate_foo(atime,t0,v0,t1,v1,p1,p2);
  425. }
  426. bool IsSorted() const
  427. {
  428. return std::is_sorted(m_nodes.begin(), m_nodes.end(), []
  429. (const envelope_node& lhs, const envelope_node& rhs)
  430. {
  431. return lhs.Time<rhs.Time;
  432. });
  433. }
  434. void SortNodes()
  435. {
  436. stable_sort(m_nodes.begin(),m_nodes.end(),
  437. [](const envelope_node& a, const envelope_node& b){ return a.Time<b.Time; } );
  438. }
  439. double minimum_value() const { return m_minvalue; }
  440. double maximum_value() const { return m_maxvalue; }
  441. void set_minimum_value(double v) { m_minvalue=v; }
  442. void set_maximum_value(double v) { m_maxvalue=v; }
  443. std::function<double(double)> normalized_to_scaled_func;
  444. std::function<double(double)> scaled_to_normalized_func;
  445. void beginRelativeTransformation()
  446. {
  447. m_old_nodes=m_nodes;
  448. }
  449. void endRelativeTransformation()
  450. {
  451. m_old_nodes.clear();
  452. }
  453. nodes_t& getRelativeTransformBaseNodes()
  454. {
  455. return m_old_nodes;
  456. }
  457. template<typename F>
  458. inline void performRelativeTransformation(F&& f)
  459. {
  460. for (int i = 0; i < m_old_nodes.size(); ++i)
  461. {
  462. envelope_node node = m_old_nodes[i];
  463. f(i, node);
  464. node.ShapeParam1 = jlimit(0.0, 1.0, node.ShapeParam1);
  465. m_nodes[i] = node;
  466. }
  467. }
  468. void adjustEnvelopeSegmentValues(int index, double amount)
  469. {
  470. if (index >= m_old_nodes.size())
  471. {
  472. m_nodes.back().Value = jlimit(0.0,1.0,m_old_nodes.back().Value+amount);
  473. return;
  474. }
  475. m_nodes[index].Value = jlimit(0.0, 1.0, m_old_nodes[index].Value + amount);
  476. m_nodes[index+1].Value = jlimit(0.0, 1.0, m_old_nodes[index+1].Value + amount);
  477. }
  478. const nodes_t& repeater_nodes() const
  479. {
  480. return m_repeater_nodes;
  481. }
  482. void store_repeater_nodes()
  483. {
  484. m_repeater_nodes.clear();
  485. for (int i=0;i<m_nodes.size();++i)
  486. {
  487. if (m_nodes[i].Time>=m_playoffset && m_nodes[i].Time<=m_playoffset+1.0)
  488. {
  489. envelope_node temp=m_nodes[i];
  490. temp.Time-=m_playoffset;
  491. m_repeater_nodes.push_back(temp);
  492. }
  493. }
  494. }
  495. double get_play_offset() const { return m_playoffset; }
  496. //void set_play_offset(double x) { m_playoffset=bound_value(m_mintime,x,m_maxtime); }
  497. //time_range get_play_offset_range() const { return std::make_pair(m_mintime,m_maxtime); }
  498. const grid_t& get_value_grid() const { return m_value_grid; }
  499. void set_value_grid(grid_t g) { m_value_grid=std::move(g); }
  500. template<typename F>
  501. void manipulate(F&& f)
  502. {
  503. nodes_t backup=m_nodes;
  504. if (f(backup)==true)
  505. {
  506. std::swap(backup,m_nodes);
  507. SortNodes();
  508. }
  509. }
  510. template<typename F0, typename F1>
  511. inline void resamplePointToLinearSegments(int point_index,double /*xmin*/, double /*xmax*/, double /*ymin*/, double /*ymax*/,
  512. F0&& handlesegmentfunc, F1&& numsegmentsfunc)
  513. {
  514. if (m_nodes.size() == 0)
  515. return;
  516. envelope_node pt0 = GetNodeAtIndex(point_index);
  517. envelope_node pt1 = GetNodeAtIndex(point_index+1);
  518. double xdiff = pt1.Time - pt0.Time;
  519. if (xdiff > 0.0)
  520. {
  521. int numsegments = numsegmentsfunc(xdiff);
  522. for (int j=0;j<numsegments;++j)
  523. {
  524. double cb_x0 = pt0.Time + xdiff / (numsegments)*j;
  525. double cb_y0 = GetInterpolatedNodeValue(cb_x0);
  526. double cb_x1 = pt0.Time + xdiff / (numsegments)*(j+1);
  527. double cb_y1 = GetInterpolatedNodeValue(cb_x1);
  528. handlesegmentfunc(cb_x0, cb_y0,cb_x1,cb_y1);
  529. }
  530. }
  531. }
  532. String m_script;
  533. private:
  534. nodes_t m_nodes;
  535. double m_playoffset=0.0;
  536. double m_minvalue=0.0;
  537. double m_maxvalue=1.0;
  538. double m_mintime=-2.0;
  539. double m_maxtime=2.0;
  540. int m_defshape;
  541. Colour m_colour;
  542. String m_name;
  543. bool m_updateopinprogress;
  544. double m_defvalue; // "neutral" value to be used for resets and stuff
  545. nodes_t m_reset_nodes;
  546. nodes_t m_old_nodes;
  547. nodes_t m_repeater_nodes;
  548. grid_t m_value_grid;
  549. JUCE_LEAK_DETECTOR(breakpoint_envelope)
  550. };
  551. template<typename F, typename... Args>
  552. inline double derivative(const F& f, double x, const Args&... func_args)
  553. {
  554. const double epsilon = std::numeric_limits<double>::epsilon() * 100;
  555. //const double epsilon=0.000001;
  556. return (f(x + epsilon, func_args...) - f(x, func_args...)) / epsilon;
  557. }
  558. using shared_envelope = std::shared_ptr<breakpoint_envelope>;
  559. #endif // JCDP_ENVELOPE_H