Play a video & a midi somehow in sync

Hi all

I have a nice beginners question: I use a patch to play video over a led panel I built. For an installation I’d like to play a video and a midi file in the patch. both have to run somehow in sync. With somehow I mean, they don’t have to be clocked, they may have a little drift. I have to option, Either send a message (midi or OSC) to PD and play the file there, or play the file within processing BUT as I’m new to processing I didin’t get there yet. Option one would need a bang on every new loop of the video. Option 2 would be a maybe a melt of these two patches.

any idea ?


 

/*  OctoWS2811 movie2serial.pde - Transmit video data to 1 or more
      Teensy 3.0 boards running OctoWS2811 VideoDisplay.ino
    http://www.pjrc.com/teensy/td_libs_OctoWS2811.html
    Copyright (c) 2013 Paul Stoffregen, PJRC.COM, LLC
    Permission is hereby granted, free of charge, to any person obtaining a copy
    of this software and associated documentation files (the "Software"), to deal
    in the Software without restriction, including without limitation the rights
    to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    copies of the Software, and to permit persons to whom the Software is
    furnished to do so, subject to the following conditions:
    The above copyright notice and this permission notice shall be included in
    all copies or substantial portions of the Software.
    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    THE SOFTWARE.
*/

// To configure this program, edit the following sections:
//
//  1: change myMovie to open a video file of your choice    ;-)
//
//  2: edit the serialConfigure() lines in setup() for your
//     serial device names (Mac, Linux) or COM ports (Windows)
//
//  3: if your LED strips have unusual color configuration,
//     edit colorWiring().  Nearly all strips have GRB wiring,
//     so normally you can leave this as-is.
//
//  4: if playing 50 or 60 Hz progressive video (or faster),
//     edit framerate in movieEvent().

import processing.video.*;
import processing.serial.*;
import java.awt.Rectangle;

 

//Movie myMovie = new Movie(this, "/Users/nicholas/Documents/LEDrevolution/1776.mov");
//Movie myMovie = new Movie(this, "/Users/nicholas/Music/revolutionary_songs_in_a_AI_Environment/LEDrevolution/1789.mov");
//Movie myMovie = new Movie(this, "/Users/nicholas/Music/revolutionary_songs_in_a_AI_Environment/LEDrevolution/1848.mov");
Movie myMovie = new Movie(this, "//Users/nicholas/Music/revolutionary_songs_in_a_AI_Environment/LEDrevolution/1980.mov");
//Movie myMovie = new Movie(this, "/Users/nicholas/Music/revolutionary_songs_in_a_AI_Environment/LEDrevolution/1917.mov");
//Movie myMovie = new Movie(this, "/Users/nicholas/Documents/LEDrevolution/1949.mov");
//Movie myMovie = new Movie(this, "/Users/nicholas/Documents/LEDrevolution/1966.mov");
//Movie myMovie = new Movie(this, "/Users/nicholas/Documents/LEDrevolution/1970.mov");
//Movie myMovie = new Movie(this, "/Users/nicholas/Music/revolutionary_songs_in_a_AI_Environment/LEDrevolution/1978.mov");
//Movie myMovie = new Movie(this, "/Users/nicholas/Music/revolutionary_songs_in_a_AI_Environment/LEDrevolution/1980.mov");




float gamma = 2.8;

int numPorts=0;  // the number of serial ports in use
int maxPorts=24; // maximum number of serial ports

Serial[] ledSerial = new Serial[maxPorts];     // each port's actual Serial port
Rectangle[] ledArea = new Rectangle[maxPorts]; // the area of the movie each port gets, in % (0-100)
boolean[] ledLayout = new boolean[maxPorts];   // layout of rows, true = even is left->right
PImage[] ledImage = new PImage[maxPorts];      // image sent to each port
int[] gammatable = new int[256];
int errorCount=0;
float framerate=0;

