點這抓 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 檔案丟入該目錄就可以!)