Visualizzazione post con etichetta player. Mostra tutti i post
Visualizzazione post con etichetta player. Mostra tutti i post

martedì 10 giugno 2014

Implementing a seekbar for the audio player

Following the tutorial regarding the mp3 player, let's now focus on how to implement a simple seek bar for skipping music to a certain time. The perfect component for this might seem to be JSlider, however this component listener action is called each time the value of the slider is changed, we don't want to do this, mostly because the value is changed during playing. Let's start making our Seekbar class by extending a JProgressBar then.

public class SeekBar extends JProgressBar {

 private int updatedValue = 0; //sharing between different scopes

 /**
  * Update SeekBar position
  * @param progress in microseconds
  * @param totalVal in seconds
  */
 public void updateSeekBar(long progress, float totalVal)
 {
  BackgroundExecutor.get().execute(new UpdatingTask(progress, totalVal)); //Another thread will calculate the relative position
  setValue(updatedValue);
 }
 
 /**
  * Task used for updating the seek value in another thread.
  * @author Pierluigi
  */
 private class UpdatingTask implements Runnable {

  long progress; float totalVal;
  public UpdatingTask(long progress, float totalVal) {
   this.progress = progress;
   this.totalVal = totalVal;
  }
  
  @Override
  public void run() {
   int lp = (int) (progress / 1000); //progress comes in microseconds
   int seekLenght = getMaximum();
   int n = (int) ((lp/(totalVal*1000))*seekLenght); 
   updatedValue = lastSeekVal+n; 
  }
 }
 ///////////////////////////////////////////////////////////
 
 /**
  * New Constructor, sets a mouseListener
  * (extends JProgressBar)
  */
 public SeekBar()
 {
  super();
  setMaximum(10000); //it's smoother this way
  addMouseListener(new MouseListener() {
   
   @Override
   public void mouseReleased(MouseEvent e) {
   }
   
   @Override
   public void mousePressed(MouseEvent e) {
    float val =  ((float)e.getX()/getWidth()) * getMaximum();
    returnValueToPlayer(val);
    setValue((int)val);
    log("SeekBar pressed: " + val + " x: " + e.getX());
       
   }
   
   @Override
   public void mouseExited(MouseEvent e) {
   }
   
   @Override
   public void mouseEntered(MouseEvent e) {
   }
   
   @Override
   public void mouseClicked(MouseEvent e) {
   }
  });
 }
 
 /**
  * Informs the player about the relative value selected in the seekbar 
  * @throws BasicPlayerException 
  */
 private void returnValueToPlayer(float val){
  //TODO inform our player
 }

 private void log(String str)
 {
  System.out.println("SeekBar] " +str);
 }
}

As you can see I've used a simple MouseListener to implement what the a slider have native, by clicking in a certain x relative to the component I can set a correct value thanks to the power of proportions.
Let's recall that we don't want the swing single thread do math, even when it's this easy, for this we call a new Task executed by one background executor, since I want to have a central use of this class, I've implemented the following singleton:

/**
 * Using this for computing outside swing UI thread
 * @author Pierluigi
 *
 */
public class BackgroundExecutor {
 private static ExecutorService backgroundEx = Executors.newCachedThreadPool(); //UI thread shouldn't do math
 
 public BackgroundExecutor(){}
 
 public static ExecutorService get() { return backgroundEx;}
}

For more information about this see how a thread executor works. Now we can add and test our seekbar, let's add it into init() method from the MainView class like every simple other component.
SeekBar seekbar = new SeekBar();
...
//SeekBar
seekbar.setBounds(5, 10, _W-15, 10);
container.add(seekbar);

domenica 1 giugno 2014

Making a simple UI for the audio player

First thing first, let's make a nice and simple user interface for our audio player in java. For making the UI we'll use java Swing libraries. Swing is a single threaded model for building graphical interfaces in java, it became standard with java 5 (I think), you don't need to download external libs if you are using a recent version of java.
Let's say this is our basic idea, we'll start by defining the MainView.
Let's create a MainView class that extends JFrame, we'll define a main method that instantiate the main view of our program by calling SwingUtilities.invokeLater, this ensure that the component is created inside swing single threaded envoirment.
Important: Every action that modifies the state of the UI must be performed into the swing thread, however same thread is responsable for rendering, we'll see later in the tutorial how to let other thread execute medium-large computation that shouldn't be performed by java swing thread.
public class MainView extends JFrame{
 /**
  * Class/Frame constructor
  */
 public MainView()
 {
  init(); //see later implementation
  //initMenu();
  //uiBehaviour(); We'll define it later
 }

 //MAIN
 public static void main(String[] args){
  SwingUtilities.invokeLater(new Runnable(){
   @Override
   public void run()
   {
    MainView mv = new MainView();
    mv.setVisible(true);
   }
  });
 }
 
 private void log(String line)
 {
  System.out.println("UI-Main] " + line);
 }
}

Now let's define our components, let's not think about the seekbar now and discuss it later.

public class MainView extends JFrame{
 //Other
 DefaultListModel songList = new DefaultListModel();
 //Components
 JPanel container = new JPanel();
 JButton btnPlay = new JButton();
 JButton btnAdd = new JButton();
 JButton btnNext = new JButton();
 JButton btnPrev = new JButton();
 JButton btnShSt = new JButton();
 JButton btnShWf = new JButton();
 JButton btnShDi = new JButton();
 JButton btnDel = new JButton();
 JButton btnDelAll = new JButton();
 JMenuBar topMenu = new JMenuBar();
 JList jSongList = new JList(songList);
 JLabel lblplaying = new JLabel();
 JLabel lblst = new JLabel();
 JLabel lblet = new JLabel();
 JFileChooser fc = new JFileChooser();
...
}

Every component has a common and unique behaviour, if it's your first time with java swing, check component page docs.
Now let's see how to build the UI, for this I've created a single use isolated method, components listeners will be added in another one.
/**
  * Init Swing graphics UI 
  */
 private void init()
 {
  //MainView
  setTitle("Music Player - Java - 1.0");
  int _H = 300;
  int _W = 330;
  setSize(_W,_H);
  setLocationRelativeTo(null);
  setDefaultCloseOperation(EXIT_ON_CLOSE);
  //setResizable(false);
  //Container
  container.setLayout(null);
  getContentPane().add(container);
  //Buttons
  int btn_h = 35;
  int line1 = 80;
  JPanel contBtns = new JPanel();
  contBtns.setBounds(0, line1, 180, btn_h);
  btnPrev.setText("<<");
  btnPrev.setBounds(0, 0, 50, btn_h);
  btnPlay.setText(">");
  btnPlay.setMnemonic(KeyEvent.VK_SPACE);
  btnPlay.setBounds(0, 0, 50, btn_h);
  btnNext.setText(">>");
  btnNext.setBounds(0, 0, 50, btn_h);
  btnAdd.setText("Add Song");
  btnAdd.setBounds(_W-80,line1,70,btn_h);
  contBtns.add(btnPrev);
  contBtns.add(btnPlay);
  contBtns.add(btnNext);
  container.add(contBtns);
  container.add(btnAdd);
  //Now Playing Panel
  JPanel panelNP = new JPanel();
  panelNP.setLayout(new BoxLayout(panelNP, BoxLayout.PAGE_AXIS));
  panelNP.setToolTipText("Now Playing");
  panelNP.setBorder(BorderFactory.createMatteBorder(1, 0, 2, 0, Color.gray));
  panelNP.setBounds(5, line1-25, _W-15, 20);
  //JLabel lblnp = new JLabel("Now Playing:");
  lblplaying.setText("Now Playing: ");
  lblplaying.setBounds(5, 0, 100, 40);
  //panelNP.add(lblnp);
  panelNP.add(lblplaying);
  container.add(panelNP);
  //SongList
  int h_list = 100;
  //jSongList.setBounds(0, line1+50, _W, h_list);
  JScrollPane listScroller = new JScrollPane(jSongList);
  listScroller.setPreferredSize(new Dimension(_W-10,h_list));
  listScroller.setBounds(0, line1+50, _W-10, h_list);
  container.add(listScroller);
  //container.add(jSongList);
  //2Row Buttons
  int line2 = line1+h_list+50;
  JPanel contBtns2 = new JPanel();
  //contBtns2.setLayout(new BoxLayout(contBtns2, BoxLayout.PAGE_AXIS));
  contBtns2.setBounds(0, line2, 220, 50);
  //contBtns2.setBackground(Color.lightGray);
  btnShSt.setText("STAT");
  btnShWf.setText("ShWf");
  btnShDi.setText("ShDi");
  contBtns2.add(btnShSt);
  contBtns2.add(btnShWf);
  contBtns2.add(btnShDi);
  container.add(contBtns2);
  //DelBtns
  btnDel.setBounds(_W-55, line2+5, 45, 30);
  btnDel.setText("X");
  container.add(btnDel);
  //Labels song time
  JPanel contSlbl = new JPanel();
  contSlbl.setBounds(10, 15, _W-20, 20);
  contSlbl.add(lblst);
  contSlbl.add(lblet);
  lblst.setText("00:00");
  lblst.setBorder(new EmptyBorder(0, 0, 0, 200));
  lblet.setText("00:00");
  container.add(contSlbl);
 }

The code should be easy to read, I've used a JPanel as a general container, then by using other panels and setbounds I've created the UI. Pay a closer look about the JList and JScrollPane components though. Also, take a read here if you want to know more about layouts, by default a new Jpanel creates a BoxLayout (that's how I've made the row of buttons).

Next time we'll see how to add some functionality to our UI.

mercoledì 28 maggio 2014

How to make your own audio mp3 player in Java with BasicPlayer & Swing

Introduction

The focus of this and the next articles is to guide the reader thought the making of a simple and small mp3 player with Java. The goal is to give the player it's basic functionality (play, pause, skip, next song, etc), but also more sophisticated and useful features like a waveform visualizer. I can provide code for new missing features in the following lasts articles, I'm open for suggestions, just ask me in the comments or email.
Used technology for the mp3 player are: BasicPlayer API from javazoom and java Swing for making the User Interface.

Index
The project it's quite simple but it requires a lot of code, because it's better to divide the project covering different arguments. I'll add and update articles regarding the player in this section.

Why should I care?
The project should be interesting enough for who's interested in building a media player, for common folks interested in Java and programming it covers some general aspects like the usage of swing libraries, using multi threading in a "real time" model.

Download Project: here
Executable Jar: here