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 |
|
|
} |