Example to use Mp3Player.java, @CopyLeft by tsaiwn@cs.nctu.edu.tw


點這抓 mp333.jar (約24MB)
可以用 java -jar mp333.jar 執行 (當作 Application)
以下是這網頁啟動 Applet 的 code:

<applet code="P3P.class" 
   archive="mp333.jar"
   codebase="http://www.cs.nctu.edu.tw/~tsaiwn/oop/java/mp3/"
   width="798" height="500">
</applet>
<hr size=6 color=red width="68%" align=Left>
<br>

以下是 Mp3Player.java
   01 //Mp3Player.java -- by tsaiwn@cs.nctu.edu.tw
   02 // using  the JLayer MP3 library.
   03 // See http://www.javazoom.net/javalayer/sources.html
   04 // 可以把 javazoom 的 javaLayer 解壓在同一個目錄
   05 // 或是指定 classpath 含有 JavaLayer 的 jar 檔:  
   06 //    javac -cp javazoomJL的jar檔案 Mp3Player.java
   07 // To use this Mp3Player: simply new an instance m3,
   08 // then m3.play(filename); m3.stop( );  m3.play( );
   09 import java.io.*;
   10 import java.awt.*;
   11 import java.net.*;
   12 import javazoom.jl.player.*;
   13 
   14 public class Mp3Player extends java.applet.Applet {
   15       //  public void stop( );
   16       //  public void close( );
   17       //  public void play( );
   18       //  public void play( String filename );
   19       // pause? restart?
   20     protected String filename = "";
   21     protected Player player = null; 
   22     protected int pos = 0;  // postition
   23 
   24     // constructor that takes the name of an Mp3Player file 
   25     public Mp3Player(String filename) {
   26         this.filename = filename;
   27     }
   28     public Mp3Player( ) {
   29         this.filename = null;
   30     }
   31 
   32     public void close( ) { if(player != null) player.close(); }
   33     public void pause( ) {
   34         stop( );  //  not implement yet; same as stop( )
   35     } // pause(  
   36     public void stop( ) {   
   37        if( player == null ) return;
   38        //if( player. isComplete( ) ) pos = 0;
   39        //else pos = player.getPosition( );
   40        try{ pos = player.getPosition( ); }catch(Exception e){;}
   41        System.err.println(" Mp3Player Stop at " + pos);
   42        player.close( ); 
   43     } // stop
   44 
   45     public void restart( ) { // not implement yet;
   46         play( );      // now call play( )
   47     } // restart( 
   48 
   49     public void play(String filename) {
   50         this.filename = filename;  this.pos = 0;
   51         play( );
   52     } // play filename
   53 
   54     public void play( ) {   
   55         try { if(player != null) player.close( );
   56         }catch(Exception e) {;}
   57         if(filename == null) return;
   58         try {
   59             //File mp3File = getFile( filename );
   60             //FileInputStream fis     = new FileInputStream(mp3File);
   61             // .. 可惡! 上面這方法壓縮到 Jar 檔時不 work ?
   62             InputStream fis = myGetStream(filename);
   63             BufferedInputStream bis = new BufferedInputStream(fis);
   64             player = new Player(bis);
   65         } catch (Exception e) {
   66             System.out.println("Problem playing file " + filename);
   67             System.out.println("Error: " + e);
   68         } // try..catch..
   69         
   70         Slave sp = new Slave(player); 
   71                 // 其實 inner class 不必傳就看得到! :-)
   72         sp.start( );   // play in another Thread
   73     } // play(
   74 
   75     InputStream myGetStream(String filename) {
   76        InputStream file= null;
   77        URL url = null;
   78        try {  Toolkit tkt = Toolkit.getDefaultToolkit( );
   79           Class me = getClass( );   // get The class is running
   80           url = me.getResource(filename);
   81            System.err.println("filename=" + filename);
   82            System.err.println("urL=" + url);
   83        } catch (Exception e) { ; }
   84        try {
   85           file = url.openStream( );
   86           System.out.println(" stream open:" + file);
   87        }catch(Exception e){;}
   88        return file;
   89     }// getFile(
   90 
   91     File getFile(String filename) {
   92        File file= null;
   93        try {  Toolkit tkt = Toolkit.getDefaultToolkit( );
   94           Class me = getClass( );   // get The class is running
   95           URL url = me.getResource(filename);
   96           URI uri = url.toURI( );
   97    System.err.println("filename=" + filename);
   98    System.err.println("urL=" + url);
   99    System.err.println("uri=" + uri);
  100           file = new File( uri );   // 壓縮到 Jar 檔時不 work ?
  101        } catch (Exception e) { ; }
  102        return file;
  103     }// getFile(
  104   
  105    // an Inner class to play the mp3 in another thread
  106    class Slave extends Thread { // 其實 inner class 不必傳 :-)
  107        private Player player = null;
  108        Slave(Player pp) { player = pp;}
  109        public void run( ) {
  110            try{ 
  111                 player.play( );
  112            }catch (Exception e) { System.out.println("Error: "+e); }
  113        } // run
  114     }// Slave  
  115 } // class Mp3Player

本程式用到 javazoom 的 javalayer API, 連到 javazoom 網站

以下是個 使用該 Mp3Player.java 的簡單 application 範例: 
   01 // testMp3.java -- by tsaiwn@cs.nctu.edu.tw
   02 // test Mp3Player.java
   03 public class testMp3 {
   04     public static final String baseDir = "mp3/";
   05     static int getchar( ) { int gy = -1;
   06         try { gy = System.in.read( ); }catch(Exception e){;}
   07         return gy;
   08     } // getchar(
   09     public static void main(String[ ] args) {
   10         String filename = null;    // = "crysand.mp3";  // 哭沙
   11         filename = "heartgoon.mp3";  // 鐵達尼主題曲
   12         if(args.length >= 1) filename = args[0]; 
   13         Mp3Player mp3 = new Mp3Player( baseDir + filename);
   14         mp3.play( ); 
   15         System.out.print("hit Enter to stop... ");
   16         int kk = getchar( );  mp3.stop( );  skipTillNewLine( );
   17         System.out.print("hit Enter again to play 萍聚.. ");
   18         getchar( );  getchar( );  getchar( );  
   19         mp3.play(baseDir + "pinju.mp3" );  
   20         // do something
   21     } // main(
   22     static void skipTillNewLine( ) {
   23     } // 還沒寫 :-) 不重要!
   24 } // class


以下是剛剛你看到的Applet範例 P3P.java
   (當然也是可以當作 Application)
   01 //P3P.java -- P3P sample, @CopyLeft by tsaiwn@cs.nctu.edu.tw
   02 //這範例用到我寫的 Mp3Player.java
   03 //而 Mp3Player.java 則用到 javazoom 的 Javalayer API
   04 //所以, 要嘛 -cp javalayerAPI的jar檔案, 或是
   05 //要把 javalayer class 以整個 package 樹狀目錄全部放在你目錄
   06 //(其實也可以把該API的 jar 檔案copy到你 JDK的 jre\lib\ext 目錄內)
   07 //現在這範例是放 javalayer 的整個 package 樹狀目錄
   08 //參考 http://www.javazoom.net/javalayer/sources.html
   09 //在2009年之後也可用Sun 的 JMF (Java Media Framework)播放 MP3
   10 import java.applet.*;
   11 import java.awt.*;
   12 import java.awt.event.*;
   13 import javax.swing.*;
   14 import java.net.*;  // URL is in there
   15   // 注意要寫 public class 不然  Applet 有問題  
   16 public class P3P extends Applet implements ActionListener { //是 Applet
   17    // 希望讓個函數都看到的就放在這 Global 變數
   18    Mp3Player player = new Mp3Player( );  
   19    static boolean isApplication = false;  // in case that we need it
   20    Panel ppp;    // 木板 (面板)
   21    static Button btnShow;  // 按鈕 for 顯示歌名,
   22    Button btnPlay;   // 按鈕 for  播放/停止
   23    Button btRef = new Button("看 javazoom 網頁");
   24    JComboBox cbSex;  // 下拉式選單 Combo Box
   25    static final String JL_WEB = 
   26        "http://www.javazoom.net/";   // Javazoom 網站
   27 
   28    public static void main(String gg[ ]) {     // Java 的主程式都這樣寫
   29        isApplication = true;
   30        JFrame f = new JFrame("Windows 2011");        // 開個窗 f
   31        f.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );  // 3
   32        // JFrame 可以設成按右上角的 X 會關窗, 這樣不必自己處理  WindowEvent !
   33        P3P me = new P3P( );  // 模仿 Applet .. // 生出自己 (class P3P )
   34        f.add(me, "Center");   // 把 Applet (me) 放入窗 f 內
   35        f.setSize(798, 568);   // Frame 是 Window, 用 BorderLayout
   36        me.init( );      // 因為 Applet 被生出後先做 init( );
   37        me.start( );     // ..    再做  start( )
   38        f.setVisible(true);   // f.show( );
   39    } // main(
   40 
   41    static void println(String fmt, Object... oo) { print(fmt+"\n", oo); }
   42    static void print(String fmt, Object... oo){System.out.printf(fmt, oo); }
   43    static void printf(String fmt, Object... oo){System.out.printf(fmt, oo); }
   44    /// JDK1.5 (5.0)開始才有 printf( ) 
   45  
   46    public P3P( ) { 
   47        println(" Now doing ...  P3P constructor !");
   48    } // Constructor; 注意要寫 public 不然  Applet 有問題
   49 
   50    public int kk = 0;  // Global variable to this class
   51    public void paint(Graphics g) {
   52        System.out.println(" In  paint kk = " + kk++);
   53        // do drawing something ...
   54        validate( );  //
   55    } // paint(
   56 
   57 //////////////// ====== //////////// 只是看看何時會跑過來這些函數
   58    public void start( ) {
   59        super.start( );
   60        println(" Now in start( ) ... kk = " + kk++);
   61    }// start(
   62    public void update(Graphics g) {  // 只是看看何時會跑過來這
   63        System.out.println(" update ==> kk = " + kk++);
   64        super.update(g); //  叫用上層(super class)的 update( )
   65    } // update(  will called by repaint( )
   66    public void stop( ) {
   67        println(" STOP into stop( ) ... kk = " + kk++);
   68        super.stop( );
   69    }// stop(
   70    public void destroy( ) {
   71        println(" Destroy into destroy( ) ... kk = " + kk++);
   72        super.destroy( );
   73    }// destroy(
   74   ////////   //////// //////// ////// ////// //////// ////////
   75 
   76    public void init( ) {
   77        setLayout( new GridLayout(3, 1) ); // 3 rows
   78        Panel p1, p2, p3;
   79        p1=new Panel( ); p2=new Panel( ); p3=new Panel( );
   80        add(p1); add(p2); add(p3);  // 北中南三分天下
   81 
   82        btnShow = new Button("目前沒播放歌曲 ");
   83        decoratePpp(p1, btnShow);  // 重新安排 btnShow 看板在 p1 位置
   84        btnShow.setFont(new Font("標楷體",1,24));
   85 
   86        Panel p3abc = new Panel( new FlowLayout(FlowLayout.LEFT) );
   87        p3.setLayout( new BorderLayout( ) );
   88        p3.add(p3abc, "South");
   89        p3abc.add(new Label("by tsaiwn@cs.nctu.edu.tw") );
   90        p3abc.add( new Label("          ") );  //放空白
   91        p3abc.add(btRef); // 開個網頁看 JLayer 網站
   92        btRef.addActionListener(this);
   93        btRef.setCursor( new Cursor(Cursor.HAND_CURSOR) );  // 出現"手"
   94 
   95        List theList = getMyList( );   //  選單 List
   96 
   97        JPanel pSongs = new JPanel( );
   98        putList2SP(pSongs, theList);
   99 
  100        btnPlay = new Button("STOP 停");
  101        p2.add(btnPlay); 
  102        p2.add(pSongs);   // 我塞 我塞 我塞塞塞
  103        btnPlay.setForeground(Color.BLUE); 
  104        btnPlay.setCursor( new Cursor(Cursor.HAND_CURSOR) );  // 出現"手"
  105        btnPlay.setFont(new Font("標楷體",1,24));
  106 
  107 
  108       // 勞作都做好了再 add??Listener()
  109        btnShow.addActionListener(this);
  110        btnPlay.addActionListener(this);
  111 
  112        MyDog mm = new MyDog(player, theList);   
  113        theList.addItemListener (mm);  
  114 
  115        validate( );  //  做了一些對圖形元件 的動作記得要做這  validate( ); 
  116    } // init(
  117 
  118    void putList2SP(JPanel pp, List theList) {  // 塞 可捲動式選單 List
  119        Label tmpLab = new Label("請選擇歌曲");
  120        tmpLab.setFont(new Font("標楷體",1,18));   //////
  121        tmpLab.setForeground( Color.BLUE );  // 藍色 
  122        theList.setFont(new Font("細明體",1,20));
  123        pp.setLayout( new BorderLayout( ) );  // 東西南北中
  124        pp.add(tmpLab, "North");
  125        pp.add(theList, "Center"); // 把 選單 塞入 Panel
  126        // pp.setPreferredSize( new Dimension(598, 128) );
  127        pp.updateUI( );
  128    } // putList2SP(
  129 
  130 ////////   =============================================  //////////
  131    Color yyc[ ] = { Color.red, Color.blue, Color.green, Color.pink
  132        , Color.magenta,  new Color(198, 58, 198), Color.gray
  133    };  // 結束一定要有分號, 因為大括號左方是 Data !
  134    int cid = -1;   // 以便 +1 後變成 0 開始
  135 
  136    void processBBB( ) {   // 用另一個 Thread 跑它
  137        javax.swing.SwingUtilities.invokeLater(new Runnable( ) {
  138           public void run() {
  139              cid =  (cid+1) % yyc.length;
  140              btnShow.setForeground( yyc[cid] ); 
  141              repaint( );
  142              return;
  143           } // run(
  144        }); // javax...
  145    } // processBBB( 
  146 
  147 
  148    public void actionPerformed(ActionEvent e) {
  149        Object who = e.getSource( );    // 誰被按了一下 ?
  150        String gg = "You press " + e.getActionCommand( );
  151 
  152        if(who == btRef) {openWebWindow( JL_WEB ); return; }
  153 
  154        if(who == btnShow) {
  155           processBBB( );  return;
  156        }// 用另一個 Thread 跑它(若事情很多)
  157 
  158        if(who == btnPlay) {
  159            player.stop( );
  160            btnShow.setLabel( "目前沒播放歌曲");
  161        }
  162        repaint( );  // 會偷叫 update(Graphics);
  163    } // actionPerformed( 
  164 
  165  ////////////
  166    void decoratePpp(Panel ppp, Button btnToShow) {
  167        JLabel labJiang =   // 抄自 MyApplet.java(extends 就不必copy)
  168           createLabelWithPicture("img/mypic.gif", "一代歌后");
  169        ppp.setLayout( new BorderLayout( ) ); // 改用東西南北中擺法
  170        ppp.add(labJiang, "West");    // 左 (江蕙)
  171     ///
  172        btnShow.setFont(new Font("標楷體",1,36));  // 粗體 
  173        btnShow.setCursor( new Cursor(Cursor.HAND_CURSOR) );  // 出現"手"
  174        ppp.setBackground(Color.pink);    // 背景色 粉紅
  175     ///
  176        Panel p5= new Panel( new BorderLayout( ) );
  177          Panel p5Up = new Panel( );  
  178          Panel p5Down = new Panel( );
  179           p5.add(p5Up, "North");    // 塞一些空間 :-)
  180           p5.add(p5Down, "South");
  181           p5.add(btnToShow, "Center");
  182       ///
  183        p5Down.setPreferredSize(new Dimension(200,98) );
  184        p5Up.setPreferredSize(new Dimension(200,38) );
  185        Label gg = new Label("Simple MP3 Player");
  186        p5Up.setLayout( new FlowLayout( FlowLayout.LEFT ) );
  187        p5Up.add(gg);  gg.setBackground( Color.cyan);
  188        gg.setFont(new Font("標楷體", 1, 28));
  189       ////////////
  190        JPanel tmpPan = new JPanel( new BorderLayout( ) ); // !!!
  191        // tmpPan.add( something, "West");  // Left side 
  192        tmpPan.add(p5, "Center"); //
  193        tmpPan.setBackground( new Color(198, 0, 168) );
  194      /// /// //再把tmpPan塞入ppp木板Center但右邊沒東西
  195        ppp.add(tmpPan, "Center");  
  196    } // decoratePpp(
  197 
  198   ////////===================================
  199    static String songNames[ ] = {  "杜德偉-脫掉"
  200           ,"張惠妹-哭沙"
  201           ,"李翊君+孫建平-萍聚"
  202           ,"莫札特-魔笛"
  203           ,"惠妮休士頓-When You Believe"
  204           ,"席琳狄翁-My heart will go on愛無止盡(鐵達尼號)"
  205       };  // songNames[     
  206    List getMyList( ) {  
  207        List songNameList = new List(5);  // songs List, 顯示五列
  208        // 注意這 java.awt.List 不是 java.util.List (鏈結串列)
  209 
  210        for( String gg: songNames) songNameList.add( gg );  // 依序加入各顏色名稱
  211        songNameList.setBackground(Color.pink);
  212        songNameList.setFont(new Font("標楷體 ", 1, 28) ); // 粗體
  213        int kr = 5; /// 預設 5  席琳狄翁-My heart will go on愛無止盡
  214        songNameList.select(kr);  // current default 選 5-th
  215        return songNameList;
  216    } // getMyList(   
  217 
  218    public static void showSongName(int k) {
  219       btnShow.setLabel( songNames[k]);
  220    }  // showSongName(
  221 
  222    void openWebWindow(String web) {  // note different when in Application
  223        try {
  224           if(isApplication){  // utilize the Runtime exec function
  225              try {              // 注意格式, 因字串中含有 " 雙引號 "
  226                 Runtime.getRuntime( ).exec(
  227                   "cmd /c \"start " + web + "\" " );
  228              } catch (Exception e95){  // try Win 95/98
  229                 Runtime.getRuntime( ).exec(
  230                   "start " + web );   //Win95/98中 start 是內建
  231              }// try..catch..
  232           } else { // is Applet, we are in Browser, use showDocument( )
  233              URL url = new URL(web); 
  234              getAppletContext().showDocument(url, "_blank"); 
  235           }   // see AppletContext      // _blank means in New Window
  236        } catch (Exception e) {; }
  237    } // openWebWindow(
  238  
  239 /////////////////////////////////////////////////////////////////////
  240 /////////////////////////////////////////////////////////////////////
  241    JLabel createLabelWithPicture(String filename) {
  242        return createLabelWithPicture(filename, "", 
  243                             javax.swing.SwingConstants.TRAILING);
  244    }
  245    JLabel createLabelWithPicture(String filename, String caption) {
  246        return createLabelWithPicture(filename, caption, 
  247                             javax.swing.SwingConstants.TRAILING);
  248    }
  249    JLabel createLabelWithPicture(String filename, String caption,
  250                                                   int alignment ) {
  251       JLabel ans = null;
  252       ImageIcon icon = null;   
  253       try {
  254          Image image = myGetImageBoth(filename);
  255          icon = new ImageIcon( image ); 
  256          ans = new JLabel(caption, icon, alignment);
  257          ans.setVerticalTextPosition(
  258                             javax.swing.SwingConstants.BOTTOM);
  259          ans.setHorizontalTextPosition(
  260                             javax.swing.SwingConstants.CENTER);
  261       } catch (Exception e) {
  262          try { if(ans==null) ans = new JLabel(caption);
  263          } catch (Exception e2) {;}
  264       }
  265       return ans;
  266    } // createLabelWithPicture(
  267    Image getImageBoth(String filename) {
  268        return myGetImageBoth( filename);
  269    }
  270    Image myGetImageBoth(String filename) {
  271       Image image = null;
  272       try {       // Application 中讀取 Image 方法與 Applet 中不同
  273          image = newImageBoth(filename);   //try Application first
  274          //println("MyApplet got image=" + image);
  275       } catch (Exception e) { image=null; // then, try Applet
  276       } // try .. catch
  277       if(image==null) {
  278          try {       // try Applet, Applet use different method
  279             image = getImage(new URL( getCodeBase()+ filename));
  280          } catch (Exception e) { image = null;}
  281       } //if
  282       if(image != null) return image;  //////////////////
  283       try { // ok, now the last way I can try
  284          Toolkit tkt = Toolkit.getDefaultToolkit( );
  285          Class me = getClass( );   // get The class which is running
  286          URL url = me.getResource(filename);
  287          image = tkt.getImage( url ); // works for both Application+Applet
  288       } catch (Exception e) { image = null; } // sorry, I have no way
  289       return image; 
  290    } // myGetImageBoth
  291 ///
  292    public  Image  newImageBoth(String filename) {   /// NOT static
  293        Image image = null;
  294        try {   // 2011/04/02  good in Jar file
  295           Toolkit tkt = Toolkit.getDefaultToolkit( );
  296           Class me = getClass( );   // get The class is running
  297           URL url = me.getResource(filename);
  298           image = tkt.getImage(url); 
  299        } catch (Exception e) { ; }
  300        return image;
  301    } // newImageBoth(String 
  302 /////////////////////////////////////////////////////////////////
  303 /////////////////////////////////////////////////////////////////
  304  
  305    class MyDog implements ItemListener {  
  306        List choose = null;
  307        Mp3Player player = null;
  308        String baseDir = "mp3/";
  309        String songName = "pinju.mp3";
  310        MyDog(Mp3Player pp, List s) { player = pp; choose = s; }
  311          // Inner class 看得到外部 class 的 Global 變數, 
  312          /// 但看不到 在函數內的 Local 變數!
  313          /// 若放 Global 就可以不必傳啦 !
  314 
  315        public void itemStateChanged(ItemEvent e) {
  316           Object who = e.getItem( );  // Item number #
  317           // so far 只處理該 List
  318           int sel = choose.getSelectedIndex( );   // OK too
  319           //pp.setBackground( selColor[ sel ] );
  320           songName = baseDir + sName[ sel ];
  321           P3P.showSongName( sel );
  322           player.play( songName );  // in another Thread
  323        } // itemStateChanged(
  324    } // class MyDog   (an inner class)  
  325 
  326    static String sName[ ] = { "takeoff.mp3"
  327        , "crysand.mp3", "pinju.mp3", "magicflu.mp3"
  328        , "believe.mp3", "heartgoon.mp3"
  329     }; // sName[
  330    int numSongs = sName.length;  
  331 } // class



 
To use javazoom javalayer API for MP3: 
  假設你的 program 是 Ggg.java 

(1) 使用它的 jar 檔案Library 設定 classpath : 
    javac -cp .;jl1.0.jar;  Ggg.java
    java  -cp .;jl1.0.jar;  Ggg  

(2) 把它的 jl1.0.jar 先解壓縮在你 Ggg.java 的目錄下 
    jar xvf jl1.0.jar   
   這樣會生出一個目錄 javazoom 內含有該 jl (javalayer package)
   之後直接使用 javac 編譯你的 Java 程式, 用 java 或 javaw 執行你的 class
或是
(3) 擴充你的 JDK 能力 (注意這樣只有你自己可以用, 沒擴充到別人的 !)
    就是把該 jl1.0.jar 複製到你的 JDK 跟目錄下的以下子目錄: 
       jre\lib\ext\   
   請注意, 是 JDK 之下的 jre 喔!
   不是原來 Java Run Time (JVM) 的 jre 目錄! 
   (只要把你自己寫的 class 壓縮成 任意名稱.jar 檔案丟入該目錄就可以!)