Projekt Leaper: Porovnání verzí

Řádek 9: Řádek 9:
 
V první fázi byl zvuk generován přímo počítačem (bylo potřeba nastavit temperované ladění a rozmezí oktáv), v závěrečné fázi se ale podařilo systém propojit s knihovnou zvuků GarageBand pomocí protokolu MIDI – v současné době je k dispozici využití veškerých nástrojů GarageBand.
 
V první fázi byl zvuk generován přímo počítačem (bylo potřeba nastavit temperované ladění a rozmezí oktáv), v závěrečné fázi se ale podařilo systém propojit s knihovnou zvuků GarageBand pomocí protokolu MIDI – v současné době je k dispozici využití veškerých nástrojů GarageBand.
  
== Odkazy a vlastní zdrojový kód ==
+
== Vlastní zdrojový kód ==
 +
'''Upozornění! Vzhledem k omezení syntaxe wikisofia kopírujte prosím zdrojový kód přímo z editace zdroje stránky, nikoliv z podoby, do jaké je intepretována při zobrazení na stránce. Přislušný úsek je v souladu se syntaxí české wikipedie umístěn mezi značkou <nowiki><tt> a </tt></nowiki>.'''
 +
 
 +
<tt>
 +
var lifx = require('./lifx');
 +
var util = require('util');
 +
var packet = require('./packet');
 +
var leap = require('leapjs');
 +
var midi = require('midi');
 +
 
 +
 
 +
var lx = lifx.init();
 +
 
 +
lx.on('bulbstate', function(b) {
 +
//console.log('Bulb state: ' + util.inspect(b));
 +
});
 +
 
 +
lx.on('bulbonoff', function(b) {
 +
//console.log('Bulb on/off: ' + util.inspect(b));
 +
});
 +
 
 +
Number.prototype.map = function ( in_min , in_max , out_min , out_max ) {
 +
  return ( this - in_min ) * ( out_max - out_min ) / ( in_max - in_min ) + out_min;
 +
}
 +
 
 +
 
 +
 
 +
 
 +
// Set up a new output.
 +
var output = new midi.output();
 +
 
 +
// Count the available output ports.
 +
var count = output.getPortCount();
 +
 
 +
console.log("Available ports: " + count)
 +
 
 +
// Get the name of a specified output port.
 +
output.getPortName(0);
 +
 
 +
// Open the first available output port.
 +
output.openPort(0);
 +
 
 +
// Send a MIDI message.
 +
output.sendMessage([176,22,1]);
 +
 
 +
 
 +
var damperPedal = true;
 +
 
 +
var toneMap = {
 +
'c' :  [ 60,72,84],
 +
//'cis' : [277.18,554.36],
 +
'd' :  [ 62,74],
 +
//'dis' : [ 311.13,622.26],
 +
'e' :  [ 64,76],
 +
'f' :  [ 65,77],
 +
//'fis' : [ 369.00,739.98],
 +
'g' :  [67,79],
 +
//'gis' : [ 415.00,830.60],
 +
'a'  :  [69,81],
 +
//'ais' : [233.08,466.17],
 +
'h'  : [71,83]
 +
}
 +
 
 +
 
 +
 
 +
 
 +
var dateDiff = function(start,end){
 +
return (end.getTime() - start.getTime())/1000;
 +
}
 +
 
 +
 
 +
var findTone = function(freq){
 +
var diff = 9999999999;
 +
var tone = null;
 +
for(var toneName in toneMap){
 +
//console.log("looking in " + toneName)
 +
for(var i = 0; i < toneMap[toneName].length; i++){
 +
var newDiff = Math.abs(freq- toneMap[toneName][i]);
 +
//console.log("diff " + newDiff)
 +
if(newDiff < diff){
 +
diff = newDiff;
 +
tone = {name : toneName, freq : toneMap[toneName][i]}
 +
//console.log("Found " + toneName + i)
 +
}
 +
}
 +
}
 +
if(tone != null){
 +
//console.log("Found " + tone.name + " " + tone.freq + "hz")
 +
}else{
 +
//console.log("No tone for " + freq)
 +
}
 +
 +
return tone;
 +
 
 +
}
 +
 
 +
var midiMessages = {
 +
"noteOn" : parseInt('10010000', 2),
 +
"noteOff" : parseInt('10000000',2),
 +
"mode" : parseInt('10110000',2),
 +
"damper" : parseInt('01000000',2),
 +
"pedalOff" : 127,
 +
"pedalOn" : 0
 +
}
 +
 
 +
