Leap Motion Theramin

A multi-timbral Theremin controlled with a Leap Motion controller.

by Admiral Potato

HTML

<script src="http://js.leapmotion.com/leap-0.4.1.js"></script>
<h1>Move your hands above your controller!</h1>

JavaScript

/*
 4 = 16
 3 = 8
 2 = 4
 1 = 2
 0 = 1
-1 = 1 / 2
-2 = 1 / 4
-3 = 1 / 8
-4 = 1 / 16

-1 = 0.5
-2 = 0.25
-3 = 0.125
-4 = 0.0625
*/

//http://en.wikipedia.org/wiki/Piano_key_frequencies
//http://creativejs.com/resources/web-audio-api-getting-started/

var noteFrequency = function(x){
	var factor = Math.pow(2, x);
	return factor * 440;
};

var noteQuantizer = function(x){
	var baseOctave = Math.floor(x),
		octaveFraction = x - baseOctave,
		noteWithinOctave = Math.round(octaveFraction * 12) / 12;
	return baseOctave + noteWithinOctave;
};

var x = 0;
for(var i = -4; i < 5; i++){
	x = noteFrequency(i);
	console.log("i:" + i + "; ouput:" + x);
}

var oscDisplay = document.createElement('div');
document.body.appendChild(oscDisplay);

var audioContext;
if (typeof AudioContext !== "undefined") {
	audioContext = new AudioContext();
} else if (typeof webkitAudioContext !== "undefined") {
	audioContext = new webkitAudioContext();
} else {
	throw new Error('AudioContext not supported. :(');
}

var oscArray = [];

var makeOscillator = function(){
	var osc = audioContext.createOscillator();
	osc.gainNode = audioContext.createGain();
	osc.gainNode.connect(audioContext.destination);
	osc.connect(osc.gainNode);
	osc.type = osc.SINE;
	osc.timeout = function(){
		osc.gainNode.gain.value = 0;
		console.log('SILENCE!');
	};
	osc.resetTimeout = function(){
		clearTimeout(osc.timeoutId);
		osc.timeoutId = setTimeout(osc.timeout, 1000);
	};
	osc.setValues = function(freq, vol){
		osc.frequency.value = freq;
		osc.gainNode.gain.value = vol;
		osc.resetTimeout();
	};
	osc.start();
	oscArray.push(osc);
	return osc;
};



var clamp = function(x){
	return Math.max(0, Math.min(x, 1));
};
var controller = new Leap.Controller({enableGestures: true});
controller.loop(function(frame) {
	var numHands = frame.hands.length,
		handIndex,
		handData,
		z, y,
		frequency,
		volume,
		osc,
		output = [];

	if(numHands > 0){
		for(handIndex = 0; handIndex < numHands; handIndex += 1){
			if(handIndex >...