GCC Code Coverage Report
Directory: src/ Exec Total Coverage
File: src/lib/ugen.c Lines: 228 228 100.0 %
Date: 2020-09-14 09:03:05 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
2921265
static TICK(dac_tick) {
16
2921265
  m_float* out = ((VM*)u->module.gen.data)->bbq->out;
17
2921265
  uint i = 0;
18
5842530
  do out[i] = UGEN(u->connect.multi->channel[i])->in;
19
5842530
  while(++i < u->connect.multi->n_out);
20
2921265
}
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
13221091
ANN void compute_mono(const UGen u) {
33
13221091
  u->done = 1;
34
13221091
  const uint size = u->connect.net->size;
35
13221091
  if(size) {
36
7378573
    const Vector vec = &u->connect.net->from;
37
7378573
    const UGen   v   = (UGen)vector_front(vec);
38
7378573
    COMPUTE(v)
39
7378572
    u->in = v->out;
40
13701104
    for(uint i = 1; i < size; ++i) {
41
6322532
      const UGen w = (UGen)vector_at(vec, i);
42
6322532
      COMPUTE(w)
43
      static const void* dispatch[] = { &&add, &&sub, &&mul, &&div };
44
      do {
45
6322532
        goto *dispatch[u->op];
46
6034532
        add:
47
6034532
          u->in += w->out;
48
6034532
          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
13221090
}
62
__attribute__((hot))
63
3449267
ANN void compute_multi(const UGen u) {
64
3449267
  u->done = 1;
65
3449267
  uint i = 0;
66
6898534
  do compute_mono(UGEN(u->connect.multi->channel[i]));
67
6898534
  while(++i < u->connect.multi->n_chan);
68
3449267
}
69
70
__attribute__((hot))
71
3449267
ANN void compute_chan(const UGen u) {
72
3449267
  COMPUTE(u->module.ref);
73
3449267
}
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
3401289
describe_compute(mono,,)
83
3449266
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
4994
ANEW static UGen new_UGen(MemPool p) {
88
4994
  const UGen u = mp_calloc(p, UGen);
89
4994
  u->op = 0;
90
4994
  u->compute = gen_compute_mono;
91
4994
  return u;
92
}
93
94
4979
ANEW M_Object new_M_UGen(const struct Gwion_ *gwion) {
95
4979
  const M_Object o = new_object(gwion->mp, NULL, gwion->type[et_ugen]);
96
4979
  UGEN(o) = new_UGen(gwion->mp);
97
4979
  return o;
98
}
99
100
1423
ANN static void assign_channel(const struct Gwion_ *gwion, const UGen u) {
101
1423
  u->multi = 1;
102
1423
  u->compute = gen_compute_multi;
103
1423
  u->connect.multi->channel = (M_Object*)xmalloc(u->connect.multi->n_chan * SZ_INT);
104
5692
  for(uint i = u->connect.multi->n_chan + 1; --i;) {
105
2846
    const uint j = i - 1;
106
2846
    const M_Object chan = new_M_UGen(gwion);
107
2846
    ugen_ini(gwion, UGEN(chan), u->connect.multi->n_in > j, u->connect.multi->n_out > j);
108
2846
    UGEN(chan)->module.ref = u;
109
2846
    UGEN(chan)->compute = compute_chan;
110
2846
    u->connect.multi->channel[j] =  chan;
111
  }
112
1423
}
113
114
2146
ANN void ugen_gen(const struct Gwion_ *gwion, const UGen u, const f_tick tick, void* data, const m_bool trig) {
115
2146
  u->module.gen.tick = tick;
116
2146
  u->module.gen.data = data;
117
2146
  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
2146
}
124
125
4994
ANN void ugen_ini(const struct Gwion_ *gwion, const UGen u, const uint in, const uint out) {
126
4994
  const uint chan = in > out ? in : out;
127
4994
  if(chan == 1) {
128
3571
    u->connect.net = mp_calloc(gwion->mp, ugen_net);
129
3571
    vector_init(&u->connect.net->from);
130
3571
    vector_init(&u->connect.net->to);
131
  } else {
132
1423
    u->connect.multi = mp_calloc(gwion->mp, ugen_multi);
133
1423
    u->connect.multi->n_in   = in;
134
1423
    u->connect.multi->n_out  = out;
135
1423
    u->connect.multi->n_chan = chan;
136
1423
    assign_channel(gwion, u);
137
  }
138
4994
}
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
1455
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
733
ANN /* static */ void _do_(const f_connect f, const UGen lhs, const UGen rhs) {
164
733
  const m_bool l_multi = lhs->multi;
165
733
  const m_bool r_multi = rhs->multi;
166
733
  const uint l_max = l_multi ? lhs->connect.multi->n_out : 1;
167
733
  const uint r_max = r_multi ? rhs->connect.multi->n_in  : 1;
168
733
  const uint max   = l_max > r_max ? l_max : r_max;
169
733
  uint i = 0;
170
  assert(r_max > 0);
171
  do {
172
1463
    const UGen l = l_multi ? UGEN(lhs->connect.multi->channel[i % l_max]) : lhs;
173
1463
    const UGen r = r_multi ? UGEN(rhs->connect.multi->channel[i % r_max]) : rhs;
174
1463
    f(l, r);
175
1463
  } while(++i < max);
176
733
}
177
178
712
ANN void ugen_connect(const restrict UGen lhs, const restrict UGen rhs) {
179
712
  _do_(Connect, lhs, rhs);
180
712
}
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
3566
describe_release_func(from, to,)
219
3566
describe_release_func(to, from, --u->connect.net->size;)
220
221
3566
ANN static void release_mono(MemPool p, const UGen ug) {
222
3566
  release_to(ug);
223
3566
  release_from(ug);
224
3566
  mp_free(p, ugen_net, ug->connect.net);
225
3566
}
226
227
1421
ANN static void release_multi(const UGen ug, const VM_Shred shred) {
228
5684
  for(uint i = ug->connect.multi->n_chan + 1; --i;)
229
2842
    release(ug->connect.multi->channel[i - 1], shred);
230
1421
  xfree(ug->connect.multi->channel);
231
1421
}
232
233
4985
static DTOR(ugen_dtor) {
234
4985
  const UGen ug = UGEN(o);
235
4985
  MemPool p = shred->info->vm->gwion->mp;
236
4985
  vector_rem2(&shred->info->vm->ugen, (vtype)ug);
237
4985
  if(!ug->multi)
238
3564
    release_mono(p, ug);
239
  else
240
1421
    release_multi(ug, shred);
241
4985
  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
4985
  mp_free(shred->info->mp, UGen, ug);
246
4985
}
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
2133
ANN static UGen add_ugen(const Gwi gwi, struct ugen_importer* imp) {
289
2133
  VM* vm = gwi_vm(gwi);
290
2133
  const M_Object o = new_M_UGen(gwi->gwion);
291
2133
  const UGen u = UGEN(o);
292
2133
  ugen_ini(vm->gwion, u, imp->nchan, imp->nchan);
293
2133
  ugen_gen(vm->gwion, u, imp->tick, (void*)imp->vm, 0);
294
2133
  vector_add(&vm->ugen, (vtype)u);
295
2133
  gwi_item_ini(gwi, "UGen", imp->name);
296
2133
  gwi_item_end(gwi, ae_flag_const, o);
297
2133
  return u;
298
}
299
300
711
static GWION_IMPORT(global_ugens) {
301
711
  const VM* vm = gwi_vm(gwi);
302
711
  struct ugen_importer imp_hole = { vm, compute_mono, "blackhole", 1 };
303
711
  const UGen hole = add_ugen(gwi, &imp_hole);
304
711
  struct ugen_importer imp_dac = { vm, dac_tick, "dac", vm->bbq->si->out };
305
711
  const UGen dac = add_ugen(gwi, &imp_dac);
306
711
  struct ugen_importer imp_adc = { vm, adc_tick, "adc", vm->bbq->si->in };
307
711
  (void)add_ugen(gwi, &imp_adc);
308
711
  ugen_connect(dac, hole);
309
711
  SET_FLAG(gwi->gwion->type[et_ugen], abstract);
310
711
  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
711
GWION_IMPORT(ugen) {
319
711
  const Type t_ugen = gwi_class_ini(gwi, "UGen", NULL);
320
711
  gwi_class_xtor(gwi, ugen_ctor, ugen_dtor);
321
711
  gwi->gwion->type[et_ugen] = t_ugen; // use func
322
323
711
  GWI_BB(gwi_item_ini(gwi, "@internal", "@ugen"))
324
711
  GWI_BB(gwi_item_end(gwi, ae_flag_member, NULL))
325
326
711
  GWI_BB(gwi_func_ini(gwi, "UGen", "chan"))
327
711
  GWI_BB(gwi_func_arg(gwi, "int", "arg0"))
328
711
  GWI_BB(gwi_func_end(gwi, ugen_channel, ae_flag_none))
329
330
711
  GWI_BB(gwi_func_ini(gwi, "int", "op"))
331
711
  GWI_BB(gwi_func_end(gwi, ugen_get_op, ae_flag_none))
332
333
711
  GWI_BB(gwi_func_ini(gwi, "int", "op"))
334
711
  GWI_BB(gwi_func_arg(gwi, "int", "arg0"))
335
711
  GWI_BB(gwi_func_end(gwi, ugen_set_op, ae_flag_none))
336
337
711
  GWI_BB(gwi_func_ini(gwi, "float", "last"))
338
711
  GWI_BB(gwi_func_end(gwi, ugen_get_last, ae_flag_none))
339
711
  GWI_BB(gwi_class_end(gwi))
340
341
711
  GWI_BB(gwi_oper_ini(gwi, "nonnull UGen", "nonnull UGen", "nonnull UGen"))
342
711
  _CHECK_OP("=>", chuck_ugen, UgenConnect)
343
711
  _CHECK_OP("=<", chuck_ugen, UgenDisconnect)
344
711
  _CHECK_OP(":=>", chuck_ugen, TrigConnect)
345
711
  _CHECK_OP(":=<", chuck_ugen, TrigDisconnect)
346
711
  return import_global_ugens(gwi);
347
}