void setup() {

  String[] list = Serial.list();
  delay(20);
  println("Serial Ports List:");
  println(list);
  serialConfigure("/dev/tty.usbmodem3292521");  // change these to your port names
  //serialConfigure("/dev/ttyACM1");
  if (errorCount > 0) exit();
  for (int i=0; i < 256; i++) {
    gammatable[i] = (int)(pow((float)i / 255.0, gamma) * 255.0 + 0.5);
  }
  size(480, 380);  // create the window
  myMovie.play();  // start the movie :-)

}

 
// movieEvent runs for each new frame of movie data
void movieEvent(Movie m) {
  // read the movie's next frame

  m.read();

 
  
  //if (framerate == 0) framerate = m.getSourceFrameRate();
  framerate = 30.0; // TODO, how to read the frame rate???
  
  for (int i=0; i < numPorts; i++) {    
    // copy a portion of the movie's image to the LED image
    int xoffset = percentage(m.width, ledArea[i].x);
    int yoffset = percentage(m.height, ledArea[i].y);
    int xwidth =  percentage(m.width, ledArea[i].width);
    int yheight = percentage(m.height, ledArea[i].height);
    ledImage[i].copy(m, xoffset, yoffset, xwidth, yheight,
                     0, 0, ledImage[i].width, ledImage[i].height);
    // convert the LED image to raw data
    byte[] ledData =  new byte[(ledImage[i].width * ledImage[i].height * 3) + 3];
    image2data(ledImage[i], ledData, ledLayout[i]);
    if (i == 0) {
      ledData[0] = '*';  // first Teensy is the frame sync master
      int usec = (int)((1000000.0 / framerate) * 0.75);
      ledData[1] = (byte)(usec);   // request the frame sync pulse
      ledData[2] = (byte)(usec >> 8); // at 75% of the frame time
    } else {
      ledData[0] = '%';  // others sync to the master board
      ledData[1] = 0;
      ledData[2] = 0;
    }
    // send the raw data to the LEDs  :-)
    ledSerial[i].write(ledData); 
  }
}

// image2data converts an image to OctoWS2811's raw data format.
// The number of vertical pixels in the image must be a multiple
// of 8.  The data array must be the proper size for the image.
void image2data(PImage image, byte[] data, boolean layout) {
  int offset = 3;
  int x, y, xbegin, xend, xinc, mask;
  int linesPerPin = image.height / 8;
  int pixel[] = new int[8];
  
  for (y = 0; y < linesPerPin; y++) { 
    if ((y & 1) == (layout ? 1 : 0)) { //changed  from originally: (layout ? 0 : 1)
      // even numbered rows are left to right
      xbegin = 0;
      xend = image.width;
      xinc = 1;
    } else {
      // odd numbered rows are right to left
      xbegin = image.width - 1;
      xend = -1;
      xinc = -1;
    }
    for (x = xbegin; x != xend; x += xinc) {
      for (int i=0; i < 8; i++) {
        // fetch 8 pixels from the image, 1 for each pin
        pixel[i] = image.pixels[x + (y + linesPerPin * i) * image.width];
        pixel[i] = colorWiring(pixel[i]);
      }
      // convert 8 pixels to 24 bytes
      for (mask = 0x800000; mask != 0; mask >>= 1) {
        byte b = 0;
        for (int i=0; i < 8; i++) {
          if ((pixel[i] & mask) != 0) b |= (1 << i);
        }
        data[offset++] = b;
      }
    }
  } 
}

// translate the 24 bit color from RGB to the actual
// order used by the LED wiring.  GRB is the most common.
int colorWiring(int c) {
  int red = (c & 0xFF0000) >> 16;
  int green = (c & 0x00FF00) >> 8;
  int blue = (c & 0x0000FF);
  red = gammatable[red];
  green = gammatable[green];
  blue = gammatable[blue];
  return (green << 16) | (red << 8) | (blue); // GRB - most common wiring
}

