Transform a Processing sketch into a Praxis LIVE component

Version 2 of Praxis LIVE brings in Processing as a core library, and adds a whole new OpenGL video pipeline with access to most of Processing’s features. Almost all of Praxis LIVE’s built-in components are now defined via the new live-code API, essentially as small sketches that can be defined and re-defined as your project is running.  There are also a number of base components for creating completely custom components on-the-fly.  Here we’ll explore how to use video:gl:p3d to translate Processing’s TextureCylinder example into a Praxis LIVE component. You can see this in action in the Smoky 3D example.

Smoky 3D example running with cylinder code open for editing.

Smoky 3D example running with cylinder code open for editing.

There are currently three base components that can be used to create custom components in Praxis LIVE.

  • core:custom – Control component that can be used in all types of graph (video, audio, TinkerForge, etc.). No graphics support. provides access to most of Processing’s core API that is not graphics related.
  • video:custom – Basic video component that can be used in all video pipelines (software & OpenGL). Provides a limited subset of graphics functions (and some additional Praxis LIVE only graphics functions).
  • video:gl:p3d – Provides almost complete access to Processing’s 2D & 3D graphics functions. Only works when using the OpenGL renderer.

For this example we’ll be using the video:gl:p3d component. To open the code in the editor, right-click on the top visual tab of the component in the graph and select Edit code. The code will open in the editor and the component will be updated every time you hit Save.

Here we’ll compare the original Processing code from the code running in our Praxis LIVE component, and then explain the differences.

Original Processing sketch code

int tubeRes = 32;
float[] tubeX = new float[tubeRes];
float[] tubeY = new float[tubeRes];
PImage img;

void setup() {
  size(640, 360, P3D);
  img = loadImage("berlin-1.jpg");
  float angle = 270.0 / tubeRes;
  for (int i = 0; i < tubeRes; i++) {
    tubeX[i] = cos(radians(i * angle));
    tubeY[i] = sin(radians(i * angle));
  }
  noStroke();
}

void draw() {
  background(0);
  translate(width / 2, height / 2);
  rotateX(map(mouseY, 0, height, -PI, PI));
  rotateY(map(mouseX, 0, width, -PI, PI));
  beginShape(QUAD_STRIP);
  texture(img);
  for (int i = 0; i < tubeRes; i++) {
    float x = tubeX[i] * 100;
    float z = tubeY[i] * 100;
    float u = img.width / tubeRes * i;
    vertex(x, -100, z, u, 0);
    vertex(x, 100, z, u, img.height);
  }
  endShape();
  beginShape(QUADS);
  texture(img);
  vertex(0, -100, 0, 0, 0);
  vertex(100, -100, 0, 100, 0);
  vertex(100, 100, 0, 100, 100);
  vertex(0, 100, 0, 0, 100);
  endShape();
}

Translated Praxis LIVE code

    @In(1)
    PImage in;
    @P(1) @Type.Number(min = 0, max = 1, def = 0.5)
    double x;
    @P(2) @Type.Number(min = 0, max = 1, def = 0.5)
    double y;

    int tubeRes = 32;
    double[] tubeX = new double[tubeRes];
    double[] tubeY = new double[tubeRes];
 
    public void setup() {
        double angle = 270.0 / tubeRes;
        for (int i = 0; i < tubeRes; i++) {
            tubeX[i] = cos(radians(i * angle));
            tubeY[i] = sin(radians(i * angle));
        }
        noStroke();
    }

    public void draw() {
        translate(width / 2, height / 2);
        scale(1.5);
        rotateX(map(x, 0, 1, -PI, PI));
        rotateY(map(y, 0, 1, -PI, PI));
        beginShape(QUAD_STRIP);
        texture(in);
        for (int i = 0; i < tubeRes; i++) {
            double x = tubeX[i] * 100;
            double z = tubeY[i] * 100;
            double u = in.width - (in.width / tubeRes * i);
            vertex(x, -100, z, u, 0);
            vertex(x, 100, z, u, in.height);
        }
        endShape();
        beginShape(QUADS);
        texture(in);
        vertex(0, -100, 0, 0, 0);
        vertex(100, -100, 0, 100, 0);
        vertex(100, 100, 0, 100, 100);
        vertex(0, 100, 0, 0, 100);
        endShape();
    }