var findToneByMidi = function(step){
 +
var diff = 9999999999;
 +
var tone = null;
 +
var stepIndex = 0;
 +
var  i = 0;
 +
for(i = 0; i< 3; i++){
 +
 
 +
for(var toneName in toneMap){
 +
//console.log("looking in " + toneName)
 +
 
 +
if(toneMap[toneName].length > i){
 +
 
 +
var newDiff = Math.abs(step-stepIndex);
 +
//console.log("aaa" + newDiff)
 +
//console.log("diff " + newDiff)
 +
if(newDiff < diff){
 +
diff = newDiff;
 +
tone = {name : toneName, freq : toneMap[toneName][i]}
 +
//console.log("Found " + toneName + i)
 +
}
 +
stepIndex++;
 +
    }
 +
 
 +
 +
}
 +
}
 +
 
 +
if(tone != null){
 +
//console.log("Found " + tone.name + " " + tone.freq + "hz")
 +
}else{
 +
//console.log("No tone for " + freq)
 +
}
 +
 +
return tone;
 +
}
 +
 
 +
var InterpolatedVal = function(){
 +
this.data = [];
 +
this.windowSize = 5;
 +
this.add = function(val){
 +
this.data.unshift(val);
 +
//console.log("Pusging value " + val + " win size " + this.windowSize)
 +
if(this.data.length > this.windowSize){
 +
this.data.pop(val)
 +
}
 +
//console.log("CData lenght " + this.data.length)
 +
}
 +
this.getValue = function(){
 +
var result = 0.0;
 +
for(var i = 0; i < this.data.length; i++){
 +
result += this.data[i];
 +
}
 +
//console.log("value " + result / this.data.length)
 +
return result / this.data.length
 +
}
 +
 
 +
};
 +
 
 +
var Hand = function(){
 +
this.grip = new InterpolatedVal();
 +
this.grip.windowSize  = 30;
 +
this.rotation = new InterpolatedVal();
 +
this.rotation.windowSize = 10;
 +
this.bulb = null;
 +
 
 +
this.note = new InterpolatedVal();
 +
};
 +
 
 +
var leftHand = new Hand();
 +
var rightHand = new Hand();
 +
 
 +
 
 +
var baudio = require('baudio');
 +
var leftTone = 440;
 +
var rightTone = 440;
 +
var curLeftTone = leftTone;
 +
var curRightTone = rightTone;
 +
var note = null;
 +
 
 +
var n = 0;
 +
// var b = baudio({rate: 704000},function (t) {
 +
// //console.log(t)
 +
// //console.log(leftTone)
 +
//    var x = Math.sin(2* (rightTone+0.01) * Math.PI * t) ;//+ Math.sin(n));
 +
// var next_x = Math.sin(2* (curLeftTone+0.02) * Math.PI * t);
 +
// var a = Math.sin(2* (leftTone+0.01) * Math.PI * t) ;
 +
// // if(Math.abs(x) < 0.001 &&  x < next_x) {
 +
// //  curLeftTone = leftTone
 +
// // x = 0;
 +
// // }
 +
// // if(Math.abs(a) < 0.001) {
 +
// //  curRightTone = rightTone
 +
// // a = 0;
 +
// // }
 +
//    //n += Math.sin(t);
 +
//    return (x * rightHand.grip.getValue()) + (a * leftHand.grip.getValue());
 +
// });
 +
// b.play();
 +
 
 +
// var baudio = require('baudio'), tune = require('tune');
 +
 
 +
// var blackholesun = tune(String(
 +
//  'A4 E4 A5 D5 A5 E4 A4 C4 E4 A5 D5 . . . ' +
 +
//  'G3 D4 G4 D5 G4 D4 E3 F#3 C#4 F#4 C#5 . . . ' +
 +
//  'E3 F3 C4 F4 A#5 F4 C4 F3 E3 D4 E4 B5 . . .'
 +
// ).split(' '));
 +
 
 +
// var b = baudio(function(t) {
 +
//  // black hole sun + some fx
 +
//  return blackholesun(t) + Math.sin(2 * Math.PI * t);
 +
// });
 +
// b.play();
 +
 
 +
 
 +
 
 +
 
 +
leftBulb = {};
 +
leftBulb.isOn = false;
 +
rightBulb = {};
 +
rightBulb.isOn = false;
 +
lx.on('bulb', function(b) {
 +
console.log('New bulb found: ' + b.name + " : " + b.addr.toString("hex"));
 +
addr = b.addr.toString("hex");
 +
if(addr == "d073d5001d70"){
 +
console.log("Assigning left bulb");
 +
leftBulb.bulb = lx.bulbs[addr];
 +
leftHand.bulb = leftBulb
 +
}else if(addr == "d073d50139d0"){
 +
console.log("Assigning right bulb");
 +
rightHand.bulb = rightBulb
 +
rightBulb.bulb = lx.bulbs[addr];
 +
}
 +
 +
});
 +
 
 +
lx.on('gateway', function(g) {
 +
console.log('New gateway found: ' + g.ip);
 +
});
 +
 
 +
lx.on('packet', function(p) {
 +
// Show informational packets
 +
switch (p.packetTypeShortName) {
 +
case 'powerState':
 +
case 'wifiInfo':
 +
case 'wifiFirmwareState':
 +
case 'wifiState':
 +
case 'accessPoint':
 +
case 'bulbLabel':
 +
case 'tags':
 +
case 'tagLabels':
 +
//case 'lightStatus':
 +
case 'timeState':
 +
case 'resetSwitchState':
 +
case 'meshInfo':
 +
case 'meshFirmware':
 +
case 'versionState':
 +
case 'infoState':
 +
case 'mcuRailVoltage':
 +
console.log(p.packetTypeName + " - " + p.preamble.bulbAddress.toString('hex') + " - " + util.inspect(p.payload));
 +
break;
 +
default:
 +
break;
 +
}
 +
});
 +
 
 +
