#08 Filters

A filter is a function that modifies a signal.

Similar to synths, you can define a filter using a simple lambda function (input, options) => output [l, r]

If you want to keep a state (for example, when creating a delay effect), you can also define a filter using a class that implements a process method.

Note: the input of a filter will always be a stereo signal, and you always have to return a stereo signal.

dittytoy.net/syntax#filters

#dittytoy #tutorial

Log in to post a comment.

// #08 Filters. DittyToy 2022.
// The MIT License.
//
// https://dittytoy.net/ditty/4a37b66afe
//
// A filter is a function that modifies a signal.
// 
// Similar to synths, you can define a filter using a simple lambda function
//  (input, options) => output [l, r]
//
// https://dittytoy.net/syntax#filters
//

// Define a filter using a lambda function:

const flipChannels = filter.def( (input, options) => [input[1], -input[0]], {});

// Note: the input of a filter will always be a stereo signal, and you always have to return a stereo signal.

// If you want to keep a state (for example, when creating a delay effect), you 
// can also define a filter using a class that implements a process method.

const lowpass = filter.def(class {
    constructor(options) {
        this.hist0 = [0, 0];
        this.hist1 = [0, 0];
    }

    process(input, options) {
        const alpha = options.cutoff;

        if (input) {
            for (let i = 0; i < 2; i++) {
                this.hist0[i] += alpha * (input[i] - this.hist0[i]);
                this.hist1[i] += alpha * (this.hist0[i] - this.hist1[i]);
            }

            return this.hist1;
        }
    }
}, { cutoff: 1 });

// You can apply multiply filters on an input signal by chaining.

const kick = synth.def( (phase, env, tick, options) => Math.sin(phase * 2 * Math.PI * (1.5 - tick * 4)) * env.value);
const tri  = synth.def( (phase, env, tick, options) => { const v = (phase % 1) * 4; return (v < 2 ? v - 1 : 3 - v) * env.value }, { attack: 0.0125, release: 0.25, amp: 0.8 });

ditty.bpm = 140;

loop( (loopCount) => {
    
    kick.play(c3, { attack: 0.025, release: 0.05 });
    
}, { sync: 1, name: 'kick' })
.connect( flipChannels.create() ); // connect a filter to the loop


loop( (loopCount) => {
    scale(c3, scales.minor_pentatonic, 1).forEach( note => {
        tri.play(note, { pan: Math.random() * 2 - 1 });
        sleep(0.25);
    });
}, { name: 'melody' })
.connect( flipChannels.create() ) // connect two filters to this loop
.connect( lowpass.create(  { cutoff: () => 0.4 + 0.3 * Math.sin(ditty.time) } ) );