📄 internetmusic.java
字号:
import javax.swing.JApplet;
import java.util.Vector;
import java.util.StringTokenizer;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTable;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableColumn;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.Line2D;
import java.awt.BasicStroke;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.SourceDataLine;
import java.io.IOException;
import javax.sound.sampled.LineUnavailableException;
import javax.swing.event.ListSelectionListener;
import javax.swing.event.ListSelectionEvent;
import javax.swing.DefaultListSelectionModel;
import javax.swing.JButton;
import javax.swing.JPanel;
import java.awt.GridBagLayout;
import java.awt.GridBagConstraints;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.net.URL;
public class InternetMusic extends JApplet implements ActionListener,Runnable{
Vector songVector=new Vector();
Vector songFileVector=new Vector();
JSplitPane jSplitPanel=new JSplitPane();
SongTablePane songTablePane;
Vector lines=new Vector();
AudioInputStream audioInputStream;
AudioFormat audioFormat;
final int bufferSize=16384;
WaveGraphPane waveGraphPane=new WaveGraphPane();
PlayMusic playMusic=new PlayMusic();
double seconds,duration;
URL url;
String selSong="未选择";
String selSongFile=null;
JButton oneB=new JButton("单曲播放");
JButton allB=new JButton("全部播放");
JButton stopB=new JButton("停止");
Thread backThread; // 播放全部歌曲的后台线程
boolean stopStatus;
public void init(){
setSize(560,230);
String songs=getParameter("songs");//取得网页参数songs值
String songFiles=getParameter("songFiles");//取得网页参数songFile值
//利用StringTokenizer分解出歌曲名
StringTokenizer stk1=new StringTokenizer(songs,",");
while(stk1.hasMoreTokens()){
songVector.add(stk1.nextToken());
}
// 利用StringTokenizer分解出歌曲文件名
StringTokenizer stk2=new StringTokenizer(songFiles,",");
while(stk2.hasMoreTokens()){
songFileVector.add(stk2.nextToken());
}
songTablePane = new SongTablePane(songVector);
getContentPane().add(jSplitPanel);
jSplitPanel.setLeftComponent(songTablePane);
jSplitPanel.setDividerLocation(230);
// 创建按扭面板
JPanel buttonPane= new JPanel();
buttonPane.add(oneB);
buttonPane.add(allB);
buttonPane.add(stopB);
// 设置右侧面板为网格包布局
JPanel rightPane=new JPanel();
GridBagLayout gridbag=new GridBagLayout();
rightPane.setLayout(gridbag);
GridBagConstraints c=new GridBagConstraints();
// 布置音频曲线面板
c.gridx=0;
c.gridy=0;
c.weightx=100;
c.weighty=90;
c.fill=GridBagConstraints.BOTH;
gridbag.setConstraints(waveGraphPane,c);
rightPane.add(waveGraphPane);
// 布置按扭面板
c.gridx=0;
c.gridy=1;
c.weightx=100;
c.weighty=10;
c.fill=GridBagConstraints.BOTH;
gridbag.setConstraints(buttonPane,c);
rightPane.add(buttonPane);
// 插入右侧分隔面板
jSplitPanel.setRightComponent(rightPane);
// 添加按扭单击事件处理
oneB.addActionListener(this);
allB.addActionListener(this);
stopB.addActionListener(this);
}
public void actionPerformed(ActionEvent e){
Object srcobj=e.getSource();
if(srcobj==oneB){ //单击"单曲播放"按扭
if(selSongFile!=null){
try{
//url=new URL("file:///d:/applet"+selSongFile);
url=new URL("file://"+getCodeBase().getPath()+selSongFile);
audioInputStream=AudioSystem.getAudioInputStream(url);
// 多少桢/桢频率,再同过1000乘,化为毫秒
long milliseconds=(long)((audioInputStream.getFrameLength()*1000)/audioInputStream.getFormat().getFrameRate());
duration=milliseconds / 1000.0;
waveGraphPane.drawWaveLine(null);// 绘制音频曲线
playMusic.startPlay() ;// 播放
waveGraphPane.startDraw();// 移动红线条
}catch(Exception e2){System.out.println(e2);}
}
}
if(srcobj==allB){ //单击"全部播放"按扭
stopStatus=false;
backThread=new Thread(this);//创建后台进程
backThread.start();// 启动后台进程播放所有歌曲
}
if(srcobj==stopB){ // 单击"停止"按扭
if(backThread!=null){
stopStatus=true;
playMusic.playThread=null;
waveGraphPane.graphThread=null;
backThread=null; // 停止播放全部歌曲的后台线程
}
else{
playMusic.stopPlay();
waveGraphPane.stopDraw();
}
}
}
// 后台运行全部歌曲
public void run(){
for(int i=0;i<songVector.size();i++){
if(!stopStatus){
selSong=(String)songVector.get(i); // 取出歌曲名
String selSongFile=(String)songFileVector.get(i); //取出歌曲文件名
//设置表格当前行选中
songTablePane.jTableView.changeSelection(i,0,false,false);
try{
//url=new URL("file:///d:/applet"+selSongFile);
url=new URL("file://"+getCodeBase().getPath()+selSongFile);
audioInputStream=AudioSystem.getAudioInputStream(url);
// 多少桢/桢频率,再通过乘1000,化为毫秒
long milliseconds=(long)((audioInputStream.getFrameLength()*1000)/audioInputStream.getFormat().getFrameRate());
duration = milliseconds / 1000.0;
waveGraphPane.drawWaveLine(null); // 绘制音频曲线
playMusic.startPlay(); // 播放
waveGraphPane.startDraw(); // 移动红线条
}catch(Exception e2){System.out.println(e2);}
for(; ;){ // 无限循环,直到每一首歌曲播放完毕
if(playMusic.playThread==null) break;
}
}
}
backThread=null; // 最后停止后台线程
}
// 歌曲点播面板
class SongTablePane extends JScrollPane implements ListSelectionListener{
JTable jTableView;
DefaultTableModel dtm;
int selRow;
SongTablePane(Vector songVector){
//表格的列头标题
Vector columnName=new Vector();
columnName.add("序号");
columnName.add("歌曲");
// 为歌曲加上序号
Vector rowData=new Vector();
for(int i=0;i<songVector.size();i++){
Vector temp=new Vector();
temp.add(new Integer(i)); //序号
temp.add(songVector.get(i)); //歌曲名
rowData.add(temp);
}
//设置水平和垂直滚动条
this.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
this.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
dtm = new DefaultTableModel(rowData,columnName){
// 修改下面方法的返回值为false,使表格单元数据只读。
public boolean isCellEditable(int row, int col) {return false;}
};
jTableView=new JTable(dtm);
jTableView.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
// 预置序号列的宽度
TableColumn orderColumn =jTableView.getColumn("序号");
orderColumn.setPreferredWidth(60);
//预置歌曲列的宽度
TableColumn songColumn=jTableView.getColumn("歌曲");
songColumn.setPreferredWidth(210);
//把表格插入滚动条面板
this.getViewport().setView(jTableView);
DefaultListSelectionModel dlsm=new DefaultListSelectionModel();
//为行选择模式添加行选择监听器
dlsm.addListSelectionListener(this);
jTableView.setSelectionModel(dlsm); //
}
public void valueChanged(ListSelectionEvent e){
// 取得歌曲文件名
selRow=jTableView.getSelectedRow();
selSong=(String)songVector.get(selRow);
selSongFile=(String)songFileVector.get(selRow);
}
}
// 播放音乐类
class PlayMusic implements Runnable{
SourceDataLine sdLine;
Thread playThread; // 播放线程
// 启动线程播放音乐
public void startPlay(){
playThread= new Thread(this);
playThread.start(); // 启动播放线程
}
//关闭播放线程,停止播放音乐。
public void stopPlay(){
playThread =null;
}
// 实现播放线程的Runnable接口方法
public void run(){
try{
// 重新获得audioInputStream,以免被drawWaveLine(null)覆盖掉
audioInputStream=AudioSystem.getAudioInputStream(url);
}catch(Exception e){System.out.println(e);}
if(audioInputStream==null){ //没有播放的音乐
playThread=null;
return;
}
// 检查是否支持DataLine
audioFormat= audioInputStream.getFormat();
DataLine.Info info = new DataLine.Info(SourceDataLine.class,audioFormat);
if(!AudioSystem.isLineSupported(info)){
System.out.println("不支持此格式的播放");
playThread=null;
return;
}
//打开SourceDataLine
try{
sdLine=(SourceDataLine)AudioSystem.getLine(info);
sdLine.open(audioFormat,bufferSize);
}catch(LineUnavailableException e){
System.out.println("不能打开SourceDataLine:"+e);
playThread=null;
return;
}
//创建一个只有半个SourceDataLine的缓冲区大小的字节数组
byte[] data=new byte[sdLine.getBufferSize()/2];
int numBytesRead=0;
// 启动sdLine混音播放
sdLine.start();
while(playThread!=null){
try{
// 分批将audio输入流数据读到data字节数组
if((numBytesRead=audioInputStream.read(data)) == -1){
break; //读到audio输入流尾部则跳出循环
}
int numBytesRemaining=numBytesRead;
//写入sdLine的数据队列
while(numBytesRemaining>0){ //写入sdLine以进行混音播放
numBytesRemaining-=sdLine.write(data,0,numBytesRemaining);}
}catch(IOException e){
System.out.println("播放错误:"+e);
break;
}
}
// 播放完成或出现异常时,关闭相关资源
if(playThread!=null){
sdLine.drain();
}
sdLine.stop();
sdLine.close();
sdLine=null;
playThread=null;
}
}
// 绘制音乐波形曲线图
class WaveGraphPane extends JPanel implements Runnable{
Thread graphThread; //绘制线程
private Font font12 = new Font("serif",Font.PLAIN,12);
// 背景黑色
public WaveGraphPane(){
setBackground(new Color(15,15,15));
}
// 按字节数据绘制音乐波形曲线图
public void drawWaveLine(byte[] audioBytes){
lines.removeAllElements() ; // 清除向量元素
//if(audioBytes==null){
//将long型转为int型,不支持太大文件播放
try{
audioFormat=audioInputStream.getFormat();
audioBytes=new byte[(int)(audioInputStream.getFrameLength()*audioFormat.getFrameSize())];
//读入到audioBytes字节数组
audioInputStream.read(audioBytes);
}catch(Exception e){
System.out.println(e.toString());
repaint();
return;
}
int w=getSize().width;
int h=getSize().height-20;
// 将byte数据转为int数组audioData的数据,便于绘制
int [] audioData=null;
if(audioFormat.getSampleSizeInBits() == 16)
{
int nlengthInSamples=audioBytes.length/2;
audioData=new int[nlengthInSamples];
if(audioFormat.isBigEndian()){
for(int i=0; i<nlengthInSamples;i++){
// audioBytes 偶字节HAB作高位字节处理
int HAB = (int)audioBytes[2*i];
// audioBytes奇字节作低字节处理
int LAB = (int)audioBytes[2*i+1];
//移位形成一个新整数
audioData[i]=HAB << 8 |(255 & LAB);
}
}
else{
for(int i=0; i<nlengthInSamples;i++){
// audioBytes偶字节作低位字节处理
int LAB =(int) audioBytes[2*i];
// audioBytes奇字节作高位字节处理
int HAB =(int) audioBytes[2*i+1];
audioData[i]= HAB << 8 | (255 & LAB);
}
}
}
// 一个像素点对应多少个桢
int frames_per_pixel=audioBytes.length/audioFormat.getFrameSize()/w;
byte my_byte=0;
double y_last =0;
int numChannels=audioFormat.getChannels();
for(double x=0; x<w && audioData !=null; x++){
int idx =(int) (frames_per_pixel * numChannels * x);
// 双字节采样,32768是2的15次方,128是2的7次方。
my_byte=(byte)(128*audioData[idx]/32768 ); // 确保字节大小
double y_new = (double) (h*(128-my_byte)/256);
lines.add(new Line2D.Double(x,y_last,x,y_new));
y_last = y_new;
}
repaint();
}
public void paint(Graphics g){
int w=getSize().width;
int h=getSize().height;
int INFORECT=17;// 定义一个提示信息的小矩形块高度
Graphics2D g2 = (Graphics2D)g; // 转换g为g2
g2.setBackground(getBackground());
g2.clearRect(0,0,w,h);
g2.setColor(Color.white);
g2.fillRect(0,h-INFORECT,w,INFORECT); //面板下的一块白色
g2.setColor(Color.black);
g2.setFont(font12);
g2.drawString("歌曲:"+selSong+"长度: "+String.valueOf(duration)+" 位置: "+String.valueOf(seconds),3,h-4);
if(audioInputStream !=null){
//绘制音乐曲线
g2.setColor(Color.yellow); //黄色音频曲线
for(int i=1; i<lines.size();i++){
g2.draw((Line2D)lines.get(i));
}
// 绘制红线表示当前播放位置
if(seconds!=0){
double loc=seconds/duration*w;
g2.setColor(Color.red);
g2.setStroke(new BasicStroke(3));
g2.draw(new Line2D.Double(loc,0,loc,h-INFORECT-2));
}
}
}
public void startDraw(){
graphThread=new Thread(this);
graphThread.start();
seconds=0;
}
public void stopDraw(){
if(graphThread!=null){
graphThread=null;
}
graphThread=null;
}
public void run(){
seconds=0;
while(graphThread!=null){
if((playMusic.sdLine!=null) && (playMusic.sdLine.isOpen())){
//播放情形,将毫秒化位秒
long milliseconds=(long)(playMusic.sdLine.getMicrosecondPosition()/1000);
seconds=milliseconds/1000.0;
}
try{
graphThread.sleep(100);
}catch(Exception e){
break; //
}
repaint();
while((playMusic.sdLine != null && !playMusic.sdLine.isOpen())){
try{
graphThread.sleep(10);
}catch(Exception e){
break;
}
}
}
seconds =0;
repaint();
}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -