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"17
#include "fm4.h"18
#include "fx4.h"20
/* ============================================================21
* GLOBAL STATE22
* ============================================================ */24
static sp_data *g_sp = NULL;26
/* Type tags for foreign objects */27
static Value tt_osc = SIGIL_UNDEFINED;28
static Value tt_posc3 = SIGIL_UNDEFINED;29
static Value tt_blsaw = SIGIL_UNDEFINED;30
static Value tt_blsquare = SIGIL_UNDEFINED;31
static Value tt_bltriangle = SIGIL_UNDEFINED;32
static Value tt_fosc = SIGIL_UNDEFINED;33
static Value tt_phasor = SIGIL_UNDEFINED;34
static Value tt_moogladder = SIGIL_UNDEFINED;35
static Value tt_butlp = SIGIL_UNDEFINED;36
static Value tt_buthp = SIGIL_UNDEFINED;37
static Value tt_lpf18 = SIGIL_UNDEFINED;38
static Value tt_tone = SIGIL_UNDEFINED;39
static Value tt_atone = SIGIL_UNDEFINED;40
static Value tt_dcblock = SIGIL_UNDEFINED;41
static Value tt_adsr = SIGIL_UNDEFINED;42
static Value tt_tadsr = SIGIL_UNDEFINED;43
static Value tt_tenv = SIGIL_UNDEFINED;44
static Value tt_line = SIGIL_UNDEFINED;45
static Value tt_expon = SIGIL_UNDEFINED;46
static Value tt_port = SIGIL_UNDEFINED;47
static Value tt_revsc = SIGIL_UNDEFINED;48
static Value tt_zitarev = SIGIL_UNDEFINED;49
static Value tt_delay = SIGIL_UNDEFINED;50
static Value tt_vdelay = SIGIL_UNDEFINED;51
static Value tt_noise = SIGIL_UNDEFINED;52
static Value tt_pinknoise = SIGIL_UNDEFINED;53
static Value tt_brown = SIGIL_UNDEFINED;54
static Value tt_saturator = SIGIL_UNDEFINED;55
static Value tt_clip = SIGIL_UNDEFINED;56
static Value tt_peaklim = SIGIL_UNDEFINED;57
static Value tt_pan2 = SIGIL_UNDEFINED;58
static Value tt_metro = SIGIL_UNDEFINED;59
static Value tt_clock = SIGIL_UNDEFINED;60
static Value tt_tgate = SIGIL_UNDEFINED;61
static Value tt_randh = SIGIL_UNDEFINED;62
static Value tt_randi = SIGIL_UNDEFINED;63
static Value tt_scale = SIGIL_UNDEFINED;64
static Value tt_clamp = SIGIL_UNDEFINED;65
static Value tt_crossfade = SIGIL_UNDEFINED;66
static Value tt_wavout = SIGIL_UNDEFINED;67
static Value tt_ftbl = SIGIL_UNDEFINED;68
static Value tt_ks = SIGIL_UNDEFINED;69
static Value tt_fm4 = SIGIL_UNDEFINED;70
static Value tt_chorus = SIGIL_UNDEFINED;71
static Value tt_crush = SIGIL_UNDEFINED;72
static Value tt_comp = SIGIL_UNDEFINED;74
/* ============================================================75
* HELPERS76
* ============================================================ */78
#define ENSURE_TAG(vm, tag, name) \79
if (sigil_is_undefined(tag)) { \80
tag = sigil_intern_symbol(vm, name, strlen(name)); \81
}83
#define CHECK_SP(vm, funcname) \84
if (!g_sp) { \85
sigil__vm_set_error(vm, SIGIL_ERR_RUNTIME, funcname ": DSP not initialized, call dsp-init first"); \86
return SIGIL_FALSE; \87
}89
/* Wrapper struct for wavetable oscillator (owns ftbl) */90
typedef struct {91
sp_osc *osc;92
sp_ftbl *ft;93
} dsp_osc;95
/* Wrapper struct for posc3 (owns ftbl) */96
typedef struct {97
sp_posc3 *osc;98
sp_ftbl *ft;99
} dsp_posc3;101
/* Wrapper struct for fosc (owns ftbl) */102
typedef struct {103
sp_fosc *osc;104
sp_ftbl *ft;105
} dsp_fosc;107
/* ============================================================108
* DESTRUCTORS109
* ============================================================ */111
static void destroy_osc(void *data) {112
dsp_osc *d = (dsp_osc *)data;113
if (d->osc) sp_osc_destroy(&d->osc);114
if (d->ft) sp_ftbl_destroy(&d->ft);115
free(d);116
}118
static void destroy_posc3(void *data) {119
dsp_posc3 *d = (dsp_posc3 *)data;120
if (d->osc) sp_posc3_destroy(&d->osc);121
if (d->ft) sp_ftbl_destroy(&d->ft);122
free(d);123
}125
static void destroy_blsaw(void *data) { sp_blsaw *p = (sp_blsaw *)data; sp_blsaw_destroy(&p); }126
static void destroy_blsquare(void *data) { sp_blsquare *p = (sp_blsquare *)data; sp_blsquare_destroy(&p); }127
static void destroy_bltriangle(void *data) { sp_bltriangle *p = (sp_bltriangle *)data; sp_bltriangle_destroy(&p); }129
static void destroy_fosc(void *data) {130
dsp_fosc *d = (dsp_fosc *)data;131
if (d->osc) sp_fosc_destroy(&d->osc);132
if (d->ft) sp_ftbl_destroy(&d->ft);133
free(d);134
}136
static void destroy_phasor(void *data) { sp_phasor *p = (sp_phasor *)data; sp_phasor_destroy(&p); }137
static void destroy_moogladder(void *data) { sp_moogladder *p = (sp_moogladder *)data; sp_moogladder_destroy(&p); }138
static void destroy_butlp(void *data) { sp_butlp *p = (sp_butlp *)data; sp_butlp_destroy(&p); }139
static void destroy_buthp(void *data) { sp_buthp *p = (sp_buthp *)data; sp_buthp_destroy(&p); }140
static void destroy_lpf18(void *data) { sp_lpf18 *p = (sp_lpf18 *)data; sp_lpf18_destroy(&p); }141
static void destroy_tone(void *data) { sp_tone *p = (sp_tone *)data; sp_tone_destroy(&p); }142
static void destroy_atone(void *data) { sp_atone *p = (sp_atone *)data; sp_atone_destroy(&p); }143
static void destroy_dcblock(void *data) { sp_dcblock *p = (sp_dcblock *)data; sp_dcblock_destroy(&p); }144
static void destroy_adsr(void *data) { sp_adsr *p = (sp_adsr *)data; sp_adsr_destroy(&p); }145
static void destroy_tadsr(void *data) { sp_tadsr *p = (sp_tadsr *)data; sp_tadsr_destroy(&p); }146
static void destroy_tenv(void *data) { sp_tenv *p = (sp_tenv *)data; sp_tenv_destroy(&p); }147
static void destroy_line(void *data) { sp_line *p = (sp_line *)data; sp_line_destroy(&p); }148
static void destroy_expon(void *data) { sp_expon *p = (sp_expon *)data; sp_expon_destroy(&p); }149
static void destroy_port(void *data) { sp_port *p = (sp_port *)data; sp_port_destroy(&p); }150
static void destroy_revsc(void *data) { sp_revsc *p = (sp_revsc *)data; sp_revsc_destroy(&p); }151
static void destroy_zitarev(void *data) { sp_zitarev *p = (sp_zitarev *)data; sp_zitarev_destroy(&p); }152
static void destroy_delay(void *data) { sp_delay *p = (sp_delay *)data; sp_delay_destroy(&p); }153
static void destroy_vdelay(void *data) { sp_vdelay *p = (sp_vdelay *)data; sp_vdelay_destroy(&p); }154
static void destroy_noise(void *data) { sp_noise *p = (sp_noise *)data; sp_noise_destroy(&p); }155
static void destroy_pinknoise(void *data) { sp_pinknoise *p = (sp_pinknoise *)data; sp_pinknoise_destroy(&p); }156
static void destroy_brown(void *data) { sp_brown *p = (sp_brown *)data; sp_brown_destroy(&p); }157
static void destroy_saturator(void *data) { sp_saturator *p = (sp_saturator *)data; sp_saturator_destroy(&p); }158
static void destroy_clip(void *data) { sp_clip *p = (sp_clip *)data; sp_clip_destroy(&p); }159
static void destroy_peaklim(void *data) { sp_peaklim *p = (sp_peaklim *)data; sp_peaklim_destroy(&p); }160
static void destroy_pan2(void *data) { sp_pan2 *p = (sp_pan2 *)data; sp_pan2_destroy(&p); }161
static void destroy_metro(void *data) { sp_metro *p = (sp_metro *)data; sp_metro_destroy(&p); }162
static void destroy_clock(void *data) { sp_clock *p = (sp_clock *)data; sp_clock_destroy(&p); }163
static void destroy_tgate(void *data) { sp_tgate *p = (sp_tgate *)data; sp_tgate_destroy(&p); }164
static void destroy_randh(void *data) { sp_randh *p = (sp_randh *)data; sp_randh_destroy(&p); }165
static void destroy_randi(void *data) { sp_randi *p = (sp_randi *)data; sp_randi_destroy(&p); }166
static void destroy_scale(void *data) { sp_scale *p = (sp_scale *)data; sp_scale_destroy(&p); }167
static void destroy_clamp(void *data) { sp_clamp *p = (sp_clamp *)data; sp_clamp_destroy(&p); }168
static void destroy_crossfade(void *data) { sp_crossfade *p = (sp_crossfade *)data; sp_crossfade_destroy(&p); }169
static void destroy_wavout(void *data) { sp_wavout *p = (sp_wavout *)data; sp_wavout_destroy(&p); }170
static void destroy_ftbl(void *data) { sp_ftbl *p = (sp_ftbl *)data; sp_ftbl_destroy(&p); }171
static void destroy_ks(void *data) { sp_ks *p = (sp_ks *)data; sp_ks_destroy(&p); }172
static void destroy_fm4(void *data) { sp_fm4 *p = (sp_fm4 *)data; sp_fm4_destroy(&p); }173
static void destroy_chorus(void *data) { sp_chorus *p = (sp_chorus *)data; sp_chorus_destroy(&p); }174
static void destroy_crush(void *data) { sp_crush *p = (sp_crush *)data; sp_crush_destroy(&p); }175
static void destroy_comp(void *data) { sp_comp *p = (sp_comp *)data; sp_comp_destroy(&p); }177
/* ============================================================178
* TYPE GETTERS179
* ============================================================ */181
#define DEF_GETTER(name, sp_type, tag, label) \182
static sp_type *get_##name(SigilVM *vm, Value v) { \183
ENSURE_TAG(vm, tag, "dsp-" label); \184
if (!sigil_is_foreign_type(v, tag)) return NULL; \185
return (sp_type *)sigil_foreign_get_data(v); \186
}188
/* Wrapper getters return the wrapper struct */189
static dsp_osc *get_osc(SigilVM *vm, Value v) {190
ENSURE_TAG(vm, tt_osc, "dsp-osc");191
if (!sigil_is_foreign_type(v, tt_osc)) return NULL;192
return (dsp_osc *)sigil_foreign_get_data(v);193
}194
static dsp_posc3 *get_posc3(SigilVM *vm, Value v) {195
ENSURE_TAG(vm, tt_posc3, "dsp-posc3");196
if (!sigil_is_foreign_type(v, tt_posc3)) return NULL;197
return (dsp_posc3 *)sigil_foreign_get_data(v);198
}199
static dsp_fosc *get_fosc(SigilVM *vm, Value v) {200
ENSURE_TAG(vm, tt_fosc, "dsp-fosc");201
if (!sigil_is_foreign_type(v, tt_fosc)) return NULL;202
return (dsp_fosc *)sigil_foreign_get_data(v);203
}205
DEF_GETTER(blsaw, sp_blsaw, tt_blsaw, "blsaw")206
DEF_GETTER(blsquare, sp_blsquare, tt_blsquare, "blsquare")207
DEF_GETTER(bltriangle, sp_bltriangle, tt_bltriangle, "bltriangle")208
DEF_GETTER(phasor, sp_phasor, tt_phasor, "phasor")209
DEF_GETTER(moogladder, sp_moogladder, tt_moogladder, "moogladder")210
DEF_GETTER(butlp, sp_butlp, tt_butlp, "butlp")211
DEF_GETTER(buthp, sp_buthp, tt_buthp, "buthp")212
DEF_GETTER(lpf18, sp_lpf18, tt_lpf18, "lpf18")213
DEF_GETTER(tone, sp_tone, tt_tone, "tone")214
DEF_GETTER(atone, sp_atone, tt_atone, "atone")215
DEF_GETTER(dcblock, sp_dcblock, tt_dcblock, "dcblock")216
DEF_GETTER(adsr, sp_adsr, tt_adsr, "adsr")217
DEF_GETTER(tadsr, sp_tadsr, tt_tadsr, "tadsr")218
DEF_GETTER(tenv, sp_tenv, tt_tenv, "tenv")219
DEF_GETTER(line, sp_line, tt_line, "line")220
DEF_GETTER(expon, sp_expon, tt_expon, "expon")221
DEF_GETTER(port, sp_port, tt_port, "port")222
DEF_GETTER(revsc, sp_revsc, tt_revsc, "revsc")223
DEF_GETTER(zitarev, sp_zitarev, tt_zitarev, "zitarev")224
DEF_GETTER(delay, sp_delay, tt_delay, "delay")225
DEF_GETTER(vdelay, sp_vdelay, tt_vdelay, "vdelay")226
DEF_GETTER(noise, sp_noise, tt_noise, "noise")227
DEF_GETTER(pinknoise, sp_pinknoise, tt_pinknoise, "pinknoise")228
DEF_GETTER(brown, sp_brown, tt_brown, "brown")229
DEF_GETTER(saturator, sp_saturator, tt_saturator, "saturator")230
DEF_GETTER(clip, sp_clip, tt_clip, "clip")231
DEF_GETTER(peaklim, sp_peaklim, tt_peaklim, "peaklim")232
DEF_GETTER(pan2, sp_pan2, tt_pan2, "pan2")233
DEF_GETTER(metro, sp_metro, tt_metro, "metro")234
DEF_GETTER(clock_mod, sp_clock, tt_clock, "clock")235
DEF_GETTER(tgate, sp_tgate, tt_tgate, "tgate")236
DEF_GETTER(randh, sp_randh, tt_randh, "randh")237
DEF_GETTER(randi, sp_randi, tt_randi, "randi")238
DEF_GETTER(scale, sp_scale, tt_scale, "scale")239
DEF_GETTER(clamp, sp_clamp, tt_clamp, "clamp")240
DEF_GETTER(crossfade, sp_crossfade, tt_crossfade, "crossfade")241
DEF_GETTER(wavout, sp_wavout, tt_wavout, "wavout")242
DEF_GETTER(ks, sp_ks, tt_ks, "ks")243
DEF_GETTER(fm4, sp_fm4, tt_fm4, "fm4")244
DEF_GETTER(chorus, sp_chorus, tt_chorus, "chorus")245
DEF_GETTER(crush, sp_crush, tt_crush, "crush")246
DEF_GETTER(comp, sp_comp, tt_comp, "comp")248
/* ============================================================249
* CORE — dsp-init, dsp-shutdown, dsp-sample-rate250
* ============================================================ */252
/* (dsp-init [sample-rate]) */253
/* Helper to get a number as double from either fixnum or flonum */254
static double as_number(Value v)255
{256
if (sigil_is_fixnum(v)) return (double)sigil_as_fixnum(v);257
return sigil_as_flonum(v);258
}260
/* (dsp-init [sample-rate])261
*262
* Creates the shared soundpipe context on the first call. A later call263
* WITH a rate sets the context's rate for the nodes built from then on264
* (nodes cache it at init: the fm4 voice, the chorus and the comp): a265
* program that renders at more than one rate in its life (crash the266
* stack's live soundtrack reopens its player at a lower rate when a267
* device is slow, 2026-09-21) calls (dsp-init sr) before it builds a268
* graph for that rate. Nodes already built keep the rate they were built269
* at. A call without a rate changes nothing once the context exists. */270
static Value native_dsp_init(SigilVM *vm, int argc, Value *args)271
{272
(void)vm;273
if (!g_sp) sp_create(&g_sp);274
if (argc > 0) {275
int sr = (int)as_number(args[0]);276
if (sr > 0) g_sp->sr = sr;277
}278
return SIGIL_TRUE;279
}281
/* (dsp-shutdown) */282
static Value native_dsp_shutdown(SigilVM *vm, int argc, Value *args)283
{284
(void)vm; (void)argc; (void)args;285
if (g_sp) {286
sp_destroy(&g_sp);287
g_sp = NULL;288
}289
return SIGIL_NIL;290
}292
/* (dsp-sample-rate) -> fixnum */293
static Value native_dsp_sample_rate(SigilVM *vm, int argc, Value *args)294
{295
(void)argc; (void)args;296
CHECK_SP(vm, "dsp-sample-rate");297
return sigil_fixnum(g_sp->sr);298
}300
/* ============================================================301
* FUNCTION TABLES302
* ============================================================ */304
/* (make-ftbl size) -> <ftbl> */305
static Value native_make_ftbl(SigilVM *vm, int argc, Value *args)306
{307
CHECK_SP(vm, "make-ftbl");308
size_t size = (size_t)sigil_as_flonum(args[0]);309
sp_ftbl *ft;310
sp_ftbl_create(g_sp, &ft, size);311
ENSURE_TAG(vm, tt_ftbl, "dsp-ftbl");312
return sigil_make_foreign(vm, tt_ftbl, ft, destroy_ftbl,313
sizeof(sp_ftbl) + size * sizeof(SPFLOAT));314
}316
/* (ftbl-gen-sine ftbl) */317
static Value native_ftbl_gen_sine(SigilVM *vm, int argc, Value *args)318
{319
CHECK_SP(vm, "ftbl-gen-sine");320
ENSURE_TAG(vm, tt_ftbl, "dsp-ftbl");321
if (!sigil_is_foreign_type(args[0], tt_ftbl)) {322
sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "ftbl-gen-sine: expected ftbl");323
return SIGIL_FALSE;324
}325
sp_ftbl *ft = (sp_ftbl *)sigil_foreign_get_data(args[0]);326
sp_gen_sine(g_sp, ft);327
return SIGIL_NIL;328
}330
/* (ftbl-gen-triangle ftbl) */331
static Value native_ftbl_gen_triangle(SigilVM *vm, int argc, Value *args)332
{333
CHECK_SP(vm, "ftbl-gen-triangle");334
ENSURE_TAG(vm, tt_ftbl, "dsp-ftbl");335
if (!sigil_is_foreign_type(args[0], tt_ftbl)) {336
sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "ftbl-gen-triangle: expected ftbl");337
return SIGIL_FALSE;338
}339
sp_ftbl *ft = (sp_ftbl *)sigil_foreign_get_data(args[0]);340
sp_gen_triangle(g_sp, ft);341
return SIGIL_NIL;342
}344
/* (ftbl-gen-line ftbl argstring) */345
static Value native_ftbl_gen_line(SigilVM *vm, int argc, Value *args)346
{347
CHECK_SP(vm, "ftbl-gen-line");348
ENSURE_TAG(vm, tt_ftbl, "dsp-ftbl");349
if (!sigil_is_foreign_type(args[0], tt_ftbl)) {350
sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "ftbl-gen-line: expected ftbl");351
return SIGIL_FALSE;352
}353
if (!sigil_is_string(args[1])) {354
sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "ftbl-gen-line: expected string");355
return SIGIL_FALSE;356
}357
sp_ftbl *ft = (sp_ftbl *)sigil_foreign_get_data(args[0]);358
SigilString *s = (SigilString *)sigil_as_ptr(args[1]);359
sp_gen_line(g_sp, ft, s->data);360
return SIGIL_NIL;361
}363
/* ============================================================364
* OSCILLATORS365
* ============================================================ */367
/* (make-osc freq amp [phase]) -> <osc>368
* Wavetable oscillator with sine wave table */369
static Value native_make_osc(SigilVM *vm, int argc, Value *args)370
{371
CHECK_SP(vm, "make-osc");372
SPFLOAT freq = (SPFLOAT)sigil_as_flonum(args[0]);373
SPFLOAT amp = (SPFLOAT)sigil_as_flonum(args[1]);374
SPFLOAT phase = argc > 2 ? (SPFLOAT)sigil_as_flonum(args[2]) : 0.0f;376
sp_ftbl *ft;377
sp_ftbl_create(g_sp, &ft, 4096);378
sp_gen_sine(g_sp, ft);380
sp_osc *osc;381
sp_osc_create(&osc);382
sp_osc_init(g_sp, osc, ft, phase);383
osc->freq = freq;384
osc->amp = amp;386
dsp_osc *d = malloc(sizeof(dsp_osc));387
d->osc = osc;388
d->ft = ft;390
ENSURE_TAG(vm, tt_osc, "dsp-osc");391
return sigil_make_foreign(vm, tt_osc, d, destroy_osc,392
sizeof(dsp_osc) + sizeof(sp_osc) + 4096 * sizeof(SPFLOAT));393
}395
/* (make-osc-ft ftbl freq amp [phase]) -> <osc>396
* Wavetable oscillator with custom function table */397
static Value native_make_osc_ft(SigilVM *vm, int argc, Value *args)398
{399
CHECK_SP(vm, "make-osc-ft");400
ENSURE_TAG(vm, tt_ftbl, "dsp-ftbl");401
if (!sigil_is_foreign_type(args[0], tt_ftbl)) {402
sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "make-osc-ft: expected ftbl as first argument");403
return SIGIL_FALSE;404
}405
/* Note: the ftbl is NOT owned by this osc — caller manages its lifetime */406
sp_ftbl *ft = (sp_ftbl *)sigil_foreign_get_data(args[0]);407
SPFLOAT freq = (SPFLOAT)sigil_as_flonum(args[1]);408
SPFLOAT amp = (SPFLOAT)sigil_as_flonum(args[2]);409
SPFLOAT phase = argc > 3 ? (SPFLOAT)sigil_as_flonum(args[3]) : 0.0f;411
sp_osc *osc;412
sp_osc_create(&osc);413
sp_osc_init(g_sp, osc, ft, phase);414
osc->freq = freq;415
osc->amp = amp;417
dsp_osc *d = malloc(sizeof(dsp_osc));418
d->osc = osc;419
d->ft = NULL; /* not owned */421
ENSURE_TAG(vm, tt_osc, "dsp-osc");422
return sigil_make_foreign(vm, tt_osc, d, destroy_osc,423
sizeof(dsp_osc) + sizeof(sp_osc));424
}426
/* (osc-compute osc) -> flonum */427
static Value native_osc_compute(SigilVM *vm, int argc, Value *args)428
{429
dsp_osc *d = get_osc(vm, args[0]);430
if (!d) { sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "osc-compute: expected osc"); return SIGIL_FALSE; }431
SPFLOAT in = 0, out = 0;432
sp_osc_compute(g_sp, d->osc, &in, &out);433
return sigil_flonum((double)out);434
}436
/* (osc-set-freq! osc freq) */437
static Value native_osc_set_freq(SigilVM *vm, int argc, Value *args)438
{439
dsp_osc *d = get_osc(vm, args[0]);440
if (!d) { sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "osc-set-freq!: expected osc"); return SIGIL_FALSE; }441
d->osc->freq = (SPFLOAT)sigil_as_flonum(args[1]);442
return SIGIL_NIL;443
}445
/* (osc-set-amp! osc amp) */446
static Value native_osc_set_amp(SigilVM *vm, int argc, Value *args)447
{448
dsp_osc *d = get_osc(vm, args[0]);449
if (!d) { sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "osc-set-amp!: expected osc"); return SIGIL_FALSE; }450
d->osc->amp = (SPFLOAT)sigil_as_flonum(args[1]);451
return SIGIL_NIL;452
}454
/* (make-posc3 freq amp [phase]) -> <posc3> */455
static Value native_make_posc3(SigilVM *vm, int argc, Value *args)456
{457
CHECK_SP(vm, "make-posc3");458
SPFLOAT freq = (SPFLOAT)sigil_as_flonum(args[0]);459
SPFLOAT amp = (SPFLOAT)sigil_as_flonum(args[1]);461
sp_ftbl *ft;462
sp_ftbl_create(g_sp, &ft, 4096);463
sp_gen_sine(g_sp, ft);465
sp_posc3 *osc;466
sp_posc3_create(&osc);467
sp_posc3_init(g_sp, osc, ft);468
osc->freq = freq;469
osc->amp = amp;471
dsp_posc3 *d = malloc(sizeof(dsp_posc3));472
d->osc = osc;473
d->ft = ft;475
ENSURE_TAG(vm, tt_posc3, "dsp-posc3");476
return sigil_make_foreign(vm, tt_posc3, d, destroy_posc3,477
sizeof(dsp_posc3) + sizeof(sp_posc3) + 4096 * sizeof(SPFLOAT));478
}480
/* (posc3-compute osc) -> flonum */481
static Value native_posc3_compute(SigilVM *vm, int argc, Value *args)482
{483
dsp_posc3 *d = get_posc3(vm, args[0]);484
if (!d) { sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "posc3-compute: expected posc3"); return SIGIL_FALSE; }485
SPFLOAT in = 0, out = 0;486
sp_posc3_compute(g_sp, d->osc, &in, &out);487
return sigil_flonum((double)out);488
}490
/* (posc3-set-freq! osc freq) */491
static Value native_posc3_set_freq(SigilVM *vm, int argc, Value *args)492
{493
dsp_posc3 *d = get_posc3(vm, args[0]);494
if (!d) { sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "posc3-set-freq!: expected posc3"); return SIGIL_FALSE; }495
d->osc->freq = (SPFLOAT)sigil_as_flonum(args[1]);496
return SIGIL_NIL;497
}499
/* (posc3-set-amp! osc amp) */500
static Value native_posc3_set_amp(SigilVM *vm, int argc, Value *args)501
{502
dsp_posc3 *d = get_posc3(vm, args[0]);503
if (!d) { sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "posc3-set-amp!: expected posc3"); return SIGIL_FALSE; }504
d->osc->amp = (SPFLOAT)sigil_as_flonum(args[1]);505
return SIGIL_NIL;506
}508
/* (make-blsaw freq amp) -> <blsaw> */509
static Value native_make_blsaw(SigilVM *vm, int argc, Value *args)510
{511
CHECK_SP(vm, "make-blsaw");512
SPFLOAT freq = (SPFLOAT)sigil_as_flonum(args[0]);513
SPFLOAT amp = (SPFLOAT)sigil_as_flonum(args[1]);515
sp_blsaw *p;516
sp_blsaw_create(&p);517
sp_blsaw_init(g_sp, p);518
*p->freq = freq;519
*p->amp = amp;521
ENSURE_TAG(vm, tt_blsaw, "dsp-blsaw");522
return sigil_make_foreign(vm, tt_blsaw, p, destroy_blsaw, sizeof(sp_blsaw));523
}525
/* (blsaw-compute osc) -> flonum */526
static Value native_blsaw_compute(SigilVM *vm, int argc, Value *args)527
{528
sp_blsaw *p = get_blsaw(vm, args[0]);529
if (!p) { sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "blsaw-compute: expected blsaw"); return SIGIL_FALSE; }530
SPFLOAT in = 0, out = 0;531
sp_blsaw_compute(g_sp, p, &in, &out);532
return sigil_flonum((double)out);533
}535
/* (blsaw-set-freq! osc freq) */536
static Value native_blsaw_set_freq(SigilVM *vm, int argc, Value *args)537
{538
sp_blsaw *p = get_blsaw(vm, args[0]);539
if (!p) { sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "blsaw-set-freq!: expected blsaw"); return SIGIL_FALSE; }540
*p->freq = (SPFLOAT)sigil_as_flonum(args[1]);541
return SIGIL_NIL;542
}544
/* (blsaw-set-amp! osc amp) */545
static Value native_blsaw_set_amp(SigilVM *vm, int argc, Value *args)546
{547
sp_blsaw *p = get_blsaw(vm, args[0]);548
if (!p) { sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "blsaw-set-amp!: expected blsaw"); return SIGIL_FALSE; }549
*p->amp = (SPFLOAT)sigil_as_flonum(args[1]);550
return SIGIL_NIL;551
}553
/* (make-blsquare freq amp [width]) -> <blsquare> */554
static Value native_make_blsquare(SigilVM *vm, int argc, Value *args)555
{556
CHECK_SP(vm, "make-blsquare");557
SPFLOAT freq = (SPFLOAT)sigil_as_flonum(args[0]);558
SPFLOAT amp = (SPFLOAT)sigil_as_flonum(args[1]);559
SPFLOAT width = argc > 2 ? (SPFLOAT)sigil_as_flonum(args[2]) : 0.5f;561
sp_blsquare *p;562
sp_blsquare_create(&p);563
sp_blsquare_init(g_sp, p);564
*p->freq = freq;565
*p->amp = amp;566
*p->width = width;568
ENSURE_TAG(vm, tt_blsquare, "dsp-blsquare");569
return sigil_make_foreign(vm, tt_blsquare, p, destroy_blsquare, sizeof(sp_blsquare));570
}572
/* (blsquare-compute osc) -> flonum */573
static Value native_blsquare_compute(SigilVM *vm, int argc, Value *args)574
{575
sp_blsquare *p = get_blsquare(vm, args[0]);576
if (!p) { sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "blsquare-compute: expected blsquare"); return SIGIL_FALSE; }577
SPFLOAT in = 0, out = 0;578
sp_blsquare_compute(g_sp, p, &in, &out);579
return sigil_flonum((double)out);580
}582
/* (blsquare-set-freq! osc freq) */583
static Value native_blsquare_set_freq(SigilVM *vm, int argc, Value *args)584
{585
sp_blsquare *p = get_blsquare(vm, args[0]);586
if (!p) { sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "blsquare-set-freq!: expected blsquare"); return SIGIL_FALSE; }587
*p->freq = (SPFLOAT)sigil_as_flonum(args[1]);588
return SIGIL_NIL;589
}591
/* (blsquare-set-amp! osc amp) */592
static Value native_blsquare_set_amp(SigilVM *vm, int argc, Value *args)593
{594
sp_blsquare *p = get_blsquare(vm, args[0]);595
if (!p) { sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "blsquare-set-amp!: expected blsquare"); return SIGIL_FALSE; }596
*p->amp = (SPFLOAT)sigil_as_flonum(args[1]);597
return SIGIL_NIL;598
}600
/* (make-bltriangle freq amp) -> <bltriangle> */601
static Value native_make_bltriangle(SigilVM *vm, int argc, Value *args)602
{603
CHECK_SP(vm, "make-bltriangle");604
SPFLOAT freq = (SPFLOAT)sigil_as_flonum(args[0]);605
SPFLOAT amp = (SPFLOAT)sigil_as_flonum(args[1]);607
sp_bltriangle *p;608
sp_bltriangle_create(&p);609
sp_bltriangle_init(g_sp, p);610
*p->freq = freq;611
*p->amp = amp;613
ENSURE_TAG(vm, tt_bltriangle, "dsp-bltriangle");614
return sigil_make_foreign(vm, tt_bltriangle, p, destroy_bltriangle, sizeof(sp_bltriangle));615
}617
/* (bltriangle-compute osc) -> flonum */618
static Value native_bltriangle_compute(SigilVM *vm, int argc, Value *args)619
{620
sp_bltriangle *p = get_bltriangle(vm, args[0]);621
if (!p) { sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "bltriangle-compute: expected bltriangle"); return SIGIL_FALSE; }622
SPFLOAT in = 0, out = 0;623
sp_bltriangle_compute(g_sp, p, &in, &out);624
return sigil_flonum((double)out);625
}627
/* (bltriangle-set-freq! osc freq) */628
static Value native_bltriangle_set_freq(SigilVM *vm, int argc, Value *args)629
{630
sp_bltriangle *p = get_bltriangle(vm, args[0]);631
if (!p) { sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "bltriangle-set-freq!: expected bltriangle"); return SIGIL_FALSE; }632
*p->freq = (SPFLOAT)sigil_as_flonum(args[1]);633
return SIGIL_NIL;634
}636
/* (bltriangle-set-amp! osc amp) */637
static Value native_bltriangle_set_amp(SigilVM *vm, int argc, Value *args)638
{639
sp_bltriangle *p = get_bltriangle(vm, args[0]);640
if (!p) { sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "bltriangle-set-amp!: expected bltriangle"); return SIGIL_FALSE; }641
*p->amp = (SPFLOAT)sigil_as_flonum(args[1]);642
return SIGIL_NIL;643
}645
/* (make-fosc freq car mod indx amp) -> <fosc> */646
static Value native_make_fosc(SigilVM *vm, int argc, Value *args)647
{648
CHECK_SP(vm, "make-fosc");649
SPFLOAT freq = (SPFLOAT)sigil_as_flonum(args[0]);650
SPFLOAT car = (SPFLOAT)sigil_as_flonum(args[1]);651
SPFLOAT mod = (SPFLOAT)sigil_as_flonum(args[2]);652
SPFLOAT indx = (SPFLOAT)sigil_as_flonum(args[3]);653
SPFLOAT amp = (SPFLOAT)sigil_as_flonum(args[4]);655
sp_ftbl *ft;656
sp_ftbl_create(g_sp, &ft, 4096);657
sp_gen_sine(g_sp, ft);659
sp_fosc *osc;660
sp_fosc_create(&osc);661
sp_fosc_init(g_sp, osc, ft);662
osc->freq = freq;663
osc->car = car;664
osc->mod = mod;665
osc->indx = indx;666
osc->amp = amp;668
dsp_fosc *d = malloc(sizeof(dsp_fosc));669
d->osc = osc;670
d->ft = ft;672
ENSURE_TAG(vm, tt_fosc, "dsp-fosc");673
return sigil_make_foreign(vm, tt_fosc, d, destroy_fosc,674
sizeof(dsp_fosc) + sizeof(sp_fosc) + 4096 * sizeof(SPFLOAT));675
}677
/* (fosc-compute osc) -> flonum */678
static Value native_fosc_compute(SigilVM *vm, int argc, Value *args)679
{680
dsp_fosc *d = get_fosc(vm, args[0]);681
if (!d) { sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "fosc-compute: expected fosc"); return SIGIL_FALSE; }682
SPFLOAT in = 0, out = 0;683
sp_fosc_compute(g_sp, d->osc, &in, &out);684
return sigil_flonum((double)out);685
}687
/* (fosc-set-freq! osc freq) */688
static Value native_fosc_set_freq(SigilVM *vm, int argc, Value *args)689
{690
dsp_fosc *d = get_fosc(vm, args[0]);691
if (!d) { sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "fosc-set-freq!: expected fosc"); return SIGIL_FALSE; }692
d->osc->freq = (SPFLOAT)sigil_as_flonum(args[1]);693
return SIGIL_NIL;694
}696
/* (fosc-set-index! osc indx) */697
static Value native_fosc_set_index(SigilVM *vm, int argc, Value *args)698
{699
dsp_fosc *d = get_fosc(vm, args[0]);700
if (!d) { sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "fosc-set-index!: expected fosc"); return SIGIL_FALSE; }701
d->osc->indx = (SPFLOAT)sigil_as_flonum(args[1]);702
return SIGIL_NIL;703
}705
/* (fosc-set-amp! osc amp) */706
static Value native_fosc_set_amp(SigilVM *vm, int argc, Value *args)707
{708
dsp_fosc *d = get_fosc(vm, args[0]);709
if (!d) { sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "fosc-set-amp!: expected fosc"); return SIGIL_FALSE; }710
d->osc->amp = (SPFLOAT)sigil_as_flonum(args[1]);711
return SIGIL_NIL;712
}714
/* (make-phasor freq [phase]) -> <phasor> */715
static Value native_make_phasor(SigilVM *vm, int argc, Value *args)716
{717
CHECK_SP(vm, "make-phasor");718
SPFLOAT freq = (SPFLOAT)sigil_as_flonum(args[0]);719
SPFLOAT phase = argc > 1 ? (SPFLOAT)sigil_as_flonum(args[1]) : 0.0f;721
sp_phasor *p;722
sp_phasor_create(&p);723
sp_phasor_init(g_sp, p, phase);724
p->freq = freq;726
ENSURE_TAG(vm, tt_phasor, "dsp-phasor");727
return sigil_make_foreign(vm, tt_phasor, p, destroy_phasor, sizeof(sp_phasor));728
}730
/* (phasor-compute phasor) -> flonum */731
static Value native_phasor_compute(SigilVM *vm, int argc, Value *args)732
{733
sp_phasor *p = get_phasor(vm, args[0]);734
if (!p) { sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "phasor-compute: expected phasor"); return SIGIL_FALSE; }735
SPFLOAT in = 0, out = 0;736
sp_phasor_compute(g_sp, p, &in, &out);737
return sigil_flonum((double)out);738
}740
/* (phasor-set-freq! phasor freq) */741
static Value native_phasor_set_freq(SigilVM *vm, int argc, Value *args)742
{743
sp_phasor *p = get_phasor(vm, args[0]);744
if (!p) { sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "phasor-set-freq!: expected phasor"); return SIGIL_FALSE; }745
p->freq = (SPFLOAT)sigil_as_flonum(args[1]);746
return SIGIL_NIL;747
}749
/* ============================================================750
* FILTERS751
* ============================================================ */753
/* (make-moogladder freq res) -> <moogladder> */754
static Value native_make_moogladder(SigilVM *vm, int argc, Value *args)755
{756
CHECK_SP(vm, "make-moogladder");757
sp_moogladder *p;758
sp_moogladder_create(&p);759
sp_moogladder_init(g_sp, p);760
p->freq = (SPFLOAT)sigil_as_flonum(args[0]);761
p->res = (SPFLOAT)sigil_as_flonum(args[1]);762
ENSURE_TAG(vm, tt_moogladder, "dsp-moogladder");763
return sigil_make_foreign(vm, tt_moogladder, p, destroy_moogladder, sizeof(sp_moogladder));764
}766
/* (make-butlp freq) -> <butlp> */767
static Value native_make_butlp(SigilVM *vm, int argc, Value *args)768
{769
CHECK_SP(vm, "make-butlp");770
sp_butlp *p;771
sp_butlp_create(&p);772
sp_butlp_init(g_sp, p);773
p->freq = (SPFLOAT)sigil_as_flonum(args[0]);774
ENSURE_TAG(vm, tt_butlp, "dsp-butlp");775
return sigil_make_foreign(vm, tt_butlp, p, destroy_butlp, sizeof(sp_butlp));776
}778
/* (make-buthp freq) -> <buthp> */779
static Value native_make_buthp(SigilVM *vm, int argc, Value *args)780
{781
CHECK_SP(vm, "make-buthp");782
sp_buthp *p;783
sp_buthp_create(&p);784
sp_buthp_init(g_sp, p);785
p->freq = (SPFLOAT)sigil_as_flonum(args[0]);786
ENSURE_TAG(vm, tt_buthp, "dsp-buthp");787
return sigil_make_foreign(vm, tt_buthp, p, destroy_buthp, sizeof(sp_buthp));788
}790
/* (make-lpf18 cutoff res dist) -> <lpf18> */791
static Value native_make_lpf18(SigilVM *vm, int argc, Value *args)792
{793
CHECK_SP(vm, "make-lpf18");794
sp_lpf18 *p;795
sp_lpf18_create(&p);796
sp_lpf18_init(g_sp, p);797
p->cutoff = (SPFLOAT)sigil_as_flonum(args[0]);798
p->res = (SPFLOAT)sigil_as_flonum(args[1]);799
p->dist = (SPFLOAT)sigil_as_flonum(args[2]);800
ENSURE_TAG(vm, tt_lpf18, "dsp-lpf18");801
return sigil_make_foreign(vm, tt_lpf18, p, destroy_lpf18, sizeof(sp_lpf18));802
}804
/* (make-tone freq) -> <tone> */805
static Value native_make_tone(SigilVM *vm, int argc, Value *args)806
{807
CHECK_SP(vm, "make-tone");808
sp_tone *p;809
sp_tone_create(&p);810
sp_tone_init(g_sp, p);811
p->hp = (SPFLOAT)sigil_as_flonum(args[0]);812
ENSURE_TAG(vm, tt_tone, "dsp-tone");813
return sigil_make_foreign(vm, tt_tone, p, destroy_tone, sizeof(sp_tone));814
}816
/* (make-atone freq) -> <atone> */817
static Value native_make_atone(SigilVM *vm, int argc, Value *args)818
{819
CHECK_SP(vm, "make-atone");820
sp_atone *p;821
sp_atone_create(&p);822
sp_atone_init(g_sp, p);823
p->hp = (SPFLOAT)sigil_as_flonum(args[0]);824
ENSURE_TAG(vm, tt_atone, "dsp-atone");825
return sigil_make_foreign(vm, tt_atone, p, destroy_atone, sizeof(sp_atone));826
}828
/* (make-dcblock) -> <dcblock> */829
static Value native_make_dcblock(SigilVM *vm, int argc, Value *args)830
{831
CHECK_SP(vm, "make-dcblock");832
sp_dcblock *p;833
sp_dcblock_create(&p);834
sp_dcblock_init(g_sp, p);835
ENSURE_TAG(vm, tt_dcblock, "dsp-dcblock");836
return sigil_make_foreign(vm, tt_dcblock, p, destroy_dcblock, sizeof(sp_dcblock));837
}839
/* Generic filter compute: (filter-compute filter input) -> flonum */840
static Value native_filter_compute(SigilVM *vm, int argc, Value *args)841
{842
SPFLOAT in = (SPFLOAT)sigil_as_flonum(args[1]);843
SPFLOAT out = 0;845
/* Try each filter type */846
sp_moogladder *ml; sp_butlp *bl; sp_buthp *bh; sp_lpf18 *l18;847
sp_tone *tn; sp_atone *atn; sp_dcblock *dc;849
if ((ml = get_moogladder(vm, args[0]))) { sp_moogladder_compute(g_sp, ml, &in, &out); }850
else if ((bl = get_butlp(vm, args[0]))) { sp_butlp_compute(g_sp, bl, &in, &out); }851
else if ((bh = get_buthp(vm, args[0]))) { sp_buthp_compute(g_sp, bh, &in, &out); }852
else if ((l18 = get_lpf18(vm, args[0]))) { sp_lpf18_compute(g_sp, l18, &in, &out); }853
else if ((tn = get_tone(vm, args[0]))) { sp_tone_compute(g_sp, tn, &in, &out); }854
else if ((atn = get_atone(vm, args[0]))) { sp_atone_compute(g_sp, atn, &in, &out); }855
else if ((dc = get_dcblock(vm, args[0]))) { sp_dcblock_compute(g_sp, dc, &in, &out); }856
else {857
sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "filter-compute: expected filter object");858
return SIGIL_FALSE;859
}860
return sigil_flonum((double)out);861
}863
/* (filter-set-freq! filter freq) */864
static Value native_filter_set_freq(SigilVM *vm, int argc, Value *args)865
{866
SPFLOAT freq = (SPFLOAT)sigil_as_flonum(args[1]);867
sp_moogladder *ml; sp_butlp *bl; sp_buthp *bh; sp_lpf18 *l18;868
sp_tone *tn; sp_atone *atn;870
if ((ml = get_moogladder(vm, args[0]))) { ml->freq = freq; }871
else if ((bl = get_butlp(vm, args[0]))) { bl->freq = freq; }872
else if ((bh = get_buthp(vm, args[0]))) { bh->freq = freq; }873
else if ((l18 = get_lpf18(vm, args[0]))) { l18->cutoff = freq; }874
else if ((tn = get_tone(vm, args[0]))) { tn->hp = freq; }875
else if ((atn = get_atone(vm, args[0]))) { atn->hp = freq; }876
else {877
sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "filter-set-freq!: expected filter object");878
return SIGIL_FALSE;879
}880
return SIGIL_NIL;881
}883
/* (filter-set-res! filter res) — for moogladder, lpf18 */884
static Value native_filter_set_res(SigilVM *vm, int argc, Value *args)885
{886
SPFLOAT res = (SPFLOAT)sigil_as_flonum(args[1]);887
sp_moogladder *ml; sp_lpf18 *l18;889
if ((ml = get_moogladder(vm, args[0]))) { ml->res = res; }890
else if ((l18 = get_lpf18(vm, args[0]))) { l18->res = res; }891
else {892
sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "filter-set-res!: expected resonant filter");893
return SIGIL_FALSE;894
}895
return SIGIL_NIL;896
}898
/* ============================================================899
* ENVELOPES900
* ============================================================ */902
/* (make-adsr atk dec sus rel) -> <adsr> */903
static Value native_make_adsr(SigilVM *vm, int argc, Value *args)904
{905
CHECK_SP(vm, "make-adsr");906
sp_adsr *p;907
sp_adsr_create(&p);908
sp_adsr_init(g_sp, p);909
p->atk = (SPFLOAT)sigil_as_flonum(args[0]);910
p->dec = (SPFLOAT)sigil_as_flonum(args[1]);911
p->sus = (SPFLOAT)sigil_as_flonum(args[2]);912
p->rel = (SPFLOAT)sigil_as_flonum(args[3]);913
ENSURE_TAG(vm, tt_adsr, "dsp-adsr");914
return sigil_make_foreign(vm, tt_adsr, p, destroy_adsr, sizeof(sp_adsr));915
}917
/* (adsr-compute adsr gate) -> flonum */918
static Value native_adsr_compute(SigilVM *vm, int argc, Value *args)919
{920
sp_adsr *p = get_adsr(vm, args[0]);921
if (!p) { sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "adsr-compute: expected adsr"); return SIGIL_FALSE; }922
SPFLOAT gate = (SPFLOAT)sigil_as_flonum(args[1]);923
SPFLOAT out = 0;924
sp_adsr_compute(g_sp, p, &gate, &out);925
return sigil_flonum((double)out);926
}928
/* (make-tadsr atk dec sus rel) -> <tadsr> */929
static Value native_make_tadsr(SigilVM *vm, int argc, Value *args)930
{931
CHECK_SP(vm, "make-tadsr");932
sp_tadsr *p;933
sp_tadsr_create(&p);934
sp_tadsr_init(g_sp, p);935
p->atk = (SPFLOAT)sigil_as_flonum(args[0]);936
p->dec = (SPFLOAT)sigil_as_flonum(args[1]);937
p->sus = (SPFLOAT)sigil_as_flonum(args[2]);938
p->rel = (SPFLOAT)sigil_as_flonum(args[3]);939
ENSURE_TAG(vm, tt_tadsr, "dsp-tadsr");940
return sigil_make_foreign(vm, tt_tadsr, p, destroy_tadsr, sizeof(sp_tadsr));941
}943
/* (tadsr-compute tadsr trigger) -> flonum */944
static Value native_tadsr_compute(SigilVM *vm, int argc, Value *args)945
{946
sp_tadsr *p = get_tadsr(vm, args[0]);947
if (!p) { sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "tadsr-compute: expected tadsr"); return SIGIL_FALSE; }948
SPFLOAT trig = (SPFLOAT)sigil_as_flonum(args[1]);949
SPFLOAT out = 0;950
sp_tadsr_compute(g_sp, p, &trig, &out);951
return sigil_flonum((double)out);952
}954
/* (make-tenv atk hold rel) -> <tenv> */955
static Value native_make_tenv(SigilVM *vm, int argc, Value *args)956
{957
CHECK_SP(vm, "make-tenv");958
sp_tenv *p;959
sp_tenv_create(&p);960
sp_tenv_init(g_sp, p);961
p->atk = (SPFLOAT)sigil_as_flonum(args[0]);962
p->hold = (SPFLOAT)sigil_as_flonum(args[1]);963
p->rel = (SPFLOAT)sigil_as_flonum(args[2]);964
ENSURE_TAG(vm, tt_tenv, "dsp-tenv");965
return sigil_make_foreign(vm, tt_tenv, p, destroy_tenv, sizeof(sp_tenv));966
}968
/* (tenv-compute tenv trigger) -> flonum */969
static Value native_tenv_compute(SigilVM *vm, int argc, Value *args)970
{971
sp_tenv *p = get_tenv(vm, args[0]);972
if (!p) { sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "tenv-compute: expected tenv"); return SIGIL_FALSE; }973
SPFLOAT trig = (SPFLOAT)sigil_as_flonum(args[1]);974
SPFLOAT out = 0;975
sp_tenv_compute(g_sp, p, &trig, &out);976
return sigil_flonum((double)out);977
}979
/* (make-line a dur b) -> <line> */980
static Value native_make_line(SigilVM *vm, int argc, Value *args)981
{982
CHECK_SP(vm, "make-line");983
sp_line *p;984
sp_line_create(&p);985
sp_line_init(g_sp, p);986
p->a = (SPFLOAT)sigil_as_flonum(args[0]);987
p->dur = (SPFLOAT)sigil_as_flonum(args[1]);988
p->b = (SPFLOAT)sigil_as_flonum(args[2]);989
ENSURE_TAG(vm, tt_line, "dsp-line");990
return sigil_make_foreign(vm, tt_line, p, destroy_line, sizeof(sp_line));991
}993
/* (line-compute line trigger) -> flonum */994
static Value native_line_compute(SigilVM *vm, int argc, Value *args)995
{996
sp_line *p = get_line(vm, args[0]);997
if (!p) { sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "line-compute: expected line"); return SIGIL_FALSE; }998
SPFLOAT trig = (SPFLOAT)sigil_as_flonum(args[1]);999
SPFLOAT out = 0;1000
sp_line_compute(g_sp, p, &trig, &out);1001
return sigil_flonum((double)out);1002
}1004
/* (make-expon a dur b) -> <expon> */1005
static Value native_make_expon(SigilVM *vm, int argc, Value *args)1006
{1007
CHECK_SP(vm, "make-expon");1008
sp_expon *p;1009
sp_expon_create(&p);1010
sp_expon_init(g_sp, p);1011
p->a = (SPFLOAT)sigil_as_flonum(args[0]);1012
p->dur = (SPFLOAT)sigil_as_flonum(args[1]);1013
p->b = (SPFLOAT)sigil_as_flonum(args[2]);1014
ENSURE_TAG(vm, tt_expon, "dsp-expon");1015
return sigil_make_foreign(vm, tt_expon, p, destroy_expon, sizeof(sp_expon));1016
}1018
/* (expon-compute expon trigger) -> flonum */1019
static Value native_expon_compute(SigilVM *vm, int argc, Value *args)1020
{1021
sp_expon *p = get_expon(vm, args[0]);1022
if (!p) { sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "expon-compute: expected expon"); return SIGIL_FALSE; }1023
SPFLOAT trig = (SPFLOAT)sigil_as_flonum(args[1]);1024
SPFLOAT out = 0;1025
sp_expon_compute(g_sp, p, &trig, &out);1026
return sigil_flonum((double)out);1027
}1029
/* (make-port smoothing) -> <port> */1030
static Value native_make_port(SigilVM *vm, int argc, Value *args)1031
{1032
CHECK_SP(vm, "make-port");1033
sp_port *p;1034
sp_port_create(&p);1035
sp_port_init(g_sp, p);1036
p->smooth = (SPFLOAT)sigil_as_flonum(args[0]);1037
ENSURE_TAG(vm, tt_port, "dsp-port");1038
return sigil_make_foreign(vm, tt_port, p, destroy_port, sizeof(sp_port));1039
}1041
/* (port-compute port input) -> flonum */1042
static Value native_port_compute(SigilVM *vm, int argc, Value *args)1043
{1044
sp_port *p = get_port(vm, args[0]);1045
if (!p) { sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "port-compute: expected port"); return SIGIL_FALSE; }1046
SPFLOAT in = (SPFLOAT)sigil_as_flonum(args[1]);1047
SPFLOAT out = 0;1048
sp_port_compute(g_sp, p, &in, &out);1049
return sigil_flonum((double)out);1050
}1052
/* ============================================================1053
* REVERB & DELAY1054
* ============================================================ */1056
/* (make-revsc feedback lpfreq) -> <revsc> */1057
static Value native_make_revsc(SigilVM *vm, int argc, Value *args)1058
{1059
CHECK_SP(vm, "make-revsc");1060
sp_revsc *p;1061
sp_revsc_create(&p);1062
sp_revsc_init(g_sp, p);1063
p->feedback = (SPFLOAT)sigil_as_flonum(args[0]);1064
p->lpfreq = (SPFLOAT)sigil_as_flonum(args[1]);1065
ENSURE_TAG(vm, tt_revsc, "dsp-revsc");1066
return sigil_make_foreign(vm, tt_revsc, p, destroy_revsc, sizeof(sp_revsc));1067
}1069
/* (revsc-compute revsc in-l in-r) -> (values out-l out-r) */1070
static Value native_revsc_compute(SigilVM *vm, int argc, Value *args)1071
{1072
sp_revsc *p = get_revsc(vm, args[0]);1073
if (!p) { sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "revsc-compute: expected revsc"); return SIGIL_FALSE; }1074
SPFLOAT inL = (SPFLOAT)sigil_as_flonum(args[1]);1075
SPFLOAT inR = (SPFLOAT)sigil_as_flonum(args[2]);1076
SPFLOAT outL = 0, outR = 0;1077
sp_revsc_compute(g_sp, p, &inL, &inR, &outL, &outR);1078
/* Return as a pair for simplicity */1079
Value l = sigil_flonum((double)outL);1080
Value r = sigil_flonum((double)outR);1081
return sigil_cons(vm,l, r);1082
}1084
/* (revsc-set-feedback! revsc feedback) */1085
static Value native_revsc_set_feedback(SigilVM *vm, int argc, Value *args)1086
{1087
sp_revsc *p = get_revsc(vm, args[0]);1088
if (!p) { sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "revsc-set-feedback!: expected revsc"); return SIGIL_FALSE; }1089
p->feedback = (SPFLOAT)sigil_as_flonum(args[1]);1090
return SIGIL_NIL;1091
}1093
/* (revsc-set-lpfreq! revsc lpfreq) */1094
static Value native_revsc_set_lpfreq(SigilVM *vm, int argc, Value *args)1095
{1096
sp_revsc *p = get_revsc(vm, args[0]);1097
if (!p) { sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "revsc-set-lpfreq!: expected revsc"); return SIGIL_FALSE; }1098
p->lpfreq = (SPFLOAT)sigil_as_flonum(args[1]);1099
return SIGIL_NIL;1100
}1102
/* (make-zitarev) -> <zitarev> */1103
static Value native_make_zitarev(SigilVM *vm, int argc, Value *args)1104
{1105
CHECK_SP(vm, "make-zitarev");1106
sp_zitarev *p;1107
sp_zitarev_create(&p);1108
sp_zitarev_init(g_sp, p);1109
ENSURE_TAG(vm, tt_zitarev, "dsp-zitarev");1110
return sigil_make_foreign(vm, tt_zitarev, p, destroy_zitarev, sizeof(sp_zitarev));1111
}1113
/* (zitarev-compute zitarev in-l in-r) -> (out-l . out-r) */1114
static Value native_zitarev_compute(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-compute: expected zitarev"); return SIGIL_FALSE; }1118
SPFLOAT inL = (SPFLOAT)sigil_as_flonum(args[1]);1119
SPFLOAT inR = (SPFLOAT)sigil_as_flonum(args[2]);1120
SPFLOAT outL = 0, outR = 0;1121
sp_zitarev_compute(g_sp, p, &inL, &inR, &outL, &outR);1122
Value l = sigil_flonum((double)outL);1123
Value r = sigil_flonum((double)outR);1124
return sigil_cons(vm,l, r);1125
}1127
/* (zitarev-set-mix! zitarev mix) */1128
static Value native_zitarev_set_mix(SigilVM *vm, int argc, Value *args)1129
{1130
sp_zitarev *p = get_zitarev(vm, args[0]);1131
if (!p) { sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "zitarev-set-mix!: expected zitarev"); return SIGIL_FALSE; }1132
*p->mix = (SPFLOAT)sigil_as_flonum(args[1]);1133
return SIGIL_NIL;1134
}1136
/* (zitarev-set-level! zitarev level) */1137
static Value native_zitarev_set_level(SigilVM *vm, int argc, Value *args)1138
{1139
sp_zitarev *p = get_zitarev(vm, args[0]);1140
if (!p) { sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "zitarev-set-level!: expected zitarev"); return SIGIL_FALSE; }1141
*p->level = (SPFLOAT)sigil_as_flonum(args[1]);1142
return SIGIL_NIL;1143
}1145
/* (make-delay time feedback) -> <delay> */1146
static Value native_make_delay(SigilVM *vm, int argc, Value *args)1147
{1148
CHECK_SP(vm, "make-delay");1149
SPFLOAT time = (SPFLOAT)sigil_as_flonum(args[0]);1150
SPFLOAT feedback = (SPFLOAT)sigil_as_flonum(args[1]);1151
sp_delay *p;1152
sp_delay_create(&p);1153
sp_delay_init(g_sp, p, time);1154
p->feedback = feedback;1155
ENSURE_TAG(vm, tt_delay, "dsp-delay");1156
return sigil_make_foreign(vm, tt_delay, p, destroy_delay,1157
sizeof(sp_delay) + (size_t)(time * g_sp->sr) * sizeof(SPFLOAT));1158
}1160
/* (delay-compute delay input) -> flonum */1161
static Value native_delay_compute(SigilVM *vm, int argc, Value *args)1162
{1163
sp_delay *p = get_delay(vm, args[0]);1164
if (!p) { sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "delay-compute: expected delay"); return SIGIL_FALSE; }1165
SPFLOAT in = (SPFLOAT)sigil_as_flonum(args[1]);1166
SPFLOAT out = 0;1167
sp_delay_compute(g_sp, p, &in, &out);1168
return sigil_flonum((double)out);1169
}1171
/* (delay-set-feedback! delay feedback) */1172
static Value native_delay_set_feedback(SigilVM *vm, int argc, Value *args)1173
{1174
sp_delay *p = get_delay(vm, args[0]);1175
if (!p) { sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "delay-set-feedback!: expected delay"); return SIGIL_FALSE; }1176
p->feedback = (SPFLOAT)sigil_as_flonum(args[1]);1177
return SIGIL_NIL;1178
}1180
/* (make-vdelay maxdel feedback) -> <vdelay> */1181
static Value native_make_vdelay(SigilVM *vm, int argc, Value *args)1182
{1183
CHECK_SP(vm, "make-vdelay");1184
SPFLOAT maxdel = (SPFLOAT)sigil_as_flonum(args[0]);1185
SPFLOAT feedback = (SPFLOAT)sigil_as_flonum(args[1]);1186
sp_vdelay *p;1187
sp_vdelay_create(&p);1188
sp_vdelay_init(g_sp, p, maxdel);1189
p->feedback = feedback;1190
ENSURE_TAG(vm, tt_vdelay, "dsp-vdelay");1191
return sigil_make_foreign(vm, tt_vdelay, p, destroy_vdelay,1192
sizeof(sp_vdelay) + (size_t)(maxdel * g_sp->sr) * sizeof(SPFLOAT));1193
}1195
/* (vdelay-compute vdelay input) -> flonum */1196
static Value native_vdelay_compute(SigilVM *vm, int argc, Value *args)1197
{1198
sp_vdelay *p = get_vdelay(vm, args[0]);1199
if (!p) { sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "vdelay-compute: expected vdelay"); return SIGIL_FALSE; }1200
SPFLOAT in = (SPFLOAT)sigil_as_flonum(args[1]);1201
SPFLOAT out = 0;1202
sp_vdelay_compute(g_sp, p, &in, &out);1203
return sigil_flonum((double)out);1204
}1206
/* (vdelay-set-del! vdelay del) */1207
static Value native_vdelay_set_del(SigilVM *vm, int argc, Value *args)1208
{1209
sp_vdelay *p = get_vdelay(vm, args[0]);1210
if (!p) { sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "vdelay-set-del!: expected vdelay"); return SIGIL_FALSE; }1211
p->del = (SPFLOAT)sigil_as_flonum(args[1]);1212
return SIGIL_NIL;1213
}1215
/* (vdelay-set-feedback! vdelay feedback) */1216
static Value native_vdelay_set_feedback(SigilVM *vm, int argc, Value *args)1217
{1218
sp_vdelay *p = get_vdelay(vm, args[0]);1219
if (!p) { sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "vdelay-set-feedback!: expected vdelay"); return SIGIL_FALSE; }1220
p->feedback = (SPFLOAT)sigil_as_flonum(args[1]);1221
return SIGIL_NIL;1222
}1224
/* ============================================================1225
* NOISE1226
* ============================================================ */1228
/* (make-noise amp) -> <noise> */1229
static Value native_make_noise(SigilVM *vm, int argc, Value *args)1230
{1231
CHECK_SP(vm, "make-noise");1232
sp_noise *p;1233
sp_noise_create(&p);1234
sp_noise_init(g_sp, p);1235
p->amp = (SPFLOAT)sigil_as_flonum(args[0]);1236
ENSURE_TAG(vm, tt_noise, "dsp-noise");1237
return sigil_make_foreign(vm, tt_noise, p, destroy_noise, sizeof(sp_noise));1238
}1240
/* (noise-compute noise) -> flonum */1241
static Value native_noise_compute(SigilVM *vm, int argc, Value *args)1242
{1243
sp_noise *p = get_noise(vm, args[0]);1244
if (!p) { sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "noise-compute: expected noise"); return SIGIL_FALSE; }1245
SPFLOAT in = 0, out = 0;1246
sp_noise_compute(g_sp, p, &in, &out);1247
return sigil_flonum((double)out);1248
}1250
/* (make-pinknoise amp) -> <pinknoise> */1251
static Value native_make_pinknoise(SigilVM *vm, int argc, Value *args)1252
{1253
CHECK_SP(vm, "make-pinknoise");1254
sp_pinknoise *p;1255
sp_pinknoise_create(&p);1256
sp_pinknoise_init(g_sp, p);1257
p->amp = (SPFLOAT)sigil_as_flonum(args[0]);1258
ENSURE_TAG(vm, tt_pinknoise, "dsp-pinknoise");1259
return sigil_make_foreign(vm, tt_pinknoise, p, destroy_pinknoise, sizeof(sp_pinknoise));1260
}1262
/* (pinknoise-compute pinknoise) -> flonum */1263
static Value native_pinknoise_compute(SigilVM *vm, int argc, Value *args)1264
{1265
sp_pinknoise *p = get_pinknoise(vm, args[0]);1266
if (!p) { sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "pinknoise-compute: expected pinknoise"); return SIGIL_FALSE; }1267
SPFLOAT in = 0, out = 0;1268
sp_pinknoise_compute(g_sp, p, &in, &out);1269
return sigil_flonum((double)out);1270
}1272
/* (make-brown) -> <brown> */1273
static Value native_make_brown(SigilVM *vm, int argc, Value *args)1274
{1275
CHECK_SP(vm, "make-brown");1276
sp_brown *p;1277
sp_brown_create(&p);1278
sp_brown_init(g_sp, p);1279
ENSURE_TAG(vm, tt_brown, "dsp-brown");1280
return sigil_make_foreign(vm, tt_brown, p, destroy_brown, sizeof(sp_brown));1281
}1283
/* (brown-compute brown) -> flonum */1284
static Value native_brown_compute(SigilVM *vm, int argc, Value *args)1285
{1286
sp_brown *p = get_brown(vm, args[0]);1287
if (!p) { sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "brown-compute: expected brown"); return SIGIL_FALSE; }1288
SPFLOAT in = 0, out = 0;1289
sp_brown_compute(g_sp, p, &in, &out);1290
return sigil_flonum((double)out);1291
}1293
/* ============================================================1294
* KARPLUS-STRONG1295
* ============================================================ */1297
/* (make-ks freq decay excite-gain) -> <ks> */1298
static Value native_make_ks(SigilVM *vm, int argc, Value *args)1299
{1300
(void)argc;1301
CHECK_SP(vm, "make-ks");1302
SPFLOAT freq = (SPFLOAT)sigil_as_flonum(args[0]);1303
SPFLOAT decay = (SPFLOAT)sigil_as_flonum(args[1]);1304
SPFLOAT gain = (SPFLOAT)sigil_as_flonum(args[2]);1305
sp_ks *p;1306
sp_ks_create(&p);1307
sp_ks_init(g_sp, p, freq, decay, gain);1308
ENSURE_TAG(vm, tt_ks, "dsp-ks");1309
return sigil_make_foreign(vm, tt_ks, p, destroy_ks,1310
sizeof(sp_ks) + (size_t)p->bufcap * sizeof(SPFLOAT));1311
}1313
/* (ks-compute ks gate) -> flonum */1314
static Value native_ks_compute(SigilVM *vm, int argc, Value *args)1315
{1316
(void)argc;1317
sp_ks *p = get_ks(vm, args[0]);1318
if (!p) { sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "ks-compute: expected ks"); return SIGIL_FALSE; }1319
SPFLOAT gate = (SPFLOAT)sigil_as_flonum(args[1]);1320
SPFLOAT out = 0.0f;1321
sp_ks_compute(g_sp, p, &gate, &out);1322
return sigil_flonum((double)out);1323
}1325
/* (ks-trigger! ks) — manual excitation */1326
static Value native_ks_trigger(SigilVM *vm, int argc, Value *args)1327
{1328
(void)argc;1329
sp_ks *p = get_ks(vm, args[0]);1330
if (!p) { sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "ks-trigger!: expected ks"); return SIGIL_FALSE; }1331
sp_ks_trigger(g_sp, p);1332
return SIGIL_NIL;1333
}1335
/* (ks-set-freq! ks freq) */1336
static Value native_ks_set_freq(SigilVM *vm, int argc, Value *args)1337
{1338
(void)argc;1339
sp_ks *p = get_ks(vm, args[0]);1340
if (!p) { sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "ks-set-freq!: expected ks"); return SIGIL_FALSE; }1341
p->freq = (SPFLOAT)sigil_as_flonum(args[1]);1342
sp_ks_retune(g_sp, p);1343
return SIGIL_NIL;1344
}1346
/* (ks-set-decay! ks decay) */1347
static Value native_ks_set_decay(SigilVM *vm, int argc, Value *args)1348
{1349
(void)argc;1350
sp_ks *p = get_ks(vm, args[0]);1351
if (!p) { sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "ks-set-decay!: expected ks"); return SIGIL_FALSE; }1352
p->decay = (SPFLOAT)sigil_as_flonum(args[1]);1353
sp_ks_retune(g_sp, p);1354
return SIGIL_NIL;1355
}1357
/* (ks-set-excite-gain! ks gain) */1358
static Value native_ks_set_excite_gain(SigilVM *vm, int argc, Value *args)1359
{1360
(void)argc;1361
sp_ks *p = get_ks(vm, args[0]);1362
if (!p) { sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "ks-set-excite-gain!: expected ks"); return SIGIL_FALSE; }1363
p->excite_gain = (SPFLOAT)sigil_as_flonum(args[1]);1364
return SIGIL_NIL;1365
}1367
/* ============================================================1368
* FM4 — four-operator FM voice (fm4.h)1369
* ============================================================ */1371
#define FM4_GET(vm, args, name) \1372
sp_fm4 *p = get_fm4(vm, args[0]); \1373
if (!p) { sigil__vm_set_error(vm, SIGIL_ERR_TYPE, name ": expected fm4"); return SIGIL_FALSE; }1375
/* (make-fm4 algorithm feedback vel-depth vel-curve) */1376
static Value native_make_fm4(SigilVM *vm, int argc, Value *args)1377
{1378
(void)argc;1379
CHECK_SP(vm, "make-fm4");1380
int alg = (int)as_number(args[0]);1381
if (alg < 0 || alg >= SP_FM4_ALGORITHMS) {1382
sigil__vm_set_error(vm, SIGIL_ERR_RUNTIME, "make-fm4: algorithm out of range 0..7");1383
return SIGIL_FALSE;1384
}1385
sp_fm4 *p;1386
sp_fm4_create(&p);1387
sp_fm4_init(g_sp, p);1388
sp_fm4_set_algorithm(p, alg);1389
p->feedback = (SPFLOAT)as_number(args[1]);1390
p->vel_depth = (SPFLOAT)as_number(args[2]);1391
p->vel_curve = (SPFLOAT)as_number(args[3]);1392
ENSURE_TAG(vm, tt_fm4, "dsp-fm4");1393
return sigil_make_foreign(vm, tt_fm4, p, destroy_fm4, sizeof(sp_fm4));1394
}1396
/* (fm4-set-op! fm4 op ratio level attack decay sustain release) — op is 0..3 */1397
static Value native_fm4_set_op(SigilVM *vm, int argc, Value *args)1398
{1399
(void)argc;1400
FM4_GET(vm, args, "fm4-set-op!");1401
int op = (int)as_number(args[1]);1402
if (op < 0 || op >= SP_FM4_OPS) {1403
sigil__vm_set_error(vm, SIGIL_ERR_RUNTIME, "fm4-set-op!: operator out of range 0..3");1404
return SIGIL_FALSE;1405
}1406
sp_fm4_set_op(p, op,1407
(SPFLOAT)as_number(args[2]), (SPFLOAT)as_number(args[3]),1408
(SPFLOAT)as_number(args[4]), (SPFLOAT)as_number(args[5]),1409
(SPFLOAT)as_number(args[6]), (SPFLOAT)as_number(args[7]));1410
return SIGIL_NIL;1411
}1413
/* (fm4-set-algorithm! fm4 algorithm) */1414
static Value native_fm4_set_algorithm(SigilVM *vm, int argc, Value *args)1415
{1416
(void)argc;1417
FM4_GET(vm, args, "fm4-set-algorithm!");1418
if (sp_fm4_set_algorithm(p, (int)as_number(args[1])) != SP_OK) {1419
sigil__vm_set_error(vm, SIGIL_ERR_RUNTIME, "fm4-set-algorithm!: algorithm out of range 0..7");1420
return SIGIL_FALSE;1421
}1422
return SIGIL_NIL;1423
}1425
/* (fm4-set-feedback! fm4 feedback) */1426
static Value native_fm4_set_feedback(SigilVM *vm, int argc, Value *args)1427
{1428
(void)argc;1429
FM4_GET(vm, args, "fm4-set-feedback!");1430
p->feedback = (SPFLOAT)as_number(args[1]);1431
return SIGIL_NIL;1432
}1434
/* (fm4-compute fm4 freq gate index velocity) -> flonum */1435
static Value native_fm4_compute(SigilVM *vm, int argc, Value *args)1436
{1437
(void)argc;1438
FM4_GET(vm, args, "fm4-compute");1439
SPFLOAT out = 0.0f;1440
sp_fm4_compute(g_sp, p,1441
(SPFLOAT)as_number(args[1]), (SPFLOAT)as_number(args[2]),1442
(SPFLOAT)as_number(args[3]), (SPFLOAT)as_number(args[4]),1443
&out);1444
return sigil_flonum((double)out);1445
}1447
/* (fm4-algorithm-name algorithm) -> string */1448
static Value native_fm4_algorithm_name(SigilVM *vm, int argc, Value *args)1449
{1450
(void)argc;1451
int alg = (int)as_number(args[0]);1452
if (alg < 0 || alg >= SP_FM4_ALGORITHMS) return SIGIL_FALSE;1453
const char *name = sp_fm4_algorithm_table()[alg].name;1454
return sigil_make_string(vm, name, strlen(name));1455
}1457
/* ============================================================1458
* FATTENERS — chorus, crush, compressor (fx4.h)1459
* ============================================================ */1461
/* (make-chorus) */1462
static Value native_make_chorus(SigilVM *vm, int argc, Value *args)1463
{1464
(void)argc; (void)args;1465
CHECK_SP(vm, "make-chorus");1466
sp_chorus *p;1467
sp_chorus_create(&p);1468
sp_chorus_init(g_sp, p);1469
ENSURE_TAG(vm, tt_chorus, "dsp-chorus");1470
return sigil_make_foreign(vm, tt_chorus, p, destroy_chorus,1471
sizeof(sp_chorus) + (size_t)p->bufsize * sizeof(SPFLOAT));1472
}1474
/* (chorus-compute chorus in rate depth-ms mix) -> flonum */1475
static Value native_chorus_compute(SigilVM *vm, int argc, Value *args)1476
{1477
(void)argc;1478
sp_chorus *p = get_chorus(vm, args[0]);1479
if (!p) { sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "chorus-compute: expected chorus"); return SIGIL_FALSE; }1480
SPFLOAT out = 0.0f;1481
sp_chorus_compute(g_sp, p, (SPFLOAT)as_number(args[1]),1482
(SPFLOAT)as_number(args[2]), (SPFLOAT)as_number(args[3]),1483
(SPFLOAT)as_number(args[4]), &out);1484
return sigil_flonum((double)out);1485
}1487
/* (make-crush) */1488
static Value native_make_crush(SigilVM *vm, int argc, Value *args)1489
{1490
(void)argc; (void)args;1491
CHECK_SP(vm, "make-crush");1492
sp_crush *p;1493
sp_crush_create(&p);1494
sp_crush_init(g_sp, p);1495
ENSURE_TAG(vm, tt_crush, "dsp-crush");1496
return sigil_make_foreign(vm, tt_crush, p, destroy_crush, sizeof(sp_crush));1497
}1499
/* (crush-compute crush in drive bits rate-div) -> flonum */1500
static Value native_crush_compute(SigilVM *vm, int argc, Value *args)1501
{1502
(void)argc;1503
sp_crush *p = get_crush(vm, args[0]);1504
if (!p) { sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "crush-compute: expected crush"); return SIGIL_FALSE; }1505
SPFLOAT out = 0.0f;1506
sp_crush_compute(g_sp, p, (SPFLOAT)as_number(args[1]),1507
(SPFLOAT)as_number(args[2]), (SPFLOAT)as_number(args[3]),1508
(SPFLOAT)as_number(args[4]), &out);1509
return sigil_flonum((double)out);1510
}1512
/* (make-comp attack release makeup-db) */1513
static Value native_make_comp(SigilVM *vm, int argc, Value *args)1514
{1515
(void)argc;1516
CHECK_SP(vm, "make-comp");1517
sp_comp *p;1518
sp_comp_create(&p);1519
sp_comp_init(g_sp, p, (SPFLOAT)as_number(args[0]),1520
(SPFLOAT)as_number(args[1]), (SPFLOAT)as_number(args[2]));1521
ENSURE_TAG(vm, tt_comp, "dsp-comp");1522
return sigil_make_foreign(vm, tt_comp, p, destroy_comp, sizeof(sp_comp));1523
}1525
/* (comp-compute comp in threshold-db ratio) -> flonum */1526
static Value native_comp_compute(SigilVM *vm, int argc, Value *args)1527
{1528
(void)argc;1529
sp_comp *p = get_comp(vm, args[0]);1530
if (!p) { sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "comp-compute: expected comp"); return SIGIL_FALSE; }1531
SPFLOAT out = 0.0f;1532
sp_comp_compute(g_sp, p, (SPFLOAT)as_number(args[1]),1533
(SPFLOAT)as_number(args[2]), (SPFLOAT)as_number(args[3]), &out);1534
return sigil_flonum((double)out);1535
}1537
/* ============================================================1538
* DYNAMICS / WAVESHAPING1539
* ============================================================ */1541
/* (make-saturator drive dcoffset) -> <saturator> */1542
static Value native_make_saturator(SigilVM *vm, int argc, Value *args)1543
{1544
CHECK_SP(vm, "make-saturator");1545
sp_saturator *p;1546
sp_saturator_create(&p);1547
sp_saturator_init(g_sp, p);1548
p->drive = (SPFLOAT)sigil_as_flonum(args[0]);1549
p->dcoffset = (SPFLOAT)sigil_as_flonum(args[1]);1550
ENSURE_TAG(vm, tt_saturator, "dsp-saturator");1551
return sigil_make_foreign(vm, tt_saturator, p, destroy_saturator, sizeof(sp_saturator));1552
}1554
/* (saturator-compute saturator input) -> flonum */1555
static Value native_saturator_compute(SigilVM *vm, int argc, Value *args)1556
{1557
sp_saturator *p = get_saturator(vm, args[0]);1558
if (!p) { sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "saturator-compute: expected saturator"); return SIGIL_FALSE; }1559
SPFLOAT in = (SPFLOAT)sigil_as_flonum(args[1]);1560
SPFLOAT out = 0;1561
sp_saturator_compute(g_sp, p, &in, &out);1562
return sigil_flonum((double)out);1563
}1565
/* (make-clip limit) -> <clip> */1566
static Value native_make_clip(SigilVM *vm, int argc, Value *args)1567
{1568
CHECK_SP(vm, "make-clip");1569
sp_clip *p;1570
sp_clip_create(&p);1571
sp_clip_init(g_sp, p);1572
p->lim = (SPFLOAT)sigil_as_flonum(args[0]);1573
ENSURE_TAG(vm, tt_clip, "dsp-clip");1574
return sigil_make_foreign(vm, tt_clip, p, destroy_clip, sizeof(sp_clip));1575
}1577
/* (clip-compute clip input) -> flonum */1578
static Value native_clip_compute(SigilVM *vm, int argc, Value *args)1579
{1580
sp_clip *p = get_clip(vm, args[0]);1581
if (!p) { sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "clip-compute: expected clip"); return SIGIL_FALSE; }1582
SPFLOAT in = (SPFLOAT)sigil_as_flonum(args[1]);1583
SPFLOAT out = 0;1584
sp_clip_compute(g_sp, p, &in, &out);1585
return sigil_flonum((double)out);1586
}1588
/* (make-peaklim atk rel thresh) -> <peaklim> */1589
static Value native_make_peaklim(SigilVM *vm, int argc, Value *args)1590
{1591
CHECK_SP(vm, "make-peaklim");1592
sp_peaklim *p;1593
sp_peaklim_create(&p);1594
sp_peaklim_init(g_sp, p);1595
p->atk = (SPFLOAT)sigil_as_flonum(args[0]);1596
p->rel = (SPFLOAT)sigil_as_flonum(args[1]);1597
p->thresh = (SPFLOAT)sigil_as_flonum(args[2]);1598
ENSURE_TAG(vm, tt_peaklim, "dsp-peaklim");1599
return sigil_make_foreign(vm, tt_peaklim, p, destroy_peaklim, sizeof(sp_peaklim));1600
}1602
/* (peaklim-compute peaklim input) -> flonum */1603
static Value native_peaklim_compute(SigilVM *vm, int argc, Value *args)1604
{1605
sp_peaklim *p = get_peaklim(vm, args[0]);1606
if (!p) { sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "peaklim-compute: expected peaklim"); return SIGIL_FALSE; }1607
SPFLOAT in = (SPFLOAT)sigil_as_flonum(args[1]);1608
SPFLOAT out = 0;1609
sp_peaklim_compute(g_sp, p, &in, &out);1610
return sigil_flonum((double)out);1611
}1613
/* ============================================================1614
* SPATIAL — PAN21615
* ============================================================ */1617
/* (make-pan2 [pan]) -> <pan2> */1618
static Value native_make_pan2(SigilVM *vm, int argc, Value *args)1619
{1620
CHECK_SP(vm, "make-pan2");1621
sp_pan2 *p;1622
sp_pan2_create(&p);1623
sp_pan2_init(g_sp, p);1624
p->pan = argc > 0 ? (SPFLOAT)sigil_as_flonum(args[0]) : 0.5f;1625
ENSURE_TAG(vm, tt_pan2, "dsp-pan2");1626
return sigil_make_foreign(vm, tt_pan2, p, destroy_pan2, sizeof(sp_pan2));1627
}1629
/* (pan2-compute pan2 input) -> (left . right) */1630
static Value native_pan2_compute(SigilVM *vm, int argc, Value *args)1631
{1632
sp_pan2 *p = get_pan2(vm, args[0]);1633
if (!p) { sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "pan2-compute: expected pan2"); return SIGIL_FALSE; }1634
SPFLOAT in = (SPFLOAT)sigil_as_flonum(args[1]);1635
SPFLOAT outL = 0, outR = 0;1636
sp_pan2_compute(g_sp, p, &in, &outL, &outR);1637
Value l = sigil_flonum((double)outL);1638
Value r = sigil_flonum((double)outR);1639
return sigil_cons(vm,l, r);1640
}1642
/* (pan2-set-pan! pan2 pan) */1643
static Value native_pan2_set_pan(SigilVM *vm, int argc, Value *args)1644
{1645
sp_pan2 *p = get_pan2(vm, args[0]);1646
if (!p) { sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "pan2-set-pan!: expected pan2"); return SIGIL_FALSE; }1647
p->pan = (SPFLOAT)sigil_as_flonum(args[1]);1648
return SIGIL_NIL;1649
}1651
/* ============================================================1652
* TIMING1653
* ============================================================ */1655
/* (make-metro freq) -> <metro> */1656
static Value native_make_metro(SigilVM *vm, int argc, Value *args)1657
{1658
CHECK_SP(vm, "make-metro");1659
sp_metro *p;1660
sp_metro_create(&p);1661
sp_metro_init(g_sp, p);1662
p->freq = (SPFLOAT)sigil_as_flonum(args[0]);1663
ENSURE_TAG(vm, tt_metro, "dsp-metro");1664
return sigil_make_foreign(vm, tt_metro, p, destroy_metro, sizeof(sp_metro));1665
}1667
/* (metro-compute metro) -> flonum (0 or 1) */1668
static Value native_metro_compute(SigilVM *vm, int argc, Value *args)1669
{1670
sp_metro *p = get_metro(vm, args[0]);1671
if (!p) { sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "metro-compute: expected metro"); return SIGIL_FALSE; }1672
SPFLOAT in = 0, out = 0;1673
sp_metro_compute(g_sp, p, &in, &out);1674
return sigil_flonum((double)out);1675
}1677
/* (metro-set-freq! metro freq) */1678
static Value native_metro_set_freq(SigilVM *vm, int argc, Value *args)1679
{1680
sp_metro *p = get_metro(vm, args[0]);1681
if (!p) { sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "metro-set-freq!: expected metro"); return SIGIL_FALSE; }1682
p->freq = (SPFLOAT)sigil_as_flonum(args[1]);1683
return SIGIL_NIL;1684
}1686
/* (make-clock bpm subdiv) -> <clock> */1687
static Value native_make_clock(SigilVM *vm, int argc, Value *args)1688
{1689
CHECK_SP(vm, "make-clock");1690
sp_clock *p;1691
sp_clock_create(&p);1692
sp_clock_init(g_sp, p);1693
p->bpm = (SPFLOAT)sigil_as_flonum(args[0]);1694
p->subdiv = (SPFLOAT)sigil_as_flonum(args[1]);1695
ENSURE_TAG(vm, tt_clock, "dsp-clock");1696
return sigil_make_foreign(vm, tt_clock, p, destroy_clock, sizeof(sp_clock));1697
}1699
/* (clock-compute clock trigger) -> flonum (0 or 1) */1700
static Value native_clock_compute(SigilVM *vm, int argc, Value *args)1701
{1702
sp_clock *p = get_clock_mod(vm, args[0]);1703
if (!p) { sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "clock-compute: expected clock"); return SIGIL_FALSE; }1704
SPFLOAT trig = (SPFLOAT)sigil_as_flonum(args[1]);1705
SPFLOAT out = 0;1706
sp_clock_compute(g_sp, p, &trig, &out);1707
return sigil_flonum((double)out);1708
}1710
/* (clock-set-bpm! clock bpm) */1711
static Value native_clock_set_bpm(SigilVM *vm, int argc, Value *args)1712
{1713
sp_clock *p = get_clock_mod(vm, args[0]);1714
if (!p) { sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "clock-set-bpm!: expected clock"); return SIGIL_FALSE; }1715
p->bpm = (SPFLOAT)sigil_as_flonum(args[1]);1716
return SIGIL_NIL;1717
}1719
/* (make-tgate time) -> <tgate> */1720
static Value native_make_tgate(SigilVM *vm, int argc, Value *args)1721
{1722
CHECK_SP(vm, "make-tgate");1723
sp_tgate *p;1724
sp_tgate_create(&p);1725
sp_tgate_init(g_sp, p);1726
p->time = (SPFLOAT)sigil_as_flonum(args[0]);1727
ENSURE_TAG(vm, tt_tgate, "dsp-tgate");1728
return sigil_make_foreign(vm, tt_tgate, p, destroy_tgate, sizeof(sp_tgate));1729
}1731
/* (tgate-compute tgate trigger) -> flonum (0 or 1) */1732
static Value native_tgate_compute(SigilVM *vm, int argc, Value *args)1733
{1734
sp_tgate *p = get_tgate(vm, args[0]);1735
if (!p) { sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "tgate-compute: expected tgate"); return SIGIL_FALSE; }1736
SPFLOAT trig = (SPFLOAT)sigil_as_flonum(args[1]);1737
SPFLOAT out = 0;1738
sp_tgate_compute(g_sp, p, &trig, &out);1739
return sigil_flonum((double)out);1740
}1742
/* ============================================================1743
* MODULATION — RANDOM1744
* ============================================================ */1746
/* (make-randh min max freq) -> <randh> */1747
static Value native_make_randh(SigilVM *vm, int argc, Value *args)1748
{1749
CHECK_SP(vm, "make-randh");1750
sp_randh *p;1751
sp_randh_create(&p);1752
sp_randh_init(g_sp, p);1753
p->min = (SPFLOAT)sigil_as_flonum(args[0]);1754
p->max = (SPFLOAT)sigil_as_flonum(args[1]);1755
p->freq = (SPFLOAT)sigil_as_flonum(args[2]);1756
ENSURE_TAG(vm, tt_randh, "dsp-randh");1757
return sigil_make_foreign(vm, tt_randh, p, destroy_randh, sizeof(sp_randh));1758
}1760
/* (randh-compute randh) -> flonum */1761
static Value native_randh_compute(SigilVM *vm, int argc, Value *args)1762
{1763
sp_randh *p = get_randh(vm, args[0]);1764
if (!p) { sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "randh-compute: expected randh"); return SIGIL_FALSE; }1765
SPFLOAT in = 0, out = 0;1766
sp_randh_compute(g_sp, p, &in, &out);1767
return sigil_flonum((double)out);1768
}1770
/* (make-randi min max freq) -> <randi> */1771
static Value native_make_randi(SigilVM *vm, int argc, Value *args)1772
{1773
CHECK_SP(vm, "make-randi");1774
sp_randi *p;1775
sp_randi_create(&p);1776
sp_randi_init(g_sp, p);1777
p->min = (SPFLOAT)sigil_as_flonum(args[0]);1778
p->max = (SPFLOAT)sigil_as_flonum(args[1]);1779
p->cps = (SPFLOAT)sigil_as_flonum(args[2]);1780
ENSURE_TAG(vm, tt_randi, "dsp-randi");1781
return sigil_make_foreign(vm, tt_randi, p, destroy_randi, sizeof(sp_randi));1782
}1784
/* (randi-compute randi) -> flonum */1785
static Value native_randi_compute(SigilVM *vm, int argc, Value *args)1786
{1787
sp_randi *p = get_randi(vm, args[0]);1788
if (!p) { sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "randi-compute: expected randi"); return SIGIL_FALSE; }1789
SPFLOAT in = 0, out = 0;1790
sp_randi_compute(g_sp, p, &in, &out);1791
return sigil_flonum((double)out);1792
}1794
/* ============================================================1795
* UTILITY1796
* ============================================================ */1798
/* (make-scale min max) -> <scale> */1799
static Value native_make_scale(SigilVM *vm, int argc, Value *args)1800
{1801
CHECK_SP(vm, "make-scale");1802
sp_scale *p;1803
sp_scale_create(&p);1804
sp_scale_init(g_sp, p);1805
p->min = (SPFLOAT)sigil_as_flonum(args[0]);1806
p->max = (SPFLOAT)sigil_as_flonum(args[1]);1807
ENSURE_TAG(vm, tt_scale, "dsp-scale");1808
return sigil_make_foreign(vm, tt_scale, p, destroy_scale, sizeof(sp_scale));1809
}1811
/* (scale-compute scale input) -> flonum */1812
static Value native_scale_compute(SigilVM *vm, int argc, Value *args)1813
{1814
sp_scale *p = get_scale(vm, args[0]);1815
if (!p) { sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "scale-compute: expected scale"); return SIGIL_FALSE; }1816
SPFLOAT in = (SPFLOAT)sigil_as_flonum(args[1]);1817
SPFLOAT out = 0;1818
sp_scale_compute(g_sp, p, &in, &out);1819
return sigil_flonum((double)out);1820
}1822
/* (make-clamp min max) -> <clamp> */1823
static Value native_make_clamp(SigilVM *vm, int argc, Value *args)1824
{1825
CHECK_SP(vm, "make-clamp");1826
sp_clamp *p;1827
sp_clamp_create(&p);1828
sp_clamp_init(g_sp, p);1829
p->min = (SPFLOAT)sigil_as_flonum(args[0]);1830
p->max = (SPFLOAT)sigil_as_flonum(args[1]);1831
ENSURE_TAG(vm, tt_clamp, "dsp-clamp");1832
return sigil_make_foreign(vm, tt_clamp, p, destroy_clamp, sizeof(sp_clamp));1833
}1835
/* (clamp-compute clamp input) -> flonum */1836
static Value native_clamp_compute(SigilVM *vm, int argc, Value *args)1837
{1838
sp_clamp *p = get_clamp(vm, args[0]);1839
if (!p) { sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "clamp-compute: expected clamp"); return SIGIL_FALSE; }1840
SPFLOAT in = (SPFLOAT)sigil_as_flonum(args[1]);1841
SPFLOAT out = 0;1842
sp_clamp_compute(g_sp, p, &in, &out);1843
return sigil_flonum((double)out);1844
}1846
/* (make-crossfade [pos]) -> <crossfade> */1847
static Value native_make_crossfade(SigilVM *vm, int argc, Value *args)1848
{1849
CHECK_SP(vm, "make-crossfade");1850
sp_crossfade *p;1851
sp_crossfade_create(&p);1852
sp_crossfade_init(g_sp, p);1853
p->pos = argc > 0 ? (SPFLOAT)sigil_as_flonum(args[0]) : 0.5f;1854
ENSURE_TAG(vm, tt_crossfade, "dsp-crossfade");1855
return sigil_make_foreign(vm, tt_crossfade, p, destroy_crossfade, sizeof(sp_crossfade));1856
}1858
/* (crossfade-compute crossfade in1 in2) -> flonum */1859
static Value native_crossfade_compute(SigilVM *vm, int argc, Value *args)1860
{1861
sp_crossfade *p = get_crossfade(vm, args[0]);1862
if (!p) { sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "crossfade-compute: expected crossfade"); return SIGIL_FALSE; }1863
SPFLOAT in1 = (SPFLOAT)sigil_as_flonum(args[1]);1864
SPFLOAT in2 = (SPFLOAT)sigil_as_flonum(args[2]);1865
SPFLOAT out = 0;1866
sp_crossfade_compute(g_sp, p, &in1, &in2, &out);1867
return sigil_flonum((double)out);1868
}1870
/* (crossfade-set-pos! crossfade pos) */1871
static Value native_crossfade_set_pos(SigilVM *vm, int argc, Value *args)1872
{1873
sp_crossfade *p = get_crossfade(vm, args[0]);1874
if (!p) { sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "crossfade-set-pos!: expected crossfade"); return SIGIL_FALSE; }1875
p->pos = (SPFLOAT)sigil_as_flonum(args[1]);1876
return SIGIL_NIL;1877
}1879
/* ============================================================1880
* WAV OUTPUT1881
* ============================================================ */1883
/* (make-wavout filename) -> <wavout> */1884
static Value native_make_wavout(SigilVM *vm, int argc, Value *args)1885
{1886
CHECK_SP(vm, "make-wavout");1887
if (!sigil_is_string(args[0])) {1888
sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "make-wavout: expected string filename");1889
return SIGIL_FALSE;1890
}1891
SigilString *s = (SigilString *)sigil_as_ptr(args[0]);1892
sp_wavout *p;1893
sp_wavout_create(&p);1894
sp_wavout_init(g_sp, p, s->data);1895
ENSURE_TAG(vm, tt_wavout, "dsp-wavout");1896
return sigil_make_foreign(vm, tt_wavout, p, destroy_wavout, 0);1897
}1899
/* (wavout-compute wavout sample) -> flonum */1900
static Value native_wavout_compute(SigilVM *vm, int argc, Value *args)1901
{1902
sp_wavout *p = get_wavout(vm, args[0]);1903
if (!p) { sigil__vm_set_error(vm, SIGIL_ERR_TYPE, "wavout-compute: expected wavout"); return SIGIL_FALSE; }1904
SPFLOAT in = (SPFLOAT)sigil_as_flonum(args[1]);1905
SPFLOAT out = 0;1906
sp_wavout_compute(g_sp, p, &in, &out);1907
return sigil_flonum((double)out);1908
}1910
/* ============================================================1911
* MODULE INITIALIZATION1912
* ============================================================ */1914
void sigil__init_sigil_dsp_module(SigilVM *vm)1915
{1916
/* === (sigil dsp core) === */1917
SigilModule *mod = sigil_begin_module(vm, "(sigil dsp core)");1918
if (!mod) return;1920
sigil_module_register_native(vm, "dsp-init", native_dsp_init,1921
SIGIL_ARITY_RANGE(0, 1), "Initialize DSP engine");1922
sigil_module_register_native(vm, "dsp-shutdown", native_dsp_shutdown,1923
SIGIL_ARITY_EXACT(0), "Shutdown DSP engine");1924
sigil_module_register_native(vm, "dsp-sample-rate", native_dsp_sample_rate,1925
SIGIL_ARITY_EXACT(0), "Get sample rate");1927
/* Function tables */1928
sigil_module_register_native(vm, "make-ftbl", native_make_ftbl,1929
SIGIL_ARITY_EXACT(1), "Create function table");1930
sigil_module_register_native(vm, "ftbl-gen-sine", native_ftbl_gen_sine,1931
SIGIL_ARITY_EXACT(1), "Fill table with sine wave");1932
sigil_module_register_native(vm, "ftbl-gen-triangle", native_ftbl_gen_triangle,1933
SIGIL_ARITY_EXACT(1), "Fill table with triangle wave");1934
sigil_module_register_native(vm, "ftbl-gen-line", native_ftbl_gen_line,1935
SIGIL_ARITY_EXACT(2), "Fill table with line segments");1937
sigil_module_export(vm, "dsp-init");1938
sigil_module_export(vm, "dsp-shutdown");1939
sigil_module_export(vm, "dsp-sample-rate");1940
sigil_module_export(vm, "make-ftbl");1941
sigil_module_export(vm, "ftbl-gen-sine");1942
sigil_module_export(vm, "ftbl-gen-triangle");1943
sigil_module_export(vm, "ftbl-gen-line");1944
sigil_end_module(vm);1946
/* === (sigil dsp osc) === */1947
mod = sigil_begin_module(vm, "(sigil dsp osc)");1948
if (!mod) return;1950
sigil_module_register_native(vm, "make-osc", native_make_osc,1951
SIGIL_ARITY_RANGE(2, 3), "Create wavetable osc (freq amp [phase])");1952
sigil_module_register_native(vm, "make-osc-ft", native_make_osc_ft,1953
SIGIL_ARITY_RANGE(3, 4), "Create wavetable osc with custom ftbl");1954
sigil_module_register_native(vm, "osc-compute", native_osc_compute,1955
SIGIL_ARITY_EXACT(1), "Compute one sample from osc");1956
sigil_module_register_native(vm, "osc-set-freq!", native_osc_set_freq,1957
SIGIL_ARITY_EXACT(2), "Set osc frequency");1958
sigil_module_register_native(vm, "osc-set-amp!", native_osc_set_amp,1959
SIGIL_ARITY_EXACT(2), "Set osc amplitude");1961
sigil_module_register_native(vm, "make-posc3", native_make_posc3,1962
SIGIL_ARITY_RANGE(2, 3), "Create cubic interp wavetable osc");1963
sigil_module_register_native(vm, "posc3-compute", native_posc3_compute,1964
SIGIL_ARITY_EXACT(1), "Compute one sample from posc3");1965
sigil_module_register_native(vm, "posc3-set-freq!", native_posc3_set_freq,1966
SIGIL_ARITY_EXACT(2), "Set posc3 frequency");1967
sigil_module_register_native(vm, "posc3-set-amp!", native_posc3_set_amp,1968
SIGIL_ARITY_EXACT(2), "Set posc3 amplitude");1970
sigil_module_register_native(vm, "make-blsaw", native_make_blsaw,1971
SIGIL_ARITY_EXACT(2), "Create bandlimited sawtooth (freq amp)");1972
sigil_module_register_native(vm, "blsaw-compute", native_blsaw_compute,1973
SIGIL_ARITY_EXACT(1), "Compute one sample from blsaw");1974
sigil_module_register_native(vm, "blsaw-set-freq!", native_blsaw_set_freq,1975
SIGIL_ARITY_EXACT(2), "Set blsaw frequency");1976
sigil_module_register_native(vm, "blsaw-set-amp!", native_blsaw_set_amp,1977
SIGIL_ARITY_EXACT(2), "Set blsaw amplitude");1979
sigil_module_register_native(vm, "make-blsquare", native_make_blsquare,1980
SIGIL_ARITY_RANGE(2, 3), "Create bandlimited square (freq amp [width])");1981
sigil_module_register_native(vm, "blsquare-compute", native_blsquare_compute,1982
SIGIL_ARITY_EXACT(1), "Compute one sample from blsquare");1983
sigil_module_register_native(vm, "blsquare-set-freq!", native_blsquare_set_freq,1984
SIGIL_ARITY_EXACT(2), "Set blsquare frequency");1985
sigil_module_register_native(vm, "blsquare-set-amp!", native_blsquare_set_amp,1986
SIGIL_ARITY_EXACT(2), "Set blsquare amplitude");1988
sigil_module_register_native(vm, "make-bltriangle", native_make_bltriangle,1989
SIGIL_ARITY_EXACT(2), "Create bandlimited triangle (freq amp)");1990
sigil_module_register_native(vm, "bltriangle-compute", native_bltriangle_compute,1991
SIGIL_ARITY_EXACT(1), "Compute one sample from bltriangle");1992
sigil_module_register_native(vm, "bltriangle-set-freq!", native_bltriangle_set_freq,1993
SIGIL_ARITY_EXACT(2), "Set bltriangle frequency");1994
sigil_module_register_native(vm, "bltriangle-set-amp!", native_bltriangle_set_amp,1995
SIGIL_ARITY_EXACT(2), "Set bltriangle amplitude");1997
sigil_module_register_native(vm, "make-fosc", native_make_fosc,1998
SIGIL_ARITY_EXACT(5), "Create FM osc (freq car mod indx amp)");1999
sigil_module_register_native(vm, "fosc-compute", native_fosc_compute,2000
SIGIL_ARITY_EXACT(1), "Compute one sample from fosc");2001
sigil_module_register_native(vm, "fosc-set-freq!", native_fosc_set_freq,2002
SIGIL_ARITY_EXACT(2), "Set fosc frequency");2003
sigil_module_register_native(vm, "fosc-set-index!", native_fosc_set_index,2004
SIGIL_ARITY_EXACT(2), "Set fosc modulation index");2005
sigil_module_register_native(vm, "fosc-set-amp!", native_fosc_set_amp,2006
SIGIL_ARITY_EXACT(2), "Set fosc amplitude");2008
sigil_module_register_native(vm, "make-phasor", native_make_phasor,2009
SIGIL_ARITY_RANGE(1, 2), "Create phasor (freq [phase])");2010
sigil_module_register_native(vm, "phasor-compute", native_phasor_compute,2011
SIGIL_ARITY_EXACT(1), "Compute one sample from phasor");2012
sigil_module_register_native(vm, "phasor-set-freq!", native_phasor_set_freq,2013
SIGIL_ARITY_EXACT(2), "Set phasor frequency");2015
sigil_module_register_native(vm, "make-ks", native_make_ks,2016
SIGIL_ARITY_EXACT(3), "Create Karplus-Strong (freq decay excite-gain)");2017
sigil_module_register_native(vm, "ks-compute", native_ks_compute,2018
SIGIL_ARITY_EXACT(2), "Compute Karplus-Strong (ks gate) -> sample");2019
sigil_module_register_native(vm, "ks-trigger!", native_ks_trigger,2020
SIGIL_ARITY_EXACT(1), "Excite Karplus-Strong with noise burst");2021
sigil_module_register_native(vm, "ks-set-freq!", native_ks_set_freq,2022
SIGIL_ARITY_EXACT(2), "Set KS fundamental frequency");2023
sigil_module_register_native(vm, "ks-set-decay!", native_ks_set_decay,2024
SIGIL_ARITY_EXACT(2), "Set KS -60 dB decay time");2025
sigil_module_register_native(vm, "ks-set-excite-gain!", native_ks_set_excite_gain,2026
SIGIL_ARITY_EXACT(2), "Set KS excitation amplitude");2028
sigil_module_register_native(vm, "make-fm4", native_make_fm4,2029
SIGIL_ARITY_EXACT(4), "Create 4-op FM voice (algorithm feedback vel-depth vel-curve)");2030
sigil_module_register_native(vm, "fm4-set-op!", native_fm4_set_op,2031
SIGIL_ARITY_EXACT(8), "Set operator (fm4 op ratio level attack decay sustain release)");2032
sigil_module_register_native(vm, "fm4-set-algorithm!", native_fm4_set_algorithm,2033
SIGIL_ARITY_EXACT(2), "Set fm4 algorithm 0..7");2034
sigil_module_register_native(vm, "fm4-set-feedback!", native_fm4_set_feedback,2035
SIGIL_ARITY_EXACT(2), "Set fm4 operator-4 feedback 0..1");2036
sigil_module_register_native(vm, "fm4-compute", native_fm4_compute,2037
SIGIL_ARITY_EXACT(5), "Compute fm4 (fm4 freq gate index velocity) -> sample");2038
sigil_module_register_native(vm, "fm4-algorithm-name", native_fm4_algorithm_name,2039
SIGIL_ARITY_EXACT(1), "Name of fm4 algorithm 0..7");2041
/* Export all osc bindings */2042
const char *osc_exports[] = {2043
"make-osc", "make-osc-ft", "osc-compute", "osc-set-freq!", "osc-set-amp!",2044
"make-posc3", "posc3-compute", "posc3-set-freq!", "posc3-set-amp!",2045
"make-blsaw", "blsaw-compute", "blsaw-set-freq!", "blsaw-set-amp!",2046
"make-blsquare", "blsquare-compute", "blsquare-set-freq!", "blsquare-set-amp!",2047
"make-bltriangle", "bltriangle-compute", "bltriangle-set-freq!", "bltriangle-set-amp!",2048
"make-fosc", "fosc-compute", "fosc-set-freq!", "fosc-set-index!", "fosc-set-amp!",2049
"make-phasor", "phasor-compute", "phasor-set-freq!",2050
"make-ks", "ks-compute", "ks-trigger!",2051
"ks-set-freq!", "ks-set-decay!", "ks-set-excite-gain!",2052
"make-fm4", "fm4-set-op!", "fm4-set-algorithm!", "fm4-set-feedback!",2053
"fm4-compute", "fm4-algorithm-name",2054
NULL2055
};2056
for (int i = 0; osc_exports[i]; i++) sigil_module_export(vm, osc_exports[i]);2057
sigil_end_module(vm);2059
/* === (sigil dsp filter) === */2060
mod = sigil_begin_module(vm, "(sigil dsp filter)");2061
if (!mod) return;2063
sigil_module_register_native(vm, "make-moogladder", native_make_moogladder,2064
SIGIL_ARITY_EXACT(2), "Create Moog ladder filter (freq res)");2065
sigil_module_register_native(vm, "make-butlp", native_make_butlp,2066
SIGIL_ARITY_EXACT(1), "Create Butterworth lowpass (freq)");2067
sigil_module_register_native(vm, "make-buthp", native_make_buthp,2068
SIGIL_ARITY_EXACT(1), "Create Butterworth highpass (freq)");2069
sigil_module_register_native(vm, "make-lpf18", native_make_lpf18,2070
SIGIL_ARITY_EXACT(3), "Create 3-pole resonant LP (cutoff res dist)");2071
sigil_module_register_native(vm, "make-tone", native_make_tone,2072
SIGIL_ARITY_EXACT(1), "Create 1st-order lowpass (freq)");2073
sigil_module_register_native(vm, "make-atone", native_make_atone,2074
SIGIL_ARITY_EXACT(1), "Create 1st-order highpass (freq)");2075
sigil_module_register_native(vm, "make-dcblock", native_make_dcblock,2076
SIGIL_ARITY_EXACT(0), "Create DC blocking filter");2077
sigil_module_register_native(vm, "filter-compute", native_filter_compute,2078
SIGIL_ARITY_EXACT(2), "Compute filter (filter input) -> output");2079
sigil_module_register_native(vm, "filter-set-freq!", native_filter_set_freq,2080
SIGIL_ARITY_EXACT(2), "Set filter cutoff frequency");2081
sigil_module_register_native(vm, "filter-set-res!", native_filter_set_res,2082
SIGIL_ARITY_EXACT(2), "Set filter resonance");2084
const char *filter_exports[] = {2085
"make-moogladder", "make-butlp", "make-buthp", "make-lpf18",2086
"make-tone", "make-atone", "make-dcblock",2087
"filter-compute", "filter-set-freq!", "filter-set-res!",2088
NULL2089
};2090
for (int i = 0; filter_exports[i]; i++) sigil_module_export(vm, filter_exports[i]);2091
sigil_end_module(vm);2093
/* === (sigil dsp env) === */2094
mod = sigil_begin_module(vm, "(sigil dsp env)");2095
if (!mod) return;2097
sigil_module_register_native(vm, "make-adsr", native_make_adsr,2098
SIGIL_ARITY_EXACT(4), "Create ADSR envelope (atk dec sus rel)");2099
sigil_module_register_native(vm, "adsr-compute", native_adsr_compute,2100
SIGIL_ARITY_EXACT(2), "Compute ADSR (adsr gate) -> env value");2101
sigil_module_register_native(vm, "make-tadsr", native_make_tadsr,2102
SIGIL_ARITY_EXACT(4), "Create triggered ADSR (atk dec sus rel)");2103
sigil_module_register_native(vm, "tadsr-compute", native_tadsr_compute,2104
SIGIL_ARITY_EXACT(2), "Compute triggered ADSR");2105
sigil_module_register_native(vm, "make-tenv", native_make_tenv,2106
SIGIL_ARITY_EXACT(3), "Create triggered envelope (atk hold rel)");2107
sigil_module_register_native(vm, "tenv-compute", native_tenv_compute,2108
SIGIL_ARITY_EXACT(2), "Compute triggered envelope");2109
sigil_module_register_native(vm, "make-line", native_make_line,2110
SIGIL_ARITY_EXACT(3), "Create line segment (a dur b)");2111
sigil_module_register_native(vm, "line-compute", native_line_compute,2112
SIGIL_ARITY_EXACT(2), "Compute line segment");2113
sigil_module_register_native(vm, "make-expon", native_make_expon,2114
SIGIL_ARITY_EXACT(3), "Create exponential curve (a dur b)");2115
sigil_module_register_native(vm, "expon-compute", native_expon_compute,2116
SIGIL_ARITY_EXACT(2), "Compute exponential curve");2117
sigil_module_register_native(vm, "make-port", native_make_port,2118
SIGIL_ARITY_EXACT(1), "Create portamento (smoothing)");2119
sigil_module_register_native(vm, "port-compute", native_port_compute,2120
SIGIL_ARITY_EXACT(2), "Compute portamento");2122
const char *env_exports[] = {2123
"make-adsr", "adsr-compute", "make-tadsr", "tadsr-compute",2124
"make-tenv", "tenv-compute", "make-line", "line-compute",2125
"make-expon", "expon-compute", "make-port", "port-compute",2126
NULL2127
};2128
for (int i = 0; env_exports[i]; i++) sigil_module_export(vm, env_exports[i]);2129
sigil_end_module(vm);2131
/* === (sigil dsp fx) === */2132
mod = sigil_begin_module(vm, "(sigil dsp fx)");2133
if (!mod) return;2135
sigil_module_register_native(vm, "make-revsc", native_make_revsc,2136
SIGIL_ARITY_EXACT(2), "Create stereo reverb (feedback lpfreq)");2137
sigil_module_register_native(vm, "revsc-compute", native_revsc_compute,2138
SIGIL_ARITY_EXACT(3), "Compute reverb (revsc inL inR) -> (outL . outR)");2139
sigil_module_register_native(vm, "revsc-set-feedback!", native_revsc_set_feedback,2140
SIGIL_ARITY_EXACT(2), "Set reverb feedback");2141
sigil_module_register_native(vm, "revsc-set-lpfreq!", native_revsc_set_lpfreq,2142
SIGIL_ARITY_EXACT(2), "Set reverb LP frequency");2144
sigil_module_register_native(vm, "make-zitarev", native_make_zitarev,2145
SIGIL_ARITY_EXACT(0), "Create Zita reverb");2146
sigil_module_register_native(vm, "zitarev-compute", native_zitarev_compute,2147
SIGIL_ARITY_EXACT(3), "Compute Zita reverb");2148
sigil_module_register_native(vm, "zitarev-set-mix!", native_zitarev_set_mix,2149
SIGIL_ARITY_EXACT(2), "Set Zita reverb mix");2150
sigil_module_register_native(vm, "zitarev-set-level!", native_zitarev_set_level,2151
SIGIL_ARITY_EXACT(2), "Set Zita reverb level");2153
sigil_module_register_native(vm, "make-delay", native_make_delay,2154
SIGIL_ARITY_EXACT(2), "Create delay (time feedback)");2155
sigil_module_register_native(vm, "delay-compute", native_delay_compute,2156
SIGIL_ARITY_EXACT(2), "Compute delay (delay input) -> output");2157
sigil_module_register_native(vm, "delay-set-feedback!", native_delay_set_feedback,2158
SIGIL_ARITY_EXACT(2), "Set delay feedback");2160
sigil_module_register_native(vm, "make-vdelay", native_make_vdelay,2161
SIGIL_ARITY_EXACT(2), "Create variable delay (maxdel feedback)");2162
sigil_module_register_native(vm, "vdelay-compute", native_vdelay_compute,2163
SIGIL_ARITY_EXACT(2), "Compute variable delay");2164
sigil_module_register_native(vm, "vdelay-set-del!", native_vdelay_set_del,2165
SIGIL_ARITY_EXACT(2), "Set variable delay time");2166
sigil_module_register_native(vm, "vdelay-set-feedback!", native_vdelay_set_feedback,2167
SIGIL_ARITY_EXACT(2), "Set variable delay feedback");2169
sigil_module_register_native(vm, "make-chorus", native_make_chorus,2170
SIGIL_ARITY_EXACT(0), "Create chorus");2171
sigil_module_register_native(vm, "chorus-compute", native_chorus_compute,2172
SIGIL_ARITY_EXACT(5), "Compute chorus (chorus in rate depth-ms mix) -> sample");2173
sigil_module_register_native(vm, "make-crush", native_make_crush,2174
SIGIL_ARITY_EXACT(0), "Create crush (drive + bit depth + rate reduction)");2175
sigil_module_register_native(vm, "crush-compute", native_crush_compute,2176
SIGIL_ARITY_EXACT(5), "Compute crush (crush in drive bits rate-div) -> sample");2177
sigil_module_register_native(vm, "make-comp", native_make_comp,2178
SIGIL_ARITY_EXACT(3), "Create compressor (attack release makeup-db)");2179
sigil_module_register_native(vm, "comp-compute", native_comp_compute,2180
SIGIL_ARITY_EXACT(4), "Compute compressor (comp in threshold-db ratio) -> sample");2182
const char *fx_exports[] = {2183
"make-revsc", "revsc-compute", "revsc-set-feedback!", "revsc-set-lpfreq!",2184
"make-zitarev", "zitarev-compute", "zitarev-set-mix!", "zitarev-set-level!",2185
"make-delay", "delay-compute", "delay-set-feedback!",2186
"make-vdelay", "vdelay-compute", "vdelay-set-del!", "vdelay-set-feedback!",2187
"make-chorus", "chorus-compute", "make-crush", "crush-compute",2188
"make-comp", "comp-compute",2189
NULL2190
};2191
for (int i = 0; fx_exports[i]; i++) sigil_module_export(vm, fx_exports[i]);2192
sigil_end_module(vm);2194
/* === (sigil dsp noise) === */2195
mod = sigil_begin_module(vm, "(sigil dsp noise)");2196
if (!mod) return;2198
sigil_module_register_native(vm, "make-noise", native_make_noise,2199
SIGIL_ARITY_EXACT(1), "Create white noise (amp)");2200
sigil_module_register_native(vm, "noise-compute", native_noise_compute,2201
SIGIL_ARITY_EXACT(1), "Compute one noise sample");2202
sigil_module_register_native(vm, "make-pinknoise", native_make_pinknoise,2203
SIGIL_ARITY_EXACT(1), "Create pink noise (amp)");2204
sigil_module_register_native(vm, "pinknoise-compute", native_pinknoise_compute,2205
SIGIL_ARITY_EXACT(1), "Compute one pinknoise sample");2206
sigil_module_register_native(vm, "make-brown", native_make_brown,2207
SIGIL_ARITY_EXACT(0), "Create brown noise");2208
sigil_module_register_native(vm, "brown-compute", native_brown_compute,2209
SIGIL_ARITY_EXACT(1), "Compute one brown noise sample");2211
const char *noise_exports[] = {2212
"make-noise", "noise-compute",2213
"make-pinknoise", "pinknoise-compute",2214
"make-brown", "brown-compute",2215
NULL2216
};2217
for (int i = 0; noise_exports[i]; i++) sigil_module_export(vm, noise_exports[i]);2218
sigil_end_module(vm);2220
/* === (sigil dsp util) === */2221
mod = sigil_begin_module(vm, "(sigil dsp util)");2222
if (!mod) return;2224
/* Dynamics */2225
sigil_module_register_native(vm, "make-saturator", native_make_saturator,2226
SIGIL_ARITY_EXACT(2), "Create saturator (drive dcoffset)");2227
sigil_module_register_native(vm, "saturator-compute", native_saturator_compute,2228
SIGIL_ARITY_EXACT(2), "Compute saturator");2229
sigil_module_register_native(vm, "make-clip", native_make_clip,2230
SIGIL_ARITY_EXACT(1), "Create hard clipper (limit)");2231
sigil_module_register_native(vm, "clip-compute", native_clip_compute,2232
SIGIL_ARITY_EXACT(2), "Compute clipper");2233
sigil_module_register_native(vm, "make-peaklim", native_make_peaklim,2234
SIGIL_ARITY_EXACT(3), "Create peak limiter (atk rel thresh)");2235
sigil_module_register_native(vm, "peaklim-compute", native_peaklim_compute,2236
SIGIL_ARITY_EXACT(2), "Compute peak limiter");2238
/* Panning */2239
sigil_module_register_native(vm, "make-pan2", native_make_pan2,2240
SIGIL_ARITY_RANGE(0, 1), "Create panner ([pan])");2241
sigil_module_register_native(vm, "pan2-compute", native_pan2_compute,2242
SIGIL_ARITY_EXACT(2), "Compute pan2 (pan2 input) -> (L . R)");2243
sigil_module_register_native(vm, "pan2-set-pan!", native_pan2_set_pan,2244
SIGIL_ARITY_EXACT(2), "Set pan position");2246
/* Timing */2247
sigil_module_register_native(vm, "make-metro", native_make_metro,2248
SIGIL_ARITY_EXACT(1), "Create metronome (freq)");2249
sigil_module_register_native(vm, "metro-compute", native_metro_compute,2250
SIGIL_ARITY_EXACT(1), "Compute metronome");2251
sigil_module_register_native(vm, "metro-set-freq!", native_metro_set_freq,2252
SIGIL_ARITY_EXACT(2), "Set metronome frequency");2253
sigil_module_register_native(vm, "make-clock", native_make_clock,2254
SIGIL_ARITY_EXACT(2), "Create clock (bpm subdiv)");2255
sigil_module_register_native(vm, "clock-compute", native_clock_compute,2256
SIGIL_ARITY_EXACT(2), "Compute clock");2257
sigil_module_register_native(vm, "clock-set-bpm!", native_clock_set_bpm,2258
SIGIL_ARITY_EXACT(2), "Set clock BPM");2259
sigil_module_register_native(vm, "make-tgate", native_make_tgate,2260
SIGIL_ARITY_EXACT(1), "Create triggered gate (time)");2261
sigil_module_register_native(vm, "tgate-compute", native_tgate_compute,2262
SIGIL_ARITY_EXACT(2), "Compute triggered gate");2264
/* Random */2265
sigil_module_register_native(vm, "make-randh", native_make_randh,2266
SIGIL_ARITY_EXACT(3), "Create random hold (min max freq)");2267
sigil_module_register_native(vm, "randh-compute", native_randh_compute,2268
SIGIL_ARITY_EXACT(1), "Compute random hold");2269
sigil_module_register_native(vm, "make-randi", native_make_randi,2270
SIGIL_ARITY_EXACT(3), "Create random interp (min max freq)");2271
sigil_module_register_native(vm, "randi-compute", native_randi_compute,2272
SIGIL_ARITY_EXACT(1), "Compute random interp");2274
/* Scaling */2275
sigil_module_register_native(vm, "make-scale", native_make_scale,2276
SIGIL_ARITY_EXACT(2), "Create scaler (min max)");2277
sigil_module_register_native(vm, "scale-compute", native_scale_compute,2278
SIGIL_ARITY_EXACT(2), "Compute scale");2279
sigil_module_register_native(vm, "make-clamp", native_make_clamp,2280
SIGIL_ARITY_EXACT(2), "Create clamp (min max)");2281
sigil_module_register_native(vm, "clamp-compute", native_clamp_compute,2282
SIGIL_ARITY_EXACT(2), "Compute clamp");2283
sigil_module_register_native(vm, "make-crossfade", native_make_crossfade,2284
SIGIL_ARITY_RANGE(0, 1), "Create crossfade ([pos])");2285
sigil_module_register_native(vm, "crossfade-compute", native_crossfade_compute,2286
SIGIL_ARITY_EXACT(3), "Compute crossfade (xf in1 in2)");2287
sigil_module_register_native(vm, "crossfade-set-pos!", native_crossfade_set_pos,2288
SIGIL_ARITY_EXACT(2), "Set crossfade position");2290
/* WAV output */2291
sigil_module_register_native(vm, "make-wavout", native_make_wavout,2292
SIGIL_ARITY_EXACT(1), "Create WAV file writer (filename)");2293
sigil_module_register_native(vm, "wavout-compute", native_wavout_compute,2294
SIGIL_ARITY_EXACT(2), "Write sample to WAV");2296
const char *util_exports[] = {2297
"make-saturator", "saturator-compute",2298
"make-clip", "clip-compute",2299
"make-peaklim", "peaklim-compute",2300
"make-pan2", "pan2-compute", "pan2-set-pan!",2301
"make-metro", "metro-compute", "metro-set-freq!",2302
"make-clock", "clock-compute", "clock-set-bpm!",2303
"make-tgate", "tgate-compute",2304
"make-randh", "randh-compute",2305
"make-randi", "randi-compute",2306
"make-scale", "scale-compute",2307
"make-clamp", "clamp-compute",2308
"make-crossfade", "crossfade-compute", "crossfade-set-pos!",2309
"make-wavout", "wavout-compute",2310
NULL2311
};2312
for (int i = 0; util_exports[i]; i++) sigil_module_export(vm, util_exports[i]);2313
sigil_end_module(vm);2314
}