Using a ControlP5 slider as video progress bar

edited September 12 in Library Questions

Hi. I'm doing this videoplayer but I need to see the progress of the video and be able to change it or make jumps clicking on it. I tried to update the internal value of the slider in an external function but the script got in a loop. It's possible to make this with a P5 slider?

Answers

  • edited September 2015

    I'm stuck with the same problem.. Have You found a solution for using a P5 slider as a progress bar?

  • Here the code of my sketch:

    import controlP5.*;
    import ddf.minim.*;
    import ddf.minim.analysis.*;
    
    ControlP5 cp5;
    Button b1,b2;
    Slider s1;
    Minim minim;
    AudioPlayer player;
    FFT fft;
    
    int mBand = 0;
    float maxValBand = 0;
    float maxAmp;
    boolean pause = true;
    float sliderValue = 0;
     
    void setup()
    {
      frameRate(30);
      size(600, 400);
      minim = new Minim(this);
      player = minim.loadFile("puresound.wav", 4096);
      fft = new FFT(player.bufferSize(),player.sampleRate());
      cp5 = new ControlP5(this);
      //Slider   
      s1 = cp5.addSlider("Slider")
            .setPosition(132,375)
            .setSize(450,15)
            .setLabel("")
            .setValueLabel("")
            .setRange(0,player.length())
            .setValue(0)
            .setUpdate(true)
            ;
      //Callback for Slider
      s1.addCallback(new CallbackListener() {
        public void controlEvent(CallbackEvent theEvent) {  
          if(theEvent.getAction()==ControlP5.ACTION_PRESSED){
              //println(s1.isUpdate());
              sliderValue = theEvent.getController().getValue();
              println(s1.getValue());
              println("Event fired");
              println(sliderValue);
              player.rewind();
              player.skip((int)sliderValue);
              player.play();
              s1.setValue(sliderValue);
              //s1.scrolled((int)theEvent.getController().getValue());
          }
        }
      }
      );
      //play button
      b1 = cp5.addButton("Play")
            .setValue(0)
            .setPosition(10,375)
            .setSize(50,19)
           ;
      //rewind button
      b2 = cp5.addButton("Rewind")
            .setValue(1)
            .setPosition(72,375)
            .setSize(50,19)
          ;
    }
     
    void draw()
    {
      if (!pause){
      background(0);
      stroke(255);
      fill(0);
      fft.forward(player.mix);
      stroke(255,0,0,128);
      mBand = 0;
      
      float j;
      for(int i = 0; i < fft.specSize();i++){
        j = fft.getBand(i);
        line(i, height/2, i, height/2 - j);
        maxValBand = fft.getBand(mBand);
        if(j>maxValBand){
           mBand = i; 
        }   
      }
      if (frameCount % 30 == 0) {
        thread("moveBar");
      }
    
      if(s1.getValue()==player.length()){
          b2.setValue(1);
       }
      
      }
    }
    
    public void Play(int theValue) {
      println("a button event from buttonB: "+theValue);
      if(pause){
        pause = false;
        player.play();
        cp5.getController("Play").setCaptionLabel("Pause");
      }else{
            //cp5.setStringValue("pause");
        pause = true;
        player.pause();
            cp5.getController("Play").setCaptionLabel("Play");
      }
    }
    public void Rewind(int theValue) {
      player.rewind();
      s1.setValue(0);
      pause = false;
      cp5.getController("Play").setCaptionLabel("Play");
    }
    
    void moveBar(){
      s1.setValue(player.position());
    }
    

    I want to be able to navigate inside a music track modifying the position of the slider but when the event ACTION_PRESSED is fired theEvent.getController().getValue(); doesn't contain the new value of the slider that i selected through my action but the old value( the value that indicate where the music track is arrived).. Any help? Thanks! :-S

  • edited September 2015

    Hi, following up on the code that you posted, I came up with the following 2 suggestions. Controlling the value of a slider here is indeed a bit tricky due to how mouse events and value changes are handled. Suggestion 1 below uses a Slider to achieve the effect you are looking for which works alright for a mouse pressed. when dragging the slider though the value is not set as expected due to the original implementation of the slider. Therefore, have a look at Suggestion 2 which uses a custom Controller called ProgressBar.

    Suggestion 1

    import controlP5.*;
    
    ControlP5 cp5;
    
    Slider s1; 
    Toggle t1;
    Bang b1;
    
    int slider;
    boolean play;
    
    
    void setup() {
      size(600, 400);
      cp5 = new ControlP5(this);
    
      //Slider   
      s1 = cp5.addSlider("slider")
            .setPosition(132,375)
            .setSize(450,15)
            .setLabel("")
            .setValueLabel("")
            .setRange(0,10000)
            .setValue(0)
            .setBroadcast(false)
            .listen(true)
            ;
    
      // s1.getValueLabel().hide();
    
    
      s1.addCallback(new CallbackListener() { //Callback for Slider
        public void controlEvent(CallbackEvent theEvent) { 
          if(theEvent.getAction()==ControlP5.ACTION_PRESS){
            println(s1.getMin(),s1.getMax(),s1.getValue(),theEvent.getController().getPointer());
    
            // calculate the movie-position based on the mouse position
            float x = theEvent.getController().getPointer().x();
            float a1 = 0;
            float a2 = s1.getWidth();
            float b1 = s1.getMin();
            float b2 = s1.getMax();
            float val = map(x,a1,a2,b1,b2);
            slider = int(val); // 
          }
        }
      }
      );
    
      t1 = cp5.addToggle("play")
              .setPosition(10,375)
              .setSize(50,19)
              ;
    
      t1.getCaptionLabel().align(CENTER,CENTER);
    
      b1 = cp5.addBang("rewind")
              .setPosition(72,375)
              .setSize(50,19)
              ;
    
      b1.getCaptionLabel().align(CENTER,CENTER);
    }
    
    void draw() {
      if(!play) {
        // update the slider value/position
        // replace with audio-track position: slider = player.position();
        slider++;
      }
    }
    
    public void play(boolean t) {
      play = t;
      cp5.getController("play").getCaptionLabel().setText(play ? "play":"pause"); 
    }
    
    public void rewind() {
      slider = 0;
    }
    

    Suggestion 2 using a custom Controller class.

    import controlP5.*;
    
    ControlP5 cp5;
    int progress;
    boolean play;
    
    void setup() {
      size(600, 400);
      cp5 = new ControlP5(this);
    
      ProgressBar p; // custom Controller class, see implementation below
      p = new ProgressBar(cp5, "progress"); // "progress" here will be linked to variable progress
      p.setPosition(100, 300).setSize(200, 20).setRange(0, 1000).listen(true);
    
      // callback listener for TimeLine object   
      p.addCallback(new CallbackListener() {
        public void controlEvent(CallbackEvent theEvent) {
          if(theEvent.getAction() == ControlP5.ACTION_PRESS) {
            float x = theEvent.getController().getPointer().x();
            float a1 = 0;
            float a2 = theEvent.getController().getWidth();
            float b1 = theEvent.getController().getMin();
            float b2 = theEvent.getController().getMax();
            float val = map(x,a1,a2,b1,b2);
            theEvent.getController().setValue(val);
            println("now change movie time to ",val);
          }
        }
      }
      );
    
      // a toggle to switch between play and pause mode
      cp5.addToggle("play")
         .setPosition(10,375)
         .setSize(50,19)
         .getCaptionLabel().align(CENTER,CENTER);
    }
    
    
    void draw() {
      background(0);
      if (play) {
        // update the progressBar value/position
        // replace with audio-track position: progress = player.position();
        progress++;
      }
    }
    
    class ProgressBar extends Controller<ProgressBar> {
    
      public ProgressBar(ControlP5 theControlP5, String theName) {
        super(theControlP5, theName);
    
        setView(new ControllerView<ProgressBar>() {
          public void display(PGraphics pg, ProgressBar c) {
    
            pg.fill(!isMouseOver() ? c.getColor().getForeground():c.getColor().getActive());
            pg.rect(0, 0, c.getWidth(), c.getHeight());
    
            float val = map(c.getValue(),c.getMin(), c.getMax(), 0, c.getWidth()); 
            pg.fill(255);
            pg.rect(0, 0, val, c.getHeight());
          }
        }
        );
      }
    
      public ProgressBar setValue(float theValue) {
        return super.setValue(constrain(theValue, getMin(), getMax()));
      }
    
      public ProgressBar setRange(int theStart, int theEnd) {
        _myMin = theStart;
        _myMax = theEnd;
        return this;
      }
    }
    
  • Hello,

    I decided to put here the same problem I'm having this old post due to be basing myself in the previous example.

    I'm not able to run when I put the objects to be created in a second window (extends Applets).

    When I try to run gives the following error as print below:

    Erro01

    Any idea how to solve this?

    Below the code I'm doing the test:

    //Program Menu ( Call Video )

    import controlP5.*;
    import processing.video.*;                              
    
    ControlP5 cp5;
    Movie movie1;
    
    void setup(){
      size(800, 600); 
    
      cp5 = new ControlP5(this);
    
      cp5.addButton("btn01")
         .setPosition(50,(height/2)-100)
         .setImages(loadImage("Iniciar.png"), loadImage("Iniciar.png"), loadImage("Iniciar.png"))
         .updateSize(); 
    }
    
    void draw(){
      background(255);  
    }
    
    void btn01(int theValue) {
      PApplet playVideo = new PlayVideo();
      runSketch(new String[] { "Video" }, playVideo);
    }
    

    //Program PlayVideo

    public class PlayVideo extends PApplet {
      ControlP5 cp5_Video;
    
      float md, mt;
      int progress, w, h;
      boolean playMovie = true;
    
      void setup() {
        size(352, 288, JAVA2D);
        cp5_Video = new ControlP5(this); 
        movie1    = new Movie(this, "D:/Projetos/Videos/Branca_de_Neve.mpg"); //Change path your video here
        movie1.play();
    
        w = width;
        h = height;
    
        ProgressBar p; // custom Controller class, see implementation below
        p = new ProgressBar(cp5_Video, "progress"); // "progress" here will be linked to variable progress
        p.setPosition(50, h-10).setSize(w-50, 10).setRange(0,  (int) movie1.duration()).listen(true);
    
        //size(displayWidth, displayHeight, JAVA2D);
    
        // callback listener for TimeLine object   
        p.addCallback(new controlP5.CallbackListener() {
          public void controlEvent(controlP5.CallbackEvent theEvent) {
            if(theEvent.getAction() == ControlP5.ACTION_PRESS) {
              float x = theEvent.getController().getPointer().x();
              float a1 = 0;
              float a2 = theEvent.getController().getWidth();
              float b1 = theEvent.getController().getMin();
              float b2 = theEvent.getController().getMax();
              float val = map(x,a1,a2,b1,b2);
              theEvent.getController().setValue(val);
              //println("now change movie time to ", val, movie1.time());
              movie1.jump((float) val); 
            }
          }
        }
        );
    
        // a toggle to switch between play and pause mode
        cp5_Video.addButton("btnPlay")
           .setPosition(12, height+300)
           .setSize(50,19)
           .setImages(loadImage("play.png"), loadImage("play.png"), loadImage("play.png")) //need picture at data
           .updateSize();
    
        cp5_Video.addButton("btnPause")
           .setPosition(12, h-20)
           .setSize(50,19)
           .setImages(loadImage("pause.png"), loadImage("pause.png"), loadImage("pause.png")) //need picture at data
           .updateSize();
      }
    
      void draw() {
        background(0);
        //if (playMovie) {
          // update the progressBar value/position - replace with audio-track position: progress = player.position();
          if (movie1.available()) movie1.read();
          image(movie1, 10, 10, w, h);
    
          //progress++;
          progress = (int) movie1.time();
        //}
      }
    
      void btnPlay(){
        cp5_Video.getController("btnPause").setPosition(12, h-20);
        cp5_Video.getController("btnPlay").setPosition(12, height+300); 
        movie1.play();
      }
    
      void btnPause(){
        cp5_Video.getController("btnPlay").setPosition(12, h-20); 
        cp5_Video.getController("btnPause").setPosition(12, height+300); 
        movie1.pause();
      }
    
      class ProgressBar extends controlP5.Controller<ProgressBar> {
        public ProgressBar(ControlP5 theControlP5, String theName) {
          super(theControlP5, theName);
    
          setView(new controlP5.ControllerView<ProgressBar>() {
            public void display(PGraphics pg, ProgressBar c) {
              pg.fill(!isMouseOver() ? c.getColor().getForeground():c.getColor().getActive());
              pg.rect(0, 0, c.getWidth(), c.getHeight());
    
              float val = map(c.getValue(),c.getMin(), c.getMax(), 0, c.getWidth()); 
              pg.fill(255);
              pg.rect(0, 0, val, c.getHeight());
            }
          }
          );
        }
    
        public ProgressBar setValue(float theValue) {
          return super.setValue(constrain(theValue, getMin(), getMax()));
        }
    
        public ProgressBar setRange(int theStart, int theEnd) {
          _myMin = theStart;
          _myMax = theEnd;
          return this;
        }
      }
    }
    

    Note: If you leave this unique program, works OK.

    Thank you,

  • Hello,

    I could make it work with another example that is up, I'll post here, it may be useful to someone else.

    //Program Menu

    import controlP5.*;
    import processing.video.*;                              
    
    ControlP5 cp5;
    Movie movie1;
    
    void setup(){
      size(800, 600); 
    
      cp5 = new ControlP5(this);
    
      cp5.addButton("btn01")
         .setPosition(50,(height/2)-100)
         .setImages(loadImage("Iniciar.png"), loadImage("Iniciar.png"), loadImage("Iniciar.png"))
         .updateSize(); 
    }
    
    void draw(){
      background(255);  
    }
    
    void btn01(int theValue) {
      PApplet playVideo = new PlayVideo();
      runSketch(new String[] { "Video" }, playVideo);
    }
    

    //Program Play Video

    public class PlayVideo extends PApplet {
      ControlP5 cp5_Video;
    
      Slider s1; 
      Toggle t1;
      Bang b1;
    
      int slider, w, h;
      static final String PATH = "D:/Processing/Player/Player12/data/"; //Change Path "data" ( where is Pictures )
    
      void setup() {
        size(600, 400, JAVA2D);
        cp5_Video = new ControlP5(this);
        movie1    = new Movie(this, "D:/Projetos/Videos/Branca_de_Neve.mpg"); //Change path your video here
        movie1.play();
    
        w = width;
        h = height;
        size(displayWidth, displayHeight, JAVA2D); //Redimensiona Tela
    
        criaObjetos();
      }
    
      void draw() {
        background(255);
    
        if (movie1.available()) movie1.read();
        image(movie1, 10, 10, w, h);
    
        slider = (int) movie1.time();
      }
    
      void criaObjetos(){
        //Slider   
        s1 = cp5_Video.addSlider("slider")
                      .setPosition(45, h-12)
                      .setSize(w-40, 15)
                      .setLabel("")
                      .setValueLabel("")
                      .setRange(0, (int) movie1.duration())
                      .setValue(0)
                      .setBroadcast(false)
                      .listen(true);
    
        s1.addCallback(new controlP5.CallbackListener() { //Callback for Slider
          public void controlEvent(controlP5.CallbackEvent theEvent) { 
            if(theEvent.getAction() == ControlP5.ACTION_PRESS){
              println(s1.getMin(), s1.getMax(), s1.getValue(), theEvent.getController().getPointer());
    
              //Calculate the movie-position based on the mouse position
              float x = theEvent.getController().getPointer().x();
              float a1 = 0;
              float a2 = s1.getWidth();
              float b1 = s1.getMin();
              float b2 = s1.getMax();
              float val = map(x,a1,a2,b1,b2);
              movie1.jump((float) val);
            }
          }
        }
        );
    
        cp5_Video.addButton("btnPlay")
                 .setPosition(12, height+300)
                 .setSize(50,19)
                 .setImages(loadImage(PATH+"play.png"), loadImage(PATH+"play.png"), loadImage(PATH+"play.png")) //need picture at data
                 .updateSize();
    
        cp5_Video.addButton("btnPause")
                 .setPosition(12, h-22)
                 .setSize(50,19)
                 .setImages(loadImage(PATH+"pause.png"), loadImage(PATH+"pause.png"), loadImage(PATH+"pause.png")) //need picture at data
                 .updateSize();  
      }
    
      void btnPlay(){
        cp5_Video.getController("btnPause").setPosition(12, h-20);
        cp5_Video.getController("btnPlay").setPosition(12, height+300); 
        movie1.play();
      }
    
      void btnPause(){
        cp5_Video.getController("btnPlay").setPosition(12, h-20); 
        cp5_Video.getController("btnPause").setPosition(12, height+300); 
        movie1.pause();
      }
    }
    

    Thank you,

  • Hello gumo

    Yes, the code above does this, you can append (the end button) with this code.

     movie1.jump((float) movie1.duration());
     movie1.stop();
    

    As you "click" on the bar, the movie moves to that point ...

    I just converted the time to min. I think you need to see some rule for this.

    PlayVideo

    Any questions I can send a more complete code ...

  • Nice! --and more code would be great Jose --thanks!

  • Hello grumo,

    Sorry for the delay, I was not looking at the email these days ...

    Below is the code, the first part of the program creates a Menu, which according to the example you can add other new links.

    Below is the "player" program, the examples I took here in the forum and adapted according to my need, you can adapt in the best way for you.

    You need to grab some images for the Play, Pause, End, and Start Menu button too, of course ... put it in the "date" folder ....

    I have not commented every part of the program, if you need help in this regard, return that I can improve this ...

    Regards,

    //First part of the Program (Create Menu)

    import controlP5.*;
    import processing.video.*;                              
    
    ControlP5 cp5;
    Movie movie1;
    
    static String nomeLink; //Public variable
    
    void setup(){
      size(800, 600); 
    
      //Create objects ControlP5
      cp5 = new ControlP5(this);
    
      cp5.addButton("btn01")
         .setPosition(50,(height/2)-100)
         .setImages(loadImage("Img01.jpg"), loadImage("Img01.jpg"), loadImage("Img01.jpg"))
         .setStringValue("D:/Videos/Musicas para Refletir.mpg")
         .updateSize(); 
    
      cp5.addButton("btn02")
         .setPosition(200,(height/2)-100)
         .setImages(loadImage("Img02.jpg"), loadImage("Img02.jpg"), loadImage("Img02.jpg"))
         .setStringValue("D:/Videos/Musicas para Refletir.mpg") //change Link
         .updateSize();
    
      cp5.addButton("btn03")
         .setPosition(350,(height/2)-100)
         .setImages(loadImage("Img03.jpg"), loadImage("Img03.jpg"), loadImage("Img03.jpg"))
         .setStringValue("D:/Videos/Musicas para Refletir.mpg") //change Link
         .updateSize();
    }
    
    void draw(){
      background(255);  
    }
    
    //Execute program Player
    void controlEvent(ControlEvent theControlEvent) {
      nomeLink = theControlEvent.controller().getStringValue(); 
      println("LInk: " + nomeLink);
    
      PApplet playVideo = new PlayVideo();
      runSketch(new String[] { "Video" }, playVideo);
    }      
    

    //Second Part of the Program (PLayer)

    public class PlayVideo extends PApplet {
      ControlP5 cp5_Video;
    
      Slider s1; 
      Toggle t1;
      Bang b1;
    
      int slider, w, h;
    
      void setup() {
        size(600, 400, JAVA2D);
        cp5_Video = new ControlP5(this);
        movie1    = new Movie(this, nomeLink); //Change path your video here
        movie1.play();
    
        w = width;
        h = height;
        size(displayWidth, displayHeight, JAVA2D); //Redimensiona Tela
    
        criaObjetos();
      }
    
      void draw() {
        background(255);
    
        if (movie1.available()) movie1.read();
        image(movie1, 10, 10, w, h);
    
        slider = (int) movie1.time();
      }
    
       void keyPressed() {
        //Se tecla ESC pressionado, fecha tela, retornando ao Menu Inicial.
        if (key == ESC ){
          key = 0;
          this.stop();
          this.dispose();
          frame.hide();
          frame = null;
        }
      }
    
      void criaObjetos(){
        //Slider   
        s1 = cp5_Video.addSlider("slider")
                       .setPosition(80, h-12)
                       .setSize(w-75, 15)
                       .setLabel("")
                       .setValueLabel("")
                       .setRange(0, (int) movie1.duration())
                       .setValue(0)
                       .setBroadcast(false)
                       .listen(true);
    
        s1.addCallback(new controlP5.CallbackListener() { //Callback for Slider
          public void controlEvent(controlP5.CallbackEvent theEvent) { 
            if(theEvent.getAction() == ControlP5.ACTION_PRESS){
              //println(s1.getMin(), s1.getMax(), s1.getValue(), theEvent.getController().getPointer());
    
              //Calculate the movie-position based on the mouse position
              float x   = theEvent.getController().getPointer().x();
              float a1  = 0;
              float a2  = s1.getWidth();
              float b1  = s1.getMin();
              float b2  = s1.getMax();
              float val = map(x,a1,a2,b1,b2);
              movie1.jump((float) val);
            }
          }
        });
    
        cp5_Video.addButton("btnPlay")
                 .setPosition(12, height+300)
                 .setSize(50,19)
                 .setId(2)
                 .setImages(loadImage("play.png"), loadImage("play.png"), loadImage("play.png")) //need picture at data
                 .updateSize();
    
        cp5_Video.addButton("btnPause")
                 .setPosition(12, h-22)
                 .setSize(50,19)
                 .setId(2)
                 .setImages(loadImage("pause.png"), loadImage("pause.png"), loadImage("pause.png")) //need picture at data
                 .updateSize();
    
        cp5_Video.addButton("btnFim")
                 .setPosition(45, h-22)
                 .setSize(50,19)
                 .setImages(loadImage("fim.png"), loadImage("fim.png"), loadImage("fim.png")) //need picture at data
                 .updateSize();
      }
    
      void btnPlay(){
        cp5_Video.getController("btnPause").setPosition(12, h-20);
        cp5_Video.getController("btnPlay").setPosition(12, height+300); 
        movie1.play();
      }
    
      void btnPause(){
        cp5_Video.getController("btnPlay").setPosition(12, h-20); 
        cp5_Video.getController("btnPause").setPosition(12, height+300); 
        movie1.pause();
      }
    
      void btnFim(){
        movie1.jump((float) movie1.duration());
        movie1.stop();  
      }
    }
    
  • I forgot a detail, the second part of the program being in extended class, need to add the path where the images are, does not recognize that it is in the folder "data" ...

    Put this variable before setup:

    static final String PATH = "D:/Aplicativos/Projetos/Processing/PlayerVideo/PlayerVideo/data/"; //Change Path "data" ( where is Pictures )
    

    Change this line where you upload the images

    .setImages(loadImage(PATH+"/play.png"), loadImage(PATH+"/play.png"), loadImage(PATH+"/play.png")) //need picture at data

    Print how was the example Img01 Img02

  • Has anyone got this to work - it does not work for me - maybe a problem with declaring setup() twice?

  • I haven't tested this, but if I understand right setup() is not declared twice.

    1. setup() is a function of the main sketch
    2. PlayVideo.setup() is a method of PlayVideo
Sign In or Register to comment.