| Line | Branch | Exec | Source | 
|---|---|---|---|
| 1 | #include <stdlib.h> | ||
| 2 | #include <math.h> | ||
| 3 | #include "gwion_util.h" | ||
| 4 | #include "gwion_ast.h" | ||
| 5 | #include "gwion_env.h" | ||
| 6 | #include "vm.h" | ||
| 7 | #include "gwion.h" | ||
| 8 | #include "instr.h" | ||
| 9 | #include "object.h" | ||
| 10 | #include "operator.h" | ||
| 11 | #include "import.h" | ||
| 12 | #include "ugen.h" | ||
| 13 | #include "gwi.h" | ||
| 14 | #include "emit.h" | ||
| 15 | |||
| 16 | 12 | static DTOR(basic_dtor) { xfree(UGEN(o)->module.gen.data); } | |
| 17 | |||
| 18 | 480000 | static TICK(gain_tick) { u->out = (u->in * *(m_float *)u->module.gen.data); } | |
| 19 | |||
| 20 | 1 | static CTOR(gain_ctor) { | |
| 21 | 1 | ugen_ini(shred->info->vm->gwion, UGEN(o), 1, 1); | |
| 22 | 1 | ugen_gen(shred->info->vm->gwion, UGEN(o), gain_tick, | |
| 23 | (m_float *)xmalloc(SZ_FLOAT), 0); | ||
| 24 | 1 | UGEN(o)->module.gen.tick = gain_tick; | |
| 25 | 1 | *(m_float *)UGEN(o)->module.gen.data = 1; | |
| 26 | 1 | } | |
| 27 | |||
| 28 | 67 | static MFUN(gain_get_gain) { | |
| 29 | 67 | *(m_float *)RETURN = *(m_float *)UGEN(o)->module.gen.data; | |
| 30 | 67 | } | |
| 31 | |||
| 32 | 67 | static MFUN(gain_set_gain) { | |
| 33 | 67 | *(m_float *)RETURN = *(m_float *)UGEN(o)->module.gen.data = | |
| 34 | 67 | *(m_float *)MEM(SZ_INT); | |
| 35 | 67 | } | |
| 36 | |||
| 37 | 638 | static GWION_IMPORT(gain) { | |
| 38 | 638 | GWI_OB(gwi_class_ini(gwi, "Gain", "UGen")) | |
| 39 | 638 | gwi_class_xtor(gwi, gain_ctor, basic_dtor); | |
| 40 | 638 | gwi_func_ini(gwi, "float", "gain"); | |
| 41 | 638 | GWI_BB(gwi_func_end(gwi, gain_get_gain, ae_flag_none)) | |
| 42 | 638 | gwi_func_ini(gwi, "float", "gain"); | |
| 43 | 638 | gwi_func_arg(gwi, "float", "arg0"); | |
| 44 | 638 | GWI_BB(gwi_func_end(gwi, gain_set_gain, ae_flag_none)) | |
| 45 | 638 | return gwi_class_end(gwi); | |
| 46 | } | ||
| 47 | |||
| 48 | 18 | static TICK(impulse_tick) { | |
| 49 | 18 | u->out = *(m_float *)u->module.gen.data; | |
| 50 | 18 | *(m_float *)u->module.gen.data = 0; | |
| 51 | 18 | } | |
| 52 | |||
| 53 | 7 | static CTOR(impulse_ctor) { | |
| 54 | 7 | ugen_ini(shred->info->vm->gwion, UGEN(o), 0, 1); | |
| 55 | 7 | ugen_gen(shred->info->vm->gwion, UGEN(o), impulse_tick, | |
| 56 | (m_float *)xmalloc(SZ_FLOAT), 0); | ||
| 57 | 7 | *(m_float *)UGEN(o)->module.gen.data = 0; | |
| 58 | 7 | } | |
| 59 | |||
| 60 | 1 | static MFUN(impulse_get_next) { | |
| 61 | 1 | *(m_float *)RETURN = *(m_float *)UGEN(o)->module.gen.data; | |
| 62 | 1 | } | |
| 63 | |||
| 64 | 8 | static MFUN(impulse_set_next) { | |
| 65 | 8 | *(m_float *)RETURN = | |
| 66 | 8 | (*(m_float *)UGEN(o)->module.gen.data = *(m_float *)MEM(SZ_INT)); | |
| 67 | 8 | } | |
| 68 | |||
| 69 | 638 | static GWION_IMPORT(impulse) { | |
| 70 | 638 | GWI_OB(gwi_class_ini(gwi, "Impulse", "UGen")) | |
| 71 | 638 | gwi_class_xtor(gwi, impulse_ctor, basic_dtor); | |
| 72 | 638 | gwi_func_ini(gwi, "float", "next"); | |
| 73 | 638 | GWI_BB(gwi_func_end(gwi, impulse_get_next, ae_flag_none)) | |
| 74 | 638 | gwi_func_ini(gwi, "float", "next"); | |
| 75 | 638 | gwi_func_arg(gwi, "float", "arg0"); | |
| 76 | 638 | GWI_BB(gwi_func_end(gwi, impulse_set_next, ae_flag_none)) | |
| 77 | 638 | return gwi_class_end(gwi); | |
| 78 | } | ||
| 79 | |||
| 80 | 2 | static TICK(fullrect_tick) { u->out = fabs(u->in); } | |
| 81 | |||
| 82 | 1 | static CTOR(fullrect_ctor) { | |
| 83 | 1 | ugen_ini(shred->info->vm->gwion, UGEN(o), 1, 1); | |
| 84 | 1 | ugen_gen(shred->info->vm->gwion, UGEN(o), fullrect_tick, | |
| 85 | (m_float *)xmalloc(SZ_FLOAT), 0); | ||
| 86 | 1 | *(m_float *)UGEN(o)->module.gen.data = 1; | |
| 87 | 1 | } | |
| 88 | |||
| 89 | 638 | static GWION_IMPORT(fullrect) { | |
| 90 | 638 | GWI_OB(gwi_class_ini(gwi, "FullRect", "UGen")) | |
| 91 | 638 | gwi_class_xtor(gwi, fullrect_ctor, basic_dtor); | |
| 92 | 638 | return gwi_class_end(gwi); | |
| 93 | } | ||
| 94 | |||
| 95 | 2 | static TICK(halfrect_tick) { | |
| 96 | 2/2✓ Branch 0 taken 1 times. ✓ Branch 1 taken 1 times. | 2 | if (u->in > 0) | 
| 97 | 1 | u->out = u->in; | |
| 98 | else | ||
| 99 | 1 | u->out = 0; | |
| 100 | 2 | } | |
| 101 | |||
| 102 | 1 | static CTOR(halfrect_ctor) { | |
| 103 | 1 | ugen_ini(shred->info->vm->gwion, UGEN(o), 1, 1); | |
| 104 | 1 | ugen_gen(shred->info->vm->gwion, UGEN(o), halfrect_tick, | |
| 105 | (m_float *)xmalloc(SZ_FLOAT), 0); | ||
| 106 | 1 | *(m_float *)UGEN(o)->module.gen.data = 1; | |
| 107 | 1 | } | |
| 108 | |||
| 109 | 638 | static GWION_IMPORT(halfrect) { | |
| 110 | 638 | GWI_OB(gwi_class_ini(gwi, "HalfRect", "UGen")) | |
| 111 | 638 | gwi_class_xtor(gwi, halfrect_ctor, basic_dtor); | |
| 112 | 638 | return gwi_class_end(gwi); | |
| 113 | } | ||
| 114 | |||
| 115 | 1 | static TICK(step_tick) { u->out = *(m_float *)u->module.gen.data; } | |
| 116 | |||
| 117 | 1 | static CTOR(step_ctor) { | |
| 118 | 1 | ugen_ini(shred->info->vm->gwion, UGEN(o), 0, 1); | |
| 119 | 1 | ugen_gen(shred->info->vm->gwion, UGEN(o), step_tick, | |
| 120 | (m_float *)xmalloc(SZ_FLOAT), 0); | ||
| 121 | 1 | *(m_float *)UGEN(o)->module.gen.data = 0; | |
| 122 | 1 | } | |
| 123 | |||
| 124 | 1 | static MFUN(step_get_next) { | |
| 125 | 1 | *(m_float *)RETURN = *(m_float *)UGEN(o)->module.gen.data; | |
| 126 | 1 | } | |
| 127 | |||
| 128 | 1 | static MFUN(step_set_next) { | |
| 129 | 1 | *(m_float *)RETURN = *(m_float *)UGEN(o)->module.gen.data = | |
| 130 | 1 | *(m_float *)(shred->mem + SZ_INT); | |
| 131 | 1 | } | |
| 132 | |||
| 133 | 638 | static GWION_IMPORT(step) { | |
| 134 | 638 | GWI_OB(gwi_class_ini(gwi, "Step", "UGen")) | |
| 135 | 638 | gwi_class_xtor(gwi, step_ctor, basic_dtor); | |
| 136 | 638 | gwi_func_ini(gwi, "float", "next"); | |
| 137 | 638 | GWI_BB(gwi_func_end(gwi, step_get_next, ae_flag_none)) | |
| 138 | 638 | gwi_func_ini(gwi, "float", "next"); | |
| 139 | 638 | gwi_func_arg(gwi, "float", "arg0"); | |
| 140 | 638 | GWI_BB(gwi_func_end(gwi, step_set_next, ae_flag_none)) | |
| 141 | 638 | return gwi_class_end(gwi); | |
| 142 | } | ||
| 143 | |||
| 144 | 4 | static TICK(zerox_tick) { | |
| 145 | 4/4✓ Branch 0 taken 3 times. ✓ Branch 1 taken 1 times. ✓ Branch 2 taken 1 times. ✓ Branch 3 taken 2 times. | 4 | m_float in = (u->in < 0) ? -1 : (u->in > 0); | 
| 146 | 4 | m_float f = *(m_float *)u->module.gen.data; | |
| 147 | 1/2✗ Branch 0 not taken. ✓ Branch 1 taken 4 times. | 4 | u->out = f == in ? 1 : 0; | 
| 148 | 4 | *(m_float *)u->module.gen.data = in; | |
| 149 | 4 | } | |
| 150 | |||
| 151 | 1 | static CTOR(zerox_ctor) { | |
| 152 | 1 | ugen_ini(shred->info->vm->gwion, UGEN(o), 1, 1); | |
| 153 | 1 | ugen_gen(shred->info->vm->gwion, UGEN(o), zerox_tick, | |
| 154 | (m_float *)xmalloc(SZ_FLOAT), 0); | ||
| 155 | 1 | *(m_float *)UGEN(o)->module.gen.data = 1; | |
| 156 | 1 | } | |
| 157 | |||
| 158 | 638 | static GWION_IMPORT(zerox) { | |
| 159 | 638 | GWI_OB(gwi_class_ini(gwi, "ZeroX", "UGen")) | |
| 160 | 638 | gwi_class_xtor(gwi, zerox_ctor, basic_dtor); | |
| 161 | 638 | return gwi_class_end(gwi); | |
| 162 | } | ||
| 163 | |||
| 164 | struct UUGen_ { | ||
| 165 | M_Object self; | ||
| 166 | VM_Code code; | ||
| 167 | VM_Shred shred; | ||
| 168 | void (*prep)(struct UUGen_ *, const m_float); | ||
| 169 | }; | ||
| 170 | |||
| 171 | ✗ | ANN static void global_prep(struct UUGen_ *uu, const m_float in) { | |
| 172 | ✗ | *(m_float *)uu->shred->mem = in; | |
| 173 | } | ||
| 174 | |||
| 175 | ✗ | ANN static void member_prep(struct UUGen_ *uu, const m_float in) { | |
| 176 | ✗ | *(M_Object *)uu->shred->mem = uu->self; | |
| 177 | ✗ | *(m_float *)(uu->shred->mem + SZ_INT) = in; | |
| 178 | } | ||
| 179 | |||
| 180 | ✗ | static TICK(id_tick) { u->out = u->in; } | |
| 181 | |||
| 182 | ✗ | static TICK(usrugen_tick) { | |
| 183 | ✗ | struct UUGen_ *uu = u->module.gen.data; | |
| 184 | ✗ | uu->prep(uu, u->in); | |
| 185 | ✗ | uu->shred->pc = 0; | |
| 186 | ✗ | shredule(uu->shred->tick->shreduler, uu->shred, 0); | |
| 187 | ✗ | vm_run(uu->shred->info->vm); | |
| 188 | ✗ | uu->shred->reg -= SZ_FLOAT; | |
| 189 | ✗ | u->out = *(m_float *)(uu->shred->reg); | |
| 190 | } | ||
| 191 | |||
| 192 | ✗ | static CTOR(usrugen_ctor) { | |
| 193 | ✗ | struct UUGen_ *uu = mp_calloc(shred->info->mp, UUGen); | |
| 194 | ✗ | uu->self = o; | |
| 195 | ✗ | ugen_ini(shred->info->vm->gwion, UGEN(o), 1, 1); | |
| 196 | ✗ | ugen_gen(shred->info->vm->gwion, UGEN(o), id_tick, uu, 0); | |
| 197 | } | ||
| 198 | |||
| 199 | ✗ | static DTOR(usrugen_dtor) { | |
| 200 | ✗ | struct UUGen_ *uu = UGEN(o)->module.gen.data; | |
| 201 | ✗ | if (uu->shred) free_vm_shred(uu->shred); | |
| 202 | ✗ | mp_free(shred->info->mp, UUGen, UGEN(o)->module.gen.data); | |
| 203 | } | ||
| 204 | |||
| 205 | 9 | static OP_CHECK(opck_usrugen) { | |
| 206 | 9 | Exp_Binary * bin = (Exp_Binary *)data; | |
| 207 | 9 | const Arg_List arg = bin->lhs->type->info->func->def->base->args; | |
| 208 | 4/4✓ Branch 0 taken 8 times. ✓ Branch 1 taken 1 times. ✓ Branch 2 taken 1 times. ✓ Branch 3 taken 7 times. | 9 | if (!arg || arg->len > 1) | 
| 209 | 2 | ERR_N(exp_self(bin)->pos, | |
| 210 | _("Tick function take one and only one argument")); | ||
| 211 | 2/2✓ Branch 0 taken 1 times. ✓ Branch 1 taken 6 times. | 7 | if (isa(((Arg*)(arg->ptr))->type, env->gwion->type[et_float]) < 0) | 
| 212 | 1 | ERR_N(exp_self(bin)->pos, | |
| 213 | _("Tick functions argument must be of type float")); | ||
| 214 | 6 | if (isa(bin->lhs->type->info->func->def->base->ret_type, | |
| 215 | 2/2✓ Branch 0 taken 1 times. ✓ Branch 1 taken 5 times. | 6 | env->gwion->type[et_float]) < 0) | 
| 216 | 1 | ERR_N(exp_self(bin)->pos, _("Tick function must return float")); | |
| 217 | 1/2✓ Branch 0 taken 5 times. ✗ Branch 1 not taken. | 5 | if (bin->lhs->type->info->func->value_ref->from->owner_class) | 
| 218 | 1/2✗ Branch 0 not taken. ✓ Branch 1 taken 5 times. | 5 | CHECK_BN(isa(bin->lhs->type->info->func->value_ref->from->owner_class, | 
| 219 | bin->rhs->type)); | ||
| 220 | 5 | return bin->rhs->type; | |
| 221 | } | ||
| 222 | |||
| 223 | ✗ | static INSTR(UURet) { shreduler_remove(shred->tick->shreduler, shred, false); } | |
| 224 | |||
| 225 | ✗ | ANN static void code_prepare(const VM_Code code) { | |
| 226 | ✗ | m_bit *byte = code->bytecode; | |
| 227 | ✗ | for (m_uint i = 0; i < vector_size(&code->instr); ++i) { | |
| 228 | ✗ | if (*(m_bit *)(byte + i * BYTECODE_SZ) == eFuncReturn) { | |
| 229 | ✗ | *(m_bit *)(byte + i * BYTECODE_SZ) = eOP_MAX; | |
| 230 | ✗ | *(f_instr *)(byte + (i * BYTECODE_SZ) + SZ_INT * 2) = UURet; | |
| 231 | } | ||
| 232 | } | ||
| 233 | } | ||
| 234 | |||
| 235 | ✗ | static MFUN(default_tick) { | |
| 236 | ✗ | struct UUGen_ *uu = UGEN(o)->module.gen.data; | |
| 237 | ✗ | if (uu->shred) { | |
| 238 | ✗ | free_vm_shred(uu->shred); | |
| 239 | ✗ | uu->shred = NULL; | |
| 240 | } | ||
| 241 | ✗ | UGEN(o)->module.gen.tick = id_tick; | |
| 242 | } | ||
| 243 | |||
| 244 | ✗ | static INSTR(UsrUGenTick) { | |
| 245 | ✗ | const m_uint offset = !instr->m_val ? SZ_INT : 0; | |
| 246 | ✗ | shred->reg -= SZ_INT * 2 - offset; | |
| 247 | ✗ | const M_Object o = *(M_Object *)(shred->reg + SZ_INT - offset); | |
| 248 | ✗ | struct UUGen_ *uu = UGEN(o)->module.gen.data; | |
| 249 | ✗ | if (uu->shred) { | |
| 250 | ✗ | free_vm_shred(uu->shred); | |
| 251 | ✗ | return; | |
| 252 | } | ||
| 253 | ✗ | UGEN(o)->module.gen.tick = usrugen_tick; | |
| 254 | ✗ | const VM_Code code = *(VM_Code *)(shred->reg - offset); | |
| 255 | ✗ | if (!code) { | |
| 256 | ✗ | handle(shred, "NullTickException"); | |
| 257 | ✗ | return; | |
| 258 | } | ||
| 259 | ✗ | uu->shred = new_vm_shred(shred->info->mp, *(VM_Code *)(shred->reg - offset)); | |
| 260 | ✗ | vmcode_addref(*(VM_Code *)(shred->reg - offset)); | |
| 261 | ✗ | uu->shred->info->vm = shred->info->vm; | |
| 262 | ✗ | code_prepare(vmcode_callback(shred->info->mp, uu->shred->code)); | |
| 263 | ✗ | shreduler_ini(uu->shred->tick->shreduler, uu->shred); | |
| 264 | ✗ | uu->prep = instr->m_val ? member_prep : global_prep; | |
| 265 | ✗ | *(M_Object *)(shred->reg - SZ_INT) = o; | |
| 266 | } | ||
| 267 | |||
| 268 | ✗ | static OP_EMIT(opem_usrugen) { | |
| 269 | ✗ | Exp_Binary *bin = (Exp_Binary *)data; | |
| 270 | ✗ | const Instr instr = emit_add_instr(emit, UsrUGenTick); | |
| 271 | ✗ | instr->m_val = !!bin->lhs->type->info->func->value_ref->from->owner_class; | |
| 272 | ✗ | return GW_OK; | |
| 273 | } | ||
| 274 | |||
| 275 | 638 | static GWION_IMPORT(usrugen) { | |
| 276 | 638 | GWI_OB(gwi_class_ini(gwi, "UsrUGen", "UGen")) | |
| 277 | 638 | gwi_class_xtor(gwi, usrugen_ctor, usrugen_dtor); | |
| 278 | 638 | GWI_BB(gwi_func_ini(gwi, "int", "default_tick")) | |
| 279 | 638 | GWI_BB(gwi_func_end(gwi, default_tick, 0)) | |
| 280 | 638 | GWI_BB(gwi_class_end(gwi)) | |
| 281 | 638 | GWI_BB(gwi_oper_ini(gwi, "function", "UsrUGen", "UsrUGen")) | |
| 282 | 638 | GWI_BB(gwi_oper_add(gwi, opck_usrugen)) | |
| 283 | 638 | GWI_BB(gwi_oper_emi(gwi, opem_usrugen)) | |
| 284 | 638 | GWI_BB(gwi_oper_end(gwi, "~=>", NULL)) | |
| 285 | 638 | return GW_OK; | |
| 286 | } | ||
| 287 | |||
| 288 | 638 | GWION_IMPORT(modules) { | |
| 289 | 638 | GWI_BB(gwimport_gain(gwi)) | |
| 290 | 638 | GWI_BB(gwimport_impulse(gwi)) | |
| 291 | 638 | GWI_BB(gwimport_fullrect(gwi)) | |
| 292 | 638 | GWI_BB(gwimport_halfrect(gwi)) | |
| 293 | 638 | GWI_BB(gwimport_step(gwi)) | |
| 294 | 638 | GWI_BB(gwimport_zerox(gwi)) | |
| 295 | 638 | return gwimport_usrugen(gwi); | |
| 296 | } | ||
| 297 |