Created
June 17, 2014 21:35
-
-
Save jonasschneider/bfa93fbb358313f5b708 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/*! | |
* | |
* stagas - need more 303 | |
* | |
*/ | |
var bpm = 125; | |
var tuning = 440; | |
var transpose = -1; | |
// constants | |
var tau = 2 * Math.PI; | |
// time coefficients | |
var t, tt; | |
function Oscillator(type, size){ | |
if (!(this instanceof Oscillator)) return new Oscillator(type, size); | |
this.pos = 0; | |
this.size = size || sampleRate; | |
this.coeff = this.size / sampleRate; | |
this.table = new Float32Array(this.size); | |
this.build(type); | |
} | |
Oscillator.prototype.build = function(type){ | |
switch (type) { | |
case 'sin': | |
var scale = 2 * Math.PI / this.size; | |
for (var i = 0; i < this.size; i++) { | |
this.table[i] = Math.sin(i * scale); | |
} | |
break; | |
case 'cos': | |
var scale = 2 * Math.PI / this.size; | |
for (var i = 0; i < this.size; i++) { | |
this.table[i] = Math.cos(i * scale); | |
} | |
break; | |
case 'saw': | |
for (var i = 0; i < this.size; i++) { | |
var x = (i / this.size); | |
this.table[i] = +2.0 * (x - Math.round(x)); | |
} | |
break; | |
case 'ramp': | |
for (var i = 0; i < this.size; i++) { | |
var x = (i / this.size); | |
this.table[i] = -2.0 * (x - Math.round(x)); | |
} | |
break; | |
case 'tri': | |
for (var i = 0; i < this.size; i++) { | |
var x = (i / this.size) - 0.25; | |
this.table[i] = 1.0 - 4.0 * Math.abs(Math.round(x) - x); | |
} | |
break; | |
case 'sqr': | |
var half = this.size / 2; | |
for (var i = 0; i < this.size; i++) { | |
this.table[i] = i < half ? +1 : -1; | |
} | |
break; | |
} | |
}; | |
Oscillator.prototype.play = function(freq){ | |
this.pos += freq * this.coeff; | |
if (this.pos >= this.size) this.pos -= this.size; | |
this.index = this.pos | 0; | |
this.alpha = this.pos - this.index; | |
this.next = this.table[this.index == this.size - 1 ? 0 : this.index + 1]; | |
this.curr = this.table[this.index]; | |
return this.curr + (this.next - this.curr) * this.alpha; | |
}; | |
function clock(_t){ | |
t = _t; | |
t *= bpm / 120; | |
tt = tau * t; | |
} | |
function clip(x){ | |
return x / (1 + Math.abs(x)); | |
} | |
function sequence(measure, seq){ | |
return seq[(t / measure / 2 | 0) % seq.length]; | |
} | |
function slide(measure, seq, speed){ | |
var pos = (t / measure / 2) % seq.length; | |
var now = pos | 0; | |
var next = now + 1; | |
var alpha = pos - now; | |
if (next == seq.length) next = 0; | |
return seq[now] + ((seq[next] - seq[now]) * Math.pow(alpha, speed)); | |
} | |
function arp(measure, x, y, z, l){ | |
if(!l) l = 0 | |
var ts = (t+l) / 2 % measure; | |
return Math.sin(x * (Math.exp(-ts * y))) * Math.exp(-ts * z); | |
} | |
function Noise(){ | |
return Math.random() * 2 - 1; | |
} | |
function note(n, octave){ | |
return Math.pow(2, ( | |
n + transpose - 33 + (12 * (octave || 0)) | |
) / 12) * tuning; // A4 tuning | |
} | |
function octave(o){ | |
return function(n){ | |
return n * o; | |
}; | |
} | |
function DiodeFilter(){ | |
this.k = 0; | |
this.A = 0; | |
this.z = [0,0,0,0,0]; | |
this.ah; | |
this.bh; | |
this.fc; | |
this.set_q(0); | |
this.set_hpf(0.5); | |
this.set_fc(.5); | |
} | |
DiodeFilter.prototype.set_hpf = function(fc){ | |
var K = fc * Math.PI; | |
this.ah = (K - 2) / (K + 2); | |
this.bh = 2 / (K + 2); | |
}; | |
DiodeFilter.prototype.reset = function(){ | |
if (this.k < 17) this.z = [0,0,0,0,0]; | |
}; | |
DiodeFilter.prototype.set_q = function(q){ | |
this.k = 20 * q; | |
this.A = 1 + 0.5 * this.k; | |
}; | |
DiodeFilter.prototype.set_fc = function(cutoff){ | |
cutoff = (cutoff * cutoff); | |
this.fc = cutoff <= 0 | |
? .02 | |
: (cutoff >= 1.0 ? .999 : cutoff); | |
}; | |
DiodeFilter.prototype.run = function(x){ | |
var a = Math.PI * this.fc; | |
a = 2 * Math.tan(0.5*a); // dewarping, not required with 2x oversampling | |
var ainv = 1 / a; | |
var a2 = a*a; | |
var b = 2*a + 1; | |
var b2 = b*b; | |
var c = 1 / (2*a2*a2 - 4*a2*b2 + b2*b2); | |
var g0 = 2*a2*a2*c; | |
var g = g0 * this.bh; | |
// current state | |
var s0 = (a2*a*this.z[0] + a2*b*this.z[1] + this.z[2]*(b2 - 2*a2)*a + this.z[3]*(b2 - 3*a2)*b) * c; | |
var s = this.bh*s0 - this.z[4]; | |
// solve feedback loop (linear) | |
var y5 = (g*x + s) / (1 + g*this.k); | |
// input clipping | |
var y0 = clip(x - this.k*y5); | |
y5 = g*y0 + s; | |
// compute integrator outputs | |
var y4 = g0*y0 + s0; | |
var y3 = (b*y4 - this.z[3]) * ainv; | |
var y2 = (b*y3 - a*y4 - this.z[2]) * ainv; | |
var y1 = (b*y2 - a*y3 - this.z[1]) * ainv; | |
// update filter state | |
this.z[0] += 4*a*(y0 - y1 + y2); | |
this.z[1] += 2*a*(y1 - 2*y2 + y3); | |
this.z[2] += 2*a*(y2 - 2*y3 + y4); | |
this.z[3] += 2*a*(y3 - 2*y4); | |
this.z[4] = this.bh*y4 + this.ah*y5; | |
return this.A*y4; | |
}; | |
var osc = Oscillator('saw', 1024); | |
var lfo = Oscillator('sin', 512); | |
var lfo2 = Oscillator('cos', 512); | |
var mprogression = [128, 64, 32]; | |
var progression = [ | |
0, 0, 0, 2, 0, 0, 0, 2, | |
0, 0, 0, 2, 0, 0, 5, 3, 5, 3, 5, 8, | |
]; | |
var filter = new DiodeFilter(); | |
filter.set_q(0.72); | |
filter.set_hpf(.0011); | |
function dsp(t){ | |
clock(t); | |
var p = sequence(1/2, progression); | |
var melody = [17, 5, 5, 17, 8, 20, 20, 20, 8, 17, 17].map(function(n){ | |
return note(n + p, 0); | |
}); | |
filter.set_fc( 0.001 + ((lfo.play(2.66) * 0.16 + 1) / 2) * (0.29 + lfo2.play(.01) * 0.17) ) ; | |
var n = slide(1/16, melody, 14); | |
var synth_osc = osc.play(n); | |
var synth = arp(1/16, synth_osc, 50, 50); | |
filter_synth = filter.run(synth * 0.6); | |
filter_synth = clip(filter_synth * 12); | |
synth = clip(synth * 12); | |
var kick = arp(1/4, 65, 63, 6); | |
var kick2 = arp(1/4, 165, 163, 16, -1/16); | |
//kick = 0; | |
// mixer | |
return 0.7 * ( | |
0.55 * synth | |
+ 0.35 * filter_synth | |
+ kick + kick2*0.2 | |
); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment