GCC Code Coverage Report
Directory: src/ Exec Total Coverage
File: src/lib/ugen.c Lines: 234 234 100.0 %
Date: 2020-07-24 14:14:26 Branches: 71 76 93.4 %

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
15
6052066
ANN static inline void ugop_add   (const UGen u, const m_float f) { u->in += f; }
16
96000
ANN static inline void ugop_sub  (const UGen u, const m_float f) { u->in -= f; }
17
96000
ANN static inline void ugop_mul  (const UGen u, const m_float f) { u->in *= f; }
18
96000
ANN static inline void ugop_div (const UGen u, const m_float f) { u->in /= f; }
19
20
2930032
static TICK(dac_tick) {
21
2930032
  m_float* out = ((VM*)u->module.gen.data)->bbq->out;
22
2930032
  uint i = 0;
23
5860064
  do out[i] = UGEN(u->connect.multi->channel[i])->in;
24
5860064
  while(++i < u->connect.multi->n_out);
25
2930032
}
26
27
528001
static TICK(adc_tick) {
28
528001
  const m_float* in = ((VM*)u->module.gen.data)->bbq->in;
29
528001
  uint i = 0;
30
1056002
  do UGEN(u->connect.multi->channel[i])->out = in[i];
31
1056002
  while(++i < u->connect.multi->n_out);
32
528001
}
33
34
#define COMPUTE(a) if(!(a)->done)(a)->compute((a));
35
36
__attribute__((hot))
37
13256158
ANN void compute_mono(const UGen u) {
38
13256158
  u->done = 1;
39
13256158
  const uint size = u->connect.net->size;
40
13256158
  if(size) {
41
7396106
    const Vector vec = &u->connect.net->from;
42
7396106
    const UGen   v   = (UGen)vector_front(vec);
43
7396106
    COMPUTE(v)
44
7396106
    u->in = v->out;
45
13736172
    for(uint i = 1; i < size; ++i) {
46
6340066
      const UGen w = (UGen)vector_at(vec, i);
47
6340066
      COMPUTE(w)
48
6340066
      u->op(u, w->out);
49
    }
50
  }
51
13256158
}
52
__attribute__((hot))
53
3458034
ANN void compute_multi(const UGen u) {
54
3458034
  u->done = 1;
55
3458034
  uint i = 0;
56
6916068
  do compute_mono(UGEN(u->connect.multi->channel[i]));
57
6916068
  while(++i < u->connect.multi->n_chan);
58
3458034
}
59
60
__attribute__((hot))
61
3458034
ANN void compute_chan(const UGen u) {
62
3458034
  COMPUTE(u->module.ref);
63
3458034
}
64
65
#define describe_compute(func, opt, aux)         \
66
__attribute__((hot))                             \
67
ANN void gen_compute_##func##opt(const UGen u) { \
68
  compute_##func(u);                             \
69
  aux                                            \
70
  u->module.gen.tick(u);                                \
71
}
72
3410055
describe_compute(mono,,)
73
3458033
describe_compute(multi,,)
74
1
describe_compute(mono,  trig, {u->module.gen.trig->compute(u->module.gen.trig);})
75
1
describe_compute(multi, trig, {u->module.gen.trig->compute(u->module.gen.trig);})
76
77
5127
ANEW static UGen new_UGen(MemPool p) {
78
5127
  const UGen u = mp_calloc(p, UGen);
79
5127
  u->op = ugop_add;
80
5127
  u->compute = gen_compute_mono;
81
5127
  return u;
82
}
83
84
5112
ANEW M_Object new_M_UGen(const struct Gwion_ *gwion) {
85
5112
  const M_Object o = new_object(gwion->mp, NULL, gwion->type[et_ugen]);
86
5112
  UGEN(o) = new_UGen(gwion->mp);
87
5112
  return o;
88
}
89
90
1461
ANN static void assign_channel(const struct Gwion_ *gwion, const UGen u) {
91
1461
  u->multi = 1;
92
1461
  u->compute = gen_compute_multi;
93
1461
  u->connect.multi->channel = (M_Object*)xmalloc(u->connect.multi->n_chan * SZ_INT);
94
5844
  for(uint i = u->connect.multi->n_chan + 1; --i;) {
95
2922
    const uint j = i - 1;
96
2922
    const M_Object chan = new_M_UGen(gwion);
97
2922
    ugen_ini(gwion, UGEN(chan), u->connect.multi->n_in > j, u->connect.multi->n_out > j);
98
2922
    UGEN(chan)->module.ref = u;
99
2922
    UGEN(chan)->compute = compute_chan;
100
2922
    u->connect.multi->channel[j] =  chan;
101
  }
102
1461
}
103
104
2203
ANN void ugen_gen(const struct Gwion_ *gwion, const UGen u, const f_tick tick, void* data, const m_bool trig) {
105
2203
  u->module.gen.tick = tick;
106
2203
  u->module.gen.data = data;
107
2203
  if(trig) {
108
2
    u->module.gen.trig = new_UGen(gwion->mp);
109
2
    u->module.gen.trig->compute = compute_mono;
110
2
    ugen_ini(gwion, u->module.gen.trig, 1, 1);
111
2
    u->compute = (u->compute == gen_compute_mono ? gen_compute_monotrig : gen_compute_multitrig);
112
  }
113
2203
}
114
115
5127
ANN void ugen_ini(const struct Gwion_ *gwion, const UGen u, const uint in, const uint out) {
116
5127
  const uint chan = in > out ? in : out;
117
5127
  if(chan == 1) {
118
3666
    u->connect.net = mp_calloc(gwion->mp, ugen_net);
119
3666
    vector_init(&u->connect.net->from);
120
3666
    vector_init(&u->connect.net->to);
121
  } else {
122
1461
    u->connect.multi = mp_calloc(gwion->mp, ugen_multi);
123
1461
    u->connect.multi->n_in   = in;
124
1461
    u->connect.multi->n_out  = out;
125
1461
    u->connect.multi->n_chan = chan;
126
1461
    assign_channel(gwion, u);
127
  }
128
5127
}
129
130
20
ANN void connect_init(const VM_Shred shred, restrict M_Object* lhs, restrict M_Object* rhs) {
131
20
  POP_REG(shred, SZ_INT * 2);
132
20
  *rhs = *(M_Object*)REG(SZ_INT);
133
20
  *lhs = *(M_Object*)REG(0);
134
20
}
135
136
#define describe_connect(name, func)                                                    \
137
ANN static inline void name##onnect(const restrict UGen lhs, const restrict UGen rhs) { \
138
  func(&rhs->connect.net->from, (vtype)lhs);                                             \
139
  func(&lhs->connect.net->to,   (vtype)rhs);                                             \
140
  rhs->connect.net->size = (uint)vector_size(&rhs->connect.net->from);                    \
141
}
142
1493
describe_connect(C,vector_add)
143
8
describe_connect(Disc,vector_rem2)
144
145
20
ANN static void release_connect(const VM_Shred shred) {
146
20
  _release(*(M_Object*)REG(0), shred);
147
20
  _release(*(M_Object*)REG(SZ_INT), shred);
148
20
  *(M_Object*)REG(0) = *(M_Object*)REG(SZ_INT);
149
20
  PUSH_REG(shred, SZ_INT);
150
20
}
151
152
typedef ANN void (*f_connect)(const UGen lhs, const UGen rhs);
153
752
ANN /* static */ void _do_(const f_connect f, const UGen lhs, const UGen rhs) {
154
752
  const m_bool l_multi = lhs->multi;
155
752
  const m_bool r_multi = rhs->multi;
156
752
  const uint l_max = l_multi ? lhs->connect.multi->n_out : 1;
157
752
  const uint r_max = r_multi ? rhs->connect.multi->n_in  : 1;
158
752
  const uint max   = l_max > r_max ? l_max : r_max;
159
752
  uint i = 0;
160
  assert(r_max > 0);
161
  do {
162
1501
    const UGen l = l_multi ? UGEN(lhs->connect.multi->channel[i % l_max]) : lhs;
163
1501
    const UGen r = r_multi ? UGEN(rhs->connect.multi->channel[i % r_max]) : rhs;
164
1501
    f(l, r);
165
1501
  } while(++i < max);
166
752
}
167
168
731
ANN void ugen_connect(const restrict UGen lhs, const restrict UGen rhs) {
169
731
  _do_(Connect, lhs, rhs);
170
731
}
171
172
1
ANN void ugen_disconnect(const restrict UGen lhs, const restrict UGen rhs) {
173
1
  _do_(Disconnect, lhs, rhs);
174
1
}
175
176
#define TRIG_EX                         \
177
if(!UGEN(rhs)->module.gen.trig) {       \
178
  release_connect(shred);               \
179
  Except(shred, "NonTriggerException"); \
180
}
181
#define describe_connect_instr(name, func, opt) \
182
static INSTR(name##func) {                      \
183
  M_Object lhs, rhs;                            \
184
  connect_init(shred, &lhs, &rhs);              \
185
  opt                                           \
186
  _do_(func, UGEN(lhs), UGEN(rhs));             \
187
  release_connect(shred);                       \
188
}
189
15
describe_connect_instr(Ugen, Connect,)
190
1
describe_connect_instr(Ugen, Disconnect,)
191
2
describe_connect_instr(Trig, Connect,    TRIG_EX)
192
2
describe_connect_instr(Trig, Disconnect, TRIG_EX)
193
194
13
static CTOR(ugen_ctor) {
195
13
  UGEN(o) = new_UGen(shred->info->mp);
196
13
  vector_add(&shred->info->vm->ugen, (vtype)UGEN(o));
197
13
}
198
199
#define describe_release_func(src, tgt, opt)                        \
200
ANN static void release_##src(const UGen ug) {                      \
201
  for(uint i = (uint)vector_size(&ug->connect.net->src) + 1; --i;) { \
202
    const UGen u = (UGen)vector_at(&ug->connect.net->src, i - 1);    \
203
    vector_rem2(&u->connect.net->tgt, (vtype)ug);                    \
204
    opt                                                             \
205
  }                                                                 \
