Video delay effect, adjustable delay time

I want to create a (live) video delay effect with adjustable delay time.
(tweaking delay time with mouseX).

Works ok at start, but then delayed image suddenly disappears.

Two video images: one without delay, and on top a delayed one.
For the latter I use a buffer, playhead continuously running between frame[0] and a middle point (adjustable), and then looping back to frame[0]:

import processing.video.*;

Capture cam;
PImage[] buffer;

int nFrames = 60; // 2" max buffer length (at 30 fps)
int iWrite = 0, iRead = 1;
int adjust_buf;
int bufSize;

void setup() {
  size(640, 480);
  cam = new Capture(this, 640, 480);
  cam.start(); // start reading from camera
  buffer = new PImage[nFrames];
}

void draw() {

  if (cam.available()) { // check if a new image is available
    cam.read(); // reads the current frame of the device

    // 1.CURRENT IMAGE (no delay)
    tint(255, 255, 255, 255);
    image(cam, 0, 0);

    // map mouseX between left <>right screen edges:
    //  longest possible delay (60 frames) <> no delay (1 frame)
    adjust_buf = round(map(mouseX, 0, width, 0, nFrames-1));

    // how far into buffer playhead can read:
    bufSize =  nFrames - adjust_buf;

    // (print values)
    println("bufSize: ", bufSize);
    println("iRead: ", iRead); // playhead position

    buffer[iWrite] = cam.get();
    if (buffer[iRead] != null) {

      // 2.DELAYED IMAGE, displayed on top of current image
      tint(255, 120);
      image(buffer[iRead], 0, 0);
    }

    // playhead progress
    iWrite++;
    iRead++;

    // loop playhead to beginning of buffer
    if (iRead >= bufSize) {
      iRead = 0;
    }
    if (iWrite >= bufSize) {
      iWrite = 0;
    }
  }
}

It seems that sudden delay-time adjustment (fast mouseX movement) causes the delayed image to ‘quit’. Or maybe when delay time becomes too short? Not entirely sure.

Hello @ilya.z,

Consider using an ArrayList of PImages:

ArrayList<PImage> buffer = new ArrayList<PImage>();

// You can do things like this:
buffer.add(cam.get(0)) ;
image(buffer.get(0), 0, 0);
buffer.remove(0);

You can sort out the flow and logic in your code. That is the fun part!

Reference:

:)

1 Like

What do you mean by quit? Do you mean that the two image become the same? as glv says you need to find the logic - it seems the buffering part is working properly, though.

My guess is that

    if (iRead >= bufSize) {
      iRead = 0;
    }
    if (iWrite >= bufSize) {
      iWrite = 0;
    }

This happens at the same time when bufSize suddenly becomes small. Then iRead and iWrite are the same value. Perhaps, instead of incrementing iRead every frame, you want to calculate it from iWrite value - but I know this is tricky!

2 Likes

Thanks @glv , ArrayList indeed seems to be the proper way to deal with a buffer!

Thanks @micuat ,

Really helpful insight!

My assumption that the delayed image ‘quits’ was of course wrong. It was only playing together with current image, without delay, so ‘invisible’.

Solution is pretty simple:

if (iRead >= bufSize) {
      iRead = 1;
    }
    if (iWrite >= bufSize) {
      iWrite = 0;
    }

:slight_smile:

1 Like