Newbie seeking help re. combining example code (& using a Leapmotion)

edited January 2017 in Library Questions

First up, hello everybody. I'm new, both to the forum, and to processing, but despite my very limited experience, what an awesome program - It's so exciting to tinker with!

I'm using processing 3.2.3, and for now, I'm learning the basics through modifying example code provided via example librarys, which is proving to be a slow but valuable learning experience.

I've now got a little project where I want to combine 2 parts of example code, and I've hit a road block - I simply can't seem to get it to work.

There is a nice SineWave demo in the official sound library (libraries/sound/examples/Oscillators/SineWave) which generates a tone, that tracks your mouse position and changes frequency, amplitude and panning based on your mouse position.

The second is from an example provided as part of the Library item: Leapmotion | Forwards Leap Motion controller events to a processing sketch by Michael Heuer, specifically, the leap_position_example. This example tracks finger tip position provided by the leap, and displays them in a processing window as circular vectors of a random colour.

What I would like to do, is to combine both parts of code - I'd like to bring the SineWave code into the Leap example and then map one of the values provided by the leap (Wrist/palm position ideally - anybody know how to visually display this also?) to SineWave code so that you are able to control the frequency etc. of the sound with you hard movements rather than the mouse. Like a simple theremin!

I'm clearly missing something fundamental, because no matter how I try to format it, I can't get both examples of working in the same processing window. As such, any help would be greatly appreciated - Thank you!

Rather than provide my numerous examples butchered code for you to untangle, here are the two examples of untouched code that I am hoping to use:

SOUND:

import processing.sound.*;

SinOsc sine;

float freq=400;
float amp=0.5;
float pos;

void setup() {
    size(800, 600);
    background(255);

    // Create and start the sine oscillator.

    sine = new SinOsc(this);

    //Start the Sine Oscillator. 
    sine.play();
}

void draw() {

  // Map mouseY from 0.0 to 1.0 for amplitude
  amp=map(mouseY, 0, height, 1.0, 0.0);
  sine.amp(amp);

  // Map mouseX from 20Hz to 1000Hz for frequency  
  freq=map(mouseX, 0, width, 80.0, 1000.0);
  sine.freq(freq);

  // Map mouseX from -1.0 to 1.0 for left to right 
  pos=map(mouseX, 0, width, -1.0, 1.0);
  sine.pan(pos);
}

LEAP:

import java.util.Map;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ConcurrentHashMap;

import com.leapmotion.leap.Controller;
import com.leapmotion.leap.Finger;
import com.leapmotion.leap.Frame;
import com.leapmotion.leap.Hand;
import com.leapmotion.leap.Tool;
import com.leapmotion.leap.Vector;
import com.leapmotion.leap.processing.LeapMotion;

LeapMotion leapMotion;

ConcurrentMap<Integer, Integer> fingerColors;
ConcurrentMap<Integer, Integer> toolColors;
ConcurrentMap<Integer, Vector> fingerPositions;
ConcurrentMap<Integer, Vector> toolPositions;

void setup()
{
  size(800, 600);
  background(20);
  frameRate(60);
  ellipseMode(CENTER);

  leapMotion = new LeapMotion(this);
  fingerColors = new ConcurrentHashMap<Integer, Integer>();
  toolColors = new ConcurrentHashMap<Integer, Integer>();
  fingerPositions = new ConcurrentHashMap<Integer, Vector>();
  toolPositions = new ConcurrentHashMap<Integer, Vector>();
}

