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.

642 lines
18KB

  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. result.setProperty("wrapxtransform", m_transform_wrap_x, nullptr);
  200. return result;
  201. }
  202. void restoreState(ValueTree state)
  203. {
  204. if (state.isValid()==false)
  205. return;
  206. m_transform_wrap_x = state.getProperty("wrapxtransform", false);
  207. int numnodes = state.getNumChildren();
  208. if (numnodes > 0)
  209. {
  210. m_nodes.clear();
  211. for (int i = 0; i < numnodes; ++i)
  212. {
  213. ValueTree pt_tree = state.getChild(i);
  214. double x, y = 0.0;
  215. double p1, p2 = 0.5;
  216. getFromTreeProperties(pt_tree, "x", x, "y", y, "p1", p1, "p2", p2);
  217. m_nodes.emplace_back(x, y, p1,p2);
  218. }
  219. SortNodes();
  220. }
  221. }
  222. MD5 getHash() const
  223. {
  224. MemoryBlock mb;
  225. for (int i = 0; i < m_nodes.size(); ++i)
  226. {
  227. appendToMemoryBlock(mb, m_nodes[i].Time);
  228. appendToMemoryBlock(mb, m_nodes[i].Value);
  229. appendToMemoryBlock(mb, m_nodes[i].ShapeParam1);
  230. appendToMemoryBlock(mb, m_nodes[i].ShapeParam2);
  231. }
  232. return MD5(mb);
  233. }
  234. int GetNumNodes() const { return (int)m_nodes.size(); }
  235. void SetDefShape(int value) { m_defshape=value; }
  236. double getNodeLeftBound(int index, double margin=0.01) const noexcept
  237. {
  238. if (m_nodes.size() == 0)
  239. return 0.0;
  240. if (index == 0)
  241. return 0.0;
  242. return m_nodes[index - 1].Time + margin;
  243. }
  244. double getNodeRightBound(int index, double margin = 0.01) const noexcept
  245. {
  246. if (m_nodes.size() == 0)
  247. return 1.0;
  248. if (index == m_nodes.size()-1)
  249. return 1.0;
  250. return m_nodes[index + 1].Time - margin;
  251. }
  252. const std::vector<envelope_node>& get_all_nodes() const { return m_nodes; }
  253. void set_all_nodes(nodes_t nds) { m_nodes=std::move(nds); }
  254. void set_reset_nodes(const std::vector<envelope_node>& nodes, bool convertvalues=false)
  255. {
  256. if (convertvalues==false)
  257. m_reset_nodes=nodes;
  258. else
  259. {
  260. if (scaled_to_normalized_func)
  261. {
  262. m_nodes.clear();
  263. for (int i=0;i<nodes.size();++i)
  264. {
  265. envelope_node node=nodes[i];
  266. node.Value=scaled_to_normalized_func(node.Value);
  267. m_nodes.push_back(node);
  268. }
  269. }
  270. }
  271. }
  272. void ResetEnvelope()
  273. {
  274. m_nodes=m_reset_nodes;
  275. m_playoffset=0.0;
  276. }
  277. Colour GetColor()
  278. {
  279. return m_colour;
  280. }
  281. void SetColor(Colour colour)
  282. {
  283. m_colour=colour;
  284. }
  285. void BeginUpdate() // used for doing larger update operations, so can avoid needlessly sorting etc
  286. {
  287. m_updateopinprogress=true;
  288. }
  289. void EndUpdate()
  290. {
  291. m_updateopinprogress=false;
  292. SortNodes();
  293. }
  294. void AddNode(envelope_node newnode)
  295. {
  296. m_nodes.push_back(newnode);
  297. if (!m_updateopinprogress)
  298. SortNodes();
  299. }
  300. void ClearAllNodes()
  301. {
  302. m_nodes.clear();
  303. }
  304. void DeleteNode(int indx)
  305. {
  306. if (indx<0 || indx>m_nodes.size()-1)
  307. return;
  308. m_nodes.erase(m_nodes.begin()+indx);
  309. }
  310. void delete_nodes_in_time_range(double t0, double t1)
  311. {
  312. m_nodes.erase(std::remove_if(std::begin(m_nodes),
  313. std::end(m_nodes),
  314. [t0,t1](const envelope_node& a) { return a.Time>=t0 && a.Time<=t1; } ),
  315. std::end(m_nodes) );
  316. }
  317. template<typename F>
  318. void removePointsConditionally(F predicate)
  319. {
  320. m_nodes.erase(std::remove_if(m_nodes.begin(), m_nodes.end(), predicate), m_nodes.end());
  321. }
  322. envelope_node& GetNodeAtIndex(int indx)
  323. {
  324. if (m_nodes.size()==0)
  325. {
  326. throw(std::length_error("Empty envelope accessed"));
  327. }
  328. if (indx<0)
  329. indx=0;
  330. if (indx>=(int)m_nodes.size())
  331. indx=(int)m_nodes.size()-1;
  332. return m_nodes[indx];
  333. }
  334. const envelope_node& GetNodeAtIndex(int indx) const
  335. {
  336. if (m_nodes.size()==0)
  337. {
  338. throw(std::length_error("Empty envelope accessed"));
  339. }
  340. if (indx<0)
  341. indx=0;
  342. if (indx>=(int)m_nodes.size())
  343. indx=(int)m_nodes.size()-1;
  344. return m_nodes[indx];
  345. }
  346. void SetNodeStatus(int indx, int nstatus)
  347. {
  348. int i=indx;
  349. if (indx<0) i=0;
  350. if (indx>(int)m_nodes.size()-1) i=(int)m_nodes.size()-1;
  351. m_nodes[i].Status=nstatus;
  352. }
  353. void SetNode(int indx, envelope_node anode)
  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]=anode;
  359. }
  360. void SetNodeTimeValue(int indx,bool setTime,bool setValue,double atime,double avalue)
  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. if (setTime) m_nodes[i].Time=atime;
  366. if (setValue) m_nodes[i].Value=avalue;
  367. }
  368. double GetInterpolatedNodeValue(double atime)
  369. {
  370. double t0=0.0;
  371. double t1=0.0;
  372. double v0=0.0;
  373. double v1=0.0;
  374. double p1=0.0;
  375. double p2=0.0;
  376. const int maxnodeind=(int)m_nodes.size()-1;
  377. if (m_nodes.size()==0)
  378. return m_defvalue;
  379. if (m_nodes.size()==1)
  380. return m_nodes[0].Value;
  381. if (atime<=m_nodes[0].Time)
  382. {
  383. #ifdef INTERPOLATING_ENVELOPE_BORDERS
  384. t1=m_nodes[0].Time;
  385. t0=0.0-(1.0-m_nodes[maxnodeind].Time);
  386. v0=m_nodes[maxnodeind].Value;
  387. p1=m_nodes[maxnodeind].ShapeParam1;
  388. p2=m_nodes[maxnodeind].ShapeParam2;
  389. v1=m_nodes[0].Value;
  390. return interpolate_foo(atime,t0,v0,t1,v1,p1,p2);
  391. #else
  392. return m_nodes[0].Value;
  393. #endif
  394. }
  395. if (atime>m_nodes[maxnodeind].Time)
  396. {
  397. #ifdef INTERPOLATING_ENVELOPE_BORDERS
  398. t0=m_nodes[maxnodeind].Time;
  399. t1=1.0+(m_nodes[0].Time);
  400. v0=m_nodes[maxnodeind].Value;
  401. v1=m_nodes[0].Value;
  402. p1=m_nodes[maxnodeind].ShapeParam1;
  403. p2=m_nodes[maxnodeind].ShapeParam2;
  404. return interpolate_foo(atime,t0,v0,t1,v1,p1,p2);
  405. #else
  406. return m_nodes.back().Value;
  407. #endif
  408. }
  409. const envelope_node to_search(atime,0.0);
  410. //to_search.Time=atime;
  411. auto it=std::lower_bound(m_nodes.begin(),m_nodes.end(),to_search,
  412. [](const envelope_node& a, const envelope_node& b)
  413. { return a.Time<b.Time; } );
  414. if (it==m_nodes.end())
  415. {
  416. return m_defvalue;
  417. }
  418. --it; // lower_bound has returned iterator to point one too far
  419. t0=it->Time;
  420. v0=it->Value;
  421. p1=it->ShapeParam1;
  422. p2=it->ShapeParam2;
  423. ++it; // next envelope point
  424. t1=it->Time;
  425. v1=it->Value;
  426. return interpolate_foo(atime,t0,v0,t1,v1,p1,p2);
  427. }
  428. bool IsSorted() const
  429. {
  430. return std::is_sorted(m_nodes.begin(), m_nodes.end(), []
  431. (const envelope_node& lhs, const envelope_node& rhs)
  432. {
  433. return lhs.Time<rhs.Time;
  434. });
  435. }
  436. void SortNodes()
  437. {
  438. stable_sort(m_nodes.begin(),m_nodes.end(),
  439. [](const envelope_node& a, const envelope_node& b){ return a.Time<b.Time; } );
  440. }
  441. double minimum_value() const { return m_minvalue; }
  442. double maximum_value() const { return m_maxvalue; }
  443. void set_minimum_value(double v) { m_minvalue=v; }
  444. void set_maximum_value(double v) { m_maxvalue=v; }
  445. std::function<double(double)> normalized_to_scaled_func;
  446. std::function<double(double)> scaled_to_normalized_func;
  447. void beginRelativeTransformation()
  448. {
  449. m_old_nodes=m_nodes;
  450. }
  451. void endRelativeTransformation()
  452. {
  453. m_old_nodes.clear();
  454. }
  455. nodes_t& getRelativeTransformBaseNodes()
  456. {
  457. return m_old_nodes;
  458. }
  459. template<typename F>
  460. inline void performRelativeTransformation(F&& f)
  461. {
  462. for (int i = 0; i < m_old_nodes.size(); ++i)
  463. {
  464. envelope_node node = m_old_nodes[i];
  465. f(i, node);
  466. node.ShapeParam1 = jlimit(0.0, 1.0, node.ShapeParam1);
  467. m_nodes[i] = node;
  468. }
  469. }
  470. void adjustEnvelopeSegmentValues(int index, double amount)
  471. {
  472. if (index >= m_old_nodes.size())
  473. {
  474. m_nodes.back().Value = jlimit(0.0,1.0,m_old_nodes.back().Value+amount);
  475. return;
  476. }
  477. m_nodes[index].Value = jlimit(0.0, 1.0, m_old_nodes[index].Value + amount);
  478. m_nodes[index+1].Value = jlimit(0.0, 1.0, m_old_nodes[index+1].Value + amount);
  479. }
  480. const nodes_t& repeater_nodes() const
  481. {
  482. return m_repeater_nodes;
  483. }
  484. void store_repeater_nodes()
  485. {
  486. m_repeater_nodes.clear();
  487. for (int i=0;i<m_nodes.size();++i)
  488. {
  489. if (m_nodes[i].Time>=m_playoffset && m_nodes[i].Time<=m_playoffset+1.0)
  490. {
  491. envelope_node temp=m_nodes[i];
  492. temp.Time-=m_playoffset;
  493. m_repeater_nodes.push_back(temp);
  494. }
  495. }
  496. }
  497. double get_play_offset() const { return m_playoffset; }
  498. //void set_play_offset(double x) { m_playoffset=bound_value(m_mintime,x,m_maxtime); }
  499. //time_range get_play_offset_range() const { return std::make_pair(m_mintime,m_maxtime); }
  500. const grid_t& get_value_grid() const { return m_value_grid; }
  501. void set_value_grid(grid_t g) { m_value_grid=std::move(g); }
  502. template<typename F>
  503. void manipulate(F&& f)
  504. {
  505. nodes_t backup=m_nodes;
  506. if (f(backup)==true)
  507. {
  508. std::swap(backup,m_nodes);
  509. SortNodes();
  510. }
  511. }
  512. template<typename F0, typename F1>
  513. inline void resamplePointToLinearSegments(int point_index,double /*xmin*/, double /*xmax*/, double /*ymin*/, double /*ymax*/,
  514. F0&& handlesegmentfunc, F1&& numsegmentsfunc)
  515. {
  516. if (m_nodes.size() == 0)
  517. return;
  518. envelope_node pt0 = GetNodeAtIndex(point_index);
  519. envelope_node pt1 = GetNodeAtIndex(point_index+1);
  520. double xdiff = pt1.Time - pt0.Time;
  521. if (xdiff > 0.0)
  522. {
  523. int numsegments = numsegmentsfunc(xdiff);
  524. for (int j=0;j<numsegments;++j)
  525. {
  526. double cb_x0 = pt0.Time + xdiff / (numsegments)*j;
  527. double cb_y0 = GetInterpolatedNodeValue(cb_x0);
  528. double cb_x1 = pt0.Time + xdiff / (numsegments)*(j+1);
  529. double cb_y1 = GetInterpolatedNodeValue(cb_x1);
  530. handlesegmentfunc(cb_x0, cb_y0,cb_x1,cb_y1);
  531. }
  532. }
  533. }
  534. String m_script;
  535. double m_transform_x_shift = 0.0;
  536. double m_transform_y_shift = 0.0;
  537. double m_transform_y_scale = 1.0;
  538. double m_transform_y_sinus = 0.0;
  539. double m_transform_y_sinus_freq = 8.0;
  540. double m_transform_y_tilt = 0.0;
  541. bool m_transform_wrap_x = false;
  542. double m_min_pt_value = 0.0;
  543. double m_max_pt_value = 0.0;
  544. inline double getTransformedValue(double x)
  545. {
  546. if (isTransformed() == false)
  547. return GetInterpolatedNodeValue(x);
  548. double temp = x-m_transform_x_shift;
  549. if (m_transform_wrap_x == true)
  550. {
  551. temp = fmod(x - m_transform_x_shift, 1.0);
  552. if (temp < 0.0)
  553. temp += 1.0;
  554. }
  555. double v = GetInterpolatedNodeValue(temp);
  556. double center_v = m_minvalue + (m_maxvalue - m_minvalue) / 2.0;
  557. double diff = center_v - v;
  558. double scaled = center_v - m_transform_y_scale * diff;
  559. double shifted = scaled + m_transform_y_shift + m_transform_y_sinus*
  560. sin(2*3.141592653*(x-m_transform_x_shift)*m_transform_y_sinus_freq);
  561. double tiltline = m_transform_y_tilt-(2.0*m_transform_y_tilt*x);
  562. double tilted = shifted+tiltline;
  563. return jlimit(0.0,1.0,tilted);
  564. }
  565. bool isTransformed() const
  566. {
  567. return m_transform_x_shift != 0.0 || m_transform_y_shift != 0.0
  568. || m_transform_y_scale!=1.0 || m_transform_y_sinus!=0.0 || m_transform_y_tilt!=0.0;
  569. }
  570. void updateMinMaxValues()
  571. {
  572. double minv = 1.0;
  573. double maxv = 0.0;
  574. for (auto& e : m_nodes)
  575. {
  576. minv = std::min(minv, e.Value);
  577. maxv = std::max(maxv, e.Value);
  578. }
  579. m_minvalue = minv;
  580. m_maxvalue = maxv;
  581. }
  582. private:
  583. nodes_t m_nodes;
  584. double m_playoffset=0.0;
  585. double m_minvalue=0.0;
  586. double m_maxvalue=1.0;
  587. double m_mintime=-2.0;
  588. double m_maxtime=2.0;
  589. int m_defshape;
  590. Colour m_colour;
  591. String m_name;
  592. bool m_updateopinprogress;
  593. double m_defvalue; // "neutral" value to be used for resets and stuff
  594. nodes_t m_reset_nodes;
  595. nodes_t m_old_nodes;
  596. nodes_t m_repeater_nodes;
  597. grid_t m_value_grid;
  598. JUCE_LEAK_DETECTOR(breakpoint_envelope)
  599. };
  600. template<typename F, typename... Args>
  601. inline double derivative(const F& f, double x, const Args&... func_args)
  602. {
  603. const double epsilon = std::numeric_limits<double>::epsilon() * 100;
  604. //const double epsilon=0.000001;
  605. return (f(x + epsilon, func_args...) - f(x, func_args...)) / epsilon;
  606. }
  607. using shared_envelope = std::shared_ptr<breakpoint_envelope>;
  608. #endif // JCDP_ENVELOPE_H