• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

ossia / score / 34039060546

06 Sep 2026 02:24PM UTC coverage: 26.369% (+1.8%) from 24.579%
34039060546

push

github

jcelerier
3rdparty: updat libossia

60871 of 230846 relevant lines covered (26.37%)

63602.32 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/src/plugins/score-plugin-controlsurface/ControlSurface/Executor.cpp
1
#include "Executor.hpp"
2

3
#include <Process/ExecutionFunctions.hpp>
4

5
#include <ossia/dataflow/execution_state.hpp>
6
#include <ossia/dataflow/graph/graph_interface.hpp>
7
#include <ossia/dataflow/port.hpp>
8
#include <ossia/network/common/destination_qualifiers.hpp>
9
#include <ossia/network/common/path.hpp>
10
namespace ossia
11
{
12
template <typename T>
13
std::function<void(T&)> set_destination_impl(
×
14
    execution_state& s, graph_interface& g, const State::AddressAccessor& address)
15
{
16
  if(address.address.device.isEmpty())
×
17
  {
18
    return [&s, &g](T& port) {
×
19
      if(port.address)
×
20
      {
21
        s.unregister_port(port);
×
22
        port.address = {};
×
23
        if(ossia::value_port* dat = port.template target<ossia::value_port>())
×
24
        {
25
          dat->address_unit = {};
×
26
          dat->index = {};
×
27
        }
×
28
        g.mark_dirty();
×
29
      }
×
30
    };
×
31
  }
32

33
  auto& qual = address.qualifiers.get();
×
34
  if(auto n = Execution::findNode(s, address.address))
×
35
  {
36
    return [&s, &g, n, qual](T& port) {
×
37
      auto p = n->get_parameter();
×
38
      if(p)
×
39
      {
40
        s.unregister_port(port);
×
41
        port.address = p;
×
42
        if(ossia::value_port* dat = port.template target<ossia::value_port>())
×
43
        {
44
          dat->address_unit = qual.unit;
×
45
          dat->index = qual.accessors;
×
46
        }
×
47
        s.register_port(port);
×
48
        g.mark_dirty();
×
49
      }
×
50
      else
51
      {
52
        s.unregister_port(port);
×
53
        port.address = n;
×
54
        s.register_port(port);
×
55
        g.mark_dirty();
×
56
      }
57
    };
×
58
  }
59
  else if(auto ad = address.address.toString_unsafe().toStdString();
×
60
          ossia::traversal::is_pattern(ad))
×
61
  {
62
    // OPTIMIZEME
63
    auto path = ossia::traversal::make_path(ad);
×
64
    if(path)
×
65
    {
66
      return [&s, &g, path = std::move(path)](T& port) {
×
67
        s.unregister_port(port);
×
68
        port.address = std::move(*path);
×
69
        if(ossia::value_port* dat = port.template target<ossia::value_port>())
×
70
        {
71
          dat->address_unit = {};
×
72
          dat->index.clear();
×
73
        }
×
74
        s.register_port(port);
×
75
        g.mark_dirty();
×
76
      };
×
77
    }
78
    else
79
    {
80
      return [&s, &g](T& port) {
×
81
        s.unregister_port(port);
×
82
        port.address = {};
×
83
        if(ossia::value_port* dat = port.template target<ossia::value_port>())
×
84
        {
85
          dat->address_unit = {};
×
86
          dat->index.clear();
×
87
        }
×
88
        g.mark_dirty();
×
89
      };
×
90
    }
91
  }
×
92
  else
93
  {
94
    return [](T& port) {};
×
95
  }
96
}
×
97

98
class control_surface_node : public ossia::nonowning_graph_node
99
{
100
public:
101
  std::vector<std::pair<ossia::value*, bool>> controls;
102

103
  std::pair<ossia::value*, bool>& add_control()
×
104
  {
105
    auto inletport = new ossia::value_inlet;
×
106
    auto outletport = new ossia::value_outlet;
×
107
    controls.push_back({new ossia::value, false});
×
108
    m_inlets.push_back(inletport);
×
109
    m_outlets.push_back(outletport);
×
110
    return controls.back();
×
111
  }
112

113
  struct control_updater
114
  {
115
    std::pair<ossia::value*, bool>& control;
116
    ossia::value v;
117

118
    void operator()() noexcept
×
119
    {
120
      *control.first = std::move(v);
×
121
      control.second = true;
×
122
    }
×
123
  };
124

125
  void run(const token_request&, exec_state_facade) noexcept override
×
126
  {
127
    // TODO take input port data into account.
128
    const int n = std::ssize(controls);
×
129
    for(int i = 0; i < n; i++)
×
130
    {
131
      auto& ctl = controls[i];
×
132
      if(ctl.second)
×
133
      {
134
        auto vp = m_outlets[i]->target<ossia::value_port>();
×
135
        vp->write_value(std::move(*ctl.first), 0);
×
136
        ctl.second = false;
×
137
      }
×
138
    }
×
139
  }
×
140

141
  std::string label() const noexcept override { return "control surface"; }
×
142
};
143
}
144

145
namespace ControlSurface
146
{
147

148
struct con_unvalidated
149
{
150
  const Execution::Context& ctx;
151
  const int i;
152
  std::weak_ptr<ossia::control_surface_node> weak_node;
153
  void operator()(const ossia::value& val)
×
154
  {
155
    if(auto node = weak_node.lock())
×
156
    {
157
      ctx.executionQueue.enqueue(
×
158
          ossia::control_surface_node::control_updater{node->controls[i], val});
×
159
    }
×
160
  }
×
161
};
162

163
ProcessExecutorComponent::ProcessExecutorComponent(
×
164
    Model& element, const Execution::Context& ctx, QObject* parent)
165
    : Execution::ProcessComponent_T<ControlSurface::Model, ossia::node_process>{
×
166
        element, ctx, "ControlSurface", parent}
×
167
{
×
168
  auto node = ossia::make_node<ossia::control_surface_node>(*ctx.execState);
×
169
  this->node = node;
×
170
  this->m_ossia_process = std::make_shared<ossia::node_process>(this->node);
×
171

172
  // Initialize all the controls in the node with the current value.
173
  // And update the node when the UI changes
174

175
  // TODO do it also when they change
176
  const auto& map = element.outputAddresses();
×
177
  for(auto& ctl : element.inlets())
×
178
  {
179
    std::pair<ossia::value*, bool>& p = node->add_control();
×
180
    auto& inlet = *node->root_inputs().back();
×
181
    auto& in_port = *inlet.target<ossia::value_port>();
×
182
    auto& outlet = *node->root_outputs().back();
×
183
    auto& out_port = *outlet.target<ossia::value_port>();
×
184

185
    auto ctrl = safe_cast<Process::ControlInlet*>(ctl);
×
186
    *p.first = ctrl->value(); // TODO does this make sense ?
×
187
    p.second = true;          // we will send the first value
×
188

189
    const State::AddressAccessor& addr = map.at(ctl->id().val());
×
190
    system().setup.set_destination(addr, &outlet);
×
191
    ctrl->setupExecution(inlet, this);
×
192

193
    // The outlet is the port that carries an address here, and register_node()
194
    // only pushes the declaration to the inlet.
195
    const ossia::unit_t declared = ctrl->unit().get();
×
196
    in_exec([&in_port, &out_port, declared] {
×
197
      if(declared)
×
198
        in_port.type = declared;
×
199
      out_port.domain = in_port.domain;
×
200
      out_port.type = in_port.type;
×
201
    });
×
202

203
    std::weak_ptr<ossia::control_surface_node> weak_node = node;
×
204
    QObject::connect(
×
205
        ctrl, &Process::ControlInlet::valueChanged, this,
×
206
        con_unvalidated{ctx, m_currentIndex++, weak_node});
×
207
  }
×
208

209
  QObject::connect(
×
210
      &element, &Model::controlAdded, this, [this](const Id<Process::Port>& id) {
×
211
        auto& inl = *static_cast<Process::ControlInlet*>(this->process().inlet(id));
×
212
        inletAdded(inl);
×
213
      });
×
214
}
×
215

216
void ProcessExecutorComponent::inletAdded(Process::ControlInlet& inl)
×
217
{
218
  auto& ctx = this->system();
×
219
  const auto& map = this->process().outputAddresses();
×
220

221
  auto v = inl.value(); // TODO does this make sense ?
×
222

223
  std::shared_ptr<ossia::value_inlet> fake = std::make_shared<ossia::value_inlet>();
×
224
  inl.setupExecution(*fake, this);
×
225

226
  const State::AddressAccessor& addr = map.at(inl.id().val());
×
227
  auto set_addr
228
      = ossia::set_destination_impl<ossia::outlet>(*ctx.execState, *ctx.execGraph, addr);
×
229

230
  const ossia::unit_t declared = inl.unit().get();
×
231

232
  std::weak_ptr<ossia::control_surface_node> weak_node
233
      = std::dynamic_pointer_cast<ossia::control_surface_node>(this->node);
×
234
  in_exec([v, weak_node, set_addr, declared, fake = std::move(fake)]() mutable {
×
235
    if(auto node = weak_node.lock())
×
236
    {
237
      std::pair<ossia::value*, bool>& p = node->add_control();
×
238
      *p.first = std::move(v);
×
239
      p.second = true;
×
240

241
      auto& inlet = *node->root_inputs().back();
×
242
      auto& in_port = *inlet.target<ossia::value_port>();
×
243
      auto& outlet = *node->root_outputs().back();
×
244
      auto& out_port = *outlet.target<ossia::value_port>();
×
245
      set_addr(outlet);
×
246

247
      auto& fake_port = *fake->target<ossia::value_port>();
×
248
      in_port.domain = fake_port.domain;
×
249
      in_port.type = declared ? ossia::complex_type{declared} : fake_port.type;
×
250
      out_port.domain = fake_port.domain;
×
251
      out_port.type = in_port.type;
×
252
    }
×
253
  });
×
254

255
  // Note: we cannot remove inlets in the exec as this would shift all the indices.
256
  // We cannot use pointers / refs in con_unvalidated as they may be invalidated upon reallocation.
257
  QObject::connect(
×
258
      &inl, &Process::ControlInlet::valueChanged, this,
×
259
      con_unvalidated{ctx, m_currentIndex++, weak_node});
×
260
}
×
261

262
ProcessExecutorComponent::~ProcessExecutorComponent() { }
×
263

264
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc