Skip to content

Commit fb09a52

Browse files
committed
ossia: add missing file
1 parent af30783 commit fb09a52

File tree

1 file changed

+352
-0
lines changed

1 file changed

+352
-0
lines changed
Lines changed: 352 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,352 @@
1+
#pragma once
2+
#include <avnd/binding/ossia/node.hpp>
3+
namespace oscr
4+
{
5+
#if 0
6+
template <typename Info, typename Type>
7+
std::span<Type*> avnd_port_idx_to_ossia_ports_old(
8+
oscr::dynamic_ports_storage<Info>& dynamic_ports,
9+
ossia::small_vector<Type, 2>& ossia_ports, int index) noexcept
10+
{
11+
int model_index = 0;
12+
13+
// We have to adjust before accessing a port as there is the first "fake"
14+
// port if the processor takes audio by argument
15+
if constexpr(avnd::audio_argument_processor<Info>)
16+
model_index += 1;
17+
else if constexpr(avnd::tag_cv<Info>)
18+
model_index += 1;
19+
20+
// The "messages" ports also go before
21+
model_index += avnd::messages_introspection<Info>::size;
22+
23+
std::span<ossia::inlet*> ret;
24+
if constexpr(avnd::dynamic_ports_input_introspection<Info>::size == 0)
25+
{
26+
ret = std::span<Type>(
27+
const_cast<Type*>(ossia_ports.data()) + model_index + index, 1);
28+
}
29+
else
30+
{
31+
avnd::input_introspection<Info>::for_all(
32+
[&dynamic_ports, index, &model_index, &ossia_ports,
33+
&ret]<std::size_t Idx, typename P>(avnd::field_reflection<Idx, P> field) {
34+
if(Idx == index)
35+
{
36+
int num_ports = 1;
37+
if constexpr(avnd::dynamic_ports_port<P>)
38+
{
39+
num_ports = dynamic_ports.num_in_ports(avnd::field_index<Idx>{});
40+
if(num_ports == 0)
41+
{
42+
ret = {};
43+
return;
44+
}
45+
}
46+
ret = std::span<Type>(
47+
const_cast<Type*>(ossia_ports.data()) + model_index, num_ports);
48+
}
49+
else
50+
{
51+
if constexpr(avnd::dynamic_ports_port<P>)
52+
{
53+
model_index += dynamic_ports.num_in_ports(avnd::field_index<Idx>{});
54+
}
55+
else
56+
{
57+
model_index += 1;
58+
}
59+
}
60+
});
61+
}
62+
63+
return ret;
64+
}
65+
template <typename Info, typename Type, std::size_t N>
66+
std::span<Type*> avnd_port_idx_to_ossia_ports(
67+
oscr::dynamic_ports_storage<Info>& dynamic_ports,
68+
oscr::outlet_storage<Info>& ossia_ports) noexcept
69+
{
70+
int model_index = 0;
71+
72+
// We have to adjust before accessing a port as there is the first "fake"
73+
// port if the processor takes audio by argument
74+
if constexpr(avnd::audio_argument_processor<Info>)
75+
model_index += 1;
76+
else if constexpr(avnd::tag_cv<Info>)
77+
model_index += 1;
78+
79+
// The "messages" ports also go before
80+
model_index += avnd::messages_introspection<Info>::size;
81+
82+
std::span<ossia::inlet*> ret;
83+
if constexpr(avnd::dynamic_ports_input_introspection<Info>::size == 0)
84+
{
85+
ret = std::span<Type>(
86+
const_cast<Type*>(ossia_ports.data()) + model_index + index, 1);
87+
}
88+
else
89+
{
90+
avnd::input_introspection<Info>::for_all(
91+
[&dynamic_ports, index, &model_index, &ossia_ports,
92+
&ret]<std::size_t Idx, typename P>(avnd::field_reflection<Idx, P> field) {
93+
if(Idx == index)
94+
{
95+
int num_ports = 1;
96+
if constexpr(avnd::dynamic_ports_port<P>)
97+
{
98+
num_ports = dynamic_ports.num_in_ports(avnd::field_index<Idx>{});
99+
if(num_ports == 0)
100+
{
101+
ret = {};
102+
return;
103+
}
104+
}
105+
ret = std::span<Type>(
106+
const_cast<Type*>(ossia_ports.data()) + model_index, num_ports);
107+
}
108+
else
109+
{
110+
if constexpr(avnd::dynamic_ports_port<P>)
111+
{
112+
model_index += dynamic_ports.num_in_ports(avnd::field_index<Idx>{});
113+
}
114+
else
115+
{
116+
model_index += 1;
117+
}
118+
}
119+
});
120+
}
121+
122+
return ret;
123+
}
124+
#endif
125+
// Special case for the case which matches exactly the ossia situation
126+
template <ossia_compatible_dynamic_audio_processor T>
127+
class safe_node<T> : public safe_node_base<T, safe_node<T>>
128+
{
129+
public:
130+
using in_channels = avnd::dynamic_mono_audio_port_input_introspection<T>;
131+
using out_channels = avnd::dynamic_mono_audio_port_output_introspection<T>;
132+
using in_busses = avnd::dynamic_poly_audio_port_input_introspection<T>;
133+
using out_busses = avnd::dynamic_poly_audio_port_output_introspection<T>;
134+
using safe_node_base<T, safe_node<T>>::safe_node_base;
135+
136+
bool scan_audio_input_channels() { return false; }
137+
138+
template <std::size_t NPred>
139+
int compute_output_channels(auto& field)
140+
{
141+
int actual_channels = 0;
142+
if constexpr(requires { field.ports; })
143+
{
144+
// avnd::dynamic_port
145+
for(auto& port : field.ports)
146+
{
147+
// channel matching logic explicitly disabled here:
148+
actual_channels += compute_output_channels<-1>(port);
149+
}
150+
}
151+
else if constexpr(requires { field.channels(); })
152+
{
153+
// Fixed at compile-time
154+
actual_channels = field.channels();
155+
}
156+
else if constexpr(requires { field.request_channels; })
157+
{
158+
// Explicitly requested: the channels are already set in field.channels;
159+
actual_channels = field.channels;
160+
}
161+
else if constexpr(requires { field.mimick_channel; })
162+
{
163+
// Mimicked from an input port
164+
auto& inputs = this->impl.inputs();
165+
auto& mimicked_port = (inputs.*field.mimick_channel);
166+
if constexpr(requires { mimicked_port.channels(); })
167+
{
168+
field.channels = mimicked_port.channels();
169+
}
170+
else if constexpr(requires { mimicked_port.channels; })
171+
{
172+
field.channels = mimicked_port.channels;
173+
}
174+
else
175+
{
176+
static_assert(decltype(field)::no_way_to_compute_the_output_channels);
177+
}
178+
actual_channels = field.channels;
179+
}
180+
else if constexpr(NPred == 0)
181+
{
182+
// Try to mimick the first audio port if everything else fails
183+
if constexpr(in_busses::size > 0)
184+
{
185+
auto& inputs = this->impl.inputs();
186+
auto& mimicked_port = in_busses::template field<0>(inputs);
187+
if constexpr(requires { mimicked_port.channels(); })
188+
{
189+
field.channels = mimicked_port.channels();
190+
}
191+
else if constexpr(requires { mimicked_port.channels; })
192+
{
193+
field.channels = mimicked_port.channels;
194+
}
195+
else
196+
{
197+
static_assert(decltype(field)::no_way_to_compute_the_output_channels);
198+
}
199+
actual_channels = field.channels;
200+
}
201+
else
202+
{
203+
static_assert(decltype(field)::no_way_to_compute_the_output_channels);
204+
}
205+
}
206+
return actual_channels;
207+
}
208+
209+
OSSIA_MAXIMUM_INLINE
210+
void run(const ossia::token_request& tk, ossia::exec_state_facade st) noexcept override
211+
{
212+
auto tm = st.timings(tk);
213+
auto start = tm.start_sample;
214+
auto frames = tm.length;
215+
216+
// Compute channel count
217+
int total_input_channels = 0;
218+
in_busses::for_all_n2(
219+
this->impl.inputs(), [&]<std::size_t NPred, std::size_t NField>(
220+
auto& field, avnd::predicate_index<NPred> pred_idx,
221+
avnd::field_index<NField> f_idx) {
222+
ossia::audio_inlet& port = tuplet::get<NField>(this->ossia_inlets.ports);
223+
224+
if constexpr(requires { field.channels(); })
225+
port->set_channels(field.channels());
226+
227+
total_input_channels += port->channels();
228+
});
229+
230+
double** in_ptr = (double**)alloca(sizeof(double*) * total_input_channels);
231+
in_busses::for_all_n2(
232+
this->impl.inputs(), [&]<std::size_t NPred, std::size_t NField>(
233+
auto& field, avnd::predicate_index<NPred> pred_idx,
234+
avnd::field_index<NField> f_idx) {
235+
ossia::audio_inlet& port = get<NField>(this->ossia_inlets.ports);
236+
auto cur_ptr = in_ptr;
237+
238+
for(int i = 0; i < port->channels(); i++)
239+
{
240+
port->channel(i).resize(st.bufferSize());
241+
cur_ptr[i] = port->channel(i).data() + start;
242+
}
243+
244+
if_possible(field.samples = cur_ptr) else if_possible(
245+
field.samples
246+
= (const double**)cur_ptr) else static_assert(field.samples.wrong_type);
247+
248+
if_possible(field.channels = port->channels());
249+
250+
in_ptr += port->channels();
251+
});
252+
253+
int output_channels = 0;
254+
out_busses::for_all_n2(
255+
this->impl.outputs(), [&]<std::size_t NPred, std::size_t NField>(
256+
auto& field, avnd::predicate_index<NPred> pred_idx,
257+
avnd::field_index<NField> f_idx) {
258+
output_channels += this->template compute_output_channels<NPred>(field);
259+
});
260+
261+
if(!this->prepare_run(tk, st, start, frames))
262+
{
263+
this->finish_run();
264+
return;
265+
}
266+
267+
// Smooth
268+
this->process_smooth();
269+
270+
out_channels::for_all_n2(
271+
this->impl.outputs(), [&]<typename Field, std::size_t NPred, std::size_t NField>(
272+
Field& field, avnd::predicate_index<NPred> pred_idx,
273+
avnd::field_index<NField> f_idx) {
274+
if constexpr(avnd::dynamic_ports_port<Field>)
275+
{
276+
const auto& ports = tuplet::get<NField>(this->ossia_outlets.ports);
277+
int port_min = std::min(field.ports.size(), ports.size());
278+
for(int port_index = 0; port_index < port_min; port_index++)
279+
{
280+
ossia::outlet* out = ports[port_index];
281+
ossia::audio_port& ossia_port = out->cast<ossia::audio_port>();
282+
// FIXME in the future maybe we want multiple dynamic_ports ?
283+
ossia_port.set_channels(1);
284+
ossia_port.channel(0).resize(st.bufferSize());
285+
286+
field.ports[port_index].channel = ossia_port.channel(0).data() + start;
287+
}
288+
}
289+
else
290+
{
291+
ossia::audio_outlet& port = tuplet::get<NField>(this->ossia_outlets.ports);
292+
port->set_channels(1);
293+
294+
port->channel(0).resize(st.bufferSize());
295+
field.channel = port->channel(0).data() + start;
296+
}
297+
});
298+
299+
double** out_ptr = (double**)alloca(sizeof(double*) * output_channels);
300+
301+
out_busses::for_all_n2(
302+
this->impl.outputs(), [&]<typename Field, std::size_t NPred, std::size_t NField>(
303+
Field& field, avnd::predicate_index<NPred> pred_idx,
304+
avnd::field_index<NField> f_idx) {
305+
const int chans = this->template compute_output_channels<NPred>(field);
306+
if constexpr(avnd::dynamic_ports_port<Field>)
307+
{
308+
const auto& ports = tuplet::get<NField>(this->ossia_outlets.ports);
309+
int port_min = std::min(field.ports.size(), ports.size());
310+
for(int port_index = 0; port_index < port_min; port_index++)
311+
{
312+
ossia::outlet* out = ports[port_index];
313+
ossia::audio_port& port = out->cast<ossia::audio_port>();
314+
// FIXME in the future maybe we want multiple dynamic_ports ?
315+
port.set_channels(1);
316+
317+
port.channel(0).resize(st.bufferSize());
318+
out_ptr[0] = port.channel(0).data() + start;
319+
320+
field.ports[port_index].samples = out_ptr;
321+
field.ports[port_index].channels = 1;
322+
out_ptr += 1;
323+
}
324+
}
325+
else
326+
{
327+
ossia::audio_outlet& port = tuplet::get<NField>(this->ossia_outlets.ports);
328+
port->set_channels(chans);
329+
330+
auto cur_ptr = out_ptr;
331+
332+
for(int i = 0; i < chans; i++)
333+
{
334+
port->channel(i).resize(st.bufferSize());
335+
cur_ptr[i] = port->channel(i).data() + start;
336+
}
337+
338+
field.samples = cur_ptr;
339+
340+
out_ptr += chans;
341+
}
342+
});
343+
344+
avnd::invoke_effect(
345+
this->impl,
346+
avnd::get_tick_or_frames(this->impl, tick_info{*this, tk, st, frames}));
347+
348+
this->finish_run();
349+
}
350+
};
351+
352+
}

0 commit comments

Comments
 (0)