// ask a Teensy board for its LED configuration, and set up the info for it.
void serialConfigure(String portName) {
  if (numPorts >= maxPorts) {
    println("too many serial ports, please increase maxPorts");
    errorCount++;
    return;
  }
  try {
    ledSerial[numPorts] = new Serial(this, portName);
    if (ledSerial[numPorts] == null) throw new NullPointerException();
    ledSerial[numPorts].write('?');
  } catch (Throwable e) {
    println("Serial port " + portName + " does not exist or is non-functional");
    errorCount++;
    return;
  }
  delay(50);
  String line = ledSerial[numPorts].readStringUntil(10);
  if (line == null) {
    println("Serial port " + portName + " is not responding.");
    println("Is it really a Teensy 3.0 running VideoDisplay?");
    errorCount++;
    return;
  }
  String param[] = line.split(",");
  if (param.length != 12) {
    println("Error: port " + portName + " did not respond to LED config query");
    errorCount++;
    return;
  }
  
  // only store the info and increase numPorts if Teensy responds properly
  ledImage[numPorts] = new PImage(Integer.parseInt(param[0]), Integer.parseInt(param[1]), RGB);
  ledArea[numPorts] = new Rectangle(Integer.parseInt(param[5]), Integer.parseInt(param[6]),
                     Integer.parseInt(param[7]), Integer.parseInt(param[8]));
  ledLayout[numPorts] = (Integer.parseInt(param[5]) == 0);
  numPorts++;
}

// draw runs every time the screen is redrawn - show the movie...
void draw() {
  // show the original video
  image(myMovie, 0, 80);
  // then try to show what was most recently sent to the LEDs
  // by displaying all the images for each port.
  for (int i=0; i < numPorts; i++) {
    // compute the intended size of the entire LED array
    int xsize = percentageInverse(ledImage[i].width, ledArea[i].width);
    int ysize = percentageInverse(ledImage[i].height, ledArea[i].height);
    // computer this image's position within it
    int xloc =  percentage(xsize, ledArea[i].x);
    int yloc =  percentage(ysize, ledArea[i].y);
    // show what should appear on the LEDs
    image(ledImage[i], 240 - xsize / 2 + xloc, 10 + yloc);
  } 
}

// respond to mouse clicks as pause/play
boolean isPlaying = true;
void mousePressed() {
  if (isPlaying) {
    myMovie.pause();
    isPlaying = false;
  } else {
    myMovie.play();
    isPlaying = true;
  }
}

// scale a number by a percentage, from 0 to 100
int percentage(int num, int percent) {
  double mult = percentageFloat(percent);
  double output = num * mult;
  return (int)output;
}

// scale a number by the inverse of a percentage, from 0 to 100
int percentageInverse(int num, int percent) {
  double div = percentageFloat(percent);
  double output = num / div;
  return (int)output;
}

// convert an integer from 0 to 100 to a float percentage
// from 0.0 to 1.0.  Special cases for 1/3, 1/6, 1/7, etc
// are handled automatically to fix integer rounding.
double percentageFloat(int percent) {
  if (percent == 33) return 1.0 / 3.0;
  if (percent == 17) return 1.0 / 6.0;
  if (percent == 14) return 1.0 / 7.0;
  if (percent == 13) return 1.0 / 8.0;
  if (percent == 11) return 1.0 / 9.0;
  if (percent ==  9) return 1.0 / 11.0;
  if (percent ==  8) return 1.0 / 12.0;
  return (double)percent / 100.0;
}

I’m not entirely following the situation.

It looks like you have a video wall that you control with the first sketch, playing a movie file. The pixels from the movie get send to the LED wall over a serial connection.

Then, you want to send a MIDI file as MIDI message or OSC (whichever is easiest)? Is the MIDI file the same length as the movie? What does the MIDI file contain, notes, CC values, multiple tracks/channels?

Is this MIDI file important, or do you just need to send specific values at specific time stamps during the movie? I’m thinking stuff like fireworks/SFX/fog machines triggering at key moments during the movie here. Correct?

You mention two options but it’s completely unclear to me what they are.

Hi colouredmirrorball !

First of all : I did a mistake, the second sketch I was posting is the wrong, I wanted to post a midi file player, I removed it now

In general you understood me correct, the video will be sent over serial connection to a LED wall. The video should run in “sync” with a midi file of the same length. The midi file information (notes, volume an controller ) are routed to pureData and are further processed to control a robot. It’s a lot of info, not just a fog machine trigger.

to play the midi file, I could either play it in the processing sketch or in pureData. These are the two options.

The pD option is maybe more easy: The video is being looped every 26 minutes. If I can send a bang (midi or osc message) on every loop start to pureData I could run the midi file there.

I hope a made myself more clear, thank you for the help

for me that would be easier, I just could find a possibility to send a bang

salut, it’s nice to read you, i’m on similar way. not exactly, but close.

i keep this by my side and will follow closely your tread.

To easy edit and sync i looking for use a served daw

Webpage–>Rhizome–>Ableton–>Resolume–>Artnet–>Esp8266–>WS2812B.

Just dicovering processing and looking for integrate it somewhere on chain.

How did you do the ESP8266 to WS2812B?

Hi, not sure this helps with your project, but in this sketch I played a midi file in Processing:

1 Like

If the video and MIDI file are 26 minutes long there’s no way they’re going to be synchronised.

The Movie class has two interesting methods, duration() and time():

void movieEvent(Movie m) {
  m.read();
  
  //This line gets the total duration of the movie in seconds
  duration = m.duration();
  
  //This line gets the time in seconds of the frame that is being read
  movieTime = m.time();
}

You can use this logic to detect when the movie restarted:

if(movieTime < prevTime)
  {
    //The movie restarted!
    println("Restarting...");
  }
  
  prevTime = movieTime;

Then you can replace the println("Restarting..."); by code that sends a MIDI or OSC message. I don’t know what pureData needs so I can’t help with that right now.
But, as I said before, I predict the movie and MIDI file will go out of sync pretty fast. (Maybe I’m wrong so be sure to test it out first, maybe this isn’t so big an issue after all).

You have three four options (but maybe I missed another, obvious, easier solution):

  • Figure out @hamoid’s MIDI file parsing code and see if it works for you. I haven’t tested it out to see how it handles timing and if you can force it to sync to the video.

  • Figure out MTC and make an implementation in Processing. First check if pD accepts MTC. To make the implementation, take theMidiBus library’s AdvancedMIDIMessageIO example as the starting point and modify the SysexMessage code. It looks like MTC messages are four bytes long. This is a bit of a headache to figure out but in the end, the least messy. Also, check out the java midi documentation, this has probably been done before.

  • Make your own file format that is easy to implement in Processing. Store timestamps with additional information (note, channel, velocity), then check when the movie time crosses the timestamp and send the message. The existing MIDI file needs to be rewritten or reparsed, which might or might not be a lot of extra work.

  • (EDIT) Create your own timecode protocol. Again, I’m not familiar with Puredata and its capabilities, but maybe you can send some OSC command with the timestamp and use that to sync the video?

1 Like

with fastled or neopixel library


same for esp with ide arduino just need to install esp library

Ah, but the effects are preprogrammed. The issue here is to send RGB(W) data as byte arrays over the serial communication from the computer to the LED strips. Which does not work with Arduino nanos (for longer strips), but apparently works with Teensy controllers.

I didn’t parse it myself, I used javax.sound.midi :slight_smile:

that’s helpful thank you very much. I will try to send the start point via osc to pD an start the midi file there. If it goes out of sync, I will break the file into 6 parts and trigger each.

stop me if I’m going into the void

Any approach that works, works. But 26/6 is only one sync signal every 4.5 minutes which might still not be enough.

Another idea. Maybe it can work in reverse and you can sync the movie with the MIDI data from pD instead. If you could convince pureData to send the current time of the midi playback over an OSC message, you can use m.jump(float s) to jump to time s (in seconds) of the video. The movie might skip or return a frame or two every once in a while. YMMV, and the choppiness of the movie will also depend on the interval time between two sync messages. But I think this might still be worth investigating. You might even get away by pausing the video and set the current frame manually by streaming OSC messages from pD! This might just work but could also end up horribly…

Not 100% clear from reading this - they’re on the same computer?

One key thing for sync is ideally to be using the same clock source for the video and midi files. If they’re on the same computer and are both using the system CPU timer, then they should stay in sync. However, note that the GStreamer pipeline inside the Processing Video player is the important clock here. This might be the system clock, but if the video has an audio track (even if not audible) it will almost certainly be using the soundcard clock instead. Actually getting PD and GStreamer to both use the audio clock is probably the best way of keeping these in sync. Even across machines, it’s possible with some soundcards to have one provide the clock for the other.

I’m the maintainer of the GStreamer Java bindings that are used in Processing Video, so a couple of other things. I’d make sure to use the beta of Processing Video v2 so that you’re using GStreamer 1.x; and I wouldn’t use jump() for this due to what it does, and the somewhat suboptimal implementation in the Processing Video library.

