⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 internetmusic.java

📁 本程序为一个多线程的显示波形图的Applet高级播放器,Applet播放器由JSplitPane分隔面板划分成左右两个部分,左边是一个JTable表格,显示歌曲的序号和歌曲名供用户选择 右边是一个网格
💻 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 + -