console.log("Keys:");
 +
console.log("Press 1 to turn the lights on");
 +
console.log("Press 2 to turn the lights off");
 +
console.log("Press 3 to turn the lights a dim red");
 +
console.log("Press 4 to turn the lights a dim purple");
 +
console.log("Press 5 to turn the lights a bright white");
 +
console.log("Press 6 to cycle forwards through colours");
 +
console.log("Press 7 to cycle backwards through colours");
 +
console.log("Press 8 to show debug messages including network traffic");
 +
console.log("Press 9 to hide debug messages including network traffic");
 +
console.log("Press letters a-m to request various status fields");
 +
 
 +
var stdin = process.openStdin();
 +
process.stdin.setRawMode(true);
 +
process.stdin.resume();
 +
 
 +
var cycledColour = 0;
 +
 
 +
 
 +
var exit = false;
 +
 
 +
 
 +
 
 +
 
 +
 
 +
 
 +
 
 +
stdin.on('data', function (key) {
 +
//process.stdout.write('Got key ' + util.inspect(key) + '\n');
 +
switch (key[0]) {
 +
case 0x20:
 +
console.log("hit")
 +
if(note != null){
 +
sendMidi(null,note.freq,127);
 +
}
 +
case 0x31: // 1
 +
console.log("Lights on");
 +
// lx.lightsOn('Bedroom Lamp'); // Can specify one bulb by name
 +
var b = lx.bulbs['d073d5014163'];
 +
lx.lightsOn(b);
 +
// lx.lightsOn();
 +
break;
 +
 
 +
case 0x32: // 2
 +
console.log("Lights off");
 +
var b = lx.bulbs['d073d5014163'];
 +
lx.lightsOff(b);
 +
// lx.lightsOff();
 +
break;
 +
 
 +
case 0x33: // 3
 +
console.log("Dim red");
 +
// BB8 7D0
 +
lx.lightsColour(0x0000, 0xffff, 1000, 0, 0);
 +
break;
 +
 
 +
case 0x34: // 4
 +
console.log("Dim purple");
 +
//lx.lightsColour(0x0000, 0xffff, 500, 0, 0);
 +
lx.lightsColour(0xcc15, 0xffff, 500, 0, 0);
 +
break;
 +
 
 +
case 0x35: // 5
 +
console.log("Bright white");
 +
lx.lightsColour(0x0000, 0x0000, 0x8000, 0x0af0, 0x0513);
 +
break;
 +
 
 +
case 0x36: // 6
 +
cycledColour = (cycledColour+100) & 0xffff; console.log("Colour value is " + cycledColour);
 +
lx.lightsColour(cycledColour, 0xffff, 0x0200, 0x0000, 0x0000);
 +
break;
 +
 
 +
case 0x37: // 7
 +
cycledColour = (cycledColour-100) & 0xffff; console.log("Colour value is " + cycledColour);
 +
lx.lightsColour(cycledColour, 0xffff, 0x0200, 0x0000, 0x0000);
 +
break;
 +
 
 +
case 0x38: // 8
 +
console.log("Enabling debug");
 +
lifx.setDebug(true);
 +
break;
 +
 
 +
case 0x39: // 9
 +
console.log("Disabling debug");
 +
lifx.setDebug(false);
 +
break;
 +
 
 +
case 0x61: // a
 +
console.log("Requesting voltage");
 +
var message = packet.getMcuRailVoltage();
 +
lx.sendToAll(message);
 +
break;
 +
 
 +
case 0x62: // b
 +
console.log("Requesting power state");
 +
var message = packet.getPowerState();
 +
lx.sendToAll(message);
 +
break;
 +
 
 +
case 0x63: // c
 +
console.log("hit")
 +
if(note != null){
 +
sendMidi(midiMessages['noteOn'],note.freq,127);
 +
}
 +
break;
 +
 
 +
case 0x64: // d
 +
console.log("Requesting wifi firmware state");
 +
var message = packet.getWifiFirmwareState();
 +
lx.sendToAll(message);
 +
break;
 +
 
 +
case 0x65: // e
 +
console.log("Requesting wifi state");
 +
var message = packet.getWifiState({interface:2});
 +
lx.sendToAll(message);
 +
break;
 +
 
 +
case 0x66: // f
 +
console.log("Requesting bulb label");
 +
var message = packet.getBulbLabel();
 +
lx.sendToAll(message);
 +
break;
 +
 
 +
case 0x67: // g
 +
console.log("Requesting tags");
 +
var message = packet.getTags();
 +
lx.sendToAll(message);
 +
break;
 +
 
 +
case 0x68: // h
 +
console.log("Requesting tag label for tag 1");
 +
var message = packet.getTagLabels({tags:new Buffer([1,0,0,0,0,0,0,0])});
 +
lx.sendToAll(message);
 +
break;
 +
 
 +
case 0x69: // i
 +
console.log("Requesting time");
 +
var message = packet.getTime();
 +
lx.sendToAll(message);
 +
break;
 +
 
 +
case 0x6a: // j
 +
console.log("Requesting info");
 +
var message = packet.getInfo();
 +
lx.sendToAll(message);
 +
break;
 +
 
 +
case 0x6b: // k
 +
console.log("Requesting reset switch state");
 +
var message = packet.getResetSwitchState();
 +
lx.sendToAll(message);
 +
break;
 +
 
 +
case 0x6c: // l
 +
console.log("Requesting mesh info");
 +
var message = packet.getMeshInfo();
 +
lx.sendToAll(message);
 +
break;
 +
 
 +
case 0x6d: // m
 +
console.log("Requesting mesh firmware");
 +
var message = packet.getMeshFirmware();
 +
lx.sendToAll(message);
 +
break;
 +
 
 +
case 0x03: // ctrl-c
 +
console.log("Closing...");
 +
lx.close();
 +
// Close the port when done.
 +
output.closePort();
 +
process.stdin.pause();
 +
exit = true;
 +
process.exit();
 +
break;
 +
 
 +
}
 +
});
 +
 
 +