A more complicated option if the soundcard clock doesn’t work for you - GStreamer does allow you to provide your own clock source for a pipeline, but you’d have to delve into the internals of the Processing Video library to access it. Incidentally, I’m currently half way through implementing pluggable clock sources in the PraxisLIVE runtime to make it possible to drive Processing sketches and GStreamer pipelines off a clock of choice.

that’s what I suspect. For that I just need to send a bang for start from pd to processing, I think I use osc.

so I tried it, the logic makes sense, nevertheless I get this: JNA: could not detach thread in processing and after a couple of minutes it starts to crash. what did I do wrong ?

 
 

/*  OctoWS2811 movie2serial.pde - Transmit video data to 1 or more
      Teensy 3.0 boards running OctoWS2811 VideoDisplay.ino
    http://www.pjrc.com/teensy/td_libs_OctoWS2811.html
    Copyright (c) 2013 Paul Stoffregen, PJRC.COM, LLC
    Permission is hereby granted, free of charge, to any person obtaining a copy
    of this software and associated documentation files (the "Software"), to deal
    in the Software without restriction, including without limitation the rights
    to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    copies of the Software, and to permit persons to whom the Software is
    furnished to do so, subject to the following conditions:
    The above copyright notice and this permission notice shall be included in
    all copies or substantial portions of the Software.
    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    THE SOFTWARE.
*/

// To configure this program, edit the following sections:
//
//  1: change myMovie to open a video file of your choice    ;-)
//
//  2: edit the serialConfigure() lines in setup() for your
//     serial device names (Mac, Linux) or COM ports (Windows)
//
//  3: if your LED strips have unusual color configuration,
//     edit colorWiring().  Nearly all strips have GRB wiring,
//     so normally you can leave this as-is.
//
//  4: if playing 50 or 60 Hz progressive video (or faster),
//     edit framerate in movieEvent().

import processing.video.*;
import processing.serial.*;
import java.awt.Rectangle;

 

//Movie myMovie = new Movie(this, "/Users/nicholas/Documents/LEDrevolution/1776.mov");
//Movie myMovie = new Movie(this, "/Users/nicholas/Music/revolutionary_songs_in_a_AI_Environment/LEDrevolution/1789.mov");
//Movie myMovie = new Movie(this, "/Users/nicholas/Music/revolutionary_songs_in_a_AI_Environment/LEDrevolution/1848.mov");
Movie myMovie = new Movie(this, "//Users/nicholas/Music/revolutionary_songs_in_a_AI_Environment/LEDrevolution/1980.mov");
//Movie myMovie = new Movie(this, "/Users/nicholas/Music/revolutionary_songs_in_a_AI_Environment/LEDrevolution/1917.mov");
//Movie myMovie = new Movie(this, "/Users/nicholas/Documents/LEDrevolution/1949.mov");
//Movie myMovie = new Movie(this, "/Users/nicholas/Documents/LEDrevolution/1966.mov");
//Movie myMovie = new Movie(this, "/Users/nicholas/Documents/LEDrevolution/1970.mov");
//Movie myMovie = new Movie(this, "/Users/nicholas/Music/revolutionary_songs_in_a_AI_Environment/LEDrevolution/1978.mov");
//Movie myMovie = new Movie(this, "/Users/nicholas/Music/revolutionary_songs_in_a_AI_Environment/LEDrevolution/1980.mov");




float gamma = 2.8;

int numPorts=0;  // the number of serial ports in use
int maxPorts=24; // maximum number of serial ports
float duration=0;
float movieTime=0;
float prevTime;

Serial[] ledSerial = new Serial[maxPorts];     // each port's actual Serial port
Rectangle[] ledArea = new Rectangle[maxPorts]; // the area of the movie each port gets, in % (0-100)
boolean[] ledLayout = new boolean[maxPorts];   // layout of rows, true = even is left->right
PImage[] ledImage = new PImage[maxPorts];      // image sent to each port
int[] gammatable = new int[256];
int errorCount=0;
float framerate=0;

