70 void operator()()
const noexcept { }
71 void operator()(ossia::impulse)
const noexcept { ret.push_back(1.f); }
72 void operator()(
int v)
const noexcept { ret.push_back(v); }
73 void operator()(
float v)
const noexcept { ret.push_back(v); }
74 void operator()(
bool v)
const noexcept { ret.push_back(v ? 1.f : 0.f); }
75 void operator()(std::string_view v)
const noexcept
77 if(
auto res = ossia::parse_strict<float>(v))
80 template <std::
size_t N>
81 void operator()(std::array<float, N> arr)
const noexcept
83 ret.insert(ret.end(), arr.begin(), arr.end());
85 void operator()(
const std::vector<ossia::value>& arr)
const noexcept
87 ret.reserve(1 + arr.size());
90 ret.push_back(ossia::convert<float>(val));
93 void operator()(
const ossia::value_map_type& arr)
const noexcept
95 ret.reserve(1 + arr.size());
96 for(
auto& [k, v] : arr)
98 ret.push_back(ossia::convert<float>(v));
123 static constexpr int timestamp_index = 0;
124 static constexpr int first_value_index = 1;
129 std::vector<vec_type> m_values;
136 QGraphicsItem* parent)
138 , m_interval{Scenario::closestParentInterval(process.parent())}
140 setAcceptedMouseButtons({});
146 auto inl = safe_cast<Process::ControlInlet*>(process.inlets().front());
148 auto fact = portFactory.
get(inl->concreteKey());
149 auto port = fact->makePortItem(*inl, doc,
this,
this);
153 m_interval, &Scenario::IntervalModel::executionEvent,
this,
154 [
this](Scenario::IntervalExecutionEvent ev) {
157 case Scenario::IntervalExecutionEvent::Playing:
158 case Scenario::IntervalExecutionEvent::Stopped:
166 auto outl = safe_cast<Process::ControlOutlet*>(process.outlets().front());
168 outl, &Process::ControlOutlet::valueChanged,
this,
169 [
this](
const ossia::value& v) {
170 auto& val = *v.target<std::vector<ossia::value>>();
171 const int N = std::ssize(val);
174 this->num_rows = std::max(this->num_rows, N - 1);
177 min.resize(N, std::numeric_limits<float>::max());
179 max.resize(N, std::numeric_limits<float>::lowest());
182 vv.resize(N, boost::container::default_init);
185 for(
auto it = val.begin(); it != val.end(); ++it)
187 const float r = *it->target<
float>();
198 if(!m_values.empty() && !m_values.back().empty())
199 if(vv[timestamp_index] < m_values.back()[timestamp_index])
205 m_values.push_back(std::move(vv));
221 void draw_row_simple(QPainter* p, qreal w, qreal h,
int row_index,
auto to_01)
const
223 for(
int start_idx = 0; start_idx < std::ssize(m_values) - 1; start_idx++)
225 int end_idx = start_idx + 1;
227 const auto* p0 = &m_values[start_idx];
228 const auto& v0 = *p0;
229 const auto N0 = std::ssize(*p0);
232 const auto* p1 = &m_values[end_idx];
233 const auto& v1 = *p1;
234 const auto N1 = std::ssize(*p1);
237 QPointF start = {v0[timestamp_index] * w, to_01(v0[row_index]) * h};
238 QPointF end = {v1[timestamp_index] * w, to_01(v1[row_index]) * h};
239 p->drawLine(start, end);
243 void draw_row(QPainter* p, qreal w, qreal h,
int row_index,
auto to_01)
const
245 double quality = std::clamp(std::ceil(std::sqrt(0.1 + num_rows)), 1., 5.);
246 std::optional<int> last_idx;
247 for(
int start_idx = 0; start_idx < std::ssize(m_values) - 1; start_idx++)
249 const auto* p0 = &m_values[start_idx];
250 const auto& v0 = *p0;
251 const auto N0 = std::ssize(*p0);
256 if(last_idx && *last_idx < start_idx)
258 const auto& v0 = m_values[*last_idx];
260 QPointF p0 = {v0[timestamp_index] * w, to_01(v0[row_index]) * h};
261 QPointF p1 = {v1[timestamp_index] * w, to_01(v1[row_index]) * h};
263 if(QLineF l{p0, p1}; l.length() > quality && p0.x() < p1.x())
266 last_idx = start_idx;
271 auto x0 = v0[timestamp_index] * w;
272 decltype(p0) p1 =
nullptr;
273 std::optional<int> last_viable_end;
275 for(
int end_idx = start_idx + 1; end_idx < std::ssize(m_values); end_idx++)
277 auto pp1 = &m_values[end_idx];
278 const auto N1 = std::ssize(*pp1);
282 last_viable_end = end_idx;
284 const auto& v1 = *pp1;
285 x1 = v1[timestamp_index] * w;
286 if((x1 - x0) < quality)
290 else if(x1 - x0 > 10.)
303 const auto& v1 = *p1;
304 QPointF p0 = {x0, to_01(v0[row_index]) * h};
305 QPointF p1 = {x1, to_01(v1[row_index]) * h};
307 last_idx = last_viable_end;
312 void draw_row_constant(QPainter* p, qreal w, qreal h,
int row_index)
const
314 for(
auto& val : m_values)
316 if(std::ssize(val) > row_index)
318 QPointF p0 = {val[timestamp_index] * w, 0.5 * h};
324 void paint_impl(QPainter* p)
const override
326 if(m_values.size() < 2 || this->num_rows == 0)
330 p->setRenderHint(QPainter::Antialiasing,
true);
331 p->setPen(score::Skin::instance().Light.main.pen1_solid_flat_miter);
333 const auto w = m_defaultWidth;
334 const auto h = height() / num_rows;
336 for(
int row = 0; row < num_rows; ++row)
338 const int row_index = row + 1;
340 const auto min = this->min[row_index];
341 const auto max = this->max[row_index];
344 draw_row_simple(p, w, h, row_index, [min, max](
float v) {
345 return 1.f - (v - min) / (max - min);
350 draw_row_constant(p, w, h, row_index);
353 p->translate(QPointF{0, h});
356 p->setRenderHint(QPainter::Antialiasing,
false);