var lastMidiMessage = new Date();
 +
 
 +
function sendMidi(c,b1,b2){
 +
var diff = dateDiff(lastMidiMessage,new Date());
 +
if(c == null){
 +
c = midiMessages['noteOn']
 +
}
 +
console.log("Diff is " + diff);
 +
if(diff > 0.10){
 +
lastMidiMessage = new Date();
 +
console.log("Sending c:"+c + " n:" + b1 + " v:" + b2)
 +
output.sendMessage([c,b1,b2]);
 +
if(c ==  midiMessages['noteOn']){
 +
setTimeout(function(){
 +
console.log("Sending OFF c:"+midiMessages['noteOff'] + " n:" + b1 + " v:" + b2)
 +
    output.sendMessage([midiMessages['noteOff'],b1,b2]);
 +
}, 20);
 +
}
 +
 +
}
 +
}
 +
 
 +
 
 +
function vectorToString(vector, digits) {
 +
  if (typeof digits === "undefined") {
 +
    digits = 1;
 +
  }
 +
  return "(" + vector[0].toFixed(digits) + ", "
 +
            + vector[1].toFixed(digits) + ", "
 +
            + vector[2].toFixed(digits) + ")";
 +
}
 +
 
 +
 
 +
 
 +
 
 +
 
 +
 
 +
var lightsOn = false;
 +
var lastNote = null;
 +
var previousFrame = null;
 +
gripInterpol = new InterpolatedVal
 +
toneInterpol = new InterpolatedVal
 +
 
 +
 
 +