206
  vector_release(&ug->connect.net->src);                             \
207
}
208
3661
describe_release_func(from, to,)
209
3661
describe_release_func(to, from, --u->connect.net->size;)
210
211
3661
ANN static void release_mono(MemPool p, const UGen ug) {
212
3661
  release_to(ug);
213
3661
  release_from(ug);
214
3661
  mp_free(p, ugen_net, ug->connect.net);
215
3661
}
216
217
1459
ANN static void release_multi(const UGen ug, const VM_Shred shred) {
218
5836
  for(uint i = ug->connect.multi->n_chan + 1; --i;)
219
2918
    release(ug->connect.multi->channel[i - 1], shred);
220
1459
  xfree(ug->connect.multi->channel);
221
1459
}
222
223
5118
static DTOR(ugen_dtor) {
224
5118
  const UGen ug = UGEN(o);
225
5118
  MemPool p = shred->info->vm->gwion->mp;
226
5118
  vector_rem2(&shred->info->vm->ugen, (vtype)ug);
227
5118
  if(!ug->multi)
228
3659
    release_mono(p, ug);
229
  else
230
1459
    release_multi(ug, shred);
231
5118
  if(ug->module.gen.trig) {
232
2
    release_mono(p, ug->module.gen.trig);
233
2
    mp_free(shred->info->mp, UGen, ug->module.gen.trig);
234
  }
235
5118
  mp_free(shred->info->mp, UGen, ug);
236
5118
}
237
238
4
static MFUN(ugen_channel) {
239
4
  const m_int i = *(m_int*)MEM(SZ_INT);
240
4
  if(!UGEN(o)->multi)
241
1
    *(M_Object*)RETURN = !i ? o : NULL;
242

3
  else if(i < 0 || (m_uint)i >= UGEN(o)->connect.multi->n_chan)
243
2
    *(M_Object*)RETURN = NULL;
244
  else
245
1
    *(M_Object*)RETURN = UGEN(o)->connect.multi->channel[i];
246
4
}
247
248
10
static MFUN(ugen_get_op) {
249
10
  const f_ugop f = UGEN(o)->op;
250
10
  if(f == ugop_add)
251
5
    *(m_uint*)RETURN = 1;
252
5
  else if(f == ugop_sub)
253
2
    *(m_uint*)RETURN = 2;
254
3
  else if(f == ugop_mul)
255
2
    *(m_uint*)RETURN = 3;
256
1
  else if(f == ugop_div)
257
1
    *(m_uint*)RETURN = 4;
258
10
}
259
260
5
ANN static void set_op(const UGen u, const f_ugop f) {
261
5
  if(u->multi) {
262
4
    for(uint i = u->connect.multi->n_chan + 1; --i;)
263
2
      UGEN(u->connect.multi->channel[i-1])->op = f;
264
  }
265
5
  u->op = f;
266
5
}
267
268
6
static MFUN(ugen_set_op) {
269
6
  const m_int i = *(m_int*)MEM(SZ_INT);
270
6
  if(i == 1)
271
2
    set_op(UGEN(o), ugop_add);
272
4
  else if(i == 2)
273
1
    set_op(UGEN(o), ugop_sub);
274
3
  else if(i == 3)
275
1
    set_op(UGEN(o), ugop_mul);
276
2
  else if(i == 4)
277
1
    set_op(UGEN(o), ugop_div);
278
6
  *(m_int*)RETURN = i;
279
6
}
280
281
8
static MFUN(ugen_get_last) {
282
8
  *(m_float*)RETURN = UGEN(o)->out;
283
8
}
284
285
struct ugen_importer {
286
  const VM* vm;
287
  const f_tick tick;
288
  const m_str name;
289
  const uint nchan;
290
};
291
292
2190
ANN static UGen add_ugen(const Gwi gwi, struct ugen_importer* imp) {
293
2190
  VM* vm = gwi_vm(gwi);
294
2190
  const M_Object o = new_M_UGen(gwi->gwion);
295
2190
  const UGen u = UGEN(o);
296
2190
  ugen_ini(vm->gwion, u, imp->nchan, imp->nchan);
297
2190
  ugen_gen(vm->gwion, u, imp->tick, (void*)imp->vm, 0);
298
2190
  vector_add(&vm->ugen, (vtype)u);
299
2190
  gwi_item_ini(gwi, "UGen", imp->name);
300
2190
  gwi_item_end(gwi, ae_flag_const, o);
301
2190
  return u;
302
}
303
304
730
static GWION_IMPORT(global_ugens) {
305
730
  const VM* vm = gwi_vm(gwi);
306
730
  struct ugen_importer imp_hole = { vm, compute_mono, "blackhole", 1 };
307
730
  const UGen hole = add_ugen(gwi, &imp_hole);
308
730
  struct ugen_importer imp_dac = { vm, dac_tick, "dac", vm->bbq->si->out };
309
730
  const UGen dac = add_ugen(gwi, &imp_dac);
310
730
  struct ugen_importer imp_adc = { vm, adc_tick, "adc", vm->bbq->si->in };
311
730
  (void)add_ugen(gwi, &imp_adc);
312
730
  ugen_connect(dac, hole);
313
730
  SET_FLAG(gwi->gwion->type[et_ugen], abstract);
314
730
  return GW_OK;
315
}
316
317
26
static OP_CHECK(opck_chuck_ugen) {
318
26
  const Exp_Binary* bin = (Exp_Binary*)data;
319
26
  return bin->rhs->info->type;
320
}
321
322
730
GWION_IMPORT(ugen) {
323
730
  const Type t_ugen = gwi_class_ini(gwi, "UGen", NULL);
324
730
  gwi_class_xtor(gwi, ugen_ctor, ugen_dtor);
325
730
  gwi->gwion->type[et_ugen] = t_ugen; // use func
326
327
730
  GWI_BB(gwi_item_ini(gwi, "@internal", "@ugen"))
328
730
  GWI_BB(gwi_item_end(gwi, ae_flag_member, NULL))
329
330
730
  GWI_BB(gwi_func_ini(gwi, "UGen", "chan"))
331
730
  GWI_BB(gwi_func_arg(gwi, "int", "arg0"))
332
730
  GWI_BB(gwi_func_end(gwi, ugen_channel, ae_flag_none))
333
334
730
  GWI_BB(gwi_func_ini(gwi, "int", "op"))
335
730
  GWI_BB(gwi_func_end(gwi, ugen_get_op, ae_flag_none))
336
337
730
  GWI_BB(gwi_func_ini(gwi, "int", "op"))
338
730
  GWI_BB(gwi_func_arg(gwi, "int", "arg0"))
339
730
  GWI_BB(gwi_func_end(gwi, ugen_set_op, ae_flag_none))
340
341
730
  GWI_BB(gwi_func_ini(gwi, "float", "last"))
342
730
  GWI_BB(gwi_func_end(gwi, ugen_get_last, ae_flag_none))
343
730
  GWI_BB(gwi_class_end(gwi))
344
345
730
  GWI_BB(gwi_oper_ini(gwi, "nonnull UGen", "nonnull UGen", "nonnull UGen"))
346
730
  _CHECK_OP("=>", chuck_ugen, UgenConnect)
347
730
  _CHECK_OP("=<", chuck_ugen, UgenDisconnect)
348
730
  _CHECK_OP(":=>", chuck_ugen, TrigConnect)
349
730
  _CHECK_OP(":=<", chuck_ugen, TrigDisconnect)
350
730
  return import_global_ugens(gwi);
351
}