Log in to post a comment.

input.waveForm = 2; //min=1 max=5 step=1 (Sine, Square, Triangle, Saw, Semi-circle)
input.overdriveLevel = 1 //min=1, max=100 step=.1

//
// RTFM You can find the DittyToy API Reference here: https://dittytoy.net/syntax
//
const WAVEFORM = {SINE: 1, SQUARE: 2, TRIANGLE: 3, SAW: 4, SEMICIRCLE: 5 };
const basicSynth = synth.def(class {
    process(note, env, tick, options) {
        switch(options.waveForm) {
            case WAVEFORM.SQUARE:
                return Array.from({length: options.k },
                    (v, i) => Math.sin(tick * midi_to_hz(note) * (2 * (i + 1) - 1) * 2 * Math.PI) / (2 * (i + 1) - 1)
                ).reduce((p, c) => p+c, 0) * 4 / Math.PI * env.value;
            case WAVEFORM.TRIANGLE:
                return Array.from({length: options.k },
                    (v, i) => (Math.sin(tick * midi_to_hz(note) * (2 * (i + 1) - 1) * 2 * Math.PI) / (2 * (i + 1) - 1)**2) * (-1)**(i+1)
                ).reduce((p, c) => p+c, 0) * 8 / Math.PI**2 * env.value;
            case WAVEFORM.SAW:
                return Array.from({length: options.k },
                    (v, i) => Math.sin(tick * midi_to_hz(note) * (i + 1) * 2 * Math.PI) / (i + 1) * (-1)**(i+1)
                ).reduce((p, c) => p+c, 0) * 2 / Math.PI * env.value;
            case WAVEFORM.SEMICIRCLE:
                // I modified the second answer from https://math.stackexchange.com/questions/44329/function-for-concatenated-semicircles
                // with a reference to https://www.desmos.com/calculator/e5xncapcnp
                const f = midi_to_hz(note) * Math.PI * tick * 2;
                return Math.sqrt(1 - ((2 * Math.asin(Math.sin(f))) / Math.PI)**2) * (Math.cos(f)/Math.abs(Math.cos(f))) * env.value;
            case WAVEFORM.SINE:
            default:
                return Math.sin(tick * midi_to_hz(note) * 2 * Math.PI) * env.value;
        }
    }
}, { name: 'basicSynth', k: 15, waveForm: WAVEFORM.SQUARE });

const overdrive = filter.def( (input, options) => [...input.map(i => clamp(i * options.level, -1, 1))], { level: 1 });

ditty.bpm = 70;
// Adapted from Bach's Cello Suite No. 1 in G Major BWV 1007, copied from https://dittytoy.net/ditty/0c920dd635
let melody = [d3,a3,fs4,e4,fs4,a3,fs4,a3,
             d3,a3,fs4,e4,fs4,a3,fs4,a3,
             d3,b3,g4,fs4,g4,b3,g4,b3,
             d3,b3,g4,fs4,g4,b3,g4,b3,
             d3,cs4,g4,fs4,g4,cs4,g4,cs4,
             d3,cs4,g4,fs4,g4,cs4,g4,cs4,
             d3,b3,fs4,e4,fs4,d4,cs4,d4,
             b3,d4,cs4,d4,fs3,a3,gs3,fs3,
             gs3,d4,e4,d4,e4,d4,e4,d4,
             gs3,d4,e4,d4,e4,d4,e4,d4,
             cs4,e4,a4,gs4,a4,e4,d4,e4,
             cs4,e4,d4,e4,a3,cs4,b3,a3,
             b2,fs3,d4,cs4,d4,fs3,d4,fs3,
             b2,fs3,d4,cs4,d4,fs3,d4,fs3,
             b2,gs3,a3,b3,a3,gs3,fs3,e3,
             d4,cs4,b3,a4,gs4,fs4,e4,d4,
             a2,b3,cs4,a4,e4,a4,cs4,e4,
             g4,b3,cs4,e4,g4,e4,cs4,a3,
             ];

loop( (count, options) => {
    melody.forEach(note => {
        [note].forEach((n, i) => {
            basicSynth.play(n, {amp:(Math.random() + 0.5 + (i%8==0?0.8:0)) * .5, pan:0.5 * (2*((n*0.618)%1)-1), release: .25, waveForm: () => input.waveForm });
            sleep(0.25);
        });
    })
}, { name: 'example' } ).connect(overdrive.create({level: () => input.overdriveLevel}));