leap.loop(function(frame){
 +
 
 +
  if (frame.hands.length > 0) {
 +
    for (var i = 0; i < frame.hands.length; i++) {
 +
      var hand = frame.hands[i];
 +
      var handString = "";
 +
      handString += "<div style='width:300px; float:left; padding:5px'>";
 +
      handString += "Hand ID: " + hand.id + "<br />";
 +
      handString += "Type: " + hand.type + " hand" + "<br />";
 +
      handString += "Direction: " + vectorToString(hand.direction, 2) + "<br />";
 +
      handString += "Palm position: " + vectorToString(hand.palmPosition) + " mm<br />";
 +
      handString += "Grab strength: " + hand.grabStrength + "<br />";
 +
      handString += "Pinch strength: " + hand.pinchStrength + "<br />";
 +
      handString += "Confidence: " + hand.confidence + "<br />";
 +
      handString += "Arm direction: " + vectorToString(hand.arm.direction()) + "<br />";
 +
      handString += "Arm center: " + vectorToString(hand.arm.center()) + "<br />";
 +
      handString += "Arm up vector: " + vectorToString(hand.arm.basis[1]) + "<br />";
 +
      //console.log(tone)
 +
 
 +
     
 +
 
 +
 
 +
   
 +
 
 +
      //console.log(handString);
 +
      var handModel = null;
 +
      if(hand.type == "right"){
 +
      handModel = rightHand;
 +
      }else{
 +
      handModel =  leftHand;
 +
      console.log(handModel.grip.getValue());
 +
      }
 +
 
 +
      handModel.grip.add(hand.grabStrength);
 +
      handModel.note.add(hand.palmPosition[1])
 +
     
 +
      var value = handModel.note.getValue();
 +
      value = Math.max(value,60);
 +
      value = Math.min(value,500);
 +
      value = value.map(60,500,0,14)
 +
      note = findToneByMidi(value);
 +
 
 +
      if(handModel.grip.getValue() > 0.8 && damperPedal == true){
 +
      console.log("gripping " + handModel.grip.getValue())
 +
     
 +
      //sendMidi(midiMessages["mode"],parseInt('00000001',2),80)
 +
      sendMidi(midiMessages["mode"],midiMessages["damper"],midiMessages["pedalOff"])
 +
      damperPedal = false
 +
      }
 +
      else if(damperPedal == false && handModel.grip.getValue() < 0.8){
 +
      damperPedal = true
 +
      console.log("letting go")
 +
      sendMidi(midiMessages["mode"],midiMessages["damper"],midiMessages["pedalOn"])
 +
      //sendMidi(midiMessages["mode"],parseInt('00000001',2),0)
 +
      }
 +
 
 +
      if(lastNote != note.freq){
 +
      lastNote = note.freq;
 +
      console.log(note.freq)
 +
      }
 +
 
 +
  if(note != null && hand.type == "right"){
 +
  // Send a MIDI message.
 +
//sendMidi(midiMessages['noteOn'],note.freq,127);
 +
 
 +
  //rightTone  = note.freq;
 +
  //console.log("assigning right tone " + rightTone)
 +
  }else if(note != null){
 +
  //leftTone  = note.freq;
 +
  //sendMidi(midiMessages['noteOn'],note.freq,127);
 +
 
 +
  //console.log("assigning left tone " + leftTone)
 +
  }
 +
 
 +
      if (previousFrame && previousFrame.valid) {
 +
        var translation = hand.translation(previousFrame);
 +
        //handString += "Translation: " + vectorToString(translation) + " mm<br />";
 +
 
 +
        var rotationAxis = hand.rotationAxis(previousFrame, 2);
 +
        var rotationAngle = hand.rotationAngle(previousFrame);
 +
        handModel.rotation.add(rotationAxis[0]);
 +
        //console.log('rotation ' + handModel.rotation.getValue())
 +
        //handString += "Rotation axis: " + vectorToString(rotationAxis) + "<br />";
 +
        //console.log(handString)
 +
      }
 +
 
 +
  // Store frame for motion functions
 +
  previousFrame = frame;
 +
 
 +
 
 +
     
 +
      // if(handModel.grip.getValue() >= 1 && handModel.bulb.isOn == false){
 +
      // lx.lightsOn(handModel.bulb.bulb);
 +
      // handModel.bulb.isOn = true;
 +
      // }else if(handModel.grip.getValue() <= 0.2  && handModel.bulb.isOn == true){
 +
      // lx.lightsOff(handModel.bulb.bulb);
 +
      // handModel.bulb.isOn = false;
 +
      // }
 +
 
 +
    }
 +
  }
 +
 
 +
});
 +
 
 +
</tt>
 +
 
 
== Popis vývoje a konečné verze vlastního produktu ==
 
== Popis vývoje a konečné verze vlastního produktu ==
 
== Fotodokumentace ==
 
== Fotodokumentace ==

Verze z 23. 12. 2015, 14:23

Členové projektu

Vratislav Kalenda, Studia nových médií, e-mail: v.kalenda@gmail.com

Marta Kolárová, Studia nových médií, e-mail: martavkolarova@gmail.com

Motivace vzniku projektu a jeho význam

Původním záměrem bylo pomocí leap motion naprogramovat světelné diody - ovládané pohyby. Následně jsme se rozhodli využít leap motion i pro vytváření a modulování zvuku, tj. vytvořit pohyby ovládaný virtuální hudební nástroj v ideálním případě napojený na knihovnu samplovaných zvuků. A ještě kombinovaný s barevnými světelnými diodami, které informují o hraných tónech. Cílem byla zároveň možnost spoluhry více hráčů a vytváření harmonií.

V první fázi byl zvuk generován přímo počítačem (bylo potřeba nastavit temperované ladění a rozmezí oktáv), v závěrečné fázi se ale podařilo systém propojit s knihovnou zvuků GarageBand pomocí protokolu MIDI – v současné době je k dispozici využití veškerých nástrojů GarageBand.

Vlastní zdrojový kód

Upozornění! Vzhledem k omezení syntaxe wikisofia kopírujte prosím zdrojový kód přímo z editace zdroje stránky, nikoliv z podoby, do jaké je intepretována při zobrazení na stránce. Přislušný úsek je v souladu se syntaxí české wikipedie umístěn mezi značkou <tt> a </tt>.

var lifx = require('./lifx'); var util = require('util'); var packet = require('./packet'); var leap = require('leapjs'); var midi = require('midi');


var lx = lifx.init();

