// Here are some thoughts I have right now regarding DittyToy: // - I find that debugging can be quite difficult, because there are many cases in which // no audio is produced, but no error is shown, e.g. incorrect option name, uninitialized member variable. // - In particular, the error when the filter returns a single value rather than two is quite cryptic: // Worker error: this._gen(...) is not iterable // - The strict CPU limitations are frustrating, is there room for optimization? // - Ctrl+Enter compiles and runs, but is there a shortcut to pause the synth? // - I don't like the code completion tool, which suggests inappropriate completions most of the time, // and gets in my way during coding. // - Sometimes the code compiles but the synths don't start...? // - Is it possible to create envs manually, to use in the synth definition and/or in the loop()s? input.cutoff = 0.5; // min=0, max=1, step=0.001 const saw = synth.def( (phase, env) => (phase%1-0.5) * env.value); const linexp = (x,x0,x1,y0,y1) => y0 * (y1/y0) ** ((x-x0)/(x1-x0)); // Second order lowpass filter without resonance (mono) const lpf = filter.def(class { constructor(options) { this.s0 = 0; this.s1 = 0; } process(input, options) { this.a0 = clamp01(2*Math.PI * ditty.dt * options.cutoff); this.s0 += this.a0 * (input[0] - this.s0); this.s1 += this.a0 * (this.s0 - this.s1); //return this.s1; // Uncomment this line to get a cryptic error message return [this.s1, this.s1]; } }, {cutoff: 5000}); loop(() => { saw.play(c4); sleep(1); }, {name:"saw"}) .connect( lpf.create({cutoff: () => linexp(input.cutoff,0,1,20,20000)}) );