Key Differences

So, the code isn’t that different to the original sketch, but there are a few things to keep in mind.

  • You may not always find all the methods you’re expecting! You’re not actually writing a PApplet. Instead, all Processing code is called through delegates, and you’re actually drawing on an off-screen graphics. Some methods that don’t make sense in the Praxis LIVE context are not available.
  • You’re coding in Java, without any of Processing’s language additions (like the color datatype). This also means that setup() and draw() need to be marked public.
  • Float literals have a suffix (eg. 1.45f) – it’s Java! However, as double is used often throughout Praxis LIVE code, all the delegate methods support it.  Therefore it’s better just to find and replace float to double.
  • There is no size(..) method. Size is determined by the video graph as a whole.
  • There is no loadImage(..) method. Instead …
  • Use @In for video input. Our PImage variable is annotated with @In, which automatically creates a video input port and creates the image for us. We didn’t have to change the variable name from img, but in is more common in Praxis LIVE.
  • There is no access to mouse position (yet!) Instead …
  • Use @P for external properties. Instead of mouse position we create two double fields, x and y. These are annotated with @P (short for property) which creates ports and controls on the component. This way we can use another object in the graph to control the rotation, or control the rotation through MIDI, OSC, GUI, etc.
  • Use @Type.Number (optional) to define range. Note this means we automatically get sliders as well as text in the component editor (see image above).
  • Load images with @P on PImage. Instead of annotating our PImage with @In, we could also use @P here, which would allow us to load an image from a file (asynchronously) using the GUI. If doing this, you must check whether the image is null before attempting to use it.
  • Note the use of scale(..). The example uses fixed dimensions, and our image size is bigger than the original. In general it’s better (in Praxis LIVE and Processing) to set your dimensions in proportion to the frame size.

So, hopefully that’s enough info to get you started, and maybe you can contribute to the custom component repository.  Feel free to ask questions here or on the mailing list, and lots more documentation on annotations and extensions to the Processing API will follow soon.

Advertisements

4 thoughts on “Transform a Processing sketch into a Praxis LIVE component

  1. This looks awesome. I wonder if you’d consider making it possible to integrate components written in other languages?

    There’s always freeframegl as one way of combining the output, and when it comes to editing Netbeans can support other languages.

    I’d be very interested in seeing integration with stuff not inside the JVM, though even just using python via jython could be OK.

    Outside the JVM there are interesting libraries, like Essentia and Aubio for audio analysis and a whole load of other graphics tech.

    BTW, your /contact link is broken.

    • Thanks! Glad you like it.

      Support for other languages isn’t on the roadmap at the moment, although I’m happy to help anyone who’d like to write support for another JVM language. Non-JVM language support is unlikely to impossible – while NetBeans supports editing other languages, the Praxis LIVE infrastructure relies heavily on the JIT compilation support of the JVM.

      FreeFrameGL is also unlikely as it bypasses the benefits of live editing. The current mix of Java and GLSL support should be more flexible in the longer term, and a custom component repository is being built up. OTOH, Syphon / Sprout support is being considered.

      Audio-wise, Java-based live DSP coding is the current priority, and close to ready for release. Native library support may come, but also bear in mind that Praxis LIVE supports JACK, so you can route audio into other tools (like aubio?) too.

      Thanks for the heads up on the contact link – a forward missed in the site update. Should now work OK? Do consider signing up to the mailing list – these sort of conversations might be better suited to that, and I’d value your input.

      • Yeah, will sign up the mailinglist. I like stuff outside the JVM and Java.. having said that praxis looks so complete it is tempting – a lot of things I was tempted to build myself are there aready 🙂

      • Simply put, the JVM is the right tech for the job. There aren’t that many options for doing all that Praxis LIVE does.

        So, come get involved and make sure it does all the things you were tempted to build! 😉

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s