Gwion coverage report


Directory: src/
File: src/lib/ugen.c
Date: 2023-01-30 18:32:28
Exec Total Coverage
Lines: 235 261 90.0%
Functions: 35 52 67.3%
Branches: 50 132 37.9%

Line Branch Exec Source
1 #include "gwion_util.h"
2 #include "gwion_ast.h"
3 #include "gwion_env.h"
4 #include "vm.h"
5 #include "gwion.h"
6 #include "object.h"
7 #include "instr.h"
8 #include "operator.h"
9 #include "import.h"
10 #include "gwi.h"
11 #include "ugen.h"
12 #include "driver.h"
13 #include "gwi.h"
14 #include "array.h"
15
16 3287132 static TICK(dac_tick) {
17 3287132 m_float *out = ((VM *)u->module.gen.data)->bbq->out;
18 3287132 uint i = 0;
19 3287132 m_float sum = 0;
20 do {
21 6574264 sum += out[i] = UGEN(u->connect.multi->channel[i])->in;
22
2/2
✓ Branch 0 taken 3287132 times.
✓ Branch 1 taken 3287132 times.
6574264 } while (++i < u->connect.multi->n_out);
23 3287132 u->out = sum / u->connect.multi->n_out;
24 3287132 }
25
26 528001 static TICK(adc_tick) {
27 528001 const m_float *in = ((VM *)u->module.gen.data)->bbq->in;
28 528001 uint i = 0;
29 528001 m_float sum = 0;
30 1056002 do sum += UGEN(u->connect.multi->channel[i])->out = in[i];
31
2/2
✓ Branch 0 taken 528001 times.
✓ Branch 1 taken 528001 times.
1056002 while (++i < u->connect.multi->n_out);
32 528001 u->out = sum / u->connect.multi->n_out;
33 528001 }
34
35 #define COMPUTE(a) \
36 if (!(a)->done) (a)->compute((a));
37
38 19393336 __attribute__((hot)) ANN void compute_mono(const UGen u) {
39 19393336 u->done = 1;
40 19393336 const uint size = u->connect.net->size;
41
2/2
✓ Branch 0 taken 8110302 times.
✓ Branch 1 taken 11283034 times.
19393336 if (size) {
42 8110302 const Vector vec = &u->connect.net->from;
43 8110302 const UGen v = (UGen)vector_front(vec);
44
2/2
✓ Branch 0 taken 4295155 times.
✓ Branch 1 taken 3815147 times.
8110302 COMPUTE(v)
45 8110302 u->in = v->out;
46
2/2
✓ Branch 0 taken 7054274 times.
✓ Branch 1 taken 8110302 times.
15164576 for (uint i = 1; i < size; ++i) {
47 7054274 const UGen w = (UGen)vector_at(vec, i);
48
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 7054269 times.
7054274 COMPUTE(w)
49 static const void *dispatch[] = {&&add, &&sub, &&mul, &&div};
50 do {
51 7054274 goto *dispatch[u->op];
52 6766274 add:
53 6766274 u->in += w->out;
54 6766274 break;
55 96000 sub:
56 96000 u->in -= w->out;
57 96000 break;
58 96000 mul:
59 96000 u->in *= w->out;
60 96000 break;
61 96000 div:
62 96000 u->in *= w->out;
63 96000 break;
64 } while (0);
65 }
66 }
67 19393336 }
68 3815133 __attribute__((hot)) ANN void compute_multi(const UGen u) {
69 3815133 u->done = 1;
70 3815133 uint i = 0;
71 7630266 do compute_mono(UGEN(u->connect.multi->channel[i]));
72
2/2
✓ Branch 0 taken 3815133 times.
✓ Branch 1 taken 3815133 times.
7630266 while (++i < u->connect.multi->n_chan);
73 3815133 }
74
75 3815133 __attribute__((hot)) ANN void compute_chan(const UGen u) {
76
1/2
✓ Branch 0 taken 3815133 times.
✗ Branch 1 not taken.
3815133 COMPUTE(u->module.ref);
77 3815133 }
78
79 #define describe_compute(func, opt, aux) \
80 __attribute__((hot)) ANN void gen_compute_##func##opt(const UGen u) { \
81 compute_##func(u); \
82 aux u->module.gen.tick(u); \
83 }
84 20329880 describe_compute(mono, , ) describe_compute(multi, , )
85 describe_compute(mono, trig,
86 { u->module.gen.trig->compute(u->module.gen.trig); })
87 describe_compute(multi, trig,
88 { u->module.gen.trig->compute(u->module.gen.trig); })
89
90 4483 ANEW UGen new_UGen(MemPool p) {
91 4483 const UGen u = mp_calloc(p, UGen);
92 4483 u->op = 0;
93 4483 u->compute = gen_compute_mono;
94 4483 return u;
95 }
96
97 4471 ANEW M_Object new_M_UGen(const struct Gwion_ *gwion) {
98 4471 const M_Object o = new_object(gwion->mp, gwion->type[et_ugen]);
99 4471 UGEN(o) = new_UGen(gwion->mp);
100 4471 return o;
101 }
102
103 1276 ANN static void assign_channel(const struct Gwion_ *gwion, const UGen u) {
104 1276 u->multi = 1;
105 1276 u->compute = gen_compute_multi;
106 2552 u->connect.multi->channel =
107 1276 (M_Object *)xmalloc(u->connect.multi->n_chan * SZ_INT);
108
2/2
✓ Branch 0 taken 2552 times.
✓ Branch 1 taken 1276 times.
3828 for (uint i = u->connect.multi->n_chan + 1; --i;) {
109 2552 const uint j = i - 1;
110 2552 const M_Object chan = new_M_UGen(gwion);
111 2552 ugen_ini(gwion, UGEN(chan), u->connect.multi->n_in > j,
112 2552 u->connect.multi->n_out > j);
113 2552 UGEN(chan)->module.ref = u;
114 2552 UGEN(chan)->compute = compute_chan;
115 2552 u->connect.multi->channel[j] = chan;
116 }
117 1276 }
118
119 1931 ANN void ugen_gen(const struct Gwion_ *gwion, const UGen u, const f_tick tick,
120 void *data, const m_bool trig) {
121 1931 u->module.gen.tick = tick;
122 1931 u->module.gen.data = data;
123
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1931 times.
1931 if (trig) {
124 u->module.gen.trig = new_UGen(gwion->mp);
125 u->module.gen.trig->compute = compute_mono;
126 ugen_ini(gwion, u->module.gen.trig, 1, 1);
127 u->compute = (u->compute == gen_compute_mono ? gen_compute_monotrig
128 : gen_compute_multitrig);
129 }
130 1931 }
131
132 3845 ANN void ugen_ini(const struct Gwion_ *gwion, const UGen u, const uint in,
133 const uint out) {
134 3845 const uint chan = in > out ? in : out;
135
2/2
✓ Branch 0 taken 3207 times.
✓ Branch 1 taken 638 times.
3845 if (chan == 1) {
136 3207 u->connect.net = mp_calloc(gwion->mp, ugen_net);
137 3207 vector_init(&u->connect.net->from);
138 3207 vector_init(&u->connect.net->to);
139 } else {
140 638 u->connect.multi = mp_calloc(gwion->mp, ugen_multi);
141 638 u->connect.multi->n_in = in;
142 638 u->connect.multi->n_out = out;
143 638 u->connect.multi->n_chan = chan;
144 638 assign_channel(gwion, u);
145 }
146 3845 }
147
148 16 ANN void connect_init(const VM_Shred shred, restrict M_Object *lhs,
149 restrict M_Object *rhs) {
150 16 POP_REG(shred, SZ_INT * 2);
151 16 *rhs = *(M_Object *)REG(SZ_INT);
152 16 *lhs = *(M_Object *)REG(0);
153 16 }
154
155 #define describe_connect(name, func) \
156 ANN static inline void name##onnect(const restrict UGen lhs, \
157 const restrict UGen rhs) { \
158 func(&rhs->connect.net->from, (vtype)lhs); \
159 func(&lhs->connect.net->to, (vtype)rhs); \
160 rhs->connect.net->size = (uint)vector_size(&rhs->connect.net->from); \
161 }
162 1302 describe_connect(C, vector_add)
163 2 describe_connect(Disc, vector_rem2)
164
165 16 ANN static void release_connect(const VM_Shred shred) {
166 16 *(M_Object *)REG(0) = *(M_Object *)REG(SZ_INT);
167 16 PUSH_REG(shred, SZ_INT);
168 16 }
169
170 typedef ANN void (*f_connect)(const UGen lhs, const UGen rhs);
171 654 ANN /* static */ void _do_(const f_connect f, const UGen lhs, const UGen rhs) {
172 654 const m_bool l_multi = lhs->multi;
173 654 const m_bool r_multi = rhs->multi;
174
2/2
✓ Branch 0 taken 642 times.
✓ Branch 1 taken 12 times.
654 const uint l_max = l_multi ? lhs->connect.multi->n_out : 1;
175
2/2
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 643 times.
654 const uint r_max = r_multi ? rhs->connect.multi->n_in : 1;
176 654 const uint max = l_max > r_max ? l_max : r_max;
177 654 uint i = 0;
178 assert(r_max > 0);
179 do {
180
2/2
✓ Branch 0 taken 1284 times.
✓ Branch 1 taken 20 times.
1304 const UGen l = l_multi ? UGEN(lhs->connect.multi->channel[i % l_max]) : lhs;
181
2/2
✓ Branch 0 taken 22 times.
✓ Branch 1 taken 1282 times.
1304 const UGen r = r_multi ? UGEN(rhs->connect.multi->channel[i % r_max]) : rhs;
182 1304 f(l, r);
183
2/2
✓ Branch 0 taken 650 times.
✓ Branch 1 taken 654 times.
1304 } while (++i < max);
184 654 }
185
186 638 ANN void ugen_connect(const restrict UGen lhs, const restrict UGen rhs) {
187 638 _do_(Connect, lhs, rhs);
188 638 }
189
190 ANN void ugen_disconnect(const restrict UGen lhs, const restrict UGen rhs) {
191 _do_(Disconnect, lhs, rhs);
192 }
193
194 #define TRIG_EX \
195 if (!UGEN(rhs)->module.gen.trig) { \
196 release_connect(shred); \
197 handle(shred, "NonTriggerException"); \
198 return; \
199 }
200 #define describe_connect_instr(name, func, tgt, opt) \
201 static INSTR(name##func) { \
202 M_Object lhs, rhs; \
203 connect_init(shred, &lhs, &rhs); \
204 opt _do_(func, UGEN(lhs), tgt); \
205 release_connect(shred); \
206 }
207 15 describe_connect_instr(Ugen, Connect, UGEN(rhs), );
208 1 describe_connect_instr(Ugen, Disconnect, UGEN(rhs), );
209 describe_connect_instr(Trig, Connect, UGEN(rhs)->module.gen.trig, TRIG_EX);
210 describe_connect_instr(Trig, Disconnect, UGEN(rhs)->module.gen.trig, TRIG_EX);
211
212 #define describe_connectaa_instr(name, func, tgt, opt) \
213 static INSTR(name##func) { \
214 M_Object lhs, rhs; \
215 connect_init(shred, &lhs, &rhs); \
216 const m_uint lsz = m_vector_size(ARRAY(lhs)); \
217 const m_uint rsz = m_vector_size(ARRAY(rhs)); \
218 const m_uint min = lsz < rsz ? lsz : rsz; \
219 for (m_uint i = 0; i < min; ++i) { \
220 M_Object ulhs, urhs; \
221 m_vector_get(ARRAY(lhs), i, &ulhs); \
222 m_vector_get(ARRAY(rhs), i, &urhs); \
223 opt if (ulhs && urhs) _do_(func, UGEN(ulhs), tgt); \
224 } \
225 release_connect(shred); \
226 }
227 describe_connectaa_instr(
228 UgenAA, Connect,
229 UGEN(urhs), ) describe_connectaa_instr(UgenAA, Disconnect,
230 UGEN(urhs), )
231 describe_connectaa_instr(
232 TrigAA, Connect, UGEN(urhs)->module.gen.trig,
233 TRIG_EX) describe_connectaa_instr(TrigAA, Disconnect,
234 UGEN(urhs)->module.gen.trig,
235 TRIG_EX)
236
237 #define describe_connectua_instr(name, func, tgt, opt) \
238 static INSTR(name##func) { \
239 M_Object lhs, rhs; \
240 connect_init(shred, &lhs, &rhs); \
241 const m_uint rsz = m_vector_size(ARRAY(rhs)); \
242 for (m_uint i = 0; i < rsz; ++i) { \
243 M_Object urhs; \
244 m_vector_get(ARRAY(rhs), i, &urhs); \
245 opt if (urhs) _do_(func, UGEN(lhs), tgt); \
246 } \
247 release_connect(shred); \
248 }
249 describe_connectua_instr(UgenUA, Connect, UGEN(urhs), )
250 describe_connectua_instr(UgenUA, Disconnect, UGEN(urhs), )
251 describe_connectua_instr(TrigUA, Connect,
252 UGEN(urhs)->module.gen.trig,
253 TRIG_EX)
254 describe_connectua_instr(
255 TrigUA, Disconnect, UGEN(urhs)->module.gen.trig,
256 TRIG_EX)
257
258 #define describe_connectau_instr(name, func, tgt, opt) \
259 static INSTR(name##func) { \
260 M_Object lhs, rhs; \
261 connect_init(shred, &lhs, &rhs); \
262 const m_uint lsz = m_vector_size(ARRAY(lhs)); \
263 for (m_uint i = 0; i < lsz; ++i) { \
264 M_Object ulhs; \
265 m_vector_get(ARRAY(lhs), i, &ulhs); \
266 opt if (ulhs) _do_(func, UGEN(ulhs), tgt); \
267 } \
268 release_connect(shred); \
269 }
270 describe_connectau_instr(UgenAU, Connect,
271 UGEN(rhs), )
272 describe_connectau_instr(UgenAU, Disconnect,
273 UGEN(rhs), )
274 describe_connectau_instr(
275 TrigAU, Connect,
276 UGEN(rhs)->module.gen.trig, TRIG_EX)
277 describe_connectau_instr(
278 TrigAU, Disconnect,
279 UGEN(rhs)->module.gen.trig,
280 TRIG_EX)
281
282 12 static CTOR(ugen_ctor) {
283 12 UGEN(o) = new_UGen(shred->info->mp);
284 12 vector_add(&shred->info->vm->ugen, (vtype)UGEN(o));
285 12 }
286
287 #define describe_release_func(src, tgt, opt) \
288 ANN static void release_##src(const UGen ug) { \
289 for (uint i = (uint)vector_size(&ug->connect.net->src) + 1; --i;) { \
290 const UGen u = (UGen)vector_at(&ug->connect.net->src, i - 1); \
291 vector_rem2(&u->connect.net->tgt, (vtype)ug); \
292 opt \
293 } \
294 vector_release(&ug->connect.net->src); \
295 }
296
2/2
✓ Branch 3 taken 5 times.
✓ Branch 4 taken 3203 times.
3208 describe_release_func(from, to, )
297
2/2
✓ Branch 3 taken 1295 times.
✓ Branch 4 taken 3203 times.
4498 describe_release_func(to, from, --u->connect.net->size;)
298
299 3203 ANN static void release_mono(MemPool p, const UGen ug) {
300 3203 release_to(ug);
301 3203 release_from(ug);
302 3203 mp_free(p, ugen_net, ug->connect.net);
303 3203 }
304
305 1276 ANN static void release_multi(const UGen ug, const VM_Shred shred) {
306
2/2
✓ Branch 0 taken 2552 times.
✓ Branch 1 taken 1276 times.
3828 for (uint i = ug->connect.multi->n_chan + 1; --i;)
307 2552 release(ug->connect.multi->channel[i - 1], shred);
308 1276 xfree(ug->connect.multi->channel);
309 1276 }
310
311 4479 static DTOR(ugen_dtor) {
312 4479 const UGen ug = UGEN(o);
313 4479 MemPool p = shred->info->mp;
314 4479 vector_rem2(&shred->info->vm->ugen, (vtype)ug);
315
2/2
✓ Branch 0 taken 3203 times.
✓ Branch 1 taken 1276 times.
4479 if (!ug->multi)
316 3203 release_mono(p, ug);
317 else
318 1276 release_multi(ug, shred);
319
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4479 times.
4479 if (ug->module.gen.trig) {
320 release_mono(p, ug->module.gen.trig);
321 mp_free(shred->info->mp, UGen, ug->module.gen.trig);
322 }
323 4479 mp_free(shred->info->mp, UGen, ug);
324 4479 }
325
326 2 static MFUN(ugen_channel) {
327 2 const m_int i = *(m_int *)MEM(SZ_INT);
328
3/4
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
2 if (!UGEN(o)->multi && !i)
329 1 *(M_Object *)RETURN = o;
330
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
1 else if (i >= 0 && (m_uint)i < UGEN(o)->connect.multi->n_chan)
331 *(M_Object *)RETURN = UGEN(o)->connect.multi->channel[i];
332 else
333 1 xfun_handle(shred, "InvalidChannelRequest");
334 2 }
335
336 10 static MFUN(ugen_get_op) { *(m_uint *)RETURN = UGEN(o)->op + 1; }
337
338 5 ANN static void set_op(const UGen u, const uint f) {
339
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 4 times.
5 if (u->multi) {
340
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 for (uint i = u->connect.multi->n_chan + 1; --i;)
341 2 UGEN(u->connect.multi->channel[i - 1])->op = f;
342 }
343 5 u->op = f;
344 5 }
345
346 6 static MFUN(ugen_set_op) {
347 6 const m_int i = *(m_int *)MEM(SZ_INT);
348
3/4
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
6 if (i >= 1 && i <= 4) set_op(UGEN(o), i - 1);
349 6 *(m_int *)RETURN = UGEN(o)->op + 1;
350 6 }
351
352 12 static MFUN(ugen_get_last) { *(m_float *)RETURN = UGEN(o)->out; }
353
354 struct ugen_importer {
355 const VM * vm;
356 const f_tick tick;
357 const m_str name;
358 const uint nchan;
359 };
360
361 1276 ANN static UGen add_ugen(const Gwi gwi, struct ugen_importer *imp) {
362 1276 VM * vm = gwi_vm(gwi);
363 1276 const M_Object o = new_M_UGen(gwi->gwion);
364 1276 const UGen u = UGEN(o);
365 1276 ugen_ini(vm->gwion, u, imp->nchan, imp->nchan);
366 // ugen_gen(vm->gwion, u, imp->tick, (void *)imp->vm, 0);
367 1276 ugen_gen(vm->gwion, u, imp->tick, o, 0);
368 1276 vector_add(&vm->ugen, (vtype)u);
369 1276 gwi_item_ini(gwi, "UGen", imp->name);
370 1276 gwi_item_end(gwi, ae_flag_const, obj, o);
371 1276 return u;
372 }
373
374 638 static GWION_IMPORT(global_ugens) {
375 638 VM *const vm = gwi_vm(gwi);
376 638 struct ugen_importer imp_hole = {vm, compute_mono, "blackhole", 1};
377 638 const UGen hole = add_ugen(gwi, &imp_hole);
378 // dac needs to have *multi*
379 638 const M_Object dac = new_M_UGen(gwi->gwion);
380 638 const UGen u = UGEN(dac);
381 638 u->connect.multi = mp_calloc(gwi->gwion->mp, ugen_multi);
382 638 u->connect.multi->n_in = vm->bbq->si->out;
383 638 u->connect.multi->n_out = vm->bbq->si->out;
384 638 u->connect.multi->n_chan = vm->bbq->si->out;
385 638 assign_channel(gwi->gwion, u);
386 638 ugen_gen(vm->gwion, u, dac_tick, (void *)vm, 0);
387 638 vector_add(&vm->ugen, (vtype)u);
388 638 gwi_item_ini(gwi, "UGen", "dac");
389 638 gwi_item_end(gwi, ae_flag_const, obj, dac);
390 638 ugen_connect(u, hole);
391
392
393 638 struct ugen_importer imp_adc = {vm, adc_tick, "adc", vm->bbq->si->in};
394 638 (void)add_ugen(gwi, &imp_adc);
395 638 SET_FLAG(gwi->gwion->type[et_ugen], abstract);
396 638 return GW_OK;
397 }
398
399 22 static OP_CHECK(opck_chuck_ugen) {
400 22 const Exp_Binary *bin = (Exp_Binary *)data;
401 22 return bin->rhs->type;
402 }
403
404 638 GWION_IMPORT(ugen) {
405 638 const Type t_ugen = gwi_class_ini(gwi, "UGen", NULL);
406 638 gwi_class_xtor(gwi, ugen_ctor, ugen_dtor);
407 638 gwi->gwion->type[et_ugen] = t_ugen; // use func
408 638 t_ugen->nspc->offset += SZ_INT;
409
410 638 GWI_BB(gwi_func_ini(gwi, "UGen", "chan"))
411 638 GWI_BB(gwi_func_arg(gwi, "int", "arg0"))
412 638 GWI_BB(gwi_func_end(gwi, ugen_channel, ae_flag_none))
413
414 638 GWI_BB(gwi_func_ini(gwi, "int", "op"))
415 638 GWI_BB(gwi_func_end(gwi, ugen_get_op, ae_flag_none))
416
417 638 GWI_BB(gwi_func_ini(gwi, "int", "op"))
418 638 GWI_BB(gwi_func_arg(gwi, "int", "arg0"))
419 638 GWI_BB(gwi_func_end(gwi, ugen_set_op, ae_flag_none))
420
421 638 GWI_BB(gwi_func_ini(gwi, "float", "last"))
422 638 GWI_BB(gwi_func_end(gwi, ugen_get_last, ae_flag_none))
423 638 GWI_BB(gwi_class_end(gwi))
424
425 638 GWI_BB(gwi_oper_ini(gwi, "UGen", "UGen", "UGen"))
426 638 _CHECK_OP("~>", chuck_ugen, UgenConnect)
427 638 _CHECK_OP("~<", chuck_ugen, UgenDisconnect)
428 638 _CHECK_OP(":~>", chuck_ugen, TrigConnect)
429 638 _CHECK_OP(":~<", chuck_ugen, TrigDisconnect)
430
431 638 GWI_BB(gwi_oper_ini(gwi, "UGen[]", "UGen[]", "UGen[]"))
432 638 _CHECK_OP("~>", chuck_ugen, UgenAAConnect)
433 638 _CHECK_OP("~<", chuck_ugen, UgenAADisconnect)
434 638 _CHECK_OP(":~>", chuck_ugen, TrigAAConnect)
435 638 _CHECK_OP(":~<", chuck_ugen, TrigAADisconnect)
436
437 638 GWI_BB(gwi_oper_ini(gwi, "UGen", "UGen[]", "UGen[]"))
438 638 _CHECK_OP("~>", chuck_ugen, UgenUAConnect)
439 638 _CHECK_OP("~<", chuck_ugen, UgenUADisconnect)
440 638 _CHECK_OP(":~>", chuck_ugen, TrigUAConnect)
441 638 _CHECK_OP(":~<", chuck_ugen, TrigUADisconnect)
442
443 638 GWI_BB(gwi_oper_ini(gwi, "UGen[]", "UGen", "UGen"))
444 638 _CHECK_OP("~>", chuck_ugen, UgenAUConnect)
445 638 _CHECK_OP("~<", chuck_ugen, UgenAUDisconnect)
446 638 _CHECK_OP(":~>", chuck_ugen, TrigAUConnect)
447 638 _CHECK_OP(":~<", chuck_ugen, TrigAUDisconnect)
448
449 638 return gwimport_global_ugens(gwi);
450 }
451