Java applet 音频播放器
课题需求分析
在Java2平台出现前,Java语言只能处理电话音质的声音,以单声道8KHz的采样频率存储为u-lawAU文件。
Java2平台增加了AIFF、WAV以及三种MIDI文件类型的支持。
所支持的三种MIDI文件格式为MIDI文件类型0、MIDI文件类型1以及RMF。
课程解决方案
本程序有三个文件:SoundApplet.Java是主文件,AppletSoundLoader.Java中的AppletSoundLoader类继承Thrwad负责为声音文件获得AudioClip对象并把它加到AppletSoundList中去;AppletSoundList.java中定义的AppletSoundList继承自Hashtable,提供getClip(String)和putClip(AudioClip,String)方法,分别从哈希表中取得AudioClip对象和放置AudioClip对象。
其结构是AppletSoundList中用AppletSoundLoader来装载制定URL的声音文件,AppletSoundLoader负责为声音文件产生AudioClip对象并添加到AppletSoundList中。
在SoundApplet中则只是利用AppletSoundList类。
课题实现
主要的声音文件类型如下:
AU (扩展名为AU或SND):适用于短的声音文件,为Solaris和下一代机器的通用文件格式,也是Java平台的标准音频格式。AU类型文件使用的三种音频格式为:8位u-law类型(通常采用频率为8KHz),8位线性类型以及16位线性类型。
WAV(扩展名为WAV):由Microsoft和IBM共同开发,对WAV的支持已经被加进Windows95并且被延伸到Windows98。WAV文件能存储各种格式包括u-law、a-law和PCM(线性)数据。它们几乎能被所有支持声音的Windows应用程序播放。
AIFF(扩展名为AIF或IEF)音频互换文件格式是为Macintosh计算机和Silicon Graphics(SGI)计算机所共用的标准音频文件格式。AIFF和AIFF-C几乎是相同的,除了后者支持例如u-law和IMA ADPCM类型的压缩。
MIDI(扩展名为MID)乐器数字接口MIDI是为音乐制造业所认可的标准,主要用于控制诸如合成器声卡之类的设备。
Java声音引擎支持两种MIDI文件类型:
MIDI类型0文件-包含仅仅一个序列,所有相关的乐器部分被包含在同一个逻辑“磁道”上。
MIDI类型1文件-包含多重的“磁道”使得不同的乐器被逻辑地分开,从而使对声音的操作和重组更加容易。
RMF(扩展名为RMF)混合音乐格式是由Beatnik设计出来的混合文件类型,通过交互设定将MIDI和音频采样封装在一起。RMF好比是一个所有音乐相关文件的容器。RMF也包含对有关版权的详细文件说明的支持。RMF文件可以包含多个由不同艺术家创作的存储为MIDI类型或音频采样类型的作品,每个都关联着相关的版权信息。
Java中用于播放声音的AudioClip接口提供下列机能:播放、循环、停止。恢复和播放声音最简单的方法是通过Applet类的play()方法。调用play()方法有如下两种方式:
play()带有一个参数,一个URL对象,装载并演奏储存在URL处的声音片段。Play()带有两个参数,基本URL和文件夹路径名,装载并演奏声音文件。第一参数经常是对getCodeBase()或DocumentBase()的调用。
play()一旦被调用立刻开始恢复和播放声音。如果声音文件不能被查找,将不会有出错信息,仅仅是沉默。启动和停止声音文件,或循环播放,必须用applet的getAudioClip方法把它装载进入AudioClip对象,类似上面play()方法的参数,getAudioClip方法要用一个或两个参数,当作播放的指示。第一个或唯一的一个参数是URL参数,用来指示声音文件的位置,第二参数是文件夹路径指针。
代码如下:
// SoundApplet.java
import javax.swing.*;
import java.applet.*;
import java.awt.*;
import java.awt.event.*;
public class SoundApplet extends JApplet
implements ActionListener,
ItemListener {
AppletSoundList soundList;
String auFile = "sound\\spacemusic.au";
String aiffFile = "sound\\flute+hrn+mrmba.aif";
String midiFile = "sound\\trippygaia1.mid";
String rmfFile = "sound\\jungle.rmf";
String wavFile = "sound\\bottle-open.wav";
String chosenFile;
AudioClip onceClip, loopClip;
JComboBox formats;
JButton playButton, loopButton, stopButton;
boolean looping = false;
public void init() {
String [] fileTypes = {auFile,
aiffFile,
midiFile,
rmfFile,
wavFile};
formats = new JComboBox(fileTypes);
formats.setSelectedIndex(0);
// 获得选中的声音文件名
chosenFile = (String)formats.getSelectedItem();
formats.addItemListener(this);
playButton = new JButton("Play");
playButton.addActionListener(this);
loopButton = new JButton("Loop");
loopButton.addActionListener(this);
stopButton = new JButton("Stop");
stopButton.addActionListener(this);
stopButton.setEnabled(false);
JPanel controlPanel = new JPanel();
controlPanel.add(formats);
controlPanel.add(playButton);
controlPanel.add(loopButton);
controlPanel.add(stopButton);
getContentPane().add(controlPanel);
startLoadingSounds();
}
public void itemStateChanged(ItemEvent e) {
chosenFile = (String)formats.getSelectedItem();
soundList.startLoading(chosenFile);
}
void startLoadingSounds() {
// 开始装载声音文件
soundList = new AppletSoundList(this, getCodeBase());
soundList.startLoading(auFile);
soundList.startLoading(aiffFile);
soundList.startLoading(midiFile);
soundList.startLoading(rmfFile);
soundList.startLoading(wavFile);
}
public void stop() {
onceClip.stop(); //停止一次播放
if (looping) {
loopClip.stop(); //停止循环播放
}
}
public void start() {
if (looping) {
loopClip.loop(); //重新启动循环播放
}
}
public void actionPerformed(ActionEvent event) {
Object source = event.getSource();
if (source == playButton) {
//Try to get the AudioClip.
onceClip = soundList.getClip(chosenFile);
onceClip.play(); //Play it once.
stopButton.setEnabled(true);
showStatus("Playing sound " + chosenFile + ".");
if (onceClip == null) {
showStatus("Sound " + chosenFile + " not loaded yet.");
}
return;
}
//如果按下循环按钮
if (source == loopButton) {
loopClip = soundList.getClip(chosenFile);
looping = true;
loopClip.loop(); //开始循环播放
loopButton.setEnabled(false);
stopButton.setEnabled(true);
showStatus("Playing sound " + chosenFile + " continuously.");
if (loopClip == null) {
showStatus("Sound " + chosenFile + " not loaded yet.");
}
return;
}
//如果按下停止按钮
if (source == stopButton) {
if (looping) {
looping = false;
loopClip.stop(); //停止循环播放
loopButton.setEnabled(true); //使开始按钮可用
}
else if (onceClip != null) {
onceClip.stop();
}
stopButton.setEnabled(false);
showStatus("Stopped playing " + chosenFile + ".");
return;
}
}
}
// AppletSoundLoader.java
import javax.swing.*;
import java.applet.*;
import java.net.URL;
class AppletSoundLoader extends Thread {
JApplet applet;
AppletSoundList soundList;
URL baseURL;
String relativeURL;
public AppletSoundLoader(JApplet applet,
AppletSoundList soundList,
URL baseURL,
String relativeURL) {
this.applet = applet;
this.soundList = soundList;
this.baseURL = baseURL;
this.relativeURL = relativeURL;
setPriority(MIN_PRIORITY);
start();
}
public void run() {
AudioClip audioClip = applet.getAudioClip(baseURL, relativeURL);
soundList.putClip(audioClip, relativeURL);
}
}
// AppletSoundList.java
import javax.swing.*;
import java.applet.*;
import java.net.URL;
//Loads and holds a bunch of audio files whose locations are specified
//relative to a fixed base URL.
class AppletSoundList extends java.util.Hashtable {
JApplet applet;
URL baseURL;
public AppletSoundList(JApplet applet, URL baseURL) {
super(5); //初始化哈希表的容量为5
this.applet = applet;
this.baseURL = baseURL;
}
public void startLoading(String relativeURL) {
new AppletSoundLoader(applet, this,
baseURL, relativeURL);
}
// 通过相对URL从哈希表中获得AudioClip
public AudioClip getClip(String relativeURL) {
return (AudioClip)get(relativeURL);
}
// 将AudioClip 对象放进哈希表,键值为relativeURL
public void putClip(AudioClip clip, String relativeURL) {
put(relativeURL, clip);
}
}
课题运行及调试
运行结果入下图所示:按下“Loop”时,显示如下图4.1,自动循环播放文件。
图4.1 界面图
按下“Stop”,音乐播放暂停,显示如下图4.2:
图4.2 暂停播放图
5 小结
由于编程经验的不足和知识水平有限,存在的问题比较多,播放器的功能太简单,可进行的操作太少,一些功能在实现起来也不太理想。这些都有待进一步改善。
在本项目开发的过程中,我学习了很多有关的知识。一些以前没有学得很杂实的课程的内容,由于需要在实践中运用,刚开始我也感到很头痛。但回过头再去看有关的教科书,经过一段时间的钻研,对与这些知识点的相关的背景,学习起来也越来越有兴趣。
另外我还充分体会了从事软件开发工作需要特别严谨认真的态度和作风,一点都马虎不得。每一个细微的细节都必须十分的注意,如果不认真思考决策,就会出现或大或小的错误,如果早期的错误隐藏下来,对后面的工作影响就会很大,甚至有时要推倒很多前面做的工作重来。
由于我的知识浅薄,经验不足及阅历颇浅,因此,在该播放器的设计方面还有很多不足,比如功能过少,界面不够醒目等问题,我会在学习过程中,根据设计的具体要求不断的修改,完善,争取使该播放器慢慢趋向完美。
Java applet 音频播放器.doc