Fractal Sonate

This fractal (Weierstrass function) is created for blind people to hear what fractals sound like

Log in to post a comment.

input.a = 0.5; // min=0.10, max=0.99, step=0.01
input.b = 7.00; // min=1.10, max=9.00, step=0.10

ditty.bpm = 69;

const Weierstrass = synth.def(class {
  constructor(){ this.p = 0; }
  process(note, env){
    const f = midi_to_hz(note);
    this.p += f * ditty.dt;
    let s = 0, A = 1, M = 1;
    for(let i=0;i<12;i++){ s += A * Math.cos(2*Math.PI*M*this.p); A *= input.a; M *= input.b; }
    s *= env.value * 0.18;
    return [s,s];
  }
},{attack:0.01,release:1.6});

function P(n,d){ Weierstrass.play(n,{duration:d}); }
function play_bar(bass,tri){ P(bass,12); for(let k=0;k<4;k++){ for(let i=0;i<3;i++){ P(tri[i],1); sleep(1); } } }

const BAR_SEQ=[[37,[61,64,68]],[47,[61,64,68]],[45,[57,61,64]],[42,[62,66,69]]];
const MELODY=[
  [73,6],[72,6],[71,6],[73,12],[68,6],[69,6],[71,12],
  [73,6],[72,6],[71,6],[73,12],[68,6],[69,6],[71,12],
  [73,6],[75,6],[76,6],[75,12],[73,6],[72,6],[71,12],
  [73,6],[72,6],[71,6],[73,12],[68,6],[69,6],[71,12],
];

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; }

const reverb = filter.def(class {
  constructor(options){
    this.lastReturn=0; this.krt=0.7; this.delaylines=[];
    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;
    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;
    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);
    ret[0]=ret[0]*.2+input[0];
    ret[1]=ret[1]*.2+input[1];
    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;
  }
});

const main = loop(()=>{
  for(let r=0;r<4;r++){
    for(let b=0;b<4;b++){
      const [bass,tri]=BAR_SEQ[b];
      const id=(r*4+b)%MELODY.length; const [mn,md]=MELODY[id];
      P(mn,md);
      play_bar(bass,tri);
    }
  }
});

main.connect(reverb.create());