Render an Animation while using the Minim Library

edited January 2016 in Library Questions

I recently created an audio visualizer with the Minim library. I would now like to render it into mp4. I have tried using saveFrame() to create images of the animation but when I later combine the images into an mp4 file the video does not sync with the audio anymore. I am assuming this is because the saveFrame() function is expensive and can not create the correct amount of images in the time given by the program running. So my question now is how can I render my Processing animation such that when I render it into mp4 the animation matches with audio when I combine the video and audio together in a editing software.

Answers

  • edited January 2016

    Not only saving operations are expensive, but also loading are also almost as much! :-&
    If you got RAM to spare, you may replace saveFrame() w/ get() and add() them all to an ArrayList of PImage:

    1. https://Processing.org/reference/get_.html
    2. https://Processing.org/reference/PImage.html
    3. https://Processing.org/reference/ArrayList.html

    Once the animation is finished, traverse that whole ArrayList<PImage>, use get(), then invoke save():
    https://Processing.org/reference/PImage_save_.html

    Hopefully all of those stored PImage were able to be taken @ ~60 FPS.
    And be still synched to the Minim sound played. :-\"

  • edited January 2016

    I saw your previous post when you stated this, but Im confused when I evoke the get() call as right now in my code when I run it I get a OutOfMemoryError cause the array is getting too big?

    ` import ddf.minim.*; import ddf.minim.analysis.*;

    Minim minim;
    AudioPlayer player;
    PImage img;
    FFT fft;
    final ArrayList<PImage> shots= new ArrayList();
    
    
    void setup() {
      size(728, 546);
    
      minim = new Minim(this);
    
      player = minim.loadFile("new_years_good.mp3");
      fft = new FFT(player.bufferSize(), player.sampleRate());
      player.play();
      img= loadImage("cat-in-shades-.jpg");
      frameRate(60);
    }
    
    void draw() {
    
    
      image(img, 0, 0);
      //tint(0, 100, 150);
      stroke(255);
    
      strokeWeight(4);
      float a = 0;
    
      float angle = (2*PI) / 200;
    
    
      fft.forward(player.mix);
    
    
      for(int i=0; i < player.bufferSize() - 1; i++) {
    
       //player.mix.get(i) is a value between [-1,1]
    
        float x = 250 + cos(a) * (20 * player.mix.get(i) + 100);
        float x2 = 540 + cos(a) * (20 * player.mix.get(i) + 100);    
    
        float y = 230 + sin(a) * (20 * player.mix.get(i) + 100);
        float y2 = 240 + sin(a) * (20 * player.mix.get(i) + 100);
    
    
        float xFinal = 250 + cos(a+angle) * (20 * player.mix.get(i+1) + 100);
        float x2Final = 540 + cos(a+angle) * (20 * player.mix.get(i+1) + 100);
    
    
        float yFinal = 230 + sin(a+angle) * (20 * player.mix.get(i+1) + 100);    
        float y2Final = 240 + sin(a+angle) * (20 * player.mix.get(i+1) + 100);    
    
    
        line(x,y,xFinal,yFinal);
        line(x2,y2,x2Final,y2Final);
        a += angle;     
    
      }
      noStroke();  
      fill(255, 0, 0, 128);
      for(int i = 0; i < 250; i++)
      {
        float b = fft.getBand(i);
        float yAxis = random(-b, b) + 480;
        float xAxis = i*3;
        ellipse(xAxis, yAxis, b, b);
      }
    
      **shots.add(get());**
    
    
    }
    void saveShots()
    {
      for(int i=0; i!=shots.size(); shots.get(i++))
      {
        save(frame+nf(i,4)+".tif");
      }
      shots.clear();
      stop();
    }
    
    void stop() {
      player.close();
      minim.stop();
    
      super.stop();
     }`
    
  • edited January 2016

    I added this condition within the draw function, but all it saves is the last frame image 600 times

    `if(shots.size()>600)
      {
        noLoop();
        saveShots();
      }`
    
  • edited January 2016

    I run it I get a OutOfMemoryError

    I've already warned about it would only work if you had enough RAM to spare!

    ... but I'm confused when I evoke the get() ...

    There are 2 get() methods:

    1. from Processing's API: https://Processing.org/reference/get_.html
    2. from List class: http://docs.Oracle.com/javase/8/docs/api/java/util/List.html#get-int-

    Processing's API version you've got it right: shots.add(get());

    For List, you've got it at the wrong place:
    for(int i=0; i!=shots.size(); shots.get(i++)) {}

    Besides, you've called the wrong save(): save(frame + nf(i,4) + ".tif");
    https://Processing.org/reference/save_.html

    I don't even know where that frame variable above comes from! @-)

    Rather you were supposed to call PImage's own save() method:
    https://Processing.org/reference/PImage_save_.html

    Made a new saveShots() version example which relies on an enhanced for ( : ) loop rather than the regular for ( ; ; ): https://Processing.org/reference/for.html

    This version doesn't need List's get() method. It's done behind-the-scenes: :-bd

    // forum.Processing.org/two/discussion/14501/
    // render-an-animation-while-using-the-minim-library
    
    // GoToLoop (2015-Jan-16)
    
    import java.util.List;
    
    static final String EXT = ".tif";
    static final int SHOTS = 600;
    
    final List<PImage> shots = new ArrayList<PImage>(SHOTS);
    
    void setup() {
      size(728, 546);
      smooth(4);
    
      background((color) random(#000000));
      shots.add(get());
    
      final String path = dataPath("") + '/';
      saveShots(shots, path, EXT);
    
      exit();
    }
    
    static void saveShots(List<? extends PImage> frames, String path, String ext) {
      int idx = 0;
      for (PImage img : frames)  img.save(path + nf(++idx, 4) + ext);
    }
    
  • edited January 2016

    For comparison, here's the same saveShots(), but relying on a regular for ( ; ; ) and List's get() method: >-)

    static void saveShots(List<? extends PImage> frames, String path, String ext) {
      for (int idx = 0, len = frames.size(); idx != len; 
        frames.get(idx).save(path + nf(++idx, 4) + ext));
    }
    
Sign In or Register to comment.