AtlatestRepositorysigil-dsp
1
/*2
* dsp.c - Sigil DSP Module3
*4
* Native bindings for SoundPipe DSP primitives.5
* Provides oscillators, filters, envelopes, effects, noise generators,6
* and utility modules for audio synthesis.7
*/9
#include <sigil/sigil.h>11
#include <stdlib.h>12
#include <string.h>13
#include <math.h>15
#include "soundpipe.h"16
#include "ks.h"18
/* ============================================================19
* GLOBAL STATE20
* ============================================================ */22
static sp_data *g_sp = NULL;24
/* Type tags for foreign objects */25
static Value tt_osc = SIGIL_UNDEFINED;26
static Value tt_posc3 = SIGIL_UNDEFINED;27
static Value tt_blsaw = SIGIL_UNDEFINED;28
static Value tt_blsquare = SIGIL_UNDEFINED;29
static Value tt_bltriangle = SIGIL_UNDEFINED;30
static Value tt_fosc = SIGIL_UNDEFINED;31
static Value tt_phasor = SIGIL_UNDEFINED;32
static Value tt_moogladder = SIGIL_UNDEFINED;33
static Value tt_butlp = SIGIL_UNDEFINED;34
static Value tt_buthp = SIGIL_UNDEFINED;35
static Value tt_lpf18 = SIGIL_UNDEFINED;36
static Value tt_tone = SIGIL_UNDEFINED;37
static Value tt_atone = SIGIL_UNDEFINED;38
static Value tt_dcblock = SIGIL_UNDEFINED;39
static Value tt_adsr = SIGIL_UNDEFINED;40
static Value tt_tadsr = SIGIL_UNDEFINED;41
static Value tt_tenv = SIGIL_UNDEFINED;42
static Value tt_line = SIGIL_UNDEFINED;43
static Value tt_expon = SIGIL_UNDEFINED;44
static Value tt_port = SIGIL_UNDEFINED;45
static Value tt_revsc = SIGIL_UNDEFINED;46
static Value tt_zitarev = SIGIL_UNDEFINED;47
static Value tt_delay = SIGIL_UNDEFINED;48
static Value tt_vdelay = SIGIL_UNDEFINED;49
static Value tt_noise = SIGIL_UNDEFINED;50
static Value tt_pinknoise = SIGIL_UNDEFINED;51
static Value tt_brown = SIGIL_UNDEFINED;52
static Value tt_saturator = SIGIL_UNDEFINED;53
static Value tt_clip = SIGIL_UNDEFINED;54
static Value tt_peaklim = SIGIL_UNDEFINED;55
static Value tt_pan2 = SIGIL_UNDEFINED;56
static Value tt_metro = SIGIL_UNDEFINED;57
static Value tt_clock = SIGIL_UNDEFINED;58
static Value tt_tgate = SIGIL_UNDEFINED;59
static Value tt_randh = SIGIL_UNDEFINED;60
static Value tt_randi = SIGIL_UNDEFINED;61
static Value tt_scale = SIGIL_UNDEFINED;62
static Value tt_clamp = SIGIL_UNDEFINED;63
static Value tt_crossfade = SIGIL_UNDEFINED;64
static Value tt_wavout = SIGIL_UNDEFINED;65
static Value tt_ftbl = SIGIL_UNDEFINED;66
static Value tt_ks = SIGIL_UNDEFINED;68
/* ============================================================69
* HELPERS70
* ============================================================ */72
#define ENSURE_TAG(vm, tag, name) \73
if (sigil_is_undefined(tag)) { \74
tag = sigil_intern_symbol(vm, name, strlen(name)); \75
}77
#define CHECK_SP(vm, funcname) \78
if (!g_sp) { \79
sigil__vm_set_error(vm, SIGIL_ERR_RUNTIME, funcname ": DSP not initialized, call dsp-init first"); \80
return SIGIL_FALSE; \81
}83
/* Wrapper struct for wavetable oscillator (owns ftbl) */84
typedef struct {85
sp_osc *osc;86
sp_ftbl *ft;87
} dsp_osc;89
/* Wrapper struct for posc3 (owns ftbl) */90
typedef struct {91
sp_posc3 *osc;92
sp_ftbl *ft;93
} dsp_posc3;95
/* Wrapper struct for fosc (owns ftbl) */96
typedef struct {97
sp_fosc *osc;98
sp_ftbl *ft;99
} dsp_fosc;101
/* ============================================================102
* DESTRUCTORS103
* ============================================================ */105
static void destroy_osc(void *data) {106
dsp_osc *d = (dsp_osc *)data;107
if (d->osc) sp_osc_destroy(&d->osc);108
if (d->ft) sp_ftbl_destroy(&d->ft);109
free(d);110
}112
static void destroy_posc3(void *data) {113
dsp_posc3 *d = (dsp_posc3 *)data;114
if (d->osc) sp_posc3_destroy(&d->osc);115
if (d->ft) sp_ftbl_destroy(&d->ft);116
free(d);117
}119
static void destroy_blsaw(void *data) { sp_blsaw *p = (sp_blsaw *)data; sp_blsaw_destroy(&p); }120
static void destroy_blsquare(void *data) { sp_blsquare *p = (sp_blsquare *)data; sp_blsquare_destroy(&p); }121
static void destroy_bltriangle(void *data) { sp_bltriangle *p = (sp_bltriangle *)data; sp_bltriangle_destroy(&p); }123
static void destroy_fosc(void *data) {124
dsp_fosc *d = (dsp_fosc *)data;125
if (d->osc) sp_fosc_destroy(&d->osc);126
if (d->ft) sp_ftbl_destroy(&d->ft);127
free(d);128
}130
static void destroy_phasor(void *data) { sp_phasor *p = (sp_phasor *)data; sp_phasor_destroy(&p); }131
static void destroy_moogladder(void *data) { sp_moogladder *p = (sp_moogladder *)data; sp_moogladder_destroy(&p); }132
static void destroy_butlp(void *data) { sp_butlp *p = (sp_butlp *)data; sp_butlp_destroy(&p); }133
static void destroy_buthp(void *data) { sp_buthp *p = (sp_buthp *)data; sp_buthp_destroy(&p); }134
static void destroy_lpf18(void *data) { sp_lpf18 *p = (sp_lpf18 *)data; sp_lpf18_destroy(&p); }135
static void destroy_tone(void *data) { sp_tone *p = (sp_tone *)data; sp_tone_destroy(&p); }136
static void destroy_atone(void *data) { sp_atone *p = (sp_atone *)data; sp_atone_destroy(&p); }137
static void destroy_dcblock(void *data) { sp_dcblock *p = (sp_dcblock *)data; sp_dcblock_destroy(&p); }138
static void destroy_adsr(void *data) { sp_adsr *p = (sp_adsr *)data; sp_adsr_destroy(&p); }139
static void destroy_tadsr(void *data) { sp_tadsr *p = (sp_tadsr *)data; sp_tadsr_destroy(&p); }140
static void destroy_tenv(void *data) { sp_tenv *p = (sp_tenv *)data; sp_tenv_destroy(&p); }141
static void destroy_line(void *data) { sp_line *p = (sp_line *)data; sp_line_destroy(&p); }142
static void destroy_expon(void *data) { sp_expon *p = (sp_expon *)data; sp_expon_destroy(&p); }143
static void destroy_port(void *data) { sp_port *p = (sp_port *)data; sp_port_destroy(&p); }144
static void destroy_revsc(void *data) { sp_revsc *p = (sp_revsc *)data; sp_revsc_destroy(&p); }145
static void destroy_zitarev(void *data) { sp_zitarev *p = (sp_zitarev *)data; sp_zitarev_destroy(&p); }146
static void destroy_delay(void *data) { sp_delay *p = (sp_delay *)data; sp_delay_destroy(&p); }147
static void destroy_vdelay(void *data) { sp_vdelay *p = (sp_vdelay *)data; sp_vdelay_destroy(&p); }148
static void destroy_noise(void *data) { sp_noise *p = (sp_noise *)data; sp_noise_destroy(&p); }149
static void destroy_pinknoise(void *data) { sp_pinknoise *p = (sp_pinknoise *)data; sp_pinknoise_destroy(&p); }150
static void destroy_brown(void *data) { sp_brown *p = (sp_brown *)data; sp_brown_destroy(&p); }151
static void destroy_saturator(void *data) { sp_saturator *p = (sp_saturator *)data; sp_saturator_destroy(&p); }152
static void destroy_clip(void *data) { sp_clip *p = (sp_clip *)data; sp_clip_destroy(&p); }153
static void destroy_peaklim(void *data) { sp_peaklim *p = (sp_peaklim *)data; sp_peaklim_destroy(&p); }154
static void destroy_pan2(void *data) { sp_pan2 *p = (sp_pan2 *)data; sp_pan2_destroy(&p); }155
static void destroy_metro(void *data) { sp_metro *p = (sp_metro *)data; sp_metro_destroy(&p); }156
static void destroy_clock(void *data) { sp_clock *p = (sp_clock *)data; sp_clock_destroy(&p); }157
static void destroy_tgate(void *data) { sp_tgate *p = (sp_tgate *)data; sp_tgate_destroy(&p); }158
static void destroy_randh(void *data) { sp_randh *p = (sp_randh *)data; sp_randh_destroy(&p); }159
static void destroy_randi(void *data) { sp_randi *p = (sp_randi *)data; sp_randi_destroy(&p); }160
static void destroy_scale(void *data) { sp_scale *p = (sp_scale *)data; sp_scale_destroy(&p); }161
static void destroy_clamp(void *data) { sp_clamp *p = (sp_clamp *)data; sp_clamp_destroy(&p); }162
static void destroy_crossfade(void *data) { sp_crossfade *p = (sp_crossfade *)data; sp_crossfade_destroy(&p); }163
static void destroy_wavout(void *data) { sp_wavout *p = (sp_wavout *)data; sp_wavout_destroy(&p); }164
static void destroy_ftbl(void *data) { sp_ftbl *p = (sp_ftbl *)data; sp_ftbl_destroy(&p); }165
static void destroy_ks(void *data) { sp_ks *p = (sp_ks *)data; sp_ks_destroy(&p); }167
/* ============================================================168
* TYPE GETTERS169
* ============================================================ */171
#define DEF_GETTER(name, sp_type, tag, label) \172
static sp_type *get_##name(SigilVM *vm, Value v) { \173
ENSURE_TAG(vm, tag, "dsp-" label); \174
if (!sigil_is_foreign_type(v, tag)) return NULL; \175
return (sp_type *)sigil_foreign_get_data(v); \176
}178
/* Wrapper getters return the wrapper struct */179
static dsp_osc *get_osc(SigilVM *vm, Value v) {180
ENSURE_TAG(vm, tt_osc, "dsp-osc");181
if (!sigil_is_foreign_type(v, tt_osc)) return NULL;182
return (dsp_osc *)sigil_foreign_get_data(v);183
}184
static dsp_posc3 *get_posc3(SigilVM *vm, Value v) {185
ENSURE_TAG(vm, tt_posc3, "dsp-posc3");186
if (!sigil_is_foreign_type(v, tt_posc3)) return NULL;187
return (dsp_posc3 *)sigil_foreign_get_data(v);188
}189
static dsp_fosc *get_fosc(SigilVM *vm, Value v) {190
ENSURE_TAG(vm, tt_fosc, "dsp-fosc");191
if (!sigil_is_foreign_type(v, tt_fosc)) return NULL;192
return (dsp_fosc *)sigil_foreign_get_data(v);193
}195
DEF_GETTER(blsaw, sp_blsaw, tt_blsaw, "blsaw")196
DEF_GETTER(blsquare, sp_blsquare, tt_blsquare, "blsquare")197
DEF_GETTER(bltriangle, sp_bltriangle, tt_bltriangle, "bltriangle")198
DEF_GETTER(phasor, sp_phasor, tt_phasor, "phasor")199
DEF_GETTER(moogladder, sp_moogladder, tt_moogladder, "moogladder")200
DEF_GETTER(butlp, sp_butlp, tt_butlp, "butlp")201
DEF_GETTER(buthp, sp_buthp, tt_buthp, "buthp")202
DEF_GETTER(lpf18, sp_lpf18, tt_lpf18, "lpf18")203
DEF_GETTER(tone, sp_tone, tt_tone, "tone")204
DEF_GETTER(atone, sp_atone, tt_atone, "atone")205
DEF_GETTER(dcblock, sp_dcblock, tt_dcblock, "dcblock")206
DEF_GETTER(adsr, sp_adsr, tt_adsr, "adsr")207
DEF_GETTER(tadsr, sp_tadsr, tt_tadsr, "tadsr")208
DEF_GETTER(tenv, sp_tenv, tt_tenv, "tenv")209
DEF_GETTER(line, sp_line, tt_line, "line")210
DEF_GETTER(expon, sp_expon, tt_expon, "expon")211
DEF_GETTER(port, sp_port, tt_port, "port")212
DEF_GETTER(revsc, sp_revsc, tt_revsc, "revsc")213
DEF_GETTER(zitarev, sp_zitarev, tt_zitarev, "zitarev")214
DEF_GETTER(delay, sp_delay, tt_delay, "delay")215
DEF_GETTER(vdelay, sp_vdelay, tt_vdelay, "vdelay")216
DEF_GETTER(noise, sp_noise, tt_noise, "noise")217
DEF_GETTER(pinknoise, sp_pinknoise, tt_pinknoise, "pinknoise")218
DEF_GETTER(brown, sp_brown, tt_brown, "brown")219
DEF_GETTER(saturator, sp_saturator, tt_saturator, "saturator")220
DEF_GETTER(clip, sp_clip, tt_clip, "clip")221
DEF_GETTER(peaklim, sp_peaklim, tt_peaklim, "peaklim")222
DEF_GETTER(pan2, sp_pan2, tt_pan2, "pan2")223
DEF_GETTER(metro, sp_metro, tt_metro, "metro")224
DEF_GETTER(clock_mod, sp_clock, tt_clock, "clock")225
DEF_GETTER(tgate, sp_tgate, tt_tgate, "tgate")226
DEF_GETTER(randh, sp_randh, tt_randh, "randh")227
DEF_GETTER(randi, sp_randi, tt_randi, "randi")228
DEF_GETTER(scale, sp_scale, tt_scale, "scale")229
DEF_GETTER(clamp, sp_clamp, tt_clamp, "clamp")230
DEF_GETTER(crossfade, sp_crossfade, tt_crossfade, "crossfade")231
DEF_GETTER(wavout, sp_wavout, tt_wavout, "wavout")232
DEF_GETTER(ks, sp_ks, tt_ks, "ks")234
/* ============================================================235
* CORE — dsp-init, dsp-shutdown, dsp-sample-rate236
* ============================================================ */238
/* (dsp-init [sample-rate]) */239
/* Helper to get a number as double from either fixnum or flonum */240
static double as_number(Value v)241
{242
if (sigil_is_fixnum(v)) return (double)sigil_as_fixnum(v);243
return sigil_as_flonum(v);244
}246
static Value native_dsp_init(SigilVM *vm, int argc, Value *args)247
{248
(void)vm;249
if (g_sp) return SIGIL_TRUE;251
sp_create(&g_sp);252
if (argc > 0) {253
g_sp->sr = (int)as_number(args[0]);254
}255
return SIGIL_TRUE;256
}258
/* (dsp-shutdown) */259
static Value native_dsp_shutdown(SigilVM *vm, int argc, Value *args)260
{261
(void)vm; (void)argc; (void)args;262
if (g_sp) {263
sp_destroy(&g_sp);264
g_sp = NULL;265
}266
return SIGIL_NIL;267
}269
/* (dsp-sample-rate) -> fixnum */270
static Value native_dsp_sample_rate(SigilVM *vm, int argc, Value *args)271
{272
(void)argc; (void)args;273
CHECK_SP(vm, "dsp-sample-rate");274
return sigil_fixnum(g_sp->sr);275
}277
/* ============================================================278
* FUNCTION TABLES279
* ============================================================ */281
/* (make-ftbl size) -> <ftbl> */282
static Value native_make_ftbl(SigilVM *vm, int argc, Value *args)283
{284
CHECK_SP(vm, "make-ftbl");285
size_t size = (size_t)sigil_as_flonum(args[0]);286
sp_ftbl *ft;287
sp_ftbl_create(g_sp, &ft, size);288
ENSURE_TAG(vm, tt_ftbl, "dsp-ftbl");289
return sigil_make_foreign(vm, tt_ftbl, ft, destroy_ftbl,290
sizeof(sp_ftbl) + size * sizeof(SPFLOAT));291
}293
/* (ftbl-gen-sine ftbl) */294
static Value native_ftbl_gen_sine(SigilVM *vm, int argc, Value *args)295
{296
CHECK_SP(vm, "ftbl-gen-sine");297
ENSURE_TAG(vm, tt_ftbl, "dsp-ftbl");298
if (!sigil_is_foreign_type(args[0], tt_ftbl)) {299
sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "ftbl-gen-sine: expected ftbl");300
return SIGIL_FALSE;301
}302
sp_ftbl *ft = (sp_ftbl *)sigil_foreign_get_data(args[0]);303
sp_gen_sine(g_sp, ft);304
return SIGIL_NIL;305
}307
/* (ftbl-gen-triangle ftbl) */308
static Value native_ftbl_gen_triangle(SigilVM *vm, int argc, Value *args)309
{310
CHECK_SP(vm, "ftbl-gen-triangle");311
ENSURE_TAG(vm, tt_ftbl, "dsp-ftbl");312
if (!sigil_is_foreign_type(args[0], tt_ftbl)) {313
sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "ftbl-gen-triangle: expected ftbl");314
return SIGIL_FALSE;315
}316
sp_ftbl *ft = (sp_ftbl *)sigil_foreign_get_data(args[0]);317
sp_gen_triangle(g_sp, ft);318
return SIGIL_NIL;319
}321
/* (ftbl-gen-line ftbl argstring) */322
static Value native_ftbl_gen_line(SigilVM *vm, int argc, Value *args)323
{324
CHECK_SP(vm, "ftbl-gen-line");325
ENSURE_TAG(vm, tt_ftbl, "dsp-ftbl");326
if (!sigil_is_foreign_type(args[0], tt_ftbl)) {327
sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "ftbl-gen-line: expected ftbl");328
return SIGIL_FALSE;329
}330
if (!sigil_is_string(args[1])) {331
sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "ftbl-gen-line: expected string");332
return SIGIL_FALSE;333
}334
sp_ftbl *ft = (sp_ftbl *)sigil_foreign_get_data(args[0]);335
SigilString *s = (SigilString *)sigil_as_ptr(args[1]);336
sp_gen_line(g_sp, ft, s->data);337
return SIGIL_NIL;338
}340
/* ============================================================341
* OSCILLATORS342
* ============================================================ */344
/* (make-osc freq amp [phase]) -> <osc>345
* Wavetable oscillator with sine wave table */346
static Value native_make_osc(SigilVM *vm, int argc, Value *args)347
{348
CHECK_SP(vm, "make-osc");349
SPFLOAT freq = (SPFLOAT)sigil_as_flonum(args[0]);350
SPFLOAT amp = (SPFLOAT)sigil_as_flonum(args[1]);351
SPFLOAT phase = argc > 2 ? (SPFLOAT)sigil_as_flonum(args[2]) : 0.0f;353
sp_ftbl *ft;354
sp_ftbl_create(g_sp, &ft, 4096);355
sp_gen_sine(g_sp, ft);357
sp_osc *osc;358
sp_osc_create(&osc);359
sp_osc_init(g_sp, osc, ft, phase);360
osc->freq = freq;361
osc->amp = amp;363
dsp_osc *d = malloc(sizeof(dsp_osc));364
d->osc = osc;365
d->ft = ft;367
ENSURE_TAG(vm, tt_osc, "dsp-osc");368
return sigil_make_foreign(vm, tt_osc, d, destroy_osc,369
sizeof(dsp_osc) + sizeof(sp_osc) + 4096 * sizeof(SPFLOAT));370
}372
/* (make-osc-ft ftbl freq amp [phase]) -> <osc>373
* Wavetable oscillator with custom function table */374
static Value native_make_osc_ft(SigilVM *vm, int argc, Value *args)375
{376
CHECK_SP(vm, "make-osc-ft");377
ENSURE_TAG(vm, tt_ftbl, "dsp-ftbl");378
if (!sigil_is_foreign_type(args[0], tt_ftbl)) {379
sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "make-osc-ft: expected ftbl as first argument");380
return SIGIL_FALSE;381
}382
/* Note: the ftbl is NOT owned by this osc — caller manages its lifetime */383
sp_ftbl *ft = (sp_ftbl *)sigil_foreign_get_data(args[0]);384
SPFLOAT freq = (SPFLOAT)sigil_as_flonum(args[1]);385
SPFLOAT amp = (SPFLOAT)sigil_as_flonum(args[2]);386
SPFLOAT phase = argc > 3 ? (SPFLOAT)sigil_as_flonum(args[3]) : 0.0f;388
sp_osc *osc;389
sp_osc_create(&osc);390
sp_osc_init(g_sp, osc, ft, phase);391
osc->freq = freq;392
osc->amp = amp;394
dsp_osc *d = malloc(sizeof(dsp_osc));395
d->osc = osc;396
d->ft = NULL; /* not owned */398
ENSURE_TAG(vm, tt_osc, "dsp-osc");399
return sigil_make_foreign(vm, tt_osc, d, destroy_osc,400
sizeof(dsp_osc) + sizeof(sp_osc));401
}403
/* (osc-compute osc) -> flonum */404
static Value native_osc_compute(SigilVM *vm, int argc, Value *args)405
{406
dsp_osc *d = get_osc(vm, args[0]);407
if (!d) { sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "osc-compute: expected osc"); return SIGIL_FALSE; }408
SPFLOAT in = 0, out = 0;409
sp_osc_compute(g_sp, d->osc, &in, &out);410
return sigil_flonum((double)out);411
}413
/* (osc-set-freq! osc freq) */414
static Value native_osc_set_freq(SigilVM *vm, int argc, Value *args)415
{416
dsp_osc *d = get_osc(vm, args[0]);417
if (!d) { sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "osc-set-freq!: expected osc"); return SIGIL_FALSE; }418
d->osc->freq = (SPFLOAT)sigil_as_flonum(args[1]);419
return SIGIL_NIL;420
}422
/* (osc-set-amp! osc amp) */423
static Value native_osc_set_amp(SigilVM *vm, int argc, Value *args)424
{425
dsp_osc *d = get_osc(vm, args[0]);426
if (!d) { sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "osc-set-amp!: expected osc"); return SIGIL_FALSE; }427
d->osc->amp = (SPFLOAT)sigil_as_flonum(args[1]);428
return SIGIL_NIL;429
}431
/* (make-posc3 freq amp [phase]) -> <posc3> */432
static Value native_make_posc3(SigilVM *vm, int argc, Value *args)433
{434
CHECK_SP(vm, "make-posc3");435
SPFLOAT freq = (SPFLOAT)sigil_as_flonum(args[0]);436
SPFLOAT amp = (SPFLOAT)sigil_as_flonum(args[1]);438
sp_ftbl *ft;439
sp_ftbl_create(g_sp, &ft, 4096);440
sp_gen_sine(g_sp, ft);442
sp_posc3 *osc;443
sp_posc3_create(&osc);444
sp_posc3_init(g_sp, osc, ft);445
osc->freq = freq;446
osc->amp = amp;448
dsp_posc3 *d = malloc(sizeof(dsp_posc3));449
d->osc = osc;450
d->ft = ft;452
ENSURE_TAG(vm, tt_posc3, "dsp-posc3");453
return sigil_make_foreign(vm, tt_posc3, d, destroy_posc3,454
sizeof(dsp_posc3) + sizeof(sp_posc3) + 4096 * sizeof(SPFLOAT));455
}457
/* (posc3-compute osc) -> flonum */458
static Value native_posc3_compute(SigilVM *vm, int argc, Value *args)459
{460
dsp_posc3 *d = get_posc3(vm, args[0]);461
if (!d) { sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "posc3-compute: expected posc3"); return SIGIL_FALSE; }462
SPFLOAT in = 0, out = 0;463
sp_posc3_compute(g_sp, d->osc, &in, &out);464
return sigil_flonum((double)out);465
}467
/* (posc3-set-freq! osc freq) */468
static Value native_posc3_set_freq(SigilVM *vm, int argc, Value *args)469
{470
dsp_posc3 *d = get_posc3(vm, args[0]);471
if (!d) { sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "posc3-set-freq!: expected posc3"); return SIGIL_FALSE; }472
d->osc->freq = (SPFLOAT)sigil_as_flonum(args[1]);473
return SIGIL_NIL;474
}476
/* (posc3-set-amp! osc amp) */477
static Value native_posc3_set_amp(SigilVM *vm, int argc, Value *args)478
{479
dsp_posc3 *d = get_posc3(vm, args[0]);480
if (!d) { sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "posc3-set-amp!: expected posc3"); return SIGIL_FALSE; }481
d->osc->amp = (SPFLOAT)sigil_as_flonum(args[1]);482
return SIGIL_NIL;483
}485
/* (make-blsaw freq amp) -> <blsaw> */486
static Value native_make_blsaw(SigilVM *vm, int argc, Value *args)487
{488
CHECK_SP(vm, "make-blsaw");489
SPFLOAT freq = (SPFLOAT)sigil_as_flonum(args[0]);490
SPFLOAT amp = (SPFLOAT)sigil_as_flonum(args[1]);492
sp_blsaw *p;493
sp_blsaw_create(&p);494
sp_blsaw_init(g_sp, p);495
*p->freq = freq;496
*p->amp = amp;498
ENSURE_TAG(vm, tt_blsaw, "dsp-blsaw");499
return sigil_make_foreign(vm, tt_blsaw, p, destroy_blsaw, sizeof(sp_blsaw));500
}502
/* (blsaw-compute osc) -> flonum */503
static Value native_blsaw_compute(SigilVM *vm, int argc, Value *args)504
{505
sp_blsaw *p = get_blsaw(vm, args[0]);506
if (!p) { sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "blsaw-compute: expected blsaw"); return SIGIL_FALSE; }507
SPFLOAT in = 0, out = 0;508
sp_blsaw_compute(g_sp, p, &in, &out);509
return sigil_flonum((double)out);510
}512
/* (blsaw-set-freq! osc freq) */513
static Value native_blsaw_set_freq(SigilVM *vm, int argc, Value *args)514
{515
sp_blsaw *p = get_blsaw(vm, args[0]);516
if (!p) { sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "blsaw-set-freq!: expected blsaw"); return SIGIL_FALSE; }517
*p->freq = (SPFLOAT)sigil_as_flonum(args[1]);518
return SIGIL_NIL;519
}521
/* (blsaw-set-amp! osc amp) */522
static Value native_blsaw_set_amp(SigilVM *vm, int argc, Value *args)523
{524
sp_blsaw *p = get_blsaw(vm, args[0]);525
if (!p) { sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "blsaw-set-amp!: expected blsaw"); return SIGIL_FALSE; }526
*p->amp = (SPFLOAT)sigil_as_flonum(args[1]);527
return SIGIL_NIL;528
}530
/* (make-blsquare freq amp [width]) -> <blsquare> */531
static Value native_make_blsquare(SigilVM *vm, int argc, Value *args)532
{533
CHECK_SP(vm, "make-blsquare");534
SPFLOAT freq = (SPFLOAT)sigil_as_flonum(args[0]);535
SPFLOAT amp = (SPFLOAT)sigil_as_flonum(args[1]);536
SPFLOAT width = argc > 2 ? (SPFLOAT)sigil_as_flonum(args[2]) : 0.5f;538
sp_blsquare *p;539
sp_blsquare_create(&p);540
sp_blsquare_init(g_sp, p);541
*p->freq = freq;542
*p->amp = amp;543
*p->width = width;545
ENSURE_TAG(vm, tt_blsquare, "dsp-blsquare");546
return sigil_make_foreign(vm, tt_blsquare, p, destroy_blsquare, sizeof(sp_blsquare));547
}549
/* (blsquare-compute osc) -> flonum */550
static Value native_blsquare_compute(SigilVM *vm, int argc, Value *args)551
{552
sp_blsquare *p = get_blsquare(vm, args[0]);553
if (!p) { sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "blsquare-compute: expected blsquare"); return SIGIL_FALSE; }554
SPFLOAT in = 0, out = 0;555
sp_blsquare_compute(g_sp, p, &in, &out);556
return sigil_flonum((double)out);557
}559
/* (blsquare-set-freq! osc freq) */560
static Value native_blsquare_set_freq(SigilVM *vm, int argc, Value *args)561
{562
sp_blsquare *p = get_blsquare(vm, args[0]);563
if (!p) { sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "blsquare-set-freq!: expected blsquare"); return SIGIL_FALSE; }564
*p->freq = (SPFLOAT)sigil_as_flonum(args[1]);565
return SIGIL_NIL;566
}568
/* (blsquare-set-amp! osc amp) */569
static Value native_blsquare_set_amp(SigilVM *vm, int argc, Value *args)570
{571
sp_blsquare *p = get_blsquare(vm, args[0]);572
if (!p) { sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "blsquare-set-amp!: expected blsquare"); return SIGIL_FALSE; }573
*p->amp = (SPFLOAT)sigil_as_flonum(args[1]);574
return SIGIL_NIL;575
}577
/* (make-bltriangle freq amp) -> <bltriangle> */578
static Value native_make_bltriangle(SigilVM *vm, int argc, Value *args)579
{580
CHECK_SP(vm, "make-bltriangle");581
SPFLOAT freq = (SPFLOAT)sigil_as_flonum(args[0]);582
SPFLOAT amp = (SPFLOAT)sigil_as_flonum(args[1]);584
sp_bltriangle *p;585
sp_bltriangle_create(&p);586
sp_bltriangle_init(g_sp, p);587
*p->freq = freq;588
*p->amp = amp;590
ENSURE_TAG(vm, tt_bltriangle, "dsp-bltriangle");591
return sigil_make_foreign(vm, tt_bltriangle, p, destroy_bltriangle, sizeof(sp_bltriangle));592
}594
/* (bltriangle-compute osc) -> flonum */595
static Value native_bltriangle_compute(SigilVM *vm, int argc, Value *args)596
{597
sp_bltriangle *p = get_bltriangle(vm, args[0]);598
if (!p) { sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "bltriangle-compute: expected bltriangle"); return SIGIL_FALSE; }599
SPFLOAT in = 0, out = 0;600
sp_bltriangle_compute(g_sp, p, &in, &out);601
return sigil_flonum((double)out);602
}604
/* (bltriangle-set-freq! osc freq) */605
static Value native_bltriangle_set_freq(SigilVM *vm, int argc, Value *args)606
{607
sp_bltriangle *p = get_bltriangle(vm, args[0]);608
if (!p) { sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "bltriangle-set-freq!: expected bltriangle"); return SIGIL_FALSE; }609
*p->freq = (SPFLOAT)sigil_as_flonum(args[1]);610
return SIGIL_NIL;611
}613
/* (bltriangle-set-amp! osc amp) */614
static Value native_bltriangle_set_amp(SigilVM *vm, int argc, Value *args)615
{616
sp_bltriangle *p = get_bltriangle(vm, args[0]);617
if (!p) { sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "bltriangle-set-amp!: expected bltriangle"); return SIGIL_FALSE; }618
*p->amp = (SPFLOAT)sigil_as_flonum(args[1]);619
return SIGIL_NIL;620
}622
/* (make-fosc freq car mod indx amp) -> <fosc> */623
static Value native_make_fosc(SigilVM *vm, int argc, Value *args)624
{625
CHECK_SP(vm, "make-fosc");626
SPFLOAT freq = (SPFLOAT)sigil_as_flonum(args[0]);627
SPFLOAT car = (SPFLOAT)sigil_as_flonum(args[1]);628
SPFLOAT mod = (SPFLOAT)sigil_as_flonum(args[2]);629
SPFLOAT indx = (SPFLOAT)sigil_as_flonum(args[3]);630
SPFLOAT amp = (SPFLOAT)sigil_as_flonum(args[4]);632
sp_ftbl *ft;633
sp_ftbl_create(g_sp, &ft, 4096);634
sp_gen_sine(g_sp, ft);636
sp_fosc *osc;637
sp_fosc_create(&osc);638
sp_fosc_init(g_sp, osc, ft);639
osc->freq = freq;640
osc->car = car;641
osc->mod = mod;642
osc->indx = indx;643
osc->amp = amp;645
dsp_fosc *d = malloc(sizeof(dsp_fosc));646
d->osc = osc;647
d->ft = ft;649
ENSURE_TAG(vm, tt_fosc, "dsp-fosc");650
return sigil_make_foreign(vm, tt_fosc, d, destroy_fosc,651
sizeof(dsp_fosc) + sizeof(sp_fosc) + 4096 * sizeof(SPFLOAT));652
}654
/* (fosc-compute osc) -> flonum */655
static Value native_fosc_compute(SigilVM *vm, int argc, Value *args)656
{657
dsp_fosc *d = get_fosc(vm, args[0]);658
if (!d) { sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "fosc-compute: expected fosc"); return SIGIL_FALSE; }659
SPFLOAT in = 0, out = 0;660
sp_fosc_compute(g_sp, d->osc, &in, &out);661
return sigil_flonum((double)out);662
}664
/* (fosc-set-freq! osc freq) */665
static Value native_fosc_set_freq(SigilVM *vm, int argc, Value *args)666
{667
dsp_fosc *d = get_fosc(vm, args[0]);668
if (!d) { sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "fosc-set-freq!: expected fosc"); return SIGIL_FALSE; }669
d->osc->freq = (SPFLOAT)sigil_as_flonum(args[1]);670
return SIGIL_NIL;671
}673
/* (fosc-set-index! osc indx) */674
static Value native_fosc_set_index(SigilVM *vm, int argc, Value *args)675
{676
dsp_fosc *d = get_fosc(vm, args[0]);677
if (!d) { sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "fosc-set-index!: expected fosc"); return SIGIL_FALSE; }678
d->osc->indx = (SPFLOAT)sigil_as_flonum(args[1]);679
return SIGIL_NIL;680
}682
/* (fosc-set-amp! osc amp) */683
static Value native_fosc_set_amp(SigilVM *vm, int argc, Value *args)684
{685
dsp_fosc *d = get_fosc(vm, args[0]);686
if (!d) { sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "fosc-set-amp!: expected fosc"); return SIGIL_FALSE; }687
d->osc->amp = (SPFLOAT)sigil_as_flonum(args[1]);688
return SIGIL_NIL;689
}691
/* (make-phasor freq [phase]) -> <phasor> */692
static Value native_make_phasor(SigilVM *vm, int argc, Value *args)693
{694
CHECK_SP(vm, "make-phasor");695
SPFLOAT freq = (SPFLOAT)sigil_as_flonum(args[0]);696
SPFLOAT phase = argc > 1 ? (SPFLOAT)sigil_as_flonum(args[1]) : 0.0f;698
sp_phasor *p;699
sp_phasor_create(&p);700
sp_phasor_init(g_sp, p, phase);701
p->freq = freq;703
ENSURE_TAG(vm, tt_phasor, "dsp-phasor");704
return sigil_make_foreign(vm, tt_phasor, p, destroy_phasor, sizeof(sp_phasor));705
}707
/* (phasor-compute phasor) -> flonum */708
static Value native_phasor_compute(SigilVM *vm, int argc, Value *args)709
{710
sp_phasor *p = get_phasor(vm, args[0]);711
if (!p) { sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "phasor-compute: expected phasor"); return SIGIL_FALSE; }712
SPFLOAT in = 0, out = 0;713
sp_phasor_compute(g_sp, p, &in, &out);714
return sigil_flonum((double)out);715
}717
/* (phasor-set-freq! phasor freq) */718
static Value native_phasor_set_freq(SigilVM *vm, int argc, Value *args)719
{720
sp_phasor *p = get_phasor(vm, args[0]);721
if (!p) { sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "phasor-set-freq!: expected phasor"); return SIGIL_FALSE; }722
p->freq = (SPFLOAT)sigil_as_flonum(args[1]);723
return SIGIL_NIL;724
}726
/* ============================================================727
* FILTERS728
* ============================================================ */730
/* (make-moogladder freq res) -> <moogladder> */731
static Value native_make_moogladder(SigilVM *vm, int argc, Value *args)732
{733
CHECK_SP(vm, "make-moogladder");734
sp_moogladder *p;735
sp_moogladder_create(&p);736
sp_moogladder_init(g_sp, p);737
p->freq = (SPFLOAT)sigil_as_flonum(args[0]);738
p->res = (SPFLOAT)sigil_as_flonum(args[1]);739
ENSURE_TAG(vm, tt_moogladder, "dsp-moogladder");740
return sigil_make_foreign(vm, tt_moogladder, p, destroy_moogladder, sizeof(sp_moogladder));741
}743
/* (make-butlp freq) -> <butlp> */744
static Value native_make_butlp(SigilVM *vm, int argc, Value *args)745
{746
CHECK_SP(vm, "make-butlp");747
sp_butlp *p;748
sp_butlp_create(&p);749
sp_butlp_init(g_sp, p);750
p->freq = (SPFLOAT)sigil_as_flonum(args[0]);751
ENSURE_TAG(vm, tt_butlp, "dsp-butlp");752
return sigil_make_foreign(vm, tt_butlp, p, destroy_butlp, sizeof(sp_butlp));753
}755
/* (make-buthp freq) -> <buthp> */756
static Value native_make_buthp(SigilVM *vm, int argc, Value *args)757
{758
CHECK_SP(vm, "make-buthp");759
sp_buthp *p;760
sp_buthp_create(&p);761
sp_buthp_init(g_sp, p);762
p->freq = (SPFLOAT)sigil_as_flonum(args[0]);763
ENSURE_TAG(vm, tt_buthp, "dsp-buthp");764
return sigil_make_foreign(vm, tt_buthp, p, destroy_buthp, sizeof(sp_buthp));765
}767
/* (make-lpf18 cutoff res dist) -> <lpf18> */768
static Value native_make_lpf18(SigilVM *vm, int argc, Value *args)769
{770
CHECK_SP(vm, "make-lpf18");771
sp_lpf18 *p;772
sp_lpf18_create(&p);773
sp_lpf18_init(g_sp, p);774
p->cutoff = (SPFLOAT)sigil_as_flonum(args[0]);775
p->res = (SPFLOAT)sigil_as_flonum(args[1]);776
p->dist = (SPFLOAT)sigil_as_flonum(args[2]);777
ENSURE_TAG(vm, tt_lpf18, "dsp-lpf18");778
return sigil_make_foreign(vm, tt_lpf18, p, destroy_lpf18, sizeof(sp_lpf18));779
}781
/* (make-tone freq) -> <tone> */782
static Value native_make_tone(SigilVM *vm, int argc, Value *args)783
{784
CHECK_SP(vm, "make-tone");785
sp_tone *p;786
sp_tone_create(&p);787
sp_tone_init(g_sp, p);788
p->hp = (SPFLOAT)sigil_as_flonum(args[0]);789
ENSURE_TAG(vm, tt_tone, "dsp-tone");790
return sigil_make_foreign(vm, tt_tone, p, destroy_tone, sizeof(sp_tone));791
}793
/* (make-atone freq) -> <atone> */794
static Value native_make_atone(SigilVM *vm, int argc, Value *args)795
{796
CHECK_SP(vm, "make-atone");797
sp_atone *p;798
sp_atone_create(&p);799
sp_atone_init(g_sp, p);800
p->hp = (SPFLOAT)sigil_as_flonum(args[0]);801
ENSURE_TAG(vm, tt_atone, "dsp-atone");802
return sigil_make_foreign(vm, tt_atone, p, destroy_atone, sizeof(sp_atone));803
}805
/* (make-dcblock) -> <dcblock> */806
static Value native_make_dcblock(SigilVM *vm, int argc, Value *args)807
{808
CHECK_SP(vm, "make-dcblock");809
sp_dcblock *p;810
sp_dcblock_create(&p);811
sp_dcblock_init(g_sp, p);812
ENSURE_TAG(vm, tt_dcblock, "dsp-dcblock");813
return sigil_make_foreign(vm, tt_dcblock, p, destroy_dcblock, sizeof(sp_dcblock));814
}816
/* Generic filter compute: (filter-compute filter input) -> flonum */817
static Value native_filter_compute(SigilVM *vm, int argc, Value *args)818
{819
SPFLOAT in = (SPFLOAT)sigil_as_flonum(args[1]);820
SPFLOAT out = 0;822
/* Try each filter type */823
sp_moogladder *ml; sp_butlp *bl; sp_buthp *bh; sp_lpf18 *l18;824
sp_tone *tn; sp_atone *atn; sp_dcblock *dc;826
if ((ml = get_moogladder(vm, args[0]))) { sp_moogladder_compute(g_sp, ml, &in, &out); }827
else if ((bl = get_butlp(vm, args[0]))) { sp_butlp_compute(g_sp, bl, &in, &out); }828
else if ((bh = get_buthp(vm, args[0]))) { sp_buthp_compute(g_sp, bh, &in, &out); }829
else if ((l18 = get_lpf18(vm, args[0]))) { sp_lpf18_compute(g_sp, l18, &in, &out); }830
else if ((tn = get_tone(vm, args[0]))) { sp_tone_compute(g_sp, tn, &in, &out); }831
else if ((atn = get_atone(vm, args[0]))) { sp_atone_compute(g_sp, atn, &in, &out); }832
else if ((dc = get_dcblock(vm, args[0]))) { sp_dcblock_compute(g_sp, dc, &in, &out); }833
else {834
sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "filter-compute: expected filter object");835
return SIGIL_FALSE;836
}837
return sigil_flonum((double)out);838
}840
/* (filter-set-freq! filter freq) */841
static Value native_filter_set_freq(SigilVM *vm, int argc, Value *args)842
{843
SPFLOAT freq = (SPFLOAT)sigil_as_flonum(args[1]);844
sp_moogladder *ml; sp_butlp *bl; sp_buthp *bh; sp_lpf18 *l18;845
sp_tone *tn; sp_atone *atn;847
if ((ml = get_moogladder(vm, args[0]))) { ml->freq = freq; }848
else if ((bl = get_butlp(vm, args[0]))) { bl->freq = freq; }849
else if ((bh = get_buthp(vm, args[0]))) { bh->freq = freq; }850
else if ((l18 = get_lpf18(vm, args[0]))) { l18->cutoff = freq; }851
else if ((tn = get_tone(vm, args[0]))) { tn->hp = freq; }852
else if ((atn = get_atone(vm, args[0]))) { atn->hp = freq; }853
else {854
sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "filter-set-freq!: expected filter object");855
return SIGIL_FALSE;856
}857
return SIGIL_NIL;858
}860
/* (filter-set-res! filter res) — for moogladder, lpf18 */861
static Value native_filter_set_res(SigilVM *vm, int argc, Value *args)862
{863
SPFLOAT res = (SPFLOAT)sigil_as_flonum(args[1]);864
sp_moogladder *ml; sp_lpf18 *l18;866
if ((ml = get_moogladder(vm, args[0]))) { ml->res = res; }867
else if ((l18 = get_lpf18(vm, args[0]))) { l18->res = res; }868
else {869
sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "filter-set-res!: expected resonant filter");870
return SIGIL_FALSE;871
}872
return SIGIL_NIL;873
}875
/* ============================================================876
* ENVELOPES877
* ============================================================ */879
/* (make-adsr atk dec sus rel) -> <adsr> */880
static Value native_make_adsr(SigilVM *vm, int argc, Value *args)881
{882
CHECK_SP(vm, "make-adsr");883
sp_adsr *p;884
sp_adsr_create(&p);885
sp_adsr_init(g_sp, p);886
p->atk = (SPFLOAT)sigil_as_flonum(args[0]);887
p->dec = (SPFLOAT)sigil_as_flonum(args[1]);888
p->sus = (SPFLOAT)sigil_as_flonum(args[2]);889
p->rel = (SPFLOAT)sigil_as_flonum(args[3]);890
ENSURE_TAG(vm, tt_adsr, "dsp-adsr");891
return sigil_make_foreign(vm, tt_adsr, p, destroy_adsr, sizeof(sp_adsr));892
}894
/* (adsr-compute adsr gate) -> flonum */895
static Value native_adsr_compute(SigilVM *vm, int argc, Value *args)896
{897
sp_adsr *p = get_adsr(vm, args[0]);898
if (!p) { sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "adsr-compute: expected adsr"); return SIGIL_FALSE; }899
SPFLOAT gate = (SPFLOAT)sigil_as_flonum(args[1]);900
SPFLOAT out = 0;901
sp_adsr_compute(g_sp, p, &gate, &out);902
return sigil_flonum((double)out);903
}905
/* (make-tadsr atk dec sus rel) -> <tadsr> */906
static Value native_make_tadsr(SigilVM *vm, int argc, Value *args)907
{908
CHECK_SP(vm, "make-tadsr");909
sp_tadsr *p;910
sp_tadsr_create(&p);911
sp_tadsr_init(g_sp, p);912
p->atk = (SPFLOAT)sigil_as_flonum(args[0]);913
p->dec = (SPFLOAT)sigil_as_flonum(args[1]);914
p->sus = (SPFLOAT)sigil_as_flonum(args[2]);915
p->rel = (SPFLOAT)sigil_as_flonum(args[3]);916
ENSURE_TAG(vm, tt_tadsr, "dsp-tadsr");917
return sigil_make_foreign(vm, tt_tadsr, p, destroy_tadsr, sizeof(sp_tadsr));918
}920
/* (tadsr-compute tadsr trigger) -> flonum */921
static Value native_tadsr_compute(SigilVM *vm, int argc, Value *args)922
{923
sp_tadsr *p = get_tadsr(vm, args[0]);924
if (!p) { sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "tadsr-compute: expected tadsr"); return SIGIL_FALSE; }925
SPFLOAT trig = (SPFLOAT)sigil_as_flonum(args[1]);926
SPFLOAT out = 0;927
sp_tadsr_compute(g_sp, p, &trig, &out);928
return sigil_flonum((double)out);929
}931
/* (make-tenv atk hold rel) -> <tenv> */932
static Value native_make_tenv(SigilVM *vm, int argc, Value *args)933
{934
CHECK_SP(vm, "make-tenv");935
sp_tenv *p;936
sp_tenv_create(&p);937
sp_tenv_init(g_sp, p);938
p->atk = (SPFLOAT)sigil_as_flonum(args[0]);939
p->hold = (SPFLOAT)sigil_as_flonum(args[1]);940
p->rel = (SPFLOAT)sigil_as_flonum(args[2]);941
ENSURE_TAG(vm, tt_tenv, "dsp-tenv");942
return sigil_make_foreign(vm, tt_tenv, p, destroy_tenv, sizeof(sp_tenv));943
}945
/* (tenv-compute tenv trigger) -> flonum */946
static Value native_tenv_compute(SigilVM *vm, int argc, Value *args)947
{948
sp_tenv *p = get_tenv(vm, args[0]);949
if (!p) { sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "tenv-compute: expected tenv"); return SIGIL_FALSE; }950
SPFLOAT trig = (SPFLOAT)sigil_as_flonum(args[1]);951
SPFLOAT out = 0;952
sp_tenv_compute(g_sp, p, &trig, &out);953
return sigil_flonum((double)out);954
}956
/* (make-line a dur b) -> <line> */957
static Value native_make_line(SigilVM *vm, int argc, Value *args)958
{959
CHECK_SP(vm, "make-line");960
sp_line *p;961
sp_line_create(&p);962
sp_line_init(g_sp, p);963
p->a = (SPFLOAT)sigil_as_flonum(args[0]);964
p->dur = (SPFLOAT)sigil_as_flonum(args[1]);965
p->b = (SPFLOAT)sigil_as_flonum(args[2]);966
ENSURE_TAG(vm, tt_line, "dsp-line");967
return sigil_make_foreign(vm, tt_line, p, destroy_line, sizeof(sp_line));968
}970
/* (line-compute line trigger) -> flonum */971
static Value native_line_compute(SigilVM *vm, int argc, Value *args)972
{973
sp_line *p = get_line(vm, args[0]);974
if (!p) { sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "line-compute: expected line"); return SIGIL_FALSE; }975
SPFLOAT trig = (SPFLOAT)sigil_as_flonum(args[1]);976
SPFLOAT out = 0;977
sp_line_compute(g_sp, p, &trig, &out);978
return sigil_flonum((double)out);979
}981
/* (make-expon a dur b) -> <expon> */982
static Value native_make_expon(SigilVM *vm, int argc, Value *args)983
{984
CHECK_SP(vm, "make-expon");985
sp_expon *p;986
sp_expon_create(&p);987
sp_expon_init(g_sp, p);988
p->a = (SPFLOAT)sigil_as_flonum(args[0]);989
p->dur = (SPFLOAT)sigil_as_flonum(args[1]);990
p->b = (SPFLOAT)sigil_as_flonum(args[2]);991
ENSURE_TAG(vm, tt_expon, "dsp-expon");992
return sigil_make_foreign(vm, tt_expon, p, destroy_expon, sizeof(sp_expon));993
}995
/* (expon-compute expon trigger) -> flonum */996
static Value native_expon_compute(SigilVM *vm, int argc, Value *args)997
{998
sp_expon *p = get_expon(vm, args[0]);999
if (!p) { sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "expon-compute: expected expon"); return SIGIL_FALSE; }1000
SPFLOAT trig = (SPFLOAT)sigil_as_flonum(args[1]);1001
SPFLOAT out = 0;1002
sp_expon_compute(g_sp, p, &trig, &out);1003
return sigil_flonum((double)out);1004
}1006
/* (make-port smoothing) -> <port> */1007
static Value native_make_port(SigilVM *vm, int argc, Value *args)1008
{1009
CHECK_SP(vm, "make-port");1010
sp_port *p;1011
sp_port_create(&p);1012
sp_port_init(g_sp, p);1013
p->smooth = (SPFLOAT)sigil_as_flonum(args[0]);1014
ENSURE_TAG(vm, tt_port, "dsp-port");1015
return sigil_make_foreign(vm, tt_port, p, destroy_port, sizeof(sp_port));1016
}1018
/* (port-compute port input) -> flonum */1019
static Value native_port_compute(SigilVM *vm, int argc, Value *args)1020
{1021
sp_port *p = get_port(vm, args[0]);1022
if (!p) { sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "port-compute: expected port"); return SIGIL_FALSE; }1023
SPFLOAT in = (SPFLOAT)sigil_as_flonum(args[1]);1024
SPFLOAT out = 0;1025
sp_port_compute(g_sp, p, &in, &out);1026
return sigil_flonum((double)out);1027
}1029
/* ============================================================1030
* REVERB & DELAY1031
* ============================================================ */1033
/* (make-revsc feedback lpfreq) -> <revsc> */1034
static Value native_make_revsc(SigilVM *vm, int argc, Value *args)1035
{1036
CHECK_SP(vm, "make-revsc");1037
sp_revsc *p;1038
sp_revsc_create(&p);1039
sp_revsc_init(g_sp, p);1040
p->feedback = (SPFLOAT)sigil_as_flonum(args[0]);1041
p->lpfreq = (SPFLOAT)sigil_as_flonum(args[1]);1042
ENSURE_TAG(vm, tt_revsc, "dsp-revsc");1043
return sigil_make_foreign(vm, tt_revsc, p, destroy_revsc, sizeof(sp_revsc));1044
}1046
/* (revsc-compute revsc in-l in-r) -> (values out-l out-r) */1047
static Value native_revsc_compute(SigilVM *vm, int argc, Value *args)1048
{1049
sp_revsc *p = get_revsc(vm, args[0]);1050
if (!p) { sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "revsc-compute: expected revsc"); return SIGIL_FALSE; }1051
SPFLOAT inL = (SPFLOAT)sigil_as_flonum(args[1]);1052
SPFLOAT inR = (SPFLOAT)sigil_as_flonum(args[2]);1053
SPFLOAT outL = 0, outR = 0;1054
sp_revsc_compute(g_sp, p, &inL, &inR, &outL, &outR);1055
/* Return as a pair for simplicity */1056
Value l = sigil_flonum((double)outL);1057
Value r = sigil_flonum((double)outR);1058
return sigil_cons(vm,l, r);1059
}1061
/* (revsc-set-feedback! revsc feedback) */1062
static Value native_revsc_set_feedback(SigilVM *vm, int argc, Value *args)1063
{1064
sp_revsc *p = get_revsc(vm, args[0]);1065
if (!p) { sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "revsc-set-feedback!: expected revsc"); return SIGIL_FALSE; }1066
p->feedback = (SPFLOAT)sigil_as_flonum(args[1]);1067
return SIGIL_NIL;1068
}1070
/* (revsc-set-lpfreq! revsc lpfreq) */1071
static Value native_revsc_set_lpfreq(SigilVM *vm, int argc, Value *args)1072
{1073
sp_revsc *p = get_revsc(vm, args[0]);1074
if (!p) { sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "revsc-set-lpfreq!: expected revsc"); return SIGIL_FALSE; }1075
p->lpfreq = (SPFLOAT)sigil_as_flonum(args[1]);1076
return SIGIL_NIL;1077
}1079
/* (make-zitarev) -> <zitarev> */1080
static Value native_make_zitarev(SigilVM *vm, int argc, Value *args)1081
{1082
CHECK_SP(vm, "make-zitarev");1083
sp_zitarev *p;1084
sp_zitarev_create(&p);1085
sp_zitarev_init(g_sp, p);1086
ENSURE_TAG(vm, tt_zitarev, "dsp-zitarev");1087
return sigil_make_foreign(vm, tt_zitarev, p, destroy_zitarev, sizeof(sp_zitarev));1088
}1090
/* (zitarev-compute zitarev in-l in-r) -> (out-l . out-r) */1091
static Value native_zitarev_compute(SigilVM *vm, int argc, Value *args)1092
{1093
sp_zitarev *p = get_zitarev(vm, args[0]);1094
if (!p) { sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "zitarev-compute: expected zitarev"); return SIGIL_FALSE; }1095
SPFLOAT inL = (SPFLOAT)sigil_as_flonum(args[1]);1096
SPFLOAT inR = (SPFLOAT)sigil_as_flonum(args[2]);1097
SPFLOAT outL = 0, outR = 0;1098
sp_zitarev_compute(g_sp, p, &inL, &inR, &outL, &outR);1099
Value l = sigil_flonum((double)outL);1100
Value r = sigil_flonum((double)outR);1101
return sigil_cons(vm,l, r);1102
}1104
/* (zitarev-set-mix! zitarev mix) */1105
static Value native_zitarev_set_mix(SigilVM *vm, int argc, Value *args)1106
{1107
sp_zitarev *p = get_zitarev(vm, args[0]);1108
if (!p) { sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "zitarev-set-mix!: expected zitarev"); return SIGIL_FALSE; }1109
*p->mix = (SPFLOAT)sigil_as_flonum(args[1]);1110
return SIGIL_NIL;1111
}1113
/* (zitarev-set-level! zitarev level) */1114
static Value native_zitarev_set_level(SigilVM *vm, int argc, Value *args)1115
{1116
sp_zitarev *p = get_zitarev(vm, args[0]);1117
if (!p) { sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "zitarev-set-level!: expected zitarev"); return SIGIL_FALSE; }1118
*p->level = (SPFLOAT)sigil_as_flonum(args[1]);1119
return SIGIL_NIL;1120
}1122
/* (make-delay time feedback) -> <delay> */1123
static Value native_make_delay(SigilVM *vm, int argc, Value *args)1124
{1125
CHECK_SP(vm, "make-delay");1126
SPFLOAT time = (SPFLOAT)sigil_as_flonum(args[0]);1127
SPFLOAT feedback = (SPFLOAT)sigil_as_flonum(args[1]);1128
sp_delay *p;1129
sp_delay_create(&p);1130
sp_delay_init(g_sp, p, time);1131
p->feedback = feedback;1132
ENSURE_TAG(vm, tt_delay, "dsp-delay");1133
return sigil_make_foreign(vm, tt_delay, p, destroy_delay,1134
sizeof(sp_delay) + (size_t)(time * g_sp->sr) * sizeof(SPFLOAT));1135
}1137
/* (delay-compute delay input) -> flonum */1138
static Value native_delay_compute(SigilVM *vm, int argc, Value *args)1139
{1140
sp_delay *p = get_delay(vm, args[0]);1141
if (!p) { sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "delay-compute: expected delay"); return SIGIL_FALSE; }1142
SPFLOAT in = (SPFLOAT)sigil_as_flonum(args[1]);1143
SPFLOAT out = 0;1144
sp_delay_compute(g_sp, p, &in, &out);1145
return sigil_flonum((double)out);1146
}1148
/* (delay-set-feedback! delay feedback) */1149
static Value native_delay_set_feedback(SigilVM *vm, int argc, Value *args)1150
{1151
sp_delay *p = get_delay(vm, args[0]);1152
if (!p) { sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "delay-set-feedback!: expected delay"); return SIGIL_FALSE; }1153
p->feedback = (SPFLOAT)sigil_as_flonum(args[1]);1154
return SIGIL_NIL;1155
}1157
/* (make-vdelay maxdel feedback) -> <vdelay> */1158
static Value native_make_vdelay(SigilVM *vm, int argc, Value *args)1159
{1160
CHECK_SP(vm, "make-vdelay");1161
SPFLOAT maxdel = (SPFLOAT)sigil_as_flonum(args[0]);1162
SPFLOAT feedback = (SPFLOAT)sigil_as_flonum(args[1]);1163
sp_vdelay *p;1164
sp_vdelay_create(&p);1165
sp_vdelay_init(g_sp, p, maxdel);1166
p->feedback = feedback;1167
ENSURE_TAG(vm, tt_vdelay, "dsp-vdelay");1168
return sigil_make_foreign(vm, tt_vdelay, p, destroy_vdelay,1169
sizeof(sp_vdelay) + (size_t)(maxdel * g_sp->sr) * sizeof(SPFLOAT));1170
}1172
/* (vdelay-compute vdelay input) -> flonum */1173
static Value native_vdelay_compute(SigilVM *vm, int argc, Value *args)1174
{1175
sp_vdelay *p = get_vdelay(vm, args[0]);1176
if (!p) { sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "vdelay-compute: expected vdelay"); return SIGIL_FALSE; }1177
SPFLOAT in = (SPFLOAT)sigil_as_flonum(args[1]);1178
SPFLOAT out = 0;1179
sp_vdelay_compute(g_sp, p, &in, &out);1180
return sigil_flonum((double)out);1181
}1183
/* (vdelay-set-del! vdelay del) */1184
static Value native_vdelay_set_del(SigilVM *vm, int argc, Value *args)1185
{1186
sp_vdelay *p = get_vdelay(vm, args[0]);1187
if (!p) { sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "vdelay-set-del!: expected vdelay"); return SIGIL_FALSE; }1188
p->del = (SPFLOAT)sigil_as_flonum(args[1]);1189
return SIGIL_NIL;1190
}1192
/* (vdelay-set-feedback! vdelay feedback) */1193
static Value native_vdelay_set_feedback(SigilVM *vm, int argc, Value *args)1194
{1195
sp_vdelay *p = get_vdelay(vm, args[0]);1196
if (!p) { sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "vdelay-set-feedback!: expected vdelay"); return SIGIL_FALSE; }1197
p->feedback = (SPFLOAT)sigil_as_flonum(args[1]);1198
return SIGIL_NIL;1199
}1201
/* ============================================================1202
* NOISE1203
* ============================================================ */1205
/* (make-noise amp) -> <noise> */1206
static Value native_make_noise(SigilVM *vm, int argc, Value *args)1207
{1208
CHECK_SP(vm, "make-noise");1209
sp_noise *p;1210
sp_noise_create(&p);1211
sp_noise_init(g_sp, p);1212
p->amp = (SPFLOAT)sigil_as_flonum(args[0]);1213
ENSURE_TAG(vm, tt_noise, "dsp-noise");1214
return sigil_make_foreign(vm, tt_noise, p, destroy_noise, sizeof(sp_noise));1215
}1217
/* (noise-compute noise) -> flonum */1218
static Value native_noise_compute(SigilVM *vm, int argc, Value *args)1219
{1220
sp_noise *p = get_noise(vm, args[0]);1221
if (!p) { sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "noise-compute: expected noise"); return SIGIL_FALSE; }1222
SPFLOAT in = 0, out = 0;1223
sp_noise_compute(g_sp, p, &in, &out);1224
return sigil_flonum((double)out);1225
}1227
/* (make-pinknoise amp) -> <pinknoise> */1228
static Value native_make_pinknoise(SigilVM *vm, int argc, Value *args)1229
{1230
CHECK_SP(vm, "make-pinknoise");1231
sp_pinknoise *p;1232
sp_pinknoise_create(&p);1233
sp_pinknoise_init(g_sp, p);1234
p->amp = (SPFLOAT)sigil_as_flonum(args[0]);1235
ENSURE_TAG(vm, tt_pinknoise, "dsp-pinknoise");1236
return sigil_make_foreign(vm, tt_pinknoise, p, destroy_pinknoise, sizeof(sp_pinknoise));1237
}1239
/* (pinknoise-compute pinknoise) -> flonum */1240
static Value native_pinknoise_compute(SigilVM *vm, int argc, Value *args)1241
{1242
sp_pinknoise *p = get_pinknoise(vm, args[0]);1243
if (!p) { sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "pinknoise-compute: expected pinknoise"); return SIGIL_FALSE; }1244
SPFLOAT in = 0, out = 0;1245
sp_pinknoise_compute(g_sp, p, &in, &out);1246
return sigil_flonum((double)out);1247
}1249
/* (make-brown) -> <brown> */1250
static Value native_make_brown(SigilVM *vm, int argc, Value *args)1251
{1252
CHECK_SP(vm, "make-brown");1253
sp_brown *p;1254
sp_brown_create(&p);1255
sp_brown_init(g_sp, p);1256
ENSURE_TAG(vm, tt_brown, "dsp-brown");1257
return sigil_make_foreign(vm, tt_brown, p, destroy_brown, sizeof(sp_brown));1258
}1260
/* (brown-compute brown) -> flonum */1261
static Value native_brown_compute(SigilVM *vm, int argc, Value *args)1262
{1263
sp_brown *p = get_brown(vm, args[0]);1264
if (!p) { sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "brown-compute: expected brown"); return SIGIL_FALSE; }1265
SPFLOAT in = 0, out = 0;1266
sp_brown_compute(g_sp, p, &in, &out);1267
return sigil_flonum((double)out);1268
}1270
/* ============================================================1271
* KARPLUS-STRONG1272
* ============================================================ */1274
/* (make-ks freq decay excite-gain) -> <ks> */1275
static Value native_make_ks(SigilVM *vm, int argc, Value *args)1276
{1277
(void)argc;1278
CHECK_SP(vm, "make-ks");1279
SPFLOAT freq = (SPFLOAT)sigil_as_flonum(args[0]);1280
SPFLOAT decay = (SPFLOAT)sigil_as_flonum(args[1]);1281
SPFLOAT gain = (SPFLOAT)sigil_as_flonum(args[2]);1282
sp_ks *p;1283
sp_ks_create(&p);1284
sp_ks_init(g_sp, p, freq, decay, gain);1285
ENSURE_TAG(vm, tt_ks, "dsp-ks");1286
return sigil_make_foreign(vm, tt_ks, p, destroy_ks,1287
sizeof(sp_ks) + (size_t)p->bufcap * sizeof(SPFLOAT));1288
}1290
/* (ks-compute ks gate) -> flonum */1291
static Value native_ks_compute(SigilVM *vm, int argc, Value *args)1292
{1293
(void)argc;1294
sp_ks *p = get_ks(vm, args[0]);1295
if (!p) { sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "ks-compute: expected ks"); return SIGIL_FALSE; }1296
SPFLOAT gate = (SPFLOAT)sigil_as_flonum(args[1]);1297
SPFLOAT out = 0.0f;1298
sp_ks_compute(g_sp, p, &gate, &out);1299
return sigil_flonum((double)out);1300
}1302
/* (ks-trigger! ks) — manual excitation */1303
static Value native_ks_trigger(SigilVM *vm, int argc, Value *args)1304
{1305
(void)argc;1306
sp_ks *p = get_ks(vm, args[0]);1307
if (!p) { sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "ks-trigger!: expected ks"); return SIGIL_FALSE; }1308
sp_ks_trigger(g_sp, p);1309
return SIGIL_NIL;1310
}1312
/* (ks-set-freq! ks freq) */1313
static Value native_ks_set_freq(SigilVM *vm, int argc, Value *args)1314
{1315
(void)argc;1316
sp_ks *p = get_ks(vm, args[0]);1317
if (!p) { sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "ks-set-freq!: expected ks"); return SIGIL_FALSE; }1318
p->freq = (SPFLOAT)sigil_as_flonum(args[1]);1319
sp_ks_retune(g_sp, p);1320
return SIGIL_NIL;1321
}1323
/* (ks-set-decay! ks decay) */1324
static Value native_ks_set_decay(SigilVM *vm, int argc, Value *args)1325
{1326
(void)argc;1327
sp_ks *p = get_ks(vm, args[0]);1328
if (!p) { sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "ks-set-decay!: expected ks"); return SIGIL_FALSE; }1329
p->decay = (SPFLOAT)sigil_as_flonum(args[1]);1330
sp_ks_retune(g_sp, p);1331
return SIGIL_NIL;1332
}1334
/* (ks-set-excite-gain! ks gain) */1335
static Value native_ks_set_excite_gain(SigilVM *vm, int argc, Value *args)1336
{1337
(void)argc;1338
sp_ks *p = get_ks(vm, args[0]);1339
if (!p) { sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "ks-set-excite-gain!: expected ks"); return SIGIL_FALSE; }1340
p->excite_gain = (SPFLOAT)sigil_as_flonum(args[1]);1341
return SIGIL_NIL;1342
}1344
/* ============================================================1345
* DYNAMICS / WAVESHAPING1346
* ============================================================ */1348
/* (make-saturator drive dcoffset) -> <saturator> */1349
static Value native_make_saturator(SigilVM *vm, int argc, Value *args)1350
{1351
CHECK_SP(vm, "make-saturator");1352
sp_saturator *p;1353
sp_saturator_create(&p);1354
sp_saturator_init(g_sp, p);1355
p->drive = (SPFLOAT)sigil_as_flonum(args[0]);1356
p->dcoffset = (SPFLOAT)sigil_as_flonum(args[1]);1357
ENSURE_TAG(vm, tt_saturator, "dsp-saturator");1358
return sigil_make_foreign(vm, tt_saturator, p, destroy_saturator, sizeof(sp_saturator));1359
}1361
/* (saturator-compute saturator input) -> flonum */1362
static Value native_saturator_compute(SigilVM *vm, int argc, Value *args)1363
{1364
sp_saturator *p = get_saturator(vm, args[0]);1365
if (!p) { sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "saturator-compute: expected saturator"); return SIGIL_FALSE; }1366
SPFLOAT in = (SPFLOAT)sigil_as_flonum(args[1]);1367
SPFLOAT out = 0;1368
sp_saturator_compute(g_sp, p, &in, &out);1369
return sigil_flonum((double)out);1370
}1372
/* (make-clip limit) -> <clip> */1373
static Value native_make_clip(SigilVM *vm, int argc, Value *args)1374
{1375
CHECK_SP(vm, "make-clip");1376
sp_clip *p;1377
sp_clip_create(&p);1378
sp_clip_init(g_sp, p);1379
p->lim = (SPFLOAT)sigil_as_flonum(args[0]);1380
ENSURE_TAG(vm, tt_clip, "dsp-clip");1381
return sigil_make_foreign(vm, tt_clip, p, destroy_clip, sizeof(sp_clip));1382
}1384
/* (clip-compute clip input) -> flonum */1385
static Value native_clip_compute(SigilVM *vm, int argc, Value *args)1386
{1387
sp_clip *p = get_clip(vm, args[0]);1388
if (!p) { sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "clip-compute: expected clip"); return SIGIL_FALSE; }1389
SPFLOAT in = (SPFLOAT)sigil_as_flonum(args[1]);1390
SPFLOAT out = 0;1391
sp_clip_compute(g_sp, p, &in, &out);1392
return sigil_flonum((double)out);1393
}1395
/* (make-peaklim atk rel thresh) -> <peaklim> */1396
static Value native_make_peaklim(SigilVM *vm, int argc, Value *args)1397
{1398
CHECK_SP(vm, "make-peaklim");1399
sp_peaklim *p;1400
sp_peaklim_create(&p);1401
sp_peaklim_init(g_sp, p);1402
p->atk = (SPFLOAT)sigil_as_flonum(args[0]);1403
p->rel = (SPFLOAT)sigil_as_flonum(args[1]);1404
p->thresh = (SPFLOAT)sigil_as_flonum(args[2]);1405
ENSURE_TAG(vm, tt_peaklim, "dsp-peaklim");1406
return sigil_make_foreign(vm, tt_peaklim, p, destroy_peaklim, sizeof(sp_peaklim));1407
}1409
/* (peaklim-compute peaklim input) -> flonum */1410
static Value native_peaklim_compute(SigilVM *vm, int argc, Value *args)1411
{1412
sp_peaklim *p = get_peaklim(vm, args[0]);1413
if (!p) { sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "peaklim-compute: expected peaklim"); return SIGIL_FALSE; }1414
SPFLOAT in = (SPFLOAT)sigil_as_flonum(args[1]);1415
SPFLOAT out = 0;1416
sp_peaklim_compute(g_sp, p, &in, &out);1417
return sigil_flonum((double)out);1418
}1420
/* ============================================================1421
* SPATIAL — PAN21422
* ============================================================ */1424
/* (make-pan2 [pan]) -> <pan2> */1425
static Value native_make_pan2(SigilVM *vm, int argc, Value *args)1426
{1427
CHECK_SP(vm, "make-pan2");1428
sp_pan2 *p;1429
sp_pan2_create(&p);1430
sp_pan2_init(g_sp, p);1431
p->pan = argc > 0 ? (SPFLOAT)sigil_as_flonum(args[0]) : 0.5f;1432
ENSURE_TAG(vm, tt_pan2, "dsp-pan2");1433
return sigil_make_foreign(vm, tt_pan2, p, destroy_pan2, sizeof(sp_pan2));1434
}1436
/* (pan2-compute pan2 input) -> (left . right) */1437
static Value native_pan2_compute(SigilVM *vm, int argc, Value *args)1438
{1439
sp_pan2 *p = get_pan2(vm, args[0]);1440
if (!p) { sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "pan2-compute: expected pan2"); return SIGIL_FALSE; }1441
SPFLOAT in = (SPFLOAT)sigil_as_flonum(args[1]);1442
SPFLOAT outL = 0, outR = 0;1443
sp_pan2_compute(g_sp, p, &in, &outL, &outR);1444
Value l = sigil_flonum((double)outL);1445
Value r = sigil_flonum((double)outR);1446
return sigil_cons(vm,l, r);1447
}1449
/* (pan2-set-pan! pan2 pan) */1450
static Value native_pan2_set_pan(SigilVM *vm, int argc, Value *args)1451
{1452
sp_pan2 *p = get_pan2(vm, args[0]);1453
if (!p) { sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "pan2-set-pan!: expected pan2"); return SIGIL_FALSE; }1454
p->pan = (SPFLOAT)sigil_as_flonum(args[1]);1455
return SIGIL_NIL;1456
}1458
/* ============================================================1459
* TIMING1460
* ============================================================ */1462
/* (make-metro freq) -> <metro> */1463
static Value native_make_metro(SigilVM *vm, int argc, Value *args)1464
{1465
CHECK_SP(vm, "make-metro");1466
sp_metro *p;1467
sp_metro_create(&p);1468
sp_metro_init(g_sp, p);1469
p->freq = (SPFLOAT)sigil_as_flonum(args[0]);1470
ENSURE_TAG(vm, tt_metro, "dsp-metro");1471
return sigil_make_foreign(vm, tt_metro, p, destroy_metro, sizeof(sp_metro));1472
}1474
/* (metro-compute metro) -> flonum (0 or 1) */1475
static Value native_metro_compute(SigilVM *vm, int argc, Value *args)1476
{1477
sp_metro *p = get_metro(vm, args[0]);1478
if (!p) { sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "metro-compute: expected metro"); return SIGIL_FALSE; }1479
SPFLOAT in = 0, out = 0;1480
sp_metro_compute(g_sp, p, &in, &out);1481
return sigil_flonum((double)out);1482
}1484
/* (metro-set-freq! metro freq) */1485
static Value native_metro_set_freq(SigilVM *vm, int argc, Value *args)1486
{1487
sp_metro *p = get_metro(vm, args[0]);1488
if (!p) { sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "metro-set-freq!: expected metro"); return SIGIL_FALSE; }1489
p->freq = (SPFLOAT)sigil_as_flonum(args[1]);1490
return SIGIL_NIL;1491
}1493
/* (make-clock bpm subdiv) -> <clock> */1494
static Value native_make_clock(SigilVM *vm, int argc, Value *args)1495
{1496
CHECK_SP(vm, "make-clock");1497
sp_clock *p;1498
sp_clock_create(&p);1499
sp_clock_init(g_sp, p);1500
p->bpm = (SPFLOAT)sigil_as_flonum(args[0]);1501
p->subdiv = (SPFLOAT)sigil_as_flonum(args[1]);1502
ENSURE_TAG(vm, tt_clock, "dsp-clock");1503
return sigil_make_foreign(vm, tt_clock, p, destroy_clock, sizeof(sp_clock));1504
}1506
/* (clock-compute clock trigger) -> flonum (0 or 1) */1507
static Value native_clock_compute(SigilVM *vm, int argc, Value *args)1508
{1509
sp_clock *p = get_clock_mod(vm, args[0]);1510
if (!p) { sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "clock-compute: expected clock"); return SIGIL_FALSE; }1511
SPFLOAT trig = (SPFLOAT)sigil_as_flonum(args[1]);1512
SPFLOAT out = 0;1513
sp_clock_compute(g_sp, p, &trig, &out);1514
return sigil_flonum((double)out);1515
}1517
/* (clock-set-bpm! clock bpm) */1518
static Value native_clock_set_bpm(SigilVM *vm, int argc, Value *args)1519
{1520
sp_clock *p = get_clock_mod(vm, args[0]);1521
if (!p) { sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "clock-set-bpm!: expected clock"); return SIGIL_FALSE; }1522
p->bpm = (SPFLOAT)sigil_as_flonum(args[1]);1523
return SIGIL_NIL;1524
}1526
/* (make-tgate time) -> <tgate> */1527
static Value native_make_tgate(SigilVM *vm, int argc, Value *args)1528
{1529
CHECK_SP(vm, "make-tgate");1530
sp_tgate *p;1531
sp_tgate_create(&p);1532
sp_tgate_init(g_sp, p);1533
p->time = (SPFLOAT)sigil_as_flonum(args[0]);1534
ENSURE_TAG(vm, tt_tgate, "dsp-tgate");1535
return sigil_make_foreign(vm, tt_tgate, p, destroy_tgate, sizeof(sp_tgate));1536
}1538
/* (tgate-compute tgate trigger) -> flonum (0 or 1) */1539
static Value native_tgate_compute(SigilVM *vm, int argc, Value *args)1540
{1541
sp_tgate *p = get_tgate(vm, args[0]);1542
if (!p) { sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "tgate-compute: expected tgate"); return SIGIL_FALSE; }1543
SPFLOAT trig = (SPFLOAT)sigil_as_flonum(args[1]);1544
SPFLOAT out = 0;1545
sp_tgate_compute(g_sp, p, &trig, &out);1546
return sigil_flonum((double)out);1547
}1549
/* ============================================================1550
* MODULATION — RANDOM1551
* ============================================================ */1553
/* (make-randh min max freq) -> <randh> */1554
static Value native_make_randh(SigilVM *vm, int argc, Value *args)1555
{1556
CHECK_SP(vm, "make-randh");1557
sp_randh *p;1558
sp_randh_create(&p);1559
sp_randh_init(g_sp, p);1560
p->min = (SPFLOAT)sigil_as_flonum(args[0]);1561
p->max = (SPFLOAT)sigil_as_flonum(args[1]);1562
p->freq = (SPFLOAT)sigil_as_flonum(args[2]);1563
ENSURE_TAG(vm, tt_randh, "dsp-randh");1564
return sigil_make_foreign(vm, tt_randh, p, destroy_randh, sizeof(sp_randh));1565
}1567
/* (randh-compute randh) -> flonum */1568
static Value native_randh_compute(SigilVM *vm, int argc, Value *args)1569
{1570
sp_randh *p = get_randh(vm, args[0]);1571
if (!p) { sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "randh-compute: expected randh"); return SIGIL_FALSE; }1572
SPFLOAT in = 0, out = 0;1573
sp_randh_compute(g_sp, p, &in, &out);1574
return sigil_flonum((double)out);1575
}1577
/* (make-randi min max freq) -> <randi> */1578
static Value native_make_randi(SigilVM *vm, int argc, Value *args)1579
{1580
CHECK_SP(vm, "make-randi");1581
sp_randi *p;1582
sp_randi_create(&p);1583
sp_randi_init(g_sp, p);1584
p->min = (SPFLOAT)sigil_as_flonum(args[0]);1585
p->max = (SPFLOAT)sigil_as_flonum(args[1]);1586
p->cps = (SPFLOAT)sigil_as_flonum(args[2]);1587
ENSURE_TAG(vm, tt_randi, "dsp-randi");1588
return sigil_make_foreign(vm, tt_randi, p, destroy_randi, sizeof(sp_randi));1589
}1591
/* (randi-compute randi) -> flonum */1592
static Value native_randi_compute(SigilVM *vm, int argc, Value *args)1593
{1594
sp_randi *p = get_randi(vm, args[0]);1595
if (!p) { sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "randi-compute: expected randi"); return SIGIL_FALSE; }1596
SPFLOAT in = 0, out = 0;1597
sp_randi_compute(g_sp, p, &in, &out);1598
return sigil_flonum((double)out);1599
}1601
/* ============================================================1602
* UTILITY1603
* ============================================================ */1605
/* (make-scale min max) -> <scale> */1606
static Value native_make_scale(SigilVM *vm, int argc, Value *args)1607
{1608
CHECK_SP(vm, "make-scale");1609
sp_scale *p;1610
sp_scale_create(&p);1611
sp_scale_init(g_sp, p);1612
p->min = (SPFLOAT)sigil_as_flonum(args[0]);1613
p->max = (SPFLOAT)sigil_as_flonum(args[1]);1614
ENSURE_TAG(vm, tt_scale, "dsp-scale");1615
return sigil_make_foreign(vm, tt_scale, p, destroy_scale, sizeof(sp_scale));1616
}1618
/* (scale-compute scale input) -> flonum */1619
static Value native_scale_compute(SigilVM *vm, int argc, Value *args)1620
{1621
sp_scale *p = get_scale(vm, args[0]);1622
if (!p) { sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "scale-compute: expected scale"); return SIGIL_FALSE; }1623
SPFLOAT in = (SPFLOAT)sigil_as_flonum(args[1]);1624
SPFLOAT out = 0;1625
sp_scale_compute(g_sp, p, &in, &out);1626
return sigil_flonum((double)out);1627
}1629
/* (make-clamp min max) -> <clamp> */1630
static Value native_make_clamp(SigilVM *vm, int argc, Value *args)1631
{1632
CHECK_SP(vm, "make-clamp");1633
sp_clamp *p;1634
sp_clamp_create(&p);1635
sp_clamp_init(g_sp, p);1636
p->min = (SPFLOAT)sigil_as_flonum(args[0]);1637
p->max = (SPFLOAT)sigil_as_flonum(args[1]);1638
ENSURE_TAG(vm, tt_clamp, "dsp-clamp");1639
return sigil_make_foreign(vm, tt_clamp, p, destroy_clamp, sizeof(sp_clamp));1640
}1642
/* (clamp-compute clamp input) -> flonum */1643
static Value native_clamp_compute(SigilVM *vm, int argc, Value *args)1644
{1645
sp_clamp *p = get_clamp(vm, args[0]);1646
if (!p) { sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "clamp-compute: expected clamp"); return SIGIL_FALSE; }1647
SPFLOAT in = (SPFLOAT)sigil_as_flonum(args[1]);1648
SPFLOAT out = 0;1649
sp_clamp_compute(g_sp, p, &in, &out);1650
return sigil_flonum((double)out);1651
}1653
/* (make-crossfade [pos]) -> <crossfade> */1654
static Value native_make_crossfade(SigilVM *vm, int argc, Value *args)1655
{1656
CHECK_SP(vm, "make-crossfade");1657
sp_crossfade *p;1658
sp_crossfade_create(&p);1659
sp_crossfade_init(g_sp, p);1660
p->pos = argc > 0 ? (SPFLOAT)sigil_as_flonum(args[0]) : 0.5f;1661
ENSURE_TAG(vm, tt_crossfade, "dsp-crossfade");1662
return sigil_make_foreign(vm, tt_crossfade, p, destroy_crossfade, sizeof(sp_crossfade));1663
}1665
/* (crossfade-compute crossfade in1 in2) -> flonum */1666
static Value native_crossfade_compute(SigilVM *vm, int argc, Value *args)1667
{1668
sp_crossfade *p = get_crossfade(vm, args[0]);1669
if (!p) { sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "crossfade-compute: expected crossfade"); return SIGIL_FALSE; }1670
SPFLOAT in1 = (SPFLOAT)sigil_as_flonum(args[1]);1671
SPFLOAT in2 = (SPFLOAT)sigil_as_flonum(args[2]);1672
SPFLOAT out = 0;1673
sp_crossfade_compute(g_sp, p, &in1, &in2, &out);1674
return sigil_flonum((double)out);1675
}1677
/* (crossfade-set-pos! crossfade pos) */1678
static Value native_crossfade_set_pos(SigilVM *vm, int argc, Value *args)1679
{1680
sp_crossfade *p = get_crossfade(vm, args[0]);1681
if (!p) { sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "crossfade-set-pos!: expected crossfade"); return SIGIL_FALSE; }1682
p->pos = (SPFLOAT)sigil_as_flonum(args[1]);1683
return SIGIL_NIL;1684
}1686
/* ============================================================1687
* WAV OUTPUT1688
* ============================================================ */1690
/* (make-wavout filename) -> <wavout> */1691
static Value native_make_wavout(SigilVM *vm, int argc, Value *args)1692
{1693
CHECK_SP(vm, "make-wavout");1694
if (!sigil_is_string(args[0])) {1695
sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "make-wavout: expected string filename");1696
return SIGIL_FALSE;1697
}1698
SigilString *s = (SigilString *)sigil_as_ptr(args[0]);1699
sp_wavout *p;1700
sp_wavout_create(&p);1701
sp_wavout_init(g_sp, p, s->data);1702
ENSURE_TAG(vm, tt_wavout, "dsp-wavout");1703
return sigil_make_foreign(vm, tt_wavout, p, destroy_wavout, 0);1704
}1706
/* (wavout-compute wavout sample) -> flonum */1707
static Value native_wavout_compute(SigilVM *vm, int argc, Value *args)1708
{1709
sp_wavout *p = get_wavout(vm, args[0]);1710
if (!p) { sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "wavout-compute: expected wavout"); return SIGIL_FALSE; }1711
SPFLOAT in = (SPFLOAT)sigil_as_flonum(args[1]);1712
SPFLOAT out = 0;1713
sp_wavout_compute(g_sp, p, &in, &out);1714
return sigil_flonum((double)out);1715
}1717
/* ============================================================1718
* MODULE INITIALIZATION1719
* ============================================================ */1721
void sigil__init_sigil_dsp_module(SigilVM *vm)1722
{1723
/* === (sigil dsp core) === */1724
SigilModule *mod = sigil_begin_module(vm, "(sigil dsp core)");1725
if (!mod) return;1727
sigil_module_register_native(vm, "dsp-init", native_dsp_init,1728
SIGIL_ARITY_RANGE(0, 1), "Initialize DSP engine");1729
sigil_module_register_native(vm, "dsp-shutdown", native_dsp_shutdown,1730
SIGIL_ARITY_EXACT(0), "Shutdown DSP engine");1731
sigil_module_register_native(vm, "dsp-sample-rate", native_dsp_sample_rate,1732
SIGIL_ARITY_EXACT(0), "Get sample rate");1734
/* Function tables */1735
sigil_module_register_native(vm, "make-ftbl", native_make_ftbl,1736
SIGIL_ARITY_EXACT(1), "Create function table");1737
sigil_module_register_native(vm, "ftbl-gen-sine", native_ftbl_gen_sine,1738
SIGIL_ARITY_EXACT(1), "Fill table with sine wave");1739
sigil_module_register_native(vm, "ftbl-gen-triangle", native_ftbl_gen_triangle,1740
SIGIL_ARITY_EXACT(1), "Fill table with triangle wave");1741
sigil_module_register_native(vm, "ftbl-gen-line", native_ftbl_gen_line,1742
SIGIL_ARITY_EXACT(2), "Fill table with line segments");1744
sigil_module_export(vm, "dsp-init");1745
sigil_module_export(vm, "dsp-shutdown");1746
sigil_module_export(vm, "dsp-sample-rate");1747
sigil_module_export(vm, "make-ftbl");1748
sigil_module_export(vm, "ftbl-gen-sine");1749
sigil_module_export(vm, "ftbl-gen-triangle");1750
sigil_module_export(vm, "ftbl-gen-line");1751
sigil_end_module(vm);1753
/* === (sigil dsp osc) === */1754
mod = sigil_begin_module(vm, "(sigil dsp osc)");1755
if (!mod) return;1757
sigil_module_register_native(vm, "make-osc", native_make_osc,1758
SIGIL_ARITY_RANGE(2, 3), "Create wavetable osc (freq amp [phase])");1759
sigil_module_register_native(vm, "make-osc-ft", native_make_osc_ft,1760
SIGIL_ARITY_RANGE(3, 4), "Create wavetable osc with custom ftbl");1761
sigil_module_register_native(vm, "osc-compute", native_osc_compute,1762
SIGIL_ARITY_EXACT(1), "Compute one sample from osc");1763
sigil_module_register_native(vm, "osc-set-freq!", native_osc_set_freq,1764
SIGIL_ARITY_EXACT(2), "Set osc frequency");1765
sigil_module_register_native(vm, "osc-set-amp!", native_osc_set_amp,1766
SIGIL_ARITY_EXACT(2), "Set osc amplitude");1768
sigil_module_register_native(vm, "make-posc3", native_make_posc3,1769
SIGIL_ARITY_RANGE(2, 3), "Create cubic interp wavetable osc");1770
sigil_module_register_native(vm, "posc3-compute", native_posc3_compute,1771
SIGIL_ARITY_EXACT(1), "Compute one sample from posc3");1772
sigil_module_register_native(vm, "posc3-set-freq!", native_posc3_set_freq,1773
SIGIL_ARITY_EXACT(2), "Set posc3 frequency");1774
sigil_module_register_native(vm, "posc3-set-amp!", native_posc3_set_amp,1775
SIGIL_ARITY_EXACT(2), "Set posc3 amplitude");1777
sigil_module_register_native(vm, "make-blsaw", native_make_blsaw,1778
SIGIL_ARITY_EXACT(2), "Create bandlimited sawtooth (freq amp)");1779
sigil_module_register_native(vm, "blsaw-compute", native_blsaw_compute,1780
SIGIL_ARITY_EXACT(1), "Compute one sample from blsaw");1781
sigil_module_register_native(vm, "blsaw-set-freq!", native_blsaw_set_freq,1782
SIGIL_ARITY_EXACT(2), "Set blsaw frequency");1783
sigil_module_register_native(vm, "blsaw-set-amp!", native_blsaw_set_amp,1784
SIGIL_ARITY_EXACT(2), "Set blsaw amplitude");1786
sigil_module_register_native(vm, "make-blsquare", native_make_blsquare,1787
SIGIL_ARITY_RANGE(2, 3), "Create bandlimited square (freq amp [width])");1788
sigil_module_register_native(vm, "blsquare-compute", native_blsquare_compute,1789
SIGIL_ARITY_EXACT(1), "Compute one sample from blsquare");1790
sigil_module_register_native(vm, "blsquare-set-freq!", native_blsquare_set_freq,1791
SIGIL_ARITY_EXACT(2), "Set blsquare frequency");1792
sigil_module_register_native(vm, "blsquare-set-amp!", native_blsquare_set_amp,1793
SIGIL_ARITY_EXACT(2), "Set blsquare amplitude");1795
sigil_module_register_native(vm, "make-bltriangle", native_make_bltriangle,1796
SIGIL_ARITY_EXACT(2), "Create bandlimited triangle (freq amp)");1797
sigil_module_register_native(vm, "bltriangle-compute", native_bltriangle_compute,1798
SIGIL_ARITY_EXACT(1), "Compute one sample from bltriangle");1799
sigil_module_register_native(vm, "bltriangle-set-freq!", native_bltriangle_set_freq,1800
SIGIL_ARITY_EXACT(2), "Set bltriangle frequency");1801
sigil_module_register_native(vm, "bltriangle-set-amp!", native_bltriangle_set_amp,1802
SIGIL_ARITY_EXACT(2), "Set bltriangle amplitude");1804
sigil_module_register_native(vm, "make-fosc", native_make_fosc,1805
SIGIL_ARITY_EXACT(5), "Create FM osc (freq car mod indx amp)");1806
sigil_module_register_native(vm, "fosc-compute", native_fosc_compute,1807
SIGIL_ARITY_EXACT(1), "Compute one sample from fosc");1808
sigil_module_register_native(vm, "fosc-set-freq!", native_fosc_set_freq,1809
SIGIL_ARITY_EXACT(2), "Set fosc frequency");1810
sigil_module_register_native(vm, "fosc-set-index!", native_fosc_set_index,1811
SIGIL_ARITY_EXACT(2), "Set fosc modulation index");1812
sigil_module_register_native(vm, "fosc-set-amp!", native_fosc_set_amp,1813
SIGIL_ARITY_EXACT(2), "Set fosc amplitude");1815
sigil_module_register_native(vm, "make-phasor", native_make_phasor,1816
SIGIL_ARITY_RANGE(1, 2), "Create phasor (freq [phase])");1817
sigil_module_register_native(vm, "phasor-compute", native_phasor_compute,1818
SIGIL_ARITY_EXACT(1), "Compute one sample from phasor");1819
sigil_module_register_native(vm, "phasor-set-freq!", native_phasor_set_freq,1820
SIGIL_ARITY_EXACT(2), "Set phasor frequency");1822
sigil_module_register_native(vm, "make-ks", native_make_ks,1823
SIGIL_ARITY_EXACT(3), "Create Karplus-Strong (freq decay excite-gain)");1824
sigil_module_register_native(vm, "ks-compute", native_ks_compute,1825
SIGIL_ARITY_EXACT(2), "Compute Karplus-Strong (ks gate) -> sample");1826
sigil_module_register_native(vm, "ks-trigger!", native_ks_trigger,1827
SIGIL_ARITY_EXACT(1), "Excite Karplus-Strong with noise burst");1828
sigil_module_register_native(vm, "ks-set-freq!", native_ks_set_freq,1829
SIGIL_ARITY_EXACT(2), "Set KS fundamental frequency");1830
sigil_module_register_native(vm, "ks-set-decay!", native_ks_set_decay,1831
SIGIL_ARITY_EXACT(2), "Set KS -60 dB decay time");1832
sigil_module_register_native(vm, "ks-set-excite-gain!", native_ks_set_excite_gain,1833
SIGIL_ARITY_EXACT(2), "Set KS excitation amplitude");1835
/* Export all osc bindings */1836
const char *osc_exports[] = {1837
"make-osc", "make-osc-ft", "osc-compute", "osc-set-freq!", "osc-set-amp!",1838
"make-posc3", "posc3-compute", "posc3-set-freq!", "posc3-set-amp!",1839
"make-blsaw", "blsaw-compute", "blsaw-set-freq!", "blsaw-set-amp!",1840
"make-blsquare", "blsquare-compute", "blsquare-set-freq!", "blsquare-set-amp!",1841
"make-bltriangle", "bltriangle-compute", "bltriangle-set-freq!", "bltriangle-set-amp!",1842
"make-fosc", "fosc-compute", "fosc-set-freq!", "fosc-set-index!", "fosc-set-amp!",1843
"make-phasor", "phasor-compute", "phasor-set-freq!",1844
"make-ks", "ks-compute", "ks-trigger!",1845
"ks-set-freq!", "ks-set-decay!", "ks-set-excite-gain!",1846
NULL1847
};1848
for (int i = 0; osc_exports[i]; i++) sigil_module_export(vm, osc_exports[i]);1849
sigil_end_module(vm);1851
/* === (sigil dsp filter) === */1852
mod = sigil_begin_module(vm, "(sigil dsp filter)");1853
if (!mod) return;1855
sigil_module_register_native(vm, "make-moogladder", native_make_moogladder,1856
SIGIL_ARITY_EXACT(2), "Create Moog ladder filter (freq res)");1857
sigil_module_register_native(vm, "make-butlp", native_make_butlp,1858
SIGIL_ARITY_EXACT(1), "Create Butterworth lowpass (freq)");1859
sigil_module_register_native(vm, "make-buthp", native_make_buthp,1860
SIGIL_ARITY_EXACT(1), "Create Butterworth highpass (freq)");1861
sigil_module_register_native(vm, "make-lpf18", native_make_lpf18,1862
SIGIL_ARITY_EXACT(3), "Create 3-pole resonant LP (cutoff res dist)");1863
sigil_module_register_native(vm, "make-tone", native_make_tone,1864
SIGIL_ARITY_EXACT(1), "Create 1st-order lowpass (freq)");1865
sigil_module_register_native(vm, "make-atone", native_make_atone,1866
SIGIL_ARITY_EXACT(1), "Create 1st-order highpass (freq)");1867
sigil_module_register_native(vm, "make-dcblock", native_make_dcblock,1868
SIGIL_ARITY_EXACT(0), "Create DC blocking filter");1869
sigil_module_register_native(vm, "filter-compute", native_filter_compute,1870
SIGIL_ARITY_EXACT(2), "Compute filter (filter input) -> output");1871
sigil_module_register_native(vm, "filter-set-freq!", native_filter_set_freq,1872
SIGIL_ARITY_EXACT(2), "Set filter cutoff frequency");1873
sigil_module_register_native(vm, "filter-set-res!", native_filter_set_res,1874
SIGIL_ARITY_EXACT(2), "Set filter resonance");1876
const char *filter_exports[] = {1877
"make-moogladder", "make-butlp", "make-buthp", "make-lpf18",1878
"make-tone", "make-atone", "make-dcblock",1879
"filter-compute", "filter-set-freq!", "filter-set-res!",1880
NULL1881
};1882
for (int i = 0; filter_exports[i]; i++) sigil_module_export(vm, filter_exports[i]);1883
sigil_end_module(vm);1885
/* === (sigil dsp env) === */1886
mod = sigil_begin_module(vm, "(sigil dsp env)");1887
if (!mod) return;1889
sigil_module_register_native(vm, "make-adsr", native_make_adsr,1890
SIGIL_ARITY_EXACT(4), "Create ADSR envelope (atk dec sus rel)");1891
sigil_module_register_native(vm, "adsr-compute", native_adsr_compute,1892
SIGIL_ARITY_EXACT(2), "Compute ADSR (adsr gate) -> env value");1893
sigil_module_register_native(vm, "make-tadsr", native_make_tadsr,1894
SIGIL_ARITY_EXACT(4), "Create triggered ADSR (atk dec sus rel)");1895
sigil_module_register_native(vm, "tadsr-compute", native_tadsr_compute,1896
SIGIL_ARITY_EXACT(2), "Compute triggered ADSR");1897
sigil_module_register_native(vm, "make-tenv", native_make_tenv,1898
SIGIL_ARITY_EXACT(3), "Create triggered envelope (atk hold rel)");1899
sigil_module_register_native(vm, "tenv-compute", native_tenv_compute,1900
SIGIL_ARITY_EXACT(2), "Compute triggered envelope");1901
sigil_module_register_native(vm, "make-line", native_make_line,1902
SIGIL_ARITY_EXACT(3), "Create line segment (a dur b)");1903
sigil_module_register_native(vm, "line-compute", native_line_compute,1904
SIGIL_ARITY_EXACT(2), "Compute line segment");1905
sigil_module_register_native(vm, "make-expon", native_make_expon,1906
SIGIL_ARITY_EXACT(3), "Create exponential curve (a dur b)");1907
sigil_module_register_native(vm, "expon-compute", native_expon_compute,1908
SIGIL_ARITY_EXACT(2), "Compute exponential curve");1909
sigil_module_register_native(vm, "make-port", native_make_port,1910
SIGIL_ARITY_EXACT(1), "Create portamento (smoothing)");1911
sigil_module_register_native(vm, "port-compute", native_port_compute,1912
SIGIL_ARITY_EXACT(2), "Compute portamento");1914
const char *env_exports[] = {1915
"make-adsr", "adsr-compute", "make-tadsr", "tadsr-compute",1916
"make-tenv", "tenv-compute", "make-line", "line-compute",1917
"make-expon", "expon-compute", "make-port", "port-compute",1918
NULL1919
};1920
for (int i = 0; env_exports[i]; i++) sigil_module_export(vm, env_exports[i]);1921
sigil_end_module(vm);1923
/* === (sigil dsp fx) === */1924
mod = sigil_begin_module(vm, "(sigil dsp fx)");1925
if (!mod) return;1927
sigil_module_register_native(vm, "make-revsc", native_make_revsc,1928
SIGIL_ARITY_EXACT(2), "Create stereo reverb (feedback lpfreq)");1929
sigil_module_register_native(vm, "revsc-compute", native_revsc_compute,1930
SIGIL_ARITY_EXACT(3), "Compute reverb (revsc inL inR) -> (outL . outR)");1931
sigil_module_register_native(vm, "revsc-set-feedback!", native_revsc_set_feedback,1932
SIGIL_ARITY_EXACT(2), "Set reverb feedback");1933
sigil_module_register_native(vm, "revsc-set-lpfreq!", native_revsc_set_lpfreq,1934
SIGIL_ARITY_EXACT(2), "Set reverb LP frequency");1936
sigil_module_register_native(vm, "make-zitarev", native_make_zitarev,1937
SIGIL_ARITY_EXACT(0), "Create Zita reverb");1938
sigil_module_register_native(vm, "zitarev-compute", native_zitarev_compute,1939
SIGIL_ARITY_EXACT(3), "Compute Zita reverb");1940
sigil_module_register_native(vm, "zitarev-set-mix!", native_zitarev_set_mix,1941
SIGIL_ARITY_EXACT(2), "Set Zita reverb mix");1942
sigil_module_register_native(vm, "zitarev-set-level!", native_zitarev_set_level,1943
SIGIL_ARITY_EXACT(2), "Set Zita reverb level");1945
sigil_module_register_native(vm, "make-delay", native_make_delay,1946
SIGIL_ARITY_EXACT(2), "Create delay (time feedback)");1947
sigil_module_register_native(vm, "delay-compute", native_delay_compute,1948
SIGIL_ARITY_EXACT(2), "Compute delay (delay input) -> output");1949
sigil_module_register_native(vm, "delay-set-feedback!", native_delay_set_feedback,1950
SIGIL_ARITY_EXACT(2), "Set delay feedback");1952
sigil_module_register_native(vm, "make-vdelay", native_make_vdelay,1953
SIGIL_ARITY_EXACT(2), "Create variable delay (maxdel feedback)");1954
sigil_module_register_native(vm, "vdelay-compute", native_vdelay_compute,1955
SIGIL_ARITY_EXACT(2), "Compute variable delay");1956
sigil_module_register_native(vm, "vdelay-set-del!", native_vdelay_set_del,1957
SIGIL_ARITY_EXACT(2), "Set variable delay time");1958
sigil_module_register_native(vm, "vdelay-set-feedback!", native_vdelay_set_feedback,1959
SIGIL_ARITY_EXACT(2), "Set variable delay feedback");1961
const char *fx_exports[] = {1962
"make-revsc", "revsc-compute", "revsc-set-feedback!", "revsc-set-lpfreq!",1963
"make-zitarev", "zitarev-compute", "zitarev-set-mix!", "zitarev-set-level!",1964
"make-delay", "delay-compute", "delay-set-feedback!",1965
"make-vdelay", "vdelay-compute", "vdelay-set-del!", "vdelay-set-feedback!",1966
NULL1967
};1968
for (int i = 0; fx_exports[i]; i++) sigil_module_export(vm, fx_exports[i]);1969
sigil_end_module(vm);1971
/* === (sigil dsp noise) === */1972
mod = sigil_begin_module(vm, "(sigil dsp noise)");1973
if (!mod) return;1975
sigil_module_register_native(vm, "make-noise", native_make_noise,1976
SIGIL_ARITY_EXACT(1), "Create white noise (amp)");1977
sigil_module_register_native(vm, "noise-compute", native_noise_compute,1978
SIGIL_ARITY_EXACT(1), "Compute one noise sample");1979
sigil_module_register_native(vm, "make-pinknoise", native_make_pinknoise,1980
SIGIL_ARITY_EXACT(1), "Create pink noise (amp)");1981
sigil_module_register_native(vm, "pinknoise-compute", native_pinknoise_compute,1982
SIGIL_ARITY_EXACT(1), "Compute one pinknoise sample");1983
sigil_module_register_native(vm, "make-brown", native_make_brown,1984
SIGIL_ARITY_EXACT(0), "Create brown noise");1985
sigil_module_register_native(vm, "brown-compute", native_brown_compute,1986
SIGIL_ARITY_EXACT(1), "Compute one brown noise sample");1988
const char *noise_exports[] = {1989
"make-noise", "noise-compute",1990
"make-pinknoise", "pinknoise-compute",1991
"make-brown", "brown-compute",1992
NULL1993
};1994
for (int i = 0; noise_exports[i]; i++) sigil_module_export(vm, noise_exports[i]);1995
sigil_end_module(vm);1997
/* === (sigil dsp util) === */1998
mod = sigil_begin_module(vm, "(sigil dsp util)");1999
if (!mod) return;2001
/* Dynamics */2002
sigil_module_register_native(vm, "make-saturator", native_make_saturator,2003
SIGIL_ARITY_EXACT(2), "Create saturator (drive dcoffset)");2004
sigil_module_register_native(vm, "saturator-compute", native_saturator_compute,2005
SIGIL_ARITY_EXACT(2), "Compute saturator");2006
sigil_module_register_native(vm, "make-clip", native_make_clip,2007
SIGIL_ARITY_EXACT(1), "Create hard clipper (limit)");2008
sigil_module_register_native(vm, "clip-compute", native_clip_compute,2009
SIGIL_ARITY_EXACT(2), "Compute clipper");2010
sigil_module_register_native(vm, "make-peaklim", native_make_peaklim,2011
SIGIL_ARITY_EXACT(3), "Create peak limiter (atk rel thresh)");2012
sigil_module_register_native(vm, "peaklim-compute", native_peaklim_compute,2013
SIGIL_ARITY_EXACT(2), "Compute peak limiter");2015
/* Panning */2016
sigil_module_register_native(vm, "make-pan2", native_make_pan2,2017
SIGIL_ARITY_RANGE(0, 1), "Create panner ([pan])");2018
sigil_module_register_native(vm, "pan2-compute", native_pan2_compute,2019
SIGIL_ARITY_EXACT(2), "Compute pan2 (pan2 input) -> (L . R)");2020
sigil_module_register_native(vm, "pan2-set-pan!", native_pan2_set_pan,2021
SIGIL_ARITY_EXACT(2), "Set pan position");2023
/* Timing */2024
sigil_module_register_native(vm, "make-metro", native_make_metro,2025
SIGIL_ARITY_EXACT(1), "Create metronome (freq)");2026
sigil_module_register_native(vm, "metro-compute", native_metro_compute,2027
SIGIL_ARITY_EXACT(1), "Compute metronome");2028
sigil_module_register_native(vm, "metro-set-freq!", native_metro_set_freq,2029
SIGIL_ARITY_EXACT(2), "Set metronome frequency");2030
sigil_module_register_native(vm, "make-clock", native_make_clock,2031
SIGIL_ARITY_EXACT(2), "Create clock (bpm subdiv)");2032
sigil_module_register_native(vm, "clock-compute", native_clock_compute,2033
SIGIL_ARITY_EXACT(2), "Compute clock");2034
sigil_module_register_native(vm, "clock-set-bpm!", native_clock_set_bpm,2035
SIGIL_ARITY_EXACT(2), "Set clock BPM");2036
sigil_module_register_native(vm, "make-tgate", native_make_tgate,2037
SIGIL_ARITY_EXACT(1), "Create triggered gate (time)");2038
sigil_module_register_native(vm, "tgate-compute", native_tgate_compute,2039
SIGIL_ARITY_EXACT(2), "Compute triggered gate");2041
/* Random */2042
sigil_module_register_native(vm, "make-randh", native_make_randh,2043
SIGIL_ARITY_EXACT(3), "Create random hold (min max freq)");2044
sigil_module_register_native(vm, "randh-compute", native_randh_compute,2045
SIGIL_ARITY_EXACT(1), "Compute random hold");2046
sigil_module_register_native(vm, "make-randi", native_make_randi,2047
SIGIL_ARITY_EXACT(3), "Create random interp (min max freq)");2048
sigil_module_register_native(vm, "randi-compute", native_randi_compute,2049
SIGIL_ARITY_EXACT(1), "Compute random interp");2051
/* Scaling */2052
sigil_module_register_native(vm, "make-scale", native_make_scale,2053
SIGIL_ARITY_EXACT(2), "Create scaler (min max)");2054
sigil_module_register_native(vm, "scale-compute", native_scale_compute,2055
SIGIL_ARITY_EXACT(2), "Compute scale");2056
sigil_module_register_native(vm, "make-clamp", native_make_clamp,2057
SIGIL_ARITY_EXACT(2), "Create clamp (min max)");2058
sigil_module_register_native(vm, "clamp-compute", native_clamp_compute,2059
SIGIL_ARITY_EXACT(2), "Compute clamp");2060
sigil_module_register_native(vm, "make-crossfade", native_make_crossfade,2061
SIGIL_ARITY_RANGE(0, 1), "Create crossfade ([pos])");2062
sigil_module_register_native(vm, "crossfade-compute", native_crossfade_compute,2063
SIGIL_ARITY_EXACT(3), "Compute crossfade (xf in1 in2)");2064
sigil_module_register_native(vm, "crossfade-set-pos!", native_crossfade_set_pos,2065
SIGIL_ARITY_EXACT(2), "Set crossfade position");2067
/* WAV output */2068
sigil_module_register_native(vm, "make-wavout", native_make_wavout,2069
SIGIL_ARITY_EXACT(1), "Create WAV file writer (filename)");2070
sigil_module_register_native(vm, "wavout-compute", native_wavout_compute,2071
SIGIL_ARITY_EXACT(2), "Write sample to WAV");2073
const char *util_exports[] = {2074
"make-saturator", "saturator-compute",2075
"make-clip", "clip-compute",2076
"make-peaklim", "peaklim-compute",2077
"make-pan2", "pan2-compute", "pan2-set-pan!",2078
"make-metro", "metro-compute", "metro-set-freq!",2079
"make-clock", "clock-compute", "clock-set-bpm!",2080
"make-tgate", "tgate-compute",2081
"make-randh", "randh-compute",2082
"make-randi", "randi-compute",2083
"make-scale", "scale-compute",2084
"make-clamp", "clamp-compute",2085
"make-crossfade", "crossfade-compute", "crossfade-set-pos!",2086
"make-wavout", "wavout-compute",2087
NULL2088
};2089
for (int i = 0; util_exports[i]; i++) sigil_module_export(vm, util_exports[i]);2090
sigil_end_module(vm);2091
}