void draw()
{
  fill(20);
  rect(0, 0, width, height);

  for (Map.Entry entry : fingerPositions.entrySet())
  {
    Integer fingerId = (Integer) entry.getKey();
    Vector position = (Vector) entry.getValue();
    fill(fingerColors.get(fingerId));
    noStroke();
    ellipse(leapMotion.leapToSketchX(position.getX()), leapMotion.leapToSketchY(position.getY()), 24.0, 24.0);
  }
  for (Map.Entry entry : toolPositions.entrySet())
  {
    Integer toolId = (Integer) entry.getKey();
    Vector position = (Vector) entry.getValue();
    fill(toolColors.get(toolId));
    noStroke();
    ellipse(leapMotion.leapToSketchX(position.getX()), leapMotion.leapToSketchY(position.getY()), 24.0, 24.0);
  }
}

void onFrame(final Controller controller)
{
  Frame frame = controller.frame();
  fingerPositions.clear();
  for (Finger finger : frame.fingers())
  {
    int fingerId = finger.id();
    color c = color(random(0, 255), random(0, 255), random(0, 255));
    fingerColors.putIfAbsent(fingerId, c);
    fingerPositions.put(fingerId, finger.tipPosition());
  }
  toolPositions.clear();
  for (Tool tool : frame.tools())
  {
    int toolId = tool.id();
    color c = color(random(0, 255), random(0, 255), random(0, 255));
    toolColors.
  (toolId, c);
    toolPositions.put(toolId, tool.tipPosition());
  }
}

