#17 Portamento

One possible solution to create a portamento:

Create an additional property in the options object. When setting an options property value, it tracks the time of the setter within the loop. The actual assignment of the value is then, like the play calls, put on a timeline and executed later at the appropriate time.

dittytoy.net/syntax#portamento
dittytoy.net/syntax#options

#dittytoy #tutorial

Log in to post a comment.

// #17 Portamento. DittyToy 2022.
// The MIT License.
//
// https://dittytoy.net/ditty/220e9dcde7
//
// Forked from "How do I create a mono synth?" by athibaul - https://dittytoy.net/ditty/662d460791
//
// Every time Dittytoy starts a new iteration of a loop, the entire body of the loop is evaluated instantaneously. 
// All play-calls are collected and sorted based on the intervening sleep times and put on a timeline before playback starts.
//
// A side effect of having the body of a loop evaluated in its entirety is that if you assign a value to a variable within
// a loop at different times, it thus has the last assigned value after the evaluation. 
//
// One possible solution to this problem is not to use a separate variable but to create an additional property in the 
// options object. When setting an options property value, it tracks the time of the setter within the loop. The actual 
// assignment of the value is then, like the play calls, put on a timeline and executed later at the appropriate time.
//
// https://dittytoy.net/syntax#portamento
// https://dittytoy.net/syntax#options
//

ditty.bpm = 60;

// To create a mono synth with portamento, we need to glide between notes, so I'm creating
// a "pitch smoother" to do that

class Smoother {
    // We feed values to this object, and it smoothes them out
    constructor(v, dur) {
        this.v = v;
        this.a0 = clamp01(ditty.dt / dur);
    }
    update(target) { // should be called once per sample
        return this.v += this.a0 * (target - this.v);
    }
}

// Melody
const melody = [c4,d4,e4,b3,e4,a3,a4,e4];

loop( () => {
    const note_smoother = new Smoother(c4, 0.1);
    
    // Use the smoothed values as the note number
    const s = sine.play( (tick, options) => note_smoother.update(options.target), { duration: melody.length, target: c4 } );

    melody.forEach( note => { // We now communicate notes via the option object
        s.options.target = note;
        sleep(1);
    });
});