lx.on('bulbstate', function(b) { //console.log('Bulb state: ' + util.inspect(b)); });

lx.on('bulbonoff', function(b) { //console.log('Bulb on/off: ' + util.inspect(b)); });

Number.prototype.map = function ( in_min , in_max , out_min , out_max ) {

 return ( this - in_min ) * ( out_max - out_min ) / ( in_max - in_min ) + out_min;

}



// Set up a new output. var output = new midi.output();

// Count the available output ports. var count = output.getPortCount();

console.log("Available ports: " + count)

// Get the name of a specified output port. output.getPortName(0);

// Open the first available output port. output.openPort(0);

// Send a MIDI message. output.sendMessage([176,22,1]);


var damperPedal = true;

var toneMap = { 'c' : [ 60,72,84], //'cis' : [277.18,554.36], 'd' : [ 62,74], //'dis' : [ 311.13,622.26], 'e' : [ 64,76], 'f' : [ 65,77], //'fis' : [ 369.00,739.98], 'g' : [67,79], //'gis' : [ 415.00,830.60], 'a' : [69,81], //'ais' : [233.08,466.17], 'h' : [71,83] }



var dateDiff = function(start,end){ return (end.getTime() - start.getTime())/1000; }


var findTone = function(freq){ var diff = 9999999999; var tone = null; for(var toneName in toneMap){ //console.log("looking in " + toneName) for(var i = 0; i < toneMap[toneName].length; i++){ var newDiff = Math.abs(freq- toneMap[toneName][i]); //console.log("diff " + newDiff) if(newDiff < diff){ diff = newDiff; tone = {name : toneName, freq : toneMap[toneName][i]} //console.log("Found " + toneName + i) } } } if(tone != null){ //console.log("Found " + tone.name + " " + tone.freq + "hz") }else{ //console.log("No tone for " + freq) }

return tone;

}

var midiMessages = { "noteOn" : parseInt('10010000', 2), "noteOff" : parseInt('10000000',2), "mode" : parseInt('10110000',2), "damper" : parseInt('01000000',2), "pedalOff" : 127, "pedalOn" : 0 }

var findToneByMidi = function(step){ var diff = 9999999999; var tone = null; var stepIndex = 0; var i = 0; for(i = 0; i< 3; i++){

for(var toneName in toneMap){ //console.log("looking in " + toneName)

if(toneMap[toneName].length > i){

var newDiff = Math.abs(step-stepIndex); //console.log("aaa" + newDiff) //console.log("diff " + newDiff) if(newDiff < diff){ diff = newDiff; tone = {name : toneName, freq : toneMap[toneName][i]} //console.log("Found " + toneName + i) } stepIndex++; }


} }

if(tone != null){ //console.log("Found " + tone.name + " " + tone.freq + "hz") }else{ //console.log("No tone for " + freq) }

return tone; }

var InterpolatedVal = function(){ this.data = []; this.windowSize = 5; this.add = function(val){ this.data.unshift(val); //console.log("Pusging value " + val + " win size " + this.windowSize) if(this.data.length > this.windowSize){ this.data.pop(val) } //console.log("CData lenght " + this.data.length) } this.getValue = function(){ var result = 0.0; for(var i = 0; i < this.data.length; i++){ result += this.data[i]; } //console.log("value " + result / this.data.length) return result / this.data.length }

};

var Hand = function(){ this.grip = new InterpolatedVal(); this.grip.windowSize = 30; this.rotation = new InterpolatedVal(); this.rotation.windowSize = 10; this.bulb = null;

this.note = new InterpolatedVal(); };

var leftHand = new Hand(); var rightHand = new Hand();


var baudio = require('baudio'); var leftTone = 440; var rightTone = 440; var curLeftTone = leftTone; var curRightTone = rightTone; var note = null;

var n = 0; // var b = baudio({rate: 704000},function (t) { // //console.log(t) // //console.log(leftTone) // var x = Math.sin(2* (rightTone+0.01) * Math.PI * t) ;//+ Math.sin(n)); // var next_x = Math.sin(2* (curLeftTone+0.02) * Math.PI * t); // var a = Math.sin(2* (leftTone+0.01) * Math.PI * t) ; // // if(Math.abs(x) < 0.001 && x < next_x) { // // curLeftTone = leftTone // // x = 0; // // } // // if(Math.abs(a) < 0.001) { // // curRightTone = rightTone // // a = 0; // // } // //n += Math.sin(t); // return (x * rightHand.grip.getValue()) + (a * leftHand.grip.getValue()); // }); // b.play();

// var baudio = require('baudio'), tune = require('tune');

// var blackholesun = tune(String( // 'A4 E4 A5 D5 A5 E4 A4 C4 E4 A5 D5 . . . ' + // 'G3 D4 G4 D5 G4 D4 E3 F#3 C#4 F#4 C#5 . . . ' + // 'E3 F3 C4 F4 A#5 F4 C4 F3 E3 D4 E4 B5 . . .' // ).split(' '));

// var b = baudio(function(t) { // // black hole sun + some fx // return blackholesun(t) + Math.sin(2 * Math.PI * t); // }); // b.play();



leftBulb = {}; leftBulb.isOn = false; rightBulb = {}; rightBulb.isOn = false; lx.on('bulb', function(b) { console.log('New bulb found: ' + b.name + " : " + b.addr.toString("hex")); addr = b.addr.toString("hex"); if(addr == "d073d5001d70"){ console.log("Assigning left bulb"); leftBulb.bulb = lx.bulbs[addr]; leftHand.bulb = leftBulb }else if(addr == "d073d50139d0"){ console.log("Assigning right bulb"); rightHand.bulb = rightBulb rightBulb.bulb = lx.bulbs[addr]; }

});

lx.on('gateway', function(g) { console.log('New gateway found: ' + g.ip); });

lx.on('packet', function(p) { // Show informational packets switch (p.packetTypeShortName) { case 'powerState': case 'wifiInfo': case 'wifiFirmwareState': case 'wifiState': case 'accessPoint': case 'bulbLabel': case 'tags': case 'tagLabels': //case 'lightStatus': case 'timeState': case 'resetSwitchState': case 'meshInfo': case 'meshFirmware': case 'versionState': case 'infoState': case 'mcuRailVoltage': console.log(p.packetTypeName + " - " + p.preamble.bulbAddress.toString('hex') + " - " + util.inspect(p.payload)); break; default: break; } });

console.log("Keys:"); console.log("Press 1 to turn the lights on"); console.log("Press 2 to turn the lights off"); console.log("Press 3 to turn the lights a dim red"); console.log("Press 4 to turn the lights a dim purple"); console.log("Press 5 to turn the lights a bright white"); console.log("Press 6 to cycle forwards through colours"); console.log("Press 7 to cycle backwards through colours"); console.log("Press 8 to show debug messages including network traffic"); console.log("Press 9 to hide debug messages including network traffic"); console.log("Press letters a-m to request various status fields");

var stdin = process.openStdin(); process.stdin.setRawMode(true); process.stdin.resume();

var cycledColour = 0;


var exit = false;




stdin.on('data', function (key) { //process.stdout.write('Got key ' + util.inspect(key) + '\n'); switch (key[0]) { case 0x20: console.log("hit") if(note != null){ sendMidi(null,note.freq,127); } case 0x31: // 1 console.log("Lights on"); // lx.lightsOn('Bedroom Lamp'); // Can specify one bulb by name var b = lx.bulbs['d073d5014163']; lx.lightsOn(b); // lx.lightsOn(); break;

case 0x32: // 2 console.log("Lights off"); var b = lx.bulbs['d073d5014163']; lx.lightsOff(b); // lx.lightsOff(); break;

case 0x33: // 3 console.log("Dim red"); // BB8 7D0 lx.lightsColour(0x0000, 0xffff, 1000, 0, 0); break;

case 0x34: // 4 console.log("Dim purple"); //lx.lightsColour(0x0000, 0xffff, 500, 0, 0); lx.lightsColour(0xcc15, 0xffff, 500, 0, 0); break;

case 0x35: // 5 console.log("Bright white"); lx.lightsColour(0x0000, 0x0000, 0x8000, 0x0af0, 0x0513); break;

case 0x36: // 6 cycledColour = (cycledColour+100) & 0xffff; console.log("Colour value is " + cycledColour); lx.lightsColour(cycledColour, 0xffff, 0x0200, 0x0000, 0x0000); break;

case 0x37: // 7 cycledColour = (cycledColour-100) & 0xffff; console.log("Colour value is " + cycledColour); lx.lightsColour(cycledColour, 0xffff, 0x0200, 0x0000, 0x0000); break;

case 0x38: // 8 console.log("Enabling debug"); lifx.setDebug(true); break;

case 0x39: // 9 console.log("Disabling debug"); lifx.setDebug(false); break;

case 0x61: // a console.log("Requesting voltage"); var message = packet.getMcuRailVoltage(); lx.sendToAll(message); break;

case 0x62: // b console.log("Requesting power state"); var message = packet.getPowerState(); lx.sendToAll(message); break;

case 0x63: // c console.log("hit") if(note != null){ sendMidi(midiMessages['noteOn'],note.freq,127); } break;

case 0x64: // d console.log("Requesting wifi firmware state"); var message = packet.getWifiFirmwareState(); lx.sendToAll(message); break;

case 0x65: // e console.log("Requesting wifi state"); var message = packet.getWifiState({interface:2}); lx.sendToAll(message); break;

case 0x66: // f console.log("Requesting bulb label"); var message = packet.getBulbLabel(); lx.sendToAll(message); break;

case 0x67: // g console.log("Requesting tags"); var message = packet.getTags(); lx.sendToAll(message); break;

case 0x68: // h console.log("Requesting tag label for tag 1"); var message = packet.getTagLabels({tags:new Buffer([1,0,0,0,0,0,0,0])}); lx.sendToAll(message); break;

case 0x69: // i console.log("Requesting time"); var message = packet.getTime(); lx.sendToAll(message); break;

case 0x6a: // j console.log("Requesting info"); var message = packet.getInfo(); lx.sendToAll(message); break;

case 0x6b: // k console.log("Requesting reset switch state"); var message = packet.getResetSwitchState(); lx.sendToAll(message); break;

case 0x6c: // l console.log("Requesting mesh info"); var message = packet.getMeshInfo(); lx.sendToAll(message); break;

case 0x6d: // m console.log("Requesting mesh firmware"); var message = packet.getMeshFirmware(); lx.sendToAll(message); break;

case 0x03: // ctrl-c console.log("Closing..."); lx.close(); // Close the port when done. output.closePort(); process.stdin.pause(); exit = true; process.exit(); break;

} });

var lastMidiMessage = new Date();

function sendMidi(c,b1,b2){ var diff = dateDiff(lastMidiMessage,new Date()); if(c == null){ c = midiMessages['noteOn'] } console.log("Diff is " + diff); if(diff > 0.10){ lastMidiMessage = new Date(); console.log("Sending c:"+c + " n:" + b1 + " v:" + b2) output.sendMessage([c,b1,b2]); if(c == midiMessages['noteOn']){ setTimeout(function(){ console.log("Sending OFF c:"+midiMessages['noteOff'] + " n:" + b1 + " v:" + b2) output.sendMessage([midiMessages['noteOff'],b1,b2]); }, 20); }

} }


function vectorToString(vector, digits) {

 if (typeof digits === "undefined") {
   digits = 1;
 }
 return "(" + vector[0].toFixed(digits) + ", "
            + vector[1].toFixed(digits) + ", "
            + vector[2].toFixed(digits) + ")";

}




var lightsOn = false; var lastNote = null; var previousFrame = null; gripInterpol = new InterpolatedVal toneInterpol = new InterpolatedVal


leap.loop(function(frame){

 if (frame.hands.length > 0) {
   for (var i = 0; i < frame.hands.length; i++) {
     var hand = frame.hands[i];
     var handString = "";

handString += "

";
     handString += "Hand ID: " + hand.id + "
"; handString += "Type: " + hand.type + " hand" + "
"; handString += "Direction: " + vectorToString(hand.direction, 2) + "
"; handString += "Palm position: " + vectorToString(hand.palmPosition) + " mm
"; handString += "Grab strength: " + hand.grabStrength + "
"; handString += "Pinch strength: " + hand.pinchStrength + "
"; handString += "Confidence: " + hand.confidence + "
"; handString += "Arm direction: " + vectorToString(hand.arm.direction()) + "
"; handString += "Arm center: " + vectorToString(hand.arm.center()) + "
"; handString += "Arm up vector: " + vectorToString(hand.arm.basis[1]) + "
"; //console.log(tone)




     //console.log(handString);
     var handModel = null; 
     if(hand.type == "right"){
     	handModel = rightHand;
     }else{
     	handModel =  leftHand;
     	console.log(handModel.grip.getValue());
     }
     handModel.grip.add(hand.grabStrength);
     handModel.note.add(hand.palmPosition[1])
     
     var value = handModel.note.getValue();
     value = Math.max(value,60);
     value = Math.min(value,500);
     value = value.map(60,500,0,14)
     note = findToneByMidi(value);
     if(handModel.grip.getValue() > 0.8 && damperPedal == true){
     	console.log("gripping " + handModel.grip.getValue())
     	
     	//sendMidi(midiMessages["mode"],parseInt('00000001',2),80)
     	sendMidi(midiMessages["mode"],midiMessages["damper"],midiMessages["pedalOff"])
     	damperPedal = false
     }
     else if(damperPedal == false && handModel.grip.getValue() < 0.8){
     	damperPedal = true
     	console.log("letting go")
     	sendMidi(midiMessages["mode"],midiMessages["damper"],midiMessages["pedalOn"])
     	//sendMidi(midiMessages["mode"],parseInt('00000001',2),0)
     }
     if(lastNote != note.freq){
     	lastNote = note.freq;
     	console.log(note.freq)
     }

if(note != null && hand.type == "right"){ // Send a MIDI message. //sendMidi(midiMessages['noteOn'],note.freq,127);

//rightTone = note.freq; //console.log("assigning right tone " + rightTone) }else if(note != null){ //leftTone = note.freq; //sendMidi(midiMessages['noteOn'],note.freq,127);

//console.log("assigning left tone " + leftTone) }

     if (previousFrame && previousFrame.valid) {
       var translation = hand.translation(previousFrame);
       //handString += "Translation: " + vectorToString(translation) + " mm
";
       var rotationAxis = hand.rotationAxis(previousFrame, 2);
       var rotationAngle = hand.rotationAngle(previousFrame);
       handModel.rotation.add(rotationAxis[0]);
       //console.log('rotation ' + handModel.rotation.getValue())
       //handString += "Rotation axis: " + vectorToString(rotationAxis) + "
"; //console.log(handString) }

// Store frame for motion functions previousFrame = frame;


     // if(handModel.grip.getValue() >= 1 && handModel.bulb.isOn == false){
     // 	lx.lightsOn(handModel.bulb.bulb);
     // 	handModel.bulb.isOn = true;
     // }else if(handModel.grip.getValue() <= 0.2  && handModel.bulb.isOn == true){
     // 	lx.lightsOff(handModel.bulb.bulb);
     // 	handModel.bulb.isOn = false;
     // }
   }
  }

});

Popis vývoje a konečné verze vlastního produktu

Fotodokumentace