Creating Music Player With Processing Part III (FINAL)

It's the last section of tutorial creating music player with processing. We will adding metadata function, you can adding author name, song title, duration and other. In addition we will adding repeat button function. I forget to add this on last tutorial, so i will adding there. And we will adding FFT for creating visualization of the music.

I didn't create function for next, prev, and shuffle button. Because i don't adding playlist on my music player. If you want to add playlist, you can search the function what will you need on javadoc of minim. If you already adding playlist, you can share the code there. If i've the source code of playlist i will share there too. Let start write the code step by step


Initialization the fft, fftLog, and AudioMetaData before void setup
FFT fft;
FFT fftLog;
AudioMetaData meta;

Declarate fft, fftLog with value of bufferSize and sampleRate of the music on player
  fft = new FFT(player.bufferSize(), player.sampleRate());
  fftLog = new FFT(player.bufferSize(), player.sampleRate());

Adding fft.linAverages and fft.logAverages to get the average of spectrum
fft.linAverages(128);
fftLog.logAverages(22, 1);

Set the coordinate calculation from the corner
 rectMode(CORNERS);

Load the font we've made on tutorial before
 font = (loadFont("Ubuntu-20.vlw"));
  textMode(SCREEN);

Get metadata of music with this code on void draw
 meta=player.getMetaData();

I've tried to adding the script above on void setup, but the metadata not change when we change the music using jfchooser

Write the script below to get the spectrum bar like i want :D. You can try to change the parameter to know the function
 fftLog.forward(player.mix);
  int w = int(fft.specSize()/50);
  int xoffset = (width - (width/3))/2;
  for(int i = 0; i < fftLog.avgSize(); i++)
  {
    fill(111,110,255,0);
    rect(xoffset+i*w+4, 85, xoffset+i*w + w+2, 85 - fftLog.getAvg(i));
  }

Adding text metadata to show the metadata on screen with this script
  textFont(font, 20);
  text(meta.title(), (bg.width-textWidth(meta.title()))/2, 20);
  textSize(20);
  text(meta.author(), (bg.width-textWidth(meta.title()))/2, 40);

You can adding duration of song with this script
int timeLeft = player.position()-player.length();
  String timeLeftStr = String.format("%02d:%02d", timeLeft/1000/60, -timeLeft/1000%60);
  text( timeLeftStr, (bg.width-textWidth(timeLeftStr))/2, 80);

And now, we will adding repeat function. Initialization the repeatOn because it will be replaced the repeat image when repeat function active. You need to initialization the isRepeat variable too. Add this function before void setup
PImage repeatOn;
boolean isRepeat;

Declarate repeatOn with load repeat_on image
repeatOn = loadImage("repeat_on.png");  

Write this code for set the value of isRepeat variable when mouseClicked
 if(mouseX > 210 && mouseX < 210+repeat.width && mouseY > 104 && mouseY < repeat.height + 104){
    println("tombol repeat ditekan");
    isRepeat = !isRepeat;
  }

Don't forget to adding this code for replacing repeat image with repeat_on  and otherwise
if(isRepeat){
    image(repeatOn, 210, 104);
  }else{
    image(repeat, 210, 104);
  }

And add the function when isRepeat is true, player will be repeat the song after the song end
 if(isRepeat){
    if(player.position() >= player.length()){
      player.rewind();
      player.play();
    }
  }

There is my final code of my music player. Im so sorry for my bad english.
import ddf.minim.*;
import ddf.minim.signals.*;
import ddf.minim.analysis.*;
import ddf.minim.effects.*;

import javax.swing.*;
JFileChooser jfc;

PImage bg;
PImage seeker;
PImage seeker2;
PImage closeButton;
PImage minimizeButton;
PImage prev;
PImage play;
PImage stop;
PImage next;
PImage openfile;
PImage shuffle;
PImage repeat;
PImage repeatOn;
PImage pause;
PFont font;

Minim minim;
AudioPlayer player;
FFT fft;
FFT fftLog;
double duration;
AudioMetaData meta;
boolean isPlaying;
boolean isRepeat;

void setup(){
  size(375, 120, P2D);
  
  minim = new Minim(this);
  player = minim.loadFile("forgetjakarta.mp3");
  player.play();
  duration = player.length();
  isPlaying = true;
  isRepeat = false;
  
  fft = new FFT(player.bufferSize(), player.sampleRate());
  fft.linAverages(128);
  fftLog = new FFT(player.bufferSize(), player.sampleRate());
  fftLog.logAverages(2, 1);
  rectMode(CORNERS);
  
  font = (loadFont("Ubuntu-20.vlw"));
  textMode(SCREEN);
  
  bg = loadImage("main.png");
  seeker = loadImage("seeker.png");
  seeker2 = loadImage("seeker2.png");
  closeButton = loadImage("closeButton.png");
  minimizeButton = loadImage("minimizeButton.png");
  
  prev = loadImage("prev.png");
  play = loadImage("play.png");
  stop = loadImage("stop.png");
  next = loadImage("next.png");
  
  openfile = loadImage("openfile.png");
  shuffle = loadImage("shuffle.png");
  repeat = loadImage("repeat.png");
  pause = loadImage("pause.png");
  repeatOn = loadImage("repeat_on.png");  
  jfc = new JFileChooser();
}

void mouseClicked(){
  if(mouseX > 15 && mouseX < 15+prev.width && mouseY > 104 && mouseY < 104+prev.width){
    println("tombol previous telah ditekan");
  }
  
  if(mouseX > 35 && mouseX < 35+play.width && mouseY > 104 && mouseY < 104+play.height){
    if(isPlaying){
      isPlaying = false;
      player.pause();
    }else{
      isPlaying = true;
      player.play();
    }
  }
  
  if(mouseX > 55 && mouseX < 55+stop.width && mouseY > 104 && mouseY < 104+stop.width){
    if(isPlaying){
      isPlaying = false;
      player.pause();
      player.rewind();
    }
  }
  
  if(mouseX > 75 && mouseX < 75+next.width && mouseY > 104 && mouseY < 104+next.height){
    println("tombol next telah ditekan");
  }
  
  //repeat
  if(mouseX > 210 && mouseX < 210+repeat.width && mouseY > 104 && mouseY < repeat.height + 104){
    println("tombol repeat ditekan");
    isRepeat = !isRepeat;
  }
    
  
  if(mouseX > 120 && mouseX < 120+openfile.width && mouseY > 104 && mouseY < 104+openfile.width){
    println("tombol open file telah ditekan");
    int result = jfc.showOpenDialog(this);
    if( result == jfc.APPROVE_OPTION){
      String filename = jfc.getSelectedFile().getAbsolutePath();
      println(filename);
      player.close();
      player = minim.loadFile(filename);
      player.play();
    }
  }
}

void draw(){
  meta=player.getMetaData();
  image(bg,0,0);
  // draw the logarithmic averages
  fftLog.forward(player.mix);
  int w = int(fft.specSize()/50);
  int xoffset = (width - (width/3))/2;
  for(int i = 0; i < fftLog.avgSize(); i++)
  {
    fill(111,110,255,0);
    rect(xoffset+i*w+4, 85, xoffset+i*w + w+2, 85 - fftLog.getAvg(i));
  }
  fill(255);
  //seeker bar
  image(seeker, (int)(player.position()/duration*(bg.width-seeker.width)), 84);
  image(seeker2, 300,105);
  
  //close & minimize
  image(closeButton, 350, 5);
  image(minimizeButton, 335,5);
  
  //player
  image(prev, 15, 105);
  image(play, 35, 105);
  image(stop, 55, 105);
  image(next, 75, 105);
  image(openfile, 120, 105);
  image(shuffle, 160, 105);
  image(repeat, 210, 105);
  
  //text
  textFont(font, 20);
  text(meta.title(), (bg.width-textWidth(meta.title()))/2, 20);
  textSize(20);
  text(meta.author(), (bg.width-textWidth(meta.title()))/2, 40);
  
  int timeLeft = player.position()-player.length();
  String timeLeftStr = String.format("%02d:%02d", timeLeft/1000/60, -timeLeft/1000%60);
  text( timeLeftStr, (bg.width-textWidth(timeLeftStr))/2, 80);
  
  if(isPlaying){
    image(pause, 35, 104);
  }else{
    image(play, 35, 104);
  }

  if(isRepeat){
    image(repeatOn, 210, 104);
  }else{
    image(repeat, 210, 104);
  }
  
  if(isRepeat){
    if(player.position() >= player.length()){
      player.rewind();
      player.play();
    }
  }
}


I will upload my file nextweek maybe. Because i have slow internet connection. I hope you can enjoy my tutorial.

10 Responses to "Creating Music Player With Processing Part III (FINAL)"

  1. Hey man. I've done all buttons, like shuffle, add to playlists and others. Look, enjoy =) And we're waitin' for new parts =)

    ReplyDelete
  2. https://www.dropbox.com/s/gx6tfvl4y5szhum/Player.rar

    ReplyDelete
  3. WOW! I've downloaded your music player and anything can work. Congratulations dude!

    Iam using Ubuntu, and i getting error when play it because your file is missing or inaccessible. When i saw your source everything is fine, and i try to compare with my music player i found one different with your file. The name of your folder is Data and mine is data. I think on Ubuntu the name is case sensitive, when i change the folder name everything is workThank for share your file ;). Maybe you can share it on openprocessing.org :D

    ReplyDelete
  4. To your comment, processing's code is always sensetive. And Data folder must be like "Data" =)

    ReplyDelete
  5. no, in ubuntu the Data folder must be "data" :)

    ReplyDelete
  6. Awesome, can I use this for a university project? I won't publish it, I'll just make quite a few additions, change the layout and change the design :)

    ReplyDelete
    Replies
    1. Feel free for use it and publish, dont forget the credits :lol

      Delete
  7. Hi!great work!But i have one question.I cant find the first part.I mean i get to the page where the first part is but it is empty..Am i doing something wrong? :)

    ReplyDelete
  8. Ups. iam so sorry. I don't know why the page is empty. i never delete it before. it's the second post that emtpy >.<

    ReplyDelete