GCC Code Coverage Report
Directory: src/ Exec Total Coverage
File: src/lib/ugen.c Lines: 228 228 100.0 %
Date: 2020-10-03 11:54:50 Branches: 59 64 92.2 %

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

3
  else if(i < 0 || (m_uint)i >= UGEN(o)->connect.multi->n_chan)
253
2
    *(M_Object*)RETURN = NULL;
254
  else
255
1
    *(M_Object*)RETURN = UGEN(o)->connect.multi->channel[i];
256
4
}
257
258
10
static MFUN(ugen_get_op) {
259
10
  *(m_uint*)RETURN = UGEN(o)->op + 1;
260
10
}
261
262
5
ANN static void set_op(const UGen u, const uint f) {
263
5
  if(u->multi) {
264
4
    for(uint i = u->connect.multi->n_chan + 1; --i;)
265
2
      UGEN(u->connect.multi->channel[i-1])->op = f;
266
  }
267
5
  u->op = f;
268
5
}
269
270
6
static MFUN(ugen_set_op) {
271
6
  const m_int i = *(m_int*)MEM(SZ_INT);
272

6
  if(i >= 1 && i <= 4)
273
5
    set_op(UGEN(o), i-1);
274
6
  *(m_int*)RETURN = UGEN(o)->op + 1;
275
6
}
276
277
8
static MFUN(ugen_get_last) {
278
8
  *(m_float*)RETURN = UGEN(o)->out;
279
8
}
280
281
struct ugen_importer {
282
  const VM* vm;
283
  const f_tick tick;
284
  const m_str name;
285
  const uint nchan;
286
};
287
288
2139
ANN static UGen add_ugen(const Gwi gwi, struct ugen_importer* imp) {
289
2139
  VM* vm = gwi_vm(gwi);
290
2139
  const M_Object o = new_M_UGen(gwi->gwion);
291
2139
  const UGen u = UGEN(o);
292
2139
  ugen_ini(vm->gwion, u, imp->nchan, imp->nchan);
293
2139
  ugen_gen(vm->gwion, u, imp->tick, (void*)imp->vm, 0);
294
2139
  vector_add(&vm->ugen, (vtype)u);
295
2139
  gwi_item_ini(gwi, "UGen", imp->name);
296
2139
  gwi_item_end(gwi, ae_flag_const, o);
297
2139
  return u;
298
}
299
300
713
static GWION_IMPORT(global_ugens) {
301
713
  const VM* vm = gwi_vm(gwi);
302
713
  struct ugen_importer imp_hole = { vm, compute_mono, "blackhole", 1 };
303
713
  const UGen hole = add_ugen(gwi, &imp_hole);
304
713
  struct ugen_importer imp_dac = { vm, dac_tick, "dac", vm->bbq->si->out };
305
713
  const UGen dac = add_ugen(gwi, &imp_dac);
306
713
  struct ugen_importer imp_adc = { vm, adc_tick, "adc", vm->bbq->si->in };
307
713
  (void)add_ugen(gwi, &imp_adc);
308
713
  ugen_connect(dac, hole);
309
713
  SET_FLAG(gwi->gwion->type[et_ugen], abstract);
310
713
  return GW_OK;
311
}
312
313
26
static OP_CHECK(opck_chuck_ugen) {
314
26
  const Exp_Binary* bin = (Exp_Binary*)data;
315
26
  return bin->rhs->info->type;
316
}
317
318
713
GWION_IMPORT(ugen) {
319
713
  const Type t_ugen = gwi_class_ini(gwi, "UGen", NULL);
320
713
  gwi_class_xtor(gwi, ugen_ctor, ugen_dtor);
321
713
  gwi->gwion->type[et_ugen] = t_ugen; // use func
322
323
713
  GWI_BB(gwi_item_ini(gwi, "@internal", "@ugen"))
324
713
  GWI_BB(gwi_item_end(gwi, ae_flag_member, NULL))
325
326
713
  GWI_BB(gwi_func_ini(gwi, "UGen", "chan"))
327
713
  GWI_BB(gwi_func_arg(gwi, "int", "arg0"))
328
713
  GWI_BB(gwi_func_end(gwi, ugen_channel, ae_flag_none))
329
330
713
  GWI_BB(gwi_func_ini(gwi, "int", "op"))
331
713
  GWI_BB(gwi_func_end(gwi, ugen_get_op, ae_flag_none))
332
333
713
  GWI_BB(gwi_func_ini(gwi, "int", "op"))
334
713
  GWI_BB(gwi_func_arg(gwi, "int", "arg0"))
335
713
  GWI_BB(gwi_func_end(gwi, ugen_set_op, ae_flag_none))
336
337
713
  GWI_BB(gwi_func_ini(gwi, "float", "last"))
338
713
  GWI_BB(gwi_func_end(gwi, ugen_get_last, ae_flag_none))
339
713
  GWI_BB(gwi_class_end(gwi))
340
341
713
  GWI_BB(gwi_oper_ini(gwi, "nonnull UGen", "nonnull UGen", "nonnull UGen"))
342
713
  _CHECK_OP("=>", chuck_ugen, UgenConnect)
343
713
  _CHECK_OP("=<", chuck_ugen, UgenDisconnect)
344
713
  _CHECK_OP(":=>", chuck_ugen, TrigConnect)
345
713
  _CHECK_OP(":=<", chuck_ugen, TrigDisconnect)
346
713
  return import_global_ugens(gwi);
347
}