void setup() {

  String[] list = Serial.list();
  delay(20);
  println("Serial Ports List:");
  println(list);
  serialConfigure("/dev/tty.usbmodem3292521");  // change these to your port names
  //serialConfigure("/dev/ttyACM1");
  if (errorCount > 0) exit();
  for (int i=0; i < 256; i++) {
    gammatable[i] = (int)(pow((float)i / 255.0, gamma) * 255.0 + 0.5);
  }
  size(480, 380);  // create the window
  myMovie.play();  // start the movie :-)

}

 
// movieEvent runs for each new frame of movie data
void movieEvent(Movie m) {
  // read the movie's next frame
  m.read();

  
    //This line gets the total duration of the movie in seconds
  duration = m.duration();
  
  //This line gets the time in seconds of the frame that is being read
  movieTime = m.time();
println(movieTime);

  
if(movieTime < prevTime)
  {
    //The movie restarted!
    println("Restarting...");
  };
  
 // prevTime = movieTime;


 
  
  //if (framerate == 0) framerate = m.getSourceFrameRate();
  framerate = 30.0; // TODO, how to read the frame rate???
  
  for (int i=0; i < numPorts; i++) {    
    // copy a portion of the movie's image to the LED image
    int xoffset = percentage(m.width, ledArea[i].x);
    int yoffset = percentage(m.height, ledArea[i].y);
    int xwidth =  percentage(m.width, ledArea[i].width);
    int yheight = percentage(m.height, ledArea[i].height);
    ledImage[i].copy(m, xoffset, yoffset, xwidth, yheight,
                     0, 0, ledImage[i].width, ledImage[i].height);
    // convert the LED image to raw data
    byte[] ledData =  new byte[(ledImage[i].width * ledImage[i].height * 3) + 3];
    image2data(ledImage[i], ledData, ledLayout[i]);
    if (i == 0) {
      ledData[0] = '*';  // first Teensy is the frame sync master
      int usec = (int)((1000000.0 / framerate) * 0.75);
      ledData[1] = (byte)(usec);   // request the frame sync pulse
      ledData[2] = (byte)(usec >> 8); // at 75% of the frame time
    } else {
      ledData[0] = '%';  // others sync to the master board
      ledData[1] = 0;
      ledData[2] = 0;
    }
    // send the raw data to the LEDs  :-)
    ledSerial[i].write(ledData); 
  }
}

// image2data converts an image to OctoWS2811's raw data format.
// The number of vertical pixels in the image must be a multiple
// of 8.  The data array must be the proper size for the image.
void image2data(PImage image, byte[] data, boolean layout) {
  int offset = 3;
  int x, y, xbegin, xend, xinc, mask;
  int linesPerPin = image.height / 8;
  int pixel[] = new int[8];
  
  for (y = 0; y < linesPerPin; y++) { 
    if ((y & 1) == (layout ? 1 : 0)) { //changed  from originally: (layout ? 0 : 1)
      // even numbered rows are left to right
      xbegin = 0;
      xend = image.width;
      xinc = 1;
    } else {
      // odd numbered rows are right to left
      xbegin = image.width - 1;
      xend = -1;
      xinc = -1;
    }
    for (x = xbegin; x != xend; x += xinc) {
      for (int i=0; i < 8; i++) {
        // fetch 8 pixels from the image, 1 for each pin
        pixel[i] = image.pixels[x + (y + linesPerPin * i) * image.width];
        pixel[i] = colorWiring(pixel[i]);
      }
      // convert 8 pixels to 24 bytes
      for (mask = 0x800000; mask != 0; mask >>= 1) {
        byte b = 0;
        for (int i=0; i < 8; i++) {
          if ((pixel[i] & mask) != 0) b |= (1 << i);
        }
        data[offset++] = b;
      }
    }
  } 
}

// translate the 24 bit color from RGB to the actual
// order used by the LED wiring.  GRB is the most common.
int colorWiring(int c) {
  int red = (c & 0xFF0000) >> 16;
  int green = (c & 0x00FF00) >> 8;
  int blue = (c & 0x0000FF);
  red = gammatable[red];
  green = gammatable[green];
  blue = gammatable[blue];
  return (green << 16) | (red << 8) | (blue); // GRB - most common wiring
}

