Last active
August 29, 2015 14:05
-
-
Save srikumarks/280edda1d023b1183168 to your computer and use it in GitHub Desktop.
Functional frequency modulation ...
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
// Here is a possible pure-functional implementation of stateful signals. | |
function makeSound(signal, currState, result, endCondition) { | |
return endCondition(currState) ? reverse(result, null) : signal(currState, function (nextState, val) { | |
return makeSound(signal, nextState, pair(val, result), endCondition); | |
}); | |
} | |
// A simple implementation of pair | |
function pair(val, list) { | |
return {head: val, tail: list}; | |
} | |
function reverse(list, tail) { | |
return list ? reverse(list.tail, pair(list.head, tail)) : tail; | |
} | |
// So a signal is a function that takes a “state” as arg1 and a continuation function | |
// as arg2 ... which itself takes a state as arg1 and a value as arg2. | |
// Here is a proper sine wave using this scheme - | |
// 'freq' itself is a signal that can change over time. | |
function sine(freq) { | |
return function (state, sink) { | |
return freq(state, function (state, val) { | |
var next = (state || 0) + val * dt; // dt is a global constant = 1/sampling_rate. | |
return sink(next, Math.sin(2 * Math.PI * next)); | |
}); | |
}; | |
} | |
// Here is a way to combine two signals using a binary function - | |
function combine(func, sig1, sig2) { | |
return function (state, sink) { | |
return sig1(state[0], function (state1, v1) { | |
return sig2(state[1], function (state2, v2) { | |
return sink([state1, state2], func(v1,v2)); | |
}); | |
}); | |
}; | |
} | |
// … and some sample functions defined using them - | |
function plusOp(a,b) { return a+b; } | |
function mulOp(a,b) { return a*b; } | |
function add(sig1, sig2) { | |
return combine(plusOp, sig1, sig2); | |
} | |
function mul(sig1, sig2) { | |
return combine(mulOp, sig1, sig2); | |
} | |
function konst(k) { | |
return function (state, sink) { | |
return sink(state, k); | |
}; | |
} | |
// After all that, comes the first recursive higher order function - | |
// a set of evenly spaced harmonics that can be frequency modulated. | |
function harmonics(freq, n) { | |
if (n === 0) { | |
return konst(0); | |
} | |
return add(sine(mul(freq, konst(n))), harmonics(freq, n-1)); | |
} | |
// Signal processing folks will cringe at the mountain of inefficiencies here ;) | |
// … but it does give the ability to abstract stateful signals. If you want to, | |
// you can thread something like “current_time” through the state argument. |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment