Harping 🎸
Changing parameters might take a while until you hear it.
Reverb from Karplus synth with reverb by @srtuss
Log in to post a comment.
//
// RTFM You can find the DittyToy API Reference here: https://dittytoy.net/syntax
//
// reverb from https://dittytoy.net/ditty/827b1b3e63
class Delayline {
constructor(n) {
this.n = ~~n;
this.p = 0;
this.lastOut = 0;
this.data = new Float32Array(n);
}
clock(input) {
this.lastOut = this.data[this.p];
this.data[this.p] = input;
if(++this.p >= this.n) {
this.p = 0;
}
}
tap(offset) {
var x = this.p - offset - 1;
x %= this.n;
if(x < 0) {
x += this.n;
}
return this.data[x];
}
}
function allpass(delayline, x, k) {
var delayin = x - delayline.lastOut * k;
var y = delayline.lastOut + k * delayin;
delayline.clock(delayin);
return y;
}
// Simple allpass reverberator, based on this article:
// http://www.spinsemi.com/knowledge_base/effects.html
const reverb = filter.def(class {
constructor(options) {
this.lastReturn = 0;
this.krt = .7;
this.delaylines = [];
// Create several delay lines with random lengths
for(var i = 0; i < 12; ++i) {
this.delaylines.push(new Delayline(10 + Math.floor(Math.random() * 5000)));
}
}
process(input, options) {
var inv = input[0] + input[1];
var v = this.lastReturn;
// Let the signal pass through the loop of delay lines. Inject input signal at multiple locations.
v = allpass(this.delaylines[0], v + inv, .5);
v = allpass(this.delaylines[1], v, .5);
this.delaylines[2].clock(v);
v = this.delaylines[2].lastOut * this.krt;
v = allpass(this.delaylines[3], v + inv, .5);
v = allpass(this.delaylines[4], v, .5);
this.delaylines[5].clock(v);
v = this.delaylines[5].lastOut * this.krt;
v = allpass(this.delaylines[6], v + inv, .5);
v = allpass(this.delaylines[7], v, .5);
this.delaylines[8].clock(v);
v = this.delaylines[8].lastOut * this.krt;
v = allpass(this.delaylines[9], v + inv, .5);
v = allpass(this.delaylines[10], v, .5);
this.delaylines[11].clock(v);
v = this.delaylines[11].lastOut * this.krt;
this.lastReturn = v;
// Tap the delay lines at randomized locations and accumulate the output signal.
var ret = [0, 0];
ret[0] += this.delaylines[2].tap(111);
ret[1] += this.delaylines[2].tap(2250);
ret[0] += this.delaylines[5].tap(311);
ret[1] += this.delaylines[5].tap(1150);
ret[0] += this.delaylines[8].tap(511);
ret[1] += this.delaylines[8].tap(50);
ret[0] += this.delaylines[11].tap(4411);
ret[1] += this.delaylines[11].tap(540);
// Mix wet + dry signal.
ret[0] = ret[0] * .1 + input[0];
ret[1] = ret[1] * .1 + input[1];
// Slight stereo widening:
var m = (ret[0] + ret[1]) * .5;
var s = (ret[1] - ret[0]) * .5;
ret[0] = m + s * 1.5;
ret[1] = m - s * 1.5;
return ret;
}
});
// source: https://dittytoy.net/ditty/6f30b0885d
function tri(t) { return -1 + 4*Math.abs(t%1 - 0.5); }
const varsaw = synth.def(
(phase, env, tick) => { let x = (phase%1); return (x-0.5) * clamp01(15*x*(1-x)*(1 + 0.1*tri(tick))) * env.value; },
{attack:0.02, release:0.25, decay:0.5, sustain:0.15, duration: 1.5}
);
input.type = 1; // min=0, max=1, step=1 (Linear, Mirror)
input.sequenceLength = 16; // min=4, max=16, step=4
input.sequence = 1; // min=0, max=4, step=1 (+1, +2 -1, +3 -1 -1, +2 0 +2 -1 -2 0, custom)
input.stepSize = 2; // min=1, max=2, step=1
const scaleNotesMinor = scale(f2, scales['minor'], 64);
const scaleNotesHarmonic = scale(f2, scales['harmonic_minor'], 64);
const scaleNotesMajor = scale(f2, scales['major'], 64);
const scalesToChoose = new Array(12).fill(scaleNotesMajor);
scalesToChoose.push(scaleNotesHarmonic);
scalesToChoose.push(scaleNotesMinor);
const ease = t => t * t * (3.0 - 2.0 * t);
let stepSequence1 = [2,-1];
let stepSequence2 = [3,-1,-1];
let stepSequence3 = [2,0,2,-1,-2,0];
let stepSequenceCustom = [3,-2,-1,1]; // write your own custom arpeggio here
let stepSequences=[stepSequence1,stepSequence2,stepSequence3,stepSequenceCustom];
let step = 0;
loop( () => {
let scaleNotes = scalesToChoose.choose();
let size = input.sequenceLength;
let sequence = new Array(size).fill(0).map((_,idx) => idx*input.stepSize);
if (input.sequence >= 1) {
let stepSequence = stepSequences[input.sequence-1];
let tmp = [];
let acc=0;
for(let i=0;i<sequence.length;i++) {
acc+=stepSequence[i%stepSequence.length];
tmp.push(sequence[acc]);
}
sequence = tmp;
}
if (input.type == 1) {
sequence = sequence.mirror()
}
let stage = [0,0,0,1,2,3,4,5,6,7].choose();
for (let i=0; i<sequence.length; i++) {
if (scaleNotes[stage + (sequence[i]-1)]) varsaw.play( scaleNotes[stage + (sequence[i]-1)] , {amp: 0.5 + 0.5*ease(1-i/sequence.length), pan: Math.sin(1-i/sequence.length*3) * 0.5 });
sleep( 0.25 );
}
}, { name: 'arpeggio' }).connect(reverb.create());