SignalDisplay.hpp
1 #pragma once
2 #include <Scenario/Document/Interval/IntervalModel.hpp>
3 
4 #include <Effect/EffectLayout.hpp>
5 #include <Engine/Node/SimpleApi.hpp>
6 
7 #include <ossia/detail/math.hpp>
8 #include <ossia/math/safe_math.hpp>
9 #include <ossia/network/value/format_value.hpp>
10 
11 #include <QPainter>
12 namespace ossia
13 {
14 
15 }
16 namespace Ui
17 {
18 
19 namespace SignalDisplay
20 {
21 struct Node
22 {
24  {
25  static const constexpr auto prettyName = "Signal display";
26  static const constexpr auto objectKey = "SignalDisplay";
27  static const constexpr auto category = "Monitoring";
28  static const constexpr auto author = "ossia score";
29  static const constexpr auto tags = std::array<const char*, 0>{};
30  static const constexpr auto kind = Process::ProcessCategory::Analyzer;
31  static const constexpr auto description = "Visualize an input signal";
32  static const constexpr auto flags = Process::ProcessFlags::SupportsTemporal;
33  static const uuid_constexpr auto uuid
34  = make_uuid("9906e563-ddeb-4ecd-908c-952baee2a0a5");
35 
36  static const constexpr value_in value_ins[]{"in"};
37  static const constexpr auto control_outs
38  = tuplet::make_tuple(Control::OutControl{"value"});
39 
40  enum
41  {
42  loops_by_default
43  };
44  };
45 
46  using control_policy = ossia::safe_nodes::default_tick_controls;
47 
48  static void
49  run(const ossia::value_port& in, ossia::timed_vec<ossia::value>& out_value,
50  ossia::token_request tk, ossia::exec_state_facade st)
51  {
52  if(!in.get_data().empty())
53  {
54  const auto& v = in.get_data().back();
55  const float val = ossia::convert<float>(v.value);
56  if(ossia::safe_isnan(val) || ossia::safe_isinf(val))
57  return;
58  out_value[0] = std::vector<ossia::value>{
59  double(tk.prev_date.impl) / tk.parent_duration.impl,
60  ossia::convert<float>(v.value)};
61  }
62  }
63 
65  {
66  public:
67  Scenario::IntervalModel* m_interval{};
68  std::vector<std::pair<double, float>> m_values;
69  float min = 0;
70  float max = 1;
71 
72  Layer(
73  const Process::ProcessModel& process, const Process::Context& doc,
74  QGraphicsItem* parent)
75  : Process::EffectLayerView{parent}
76  , m_interval{Scenario::closestParentInterval(process.parent())}
77  {
78  if(m_interval)
79  {
80  connect(
81  m_interval, &Scenario::IntervalModel::executionEvent, this,
82  [this](Scenario::IntervalExecutionEvent ev) {
83  switch(ev)
84  {
85  case Scenario::IntervalExecutionEvent::Playing:
86  case Scenario::IntervalExecutionEvent::Stopped:
87  reset();
88  break;
89  default:
90  break;
91  }
92  });
93 
94  auto out = static_cast<Process::ControlOutlet*>(process.outlets().front());
95 
96  connect(
97  out, &Process::ControlOutlet::executionValueChanged, this,
98  [this](const ossia::value& v) {
99  auto& val = *v.target<std::vector<ossia::value>>();
100  float float_time = *val[0].target<float>();
101  float float_val = *val[1].target<float>();
102 
103  // Handle looping: clear when we jump back in time
104  if(!m_values.empty())
105  if(float_time < m_values.back().first)
106  m_values.clear();
107 
108  m_values.emplace_back(float_time, float_val);
109 
110  if(float_val < min)
111  min = float_val;
112  else if(float_val > max)
113  max = float_val;
114 
115  update();
116  });
117  }
118  }
119 
120  void reset()
121  {
122  min = 0.;
123  max = 1.;
124  m_values.clear();
125  update();
126  }
127 
128  void paint_impl(QPainter* p) const override
129  {
130  if(m_values.size() < 2)
131  return;
132 
133  p->setRenderHint(QPainter::Antialiasing, true);
134  p->setPen(score::Skin::instance().Light.main.pen1_solid_flat_miter);
135 
136  const auto w = width();
137  const auto h = height();
138 
139  const auto to_01 = [&](float v) { return 1. - (v - min) / (max - min); };
140  QPointF p0 = {m_values[0].first * w, to_01(m_values[0].second) * h};
141  for(std::size_t i = 1; i < m_values.size(); i++)
142  {
143  const auto& value = m_values[i];
144  QPointF p1 = {value.first * w, to_01(value.second) * h};
145 
146  if(QLineF l{p0, p1}; l.length() > 2)
147  {
148  p->drawLine(l);
149  p0 = p1;
150  }
151  }
152 
153  p->setRenderHint(QPainter::Antialiasing, false);
154  }
155  };
156 };
157 }
158 
159 namespace Display
160 {
161 struct Node
162 {
164  {
165  static const constexpr auto prettyName = "Value display";
166  static const constexpr auto objectKey = "Display";
167  static const constexpr auto category = "Monitoring";
168  static const constexpr auto author = "ossia score";
169  static const constexpr auto tags = std::array<const char*, 0>{};
170  static const constexpr auto kind = Process::ProcessCategory::Analyzer;
171  static const constexpr auto description = "Visualize an input value";
172  static const constexpr auto flags = Process::ProcessFlags::TimeIndependent
173  | Process::ProcessFlags::FullyCustomItem;
174  static const uuid_constexpr auto uuid
175  = make_uuid("3f4a41f2-fa39-420f-ab0f-0af6b8409edb");
176 
177  static const constexpr auto controls
178  = tuplet::make_tuple(Control::InControl{"value"});
179  };
180 
181  using control_policy = ossia::safe_nodes::last_tick;
182 
183  static void
184  run(const ossia::value& in, ossia::token_request tk, ossia::exec_state_facade st)
185  {
186  }
187 
189  {
190  public:
191  ossia::value m_value;
192 
193  Layer(
194  const Process::ProcessModel& process, const Process::Context& doc,
195  QGraphicsItem* parent)
196  : Process::EffectLayerView{parent}
197  {
198  setAcceptedMouseButtons({});
199 
200  const Process::PortFactoryList& portFactory
202 
203  auto inl = static_cast<Process::ControlInlet*>(process.inlets().front());
204 
205  auto fact = portFactory.get(inl->concreteKey());
206  auto port = fact->makePortItem(*inl, doc, this, this);
207  port->setPos(0, 5);
208 
209  connect(
210  inl, &Process::ControlInlet::executionValueChanged, this,
211  [this](const ossia::value& v) {
212  m_value = v;
213  update();
214  });
215  }
216 
217  void reset()
218  {
219  m_value = ossia::value{};
220  update();
221  }
222 
223  void paint_impl(QPainter* p) const override
224  {
225  if(!m_value.valid())
226  return;
227 
228  p->setRenderHint(QPainter::Antialiasing, true);
229  p->setPen(score::Skin::instance().Light.main.pen1_solid_flat_miter);
230 
231  p->drawText(boundingRect(), QString::fromStdString(fmt::format("{}", m_value)));
232 
233  p->setRenderHint(QPainter::Antialiasing, false);
234  }
235  };
236 };
237 }
238 }
Definition: score-lib-process/Process/Dataflow/Port.hpp:202
Definition: score-lib-process/Process/Dataflow/Port.hpp:415
Definition: EffectLayer.hpp:16
Definition: PortFactory.hpp:65
The Process class.
Definition: score-lib-process/Process/Process.hpp:61
Definition: IntervalModel.hpp:50
Definition: score-lib-process/Control/Widgets.hpp:45
Definition: SimpleApi.hpp:32
Definition: score-lib-process/Control/Widgets.hpp:18
Definition: ProcessContext.hpp:12
Definition: SignalDisplay.hpp:189
Definition: SignalDisplay.hpp:164
Definition: SignalDisplay.hpp:162
Definition: SignalDisplay.hpp:65
Definition: SignalDisplay.hpp:24
Definition: SignalDisplay.hpp:22
const T & interfaces() const
Access to a specific interface list.
Definition: ApplicationContext.hpp:67