Answers

  • please don't post duplicates.

  • edited January 2017

    Thanks for the warm welcome to my first post Koogs!

    Of course I didn't intend to cause problems or break any rules, so for future ref. could you explain what the difference between 'ask a question' and 'start a discussion' is? I wasn't sure which was the correct one to use and am simply eager to learn (so I erroneously tried both).

    As such, I would still really appreciate a little guidance re. my initial question too, I'm sure it's quite simple for somebody more knowledgeable than I.

  • you're welcome

    combining sketches is theoretically just a case of combining imports and global variable definitions, the setup() section and the draw() sections. rename things that clash (nothing here, i don't think).

    these

    leapMotion.leapToSketchX(position.getX())
    

    (and the corresponding y version) suggest to me that they are the leapMotion equivalent of mouseX in the first sketch. so, instead (or additional to) drawing an ellipse at the finger position you can modify the amp / freq / pan of your sine.

    the problem is that you have one mouse and potentially 10 fingers. so, er, pick one? and think of a way of dealing with 0.

    the leapmotion aspect of this means you've reduced the potential audience, possibly to zero, so don't expect too much. the above is a guess that i have no way of verifying.

  • Thanks Koogs, I'll do my best to give it another go tonight and report back.

    I'm happy to substitute just one finger for the mouse input, it doesn't need to be super accurate, I just want to experiment with the magic of hands free control. I was just getting errors when trying to launch the project (after combining it), so I must be breaking something when combining the projects (user error related sure!).

  • Hey Koogs, thanks to your encouragement, I've now got both parts of code working independently within the same sketch, the mouse position controls frequency, and the leap draws ellipses of a random colour at fingertip locations.

    However, I've spent the past 3 hours trying to map one of the leap finger positions to frequency (instead of mouseX), but I've had zero luck - the syntax is clearly beyond my current ability. I would be eternally grateful if you, or anybody else for that matter is able to help by way of complete example to try? :)

    Here is the code with both of them working independently within the same sketch:

    import processing.sound.*;
    import java.util.Map;
    import java.util.concurrent.ConcurrentMap;
    import java.util.concurrent.ConcurrentHashMap;
    
    import com.leapmotion.leap.Controller;
    import com.leapmotion.leap.Finger;
    import com.leapmotion.leap.Frame;
    import com.leapmotion.leap.Hand;
    import com.leapmotion.leap.Tool;
    import com.leapmotion.leap.Vector;
    import com.leapmotion.leap.processing.LeapMotion;
    
    SinOsc sine;
    LeapMotion leapMotion;
    
    float freq=400;
    float amp=1;
    float pos;
    
    ConcurrentMap<Integer, Integer> fingerColors;
    ConcurrentMap<Integer, Integer> toolColors;
    ConcurrentMap<Integer, Vector> fingerPositions;
    ConcurrentMap<Integer, Vector> toolPositions;
    
    void setup() {
      size(640, 360);
      background(0);
      frameRate(60);
    
        // Create and start the sine oscillator.
        sine = new SinOsc(this);
        //Start the Sine Oscillator. 
        sine.play();
    
      leapMotion = new LeapMotion(this);
      fingerColors = new ConcurrentHashMap<Integer, Integer>();
      toolColors = new ConcurrentHashMap<Integer, Integer>();
      fingerPositions = new ConcurrentHashMap<Integer, Vector>();
      toolPositions = new ConcurrentHashMap<Integer, Vector>();
    }
    
    void draw() {
    
      // Map mouseX from 20Hz to 1000Hz for frequency  
      freq=map(mouseX, 0, width, 80.0, 1000.0);
      sine.freq(freq);
    
     fill(0); //This creates a fill to prevent the solitaire effect
     rect(0, 0, width, height); //this controls the size of the above fill
    
      for (Map.Entry entry : fingerPositions.entrySet())
      {
        Integer fingerId = (Integer) entry.getKey();
        Vector position = (Vector) entry.getValue();
        fill(fingerColors.get(fingerId));
        noStroke();
        ellipse(leapMotion.leapToSketchX(position.getX()), leapMotion.leapToSketchY(position.getY()), 24.0, 24.0);
      }
      for (Map.Entry entry : toolPositions.entrySet())
      {
        Integer toolId = (Integer) entry.getKey();
        Vector position = (Vector) entry.getValue();
        fill(toolColors.get(toolId));
        noStroke();
        ellipse(leapMotion.leapToSketchX(position.getX()), leapMotion.leapToSketchY(position.getY()), 24.0, 24.0);
      }
    }
    
    void onFrame(final Controller controller)
    {
      Frame frame = controller.frame();
      fingerPositions.clear();
      for (Finger finger : frame.fingers())
      {
        int fingerId = finger.id();
        color c = color(random(70, 255), random(70, 255), random(70, 255)); //This allows me to change colour of finger ellipses
        fingerColors.putIfAbsent(fingerId, c);
        fingerPositions.put(fingerId, finger.tipPosition());
      }
      toolPositions.clear();
      for (Tool tool : frame.tools())
      {
        int toolId = tool.id();
        color c = color(random(255, 255), random(255, 255), random(255, 255));
        toolColors.putIfAbsent(toolId, c);
        toolPositions.put(toolId, tool.tipPosition());
      }
    }
    
  • If you can draw ellipses with your fingers on the screen, then I would expect changing line 46 to

    int aposx=leapMotion.leapToSketchX(position.getX());
    freq=map(aposx, 0, width, 80.0, 1000.0);
    

    would do the trick, wouldn't it?

    Kf

  • Thanks for the advice kfrajer, very much appreciated. I gave it a try and it throws up the error:

    The name "position" cannot be recognized

    It also refuses to launch the sketch.

    Any ideas? :-/

  • Right, my advice was not proper. Instead of replacing line 46, insert my previous two lines between lines 58 and 59 where position is available. Alternatively, I present next another version that is somehow more efficient. Replace all your draw() function with this code:

        int aposx;  //GLOBAL VARIABLE
        int whatFinger;
        void draw() {
    
          // Map mouseX from 20Hz to 1000Hz for frequency 
          //freq=map(mouseX, 0, width, 80.0, 1000.0);
          //sine.freq(freq);
    
         fill(0); //This creates a fill to prevent the solitaire effect
         rect(0, 0, width, height); //this controls the size of the above fill
    
          apos=0;  //INIT VARIABLE before accessing fingers
          whatFinger=-9999;
          for (Map.Entry entry : fingerPositions.entrySet())
          {
            Integer fingerId = (Integer) entry.getKey();
            Vector position = (Vector) entry.getValue();
            fill(fingerColors.get(fingerId));
            noStroke();
            ellipse(leapMotion.leapToSketchX(position.getX()), leapMotion.leapToSketchY(position.getY()), 24.0, 24.0);
            aposx=leapMotion.leapToSketchX(position.getX());
            whatFinger=fingerId;
            println("FINGER info: " + whatFinger + " at pos X=" + aposx);
          }
    
          if(aposx!=0){
            freq=map(aposx, 0, width, 80.0, 1000.0);
            sine.freq(freq);        
          }
    
          for (Map.Entry entry : toolPositions.entrySet())
          {
            Integer toolId = (Integer) entry.getKey();
            Vector position = (Vector) entry.getValue();
            fill(toolColors.get(toolId));
            noStroke();
            ellipse(leapMotion.leapToSketchX(position.getX()), leapMotion.leapToSketchY(position.getY()), 24.0, 24.0);
          }
        }
    

    You should be able to use whatFinger to select what finger you want to use for your operation. To clarify, this is untested code as I do not have the hardware to run your sketch.

    Here are two links that you could review. The first one tells you how to get a finger. The second one is a running example.
    https://github.com/nok/leap-motion-processing#usage
    https://forum.processing.org/two/discussion/4328/using-leap-motion-instead-of-mousex-and-mousey

    Kf

  • edited January 2017

    kfrajer, first up, thank you for trying, you're an absolute legend for doing so, and I fully appreciate that it must be very difficult without having a leap to test things yourself - So once again, thank you! ;;)

    Sadly, unless I'm doing something really stupid, which is entirely possible, neither method works. :(

    The first method (example 1) that introduces the code between 58 & 59 results in: Type mismatch, "float" does not match with "int".

    The second more efficient code you provided (example 2) results in: The variable "apos" does not exist

    Neither launch.

    I have provided both examples in full below, in case I am clearly doing something wrong elsewhere that is causing problems.

    Example 1:

    import processing.sound.*;
    import java.util.Map;
    import java.util.concurrent.ConcurrentMap;
    import java.util.concurrent.ConcurrentHashMap;
    
    import com.leapmotion.leap.Controller;
    import com.leapmotion.leap.Finger;
    import com.leapmotion.leap.Frame;
    import com.leapmotion.leap.Hand;
    import com.leapmotion.leap.Tool;
    import com.leapmotion.leap.Vector;
    import com.leapmotion.leap.processing.LeapMotion;
    
    SinOsc sine;
    LeapMotion leapMotion;
    
    float freq=400;
    float amp=1;
    float pos;
    
    ConcurrentMap<Integer, Integer> fingerColors;
    ConcurrentMap<Integer, Integer> toolColors;
    ConcurrentMap<Integer, Vector> fingerPositions;
    ConcurrentMap<Integer, Vector> toolPositions;
    
    void setup() {
      size(640, 360);
      background(0);
      frameRate(60);
    
        // Create and start the sine oscillator.
        sine = new SinOsc(this);
        //Start the Sine Oscillator. 
        sine.play();
    
      leapMotion = new LeapMotion(this);
      fingerColors = new ConcurrentHashMap<Integer, Integer>();
      toolColors = new ConcurrentHashMap<Integer, Integer>();
      fingerPositions = new ConcurrentHashMap<Integer, Vector>();
      toolPositions = new ConcurrentHashMap<Integer, Vector>();
    }
    
    void draw() {
    
      // Map mouseX from 20Hz to 1000Hz for frequency  
      freq=map(mouseX, 0, width, 80.0, 1000.0);
      sine.freq(freq);
    
     fill(0); //This creates a fill to prevent the solitaire effect
     rect(0, 0, width, height); //this controls the size of the above fill
    
      for (Map.Entry entry : fingerPositions.entrySet())
      {
        Integer fingerId = (Integer) entry.getKey();
        Vector position = (Vector) entry.getValue();
        fill(fingerColors.get(fingerId));
        noStroke();
        ellipse(leapMotion.leapToSketchX(position.getX()), leapMotion.leapToSketchY(position.getY()), 24.0, 24.0);
        int aposx=leapMotion.leapToSketchX(position.getX());
        freq=map(aposx, 0, width, 80.0, 1000.0);
    }
      for (Map.Entry entry : toolPositions.entrySet())
      {
        Integer toolId = (Integer) entry.getKey();
        Vector position = (Vector) entry.getValue();
        fill(toolColors.get(toolId));
        noStroke();
        ellipse(leapMotion.leapToSketchX(position.getX()), leapMotion.leapToSketchY(position.getY()), 24.0, 24.0);
      }
    }
    
    void onFrame(final Controller controller)
    {
      Frame frame = controller.frame();
      fingerPositions.clear();
      for (Finger finger : frame.fingers())
      {
        int fingerId = finger.id();
        color c = color(random(70, 255), random(70, 255), random(70, 255)); //This allows me to change colour of finger ellipses
        fingerColors.putIfAbsent(fingerId, c);
        fingerPositions.put(fingerId, finger.tipPosition());
      }
      toolPositions.clear();
      for (Tool tool : frame.tools())
      {
        int toolId = tool.id();
        color c = color(random(255, 255), random(255, 255), random(255, 255));
        toolColors.putIfAbsent(toolId, c);
        toolPositions.put(toolId, tool.tipPosition());
      }
    }
    

    Example 2:

    import processing.sound.*;
    import java.util.Map;
    import java.util.concurrent.ConcurrentMap;
    import java.util.concurrent.ConcurrentHashMap;
    
    import com.leapmotion.leap.Controller;
    import com.leapmotion.leap.Finger;
    import com.leapmotion.leap.Frame;
    import com.leapmotion.leap.Hand;
    import com.leapmotion.leap.Tool;
    import com.leapmotion.leap.Vector;
    import com.leapmotion.leap.processing.LeapMotion;
    
    SinOsc sine;
    LeapMotion leapMotion;
    
    float freq=400;
    float amp=1;
    float pos;
    
    ConcurrentMap<Integer, Integer> fingerColors;
    ConcurrentMap<Integer, Integer> toolColors;
    ConcurrentMap<Integer, Vector> fingerPositions;
    ConcurrentMap<Integer, Vector> toolPositions;
    
    void setup() {
      size(640, 360);
      background(0);
      frameRate(60);
    
        // Create and start the sine oscillator.
        sine = new SinOsc(this);
        //Start the Sine Oscillator. 
        sine.play();
    
      leapMotion = new LeapMotion(this);
      fingerColors = new ConcurrentHashMap<Integer, Integer>();
      toolColors = new ConcurrentHashMap<Integer, Integer>();
      fingerPositions = new ConcurrentHashMap<Integer, Vector>();
      toolPositions = new ConcurrentHashMap<Integer, Vector>();
    }
    
    int aposx;  //GLOBAL VARIABLE
    int whatFinger;
    void draw() {
    
      // Map mouseX from 20Hz to 1000Hz for frequency 
      //freq=map(mouseX, 0, width, 80.0, 1000.0);
      //sine.freq(freq);
    
     fill(0); //This creates a fill to prevent the solitaire effect
     rect(0, 0, width, height); //this controls the size of the above fill
    
      apos=0;  //INIT VARIABLE before accessing fingers
      whatFinger=-9999;
      for (Map.Entry entry : fingerPositions.entrySet())
      {
        Integer fingerId = (Integer) entry.getKey();
        Vector position = (Vector) entry.getValue();
        fill(fingerColors.get(fingerId));
        noStroke();
        ellipse(leapMotion.leapToSketchX(position.getX()), leapMotion.leapToSketchY(position.getY()), 24.0, 24.0);
        aposx=leapMotion.leapToSketchX(position.getX());
        whatFinger=fingerId;
        println("FINGER info: " + whatFinger + " at pos X=" + aposx);
      }
    
      if(aposx!=0){
        freq=map(aposx, 0, width, 80.0, 1000.0);
        sine.freq(freq);        
      }
    
      for (Map.Entry entry : toolPositions.entrySet())
      {
        Integer toolId = (Integer) entry.getKey();
        Vector position = (Vector) entry.getValue();
        fill(toolColors.get(toolId));
        noStroke();
        ellipse(leapMotion.leapToSketchX(position.getX()), leapMotion.leapToSketchY(position.getY()), 24.0, 24.0);
      }
    }
    
  • I will have to check the documentation more closely. For the time being, check the link I provided before (here is again https://forum.processing.org/two/discussion/4328/using-leap-motion-instead-of-mousex-and-mousey) as there is some code that shows exactly what you want to do:

    import de.voidplus.leapmotion.*;
    LeapMotion leap;
    ArrayList<PVector> points;
    PVector fp;
    
    void setup() {
      size(800, 500, P3D);
      background(255);
      leap = new LeapMotion(this);
      points = new ArrayList<PVector>();
      smooth(8);
      noStroke();
    }
    
    void draw() {
      background(255);
      int fps = leap.getFrameRate();
      frameRate(fps);
      for (Hand hand : leap.getHands()) {
        for (Finger finger : hand.getFingers()) {
          fp   = finger.getPosition();
    
          if (fp.z <= 30) {
            fill(0);
            ellipse(fp.x, fp.y, constrain(fp.z, 10, 20), constrain(fp.z, 10, 20));
          }
          else if (fp.z > 30) {
            points.add(new PVector(fp.x, fp.y));
          }
        }
      }
      for (int i = points.size()-1; i >= 0; i--) {
        PVector p = points.get(i);
        fill(23, 77, 255);
        ellipse(p.x, p.y, 20, 20);
      }
    }
    
    void keyPressed() {
      if (key == 32) {
        points = new ArrayList<PVector>();
     }
    

    Try this in a new sketch and see if it works. I will get back to you in a few hours about example 1 and example 2.

    Kf

  • edited January 2017

    kfrajer! I think you might have nailed where the problem is! If you search 'leap' in the processing library, there are 2 alternative libraries that you can install:

    Leap Motion for Processing | Library to use the [Leap Motion]

    &

    Leap Motion | Forwards Leap Motion controller events to a processing sketch

    Only one of these can be installed at a time, and I was using the latter, I think that your code changes might be based on the former?

    I tried the code above, and it didn't work (wrong library installed), this prompted me to try the other library, and it worked once I had. Once it was working I was able to adapt the far more easily understood code and sort of get the desired effect using this:

    import de.voidplus.leapmotion.*;
    import processing.sound.*;
    
    SinOsc sine;
    LeapMotion leap;
    
    float freq=400;
    float amp=1;
    float pos;  
    ArrayList<PVector> points; 
    PVector fp; 
    
    void setup() {
      size(800, 500, P3D);
      background(255);
      leap = new LeapMotion(this);
      points = new ArrayList<PVector>(); 
      smooth(8);
      noStroke();
    
        // Create and start the sine oscillator.
        sine = new SinOsc(this);
        //Start the Sine Oscillator. 
        sine.play();
    }
    
    void draw() {
      background(255);
      int fps = leap.getFrameRate();
      frameRate(fps);
    
    
      for (Hand hand : leap.getHands()) {
        for (Finger finger : hand.getFingers()) {
          fp   = finger.getPosition(); 
    
      freq=map(fp.x, 0, width, 100, 1000);
      sine.freq(freq);
    
          if (fp.z <= 30) {
            fill(0);
            ellipse(fp.x, fp.y, constrain(fp.z, 10, 20), constrain(fp.z, 10, 20));
          }
          else if (fp.z > 30) {
            points.add(new PVector(fp.x, fp.y));
          }
        }
      }
      for (int i = points.size()-1; i >= 0; i--) {
        PVector p = points.get(i);
        fill(23, 77, 255);
        ellipse(p.x, p.y, 20, 20);
      }
    }
    
    void keyPressed() {
      if (key == 32) {
        points = new ArrayList<PVector>();
      }
    }
    

    It's not quite as pretty before (I can't seem to get fixed random colours assigned to each finger - they flash like crazy if I try), BUT fp.x did allow me to control the oscillator with lateral hand movements!

    Interestingly and potentially problematically, the sound was not constrained by the sketch window. For example, while the above code should limit the frequency to a range of 100Hz (far left of the sketch), and 1000Hz (far right), the leapmotion kept tracking the position of the fingers as they left the borders of the sketch window, and the frequency also continued far beyond these confines, e.g. sub 20Hz as you broke off to the left, and ear piercingly high as you ventured further right!

  • Use constrain() on the value before you use it in your sine object. Check the reference for detrails.

    Kf

  • Answer ✓

    @Detta

    Example 1 is already deploy as part of the examples provided by the library. Here is the link: https://github.com/heuermh/leap-motion-processing/blob/master/examples/leap_position_example/leap_position_example.pde

    You can access the library source and documentation by clicking in the proper libraries in the next link: https://processing.org/reference/libraries/

    Most of the time, exploring the examples provides enough information to start a new project. You can explore the source code for extra comments associated to functions provided. Don't forget there are also videos posted online explaining processing+LeapMotion from the beginning. For instance,

    Kf

  • Thanks again Kf,

    I've come on leaps and bounds thanks to your advice!

    I now have the leap tracking fingers and palm position in a full HD window and, am able to map sound(s) to these values. One rather simple thing seems to elude me now, how on earth do I set the volume (amp) to 0 when the project starts?

    Currently the tone plays when the project opens, then when I bring a hand into play, and then move either the X or Z value of said hand out of bounds, the volume ramps down to 0, and stays and 0 until I bring a hand back into sensor range, at which point the volume ramps back up to 1 (100%).

    What I would like to do is have the amp set to 0 until a hand (hp) is detected.

    My code is as follows (please forgive newbie formatting):

    import de.voidplus.leapmotion.*;
    import processing.sound.*;
    
    SinOsc sine;
    LeapMotion leap;
    
    float freq=400;
    float amp;
    float pos;  
    ArrayList<PVector> points; 
    PVector fp;
    PVector hp; 
    
    void setup() {
      size(1920, 1080, P3D);
      background(255);
      leap = new LeapMotion(this);
      points = new ArrayList<PVector>(); 
      smooth(8);
      noStroke();
        // Create and start the sine oscillator.
        sine = new SinOsc(this);
        //Start the Sine Oscillator. 
        sine.play();
    }
    
    void draw() {
     background(10); //background colour
    
      for (Hand hand : leap.getHands()) {
        for (Finger finger : hand.getFingers()) {
          fp   = finger.getPosition(); 
          hp   = hand.getPosition();
    
       text("X=" +hp.x, 10, 15); //shows hp.x in sketch
       text("Y=" +hp.y, 10, 30); //shows hp.y in sketch
       text("Z=" +hp.z, 10, 45); //shows hp.z in sketch
       text("FREQ=" +freq, 10, 75); //shows frequency in sketch
       text("AMP=" +amp, 10, 90); //shows frequency in sketch
    
       text( "HPOS=" +hp.x, hp.x+25, hp.y-3 ); //shows hp.x in sketch on hp.x ellipse
       text( "FREQ=" +freq, hp.x+25, hp.y+12 ); //shows frequency in sketch on hp.x ellipse
    
       println (freq); //shows frequency readout in the console
       println(hp.x + " : " + hp.y + " : " + hp.z);  //shows hand position in console X:Y:Z 
    //   println(fp.x + " : " + fp.y + " : " + fp.z);  //shows finger position in console X:Y:Z 
    
    
      if( hp.z < -40 ) //if hand position(x) is less than or equal to -40...
      {
        amp = 0; //... then volume is 0%
      }
      else if( hp.z < 0 ) //if hand position(x) is less than 0...
      {
        amp = map( hp.z, 0, -40, 1, 0.01 ); //... then posx between 0 & -400 chances volume between 100 - 0%
      }
      else if( hp.z >= 0 && hp.z <= 50 ) //if hand position(z) is greater than or equal to 0 and less than or equal to 50...
      {
        amp = 1; //... set volume to 1 (100%)
      }
    
       if( hp.x < -400 ) //if hand position(x) is less than or equal to -400...
      {
        amp = 0; //... then volume is 0%
      }
      else if( hp.x < 0 ) //if hand position(x) is less than 0...
      {
        amp = map( hp.x, 0, -400, 1, 0.01 ); //... then posx between 0 & -400 chances volume between 100 - 0%
      }
    
      if( hp.x > 2320 ) //if hand position(x) greter than 2320...
      {
        amp = 0; //... then volume is 0%
      }
      else if( hp.x > 1920 ) //if hand position(x) greater than 1920...
      {
        amp = map( hp.x, 1920, 2320, 1, 0.01 ); //... then posx between 0 & -400 chances volume between 100 - 0%
      }
    
    
    sine.amp(amp); 
    
    
    
     if( hp.x >= 0 && hp.x < 100 ) //if hand position(x) is greater than 0 and less than 100...
      {
        freq = 200.0; //... set frequency to 200Hz
      }
      else if( hp.x >= 100 && hp.x < 200 ) //if hand position(x) is greter than or equal to 100 and less than 200...
      {
        freq = map( hp.x, 100, 199, 200, 300 ); //... then posx between 100 & 199 chances freq. between 200 - 300Hz
      }
      else if( hp.x >= 200 && hp.x < 300 ) //if hand position(x) is greter than or equal to 200 and less than 300...
      {
        freq = 300.0; //... set frequency to 300Hz
      }
    
    sine.freq(freq);
    
    
          if (hp.x >= -40) {
            fill(200,150,150);
            ellipse(hp.x, hp.y, constrain(hp.z, 10, 40), constrain(hp.z, 10, 40));
          }
    
          if (fp.x >= -40) {
            fill(150,150,150);
            ellipse(fp.x, fp.y, constrain(fp.z, 10, 40), constrain(fp.z, 10, 40));
          }
    
    
    
        }
      }
      for (int i = points.size()-1; i >= 0; i--) {
        PVector p = points.get(i);
        fill(255, 182, 193); //colour of the ellipse when in range specified by fp.z
    
    
    
    
      }
    }
    

    Any pointers?

  • how on earth do I set the volume (amp) to 0 when the project starts?

    Add the following line between line 24 and 25: sine.amp(amp); However I am not sure if that will do the trick bc I can't run your code and bc it is very likely than when your device starts, even if your hands are not within the interactive space, the values that your device returns could be automatically initialize inside the interactive space. If this is so, then your draw() function will override my previous line and you will have a tone playing with non-zero volume.

    I will suggest to approach your problem in a different way. Try using mouse positions in a different sketch where you control the sound bound by different regions in your sketch. Then handle the situation when the mouse leaves your sketch area fast, so the mouse positions are still returning points inside your sketch despite your mouse being outside. An idea to handle this situation is that instead of reacting to absolute pointer position, you react to differential positions aka. "previous MINUS current" position. In the trivial case, if the hand is in the active area of drawing, your hand jitters and introduces differential values. When the differential values are zero, either the hand is very still or the hand has left the active region being monitored by leapMotion.

    Kf

Sign In or Register to comment.