// ask a Teensy board for its LED configuration, and set up the info for it.
void serialConfigure(String portName) {
  if (numPorts >= maxPorts) {
    println("too many serial ports, please increase maxPorts");
    errorCount++;
    return;
  }
  try {
    ledSerial[numPorts] = new Serial(this, portName);
    if (ledSerial[numPorts] == null) throw new NullPointerException();
    ledSerial[numPorts].write('?');
  } catch (Throwable e) {
    println("Serial port " + portName + " does not exist or is non-functional");
    errorCount++;
    return;
  }
  delay(50);
  String line = ledSerial[numPorts].readStringUntil(10);
  if (line == null) {
    println("Serial port " + portName + " is not responding.");
    println("Is it really a Teensy 3.0 running VideoDisplay?");
    errorCount++;
    return;
  }
  String param[] = line.split(",");
  if (param.length != 12) {
    println("Error: port " + portName + " did not respond to LED config query");
    errorCount++;
    return;
  }
  
  // only store the info and increase numPorts if Teensy responds properly
  ledImage[numPorts] = new PImage(Integer.parseInt(param[0]), Integer.parseInt(param[1]), RGB);
  ledArea[numPorts] = new Rectangle(Integer.parseInt(param[5]), Integer.parseInt(param[6]),
                     Integer.parseInt(param[7]), Integer.parseInt(param[8]));
  ledLayout[numPorts] = (Integer.parseInt(param[5]) == 0);
  numPorts++;
}

// draw runs every time the screen is redrawn - show the movie...
void draw() {
  // show the original video
  image(myMovie, 0, 80);
  // then try to show what was most recently sent to the LEDs
  // by displaying all the images for each port.
  for (int i=0; i < numPorts; i++) {
    // compute the intended size of the entire LED array
    int xsize = percentageInverse(ledImage[i].width, ledArea[i].width);
    int ysize = percentageInverse(ledImage[i].height, ledArea[i].height);
    // computer this image's position within it
    int xloc =  percentage(xsize, ledArea[i].x);
    int yloc =  percentage(ysize, ledArea[i].y);
    // show what should appear on the LEDs
    image(ledImage[i], 240 - xsize / 2 + xloc, 10 + yloc);
  } 
}

// respond to mouse clicks as pause/play
boolean isPlaying = true;
void mousePressed() {
  if (isPlaying) {
    myMovie.pause();
    isPlaying = false;
  } else {
    myMovie.play();
    isPlaying = true;
  }
}

// scale a number by a percentage, from 0 to 100
int percentage(int num, int percent) {
  double mult = percentageFloat(percent);
  double output = num * mult;
  return (int)output;
}

// scale a number by the inverse of a percentage, from 0 to 100
int percentageInverse(int num, int percent) {
  double div = percentageFloat(percent);
  double output = num / div;
  return (int)output;
}

// convert an integer from 0 to 100 to a float percentage
// from 0.0 to 1.0.  Special cases for 1/3, 1/6, 1/7, etc
// are handled automatically to fix integer rounding.
double percentageFloat(int percent) {
  if (percent == 33) return 1.0 / 3.0;
  if (percent == 17) return 1.0 / 6.0;
  if (percent == 14) return 1.0 / 7.0;
  if (percent == 13) return 1.0 / 8.0;
  if (percent == 11) return 1.0 / 9.0;
  if (percent ==  9) return 1.0 / 11.0;
  if (percent ==  8) return 1.0 / 12.0;
  return (double)percent / 100.0;
}

I would try moving the code to transmit the images out of movieEvent() and into draw().

What version of the video library - v1 or v2 beta?

That JNA error message might not be the problem.

well the thing is the sketch works for movie transmitting, also very stable, so I’d rather not fiddle with that. I use v1. the source of crash is this part, or maybe the declaration of the variables: ???

//This line gets the total duration of the movie in seconds

duration = m.duration();

//This line gets the time in seconds of the frame that is being read
movieTime = m.time();
println(movieTime);

if(movieTime < prevTime)
{
//The movie restarted!
println(“Restarting…”);
};

The println(movieTime) could become an issue, the IDE doesn’t like it when there are too many println()'s printed to it…

Also, if you comment out prevTime = movieTime; the restarting logic doesn’t work.

just changed it, took out the println and uncommented the logic

nevertheless… the problem stays

Can you give some more explanation when you say it “starts to crash”? What exactly happens? Printed errors?