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