📄 internetmusic.java
字号:
Thread playThread;
//启动线程播放音乐
public void startPlay(){
playThread = new Thread(this);
playThread.start();
}
//关闭线程,停止播放音乐。
public void stopPlay(){
playThread = null;
}
//实现Runnable接口方法
public void run(){
try{
//重新取得audioInputStram,以免被waveGraphPane.drawWaveLine(null).
audioInputStream=AudioSystem.getAudioInputStream(url);
}catch(Exception e){System.out.println(e);}
if(audioInputStream==null){ //没有播放的音乐
playThread=null;
return;
}
/* try{ //对输入流进行复位到上次标记位置,准备继续播放。
audioInputStream.reset();
} catch(IOException e){
System.out.println("复位失败"+e.toString());
playThread=null;
return;
}*/
//检查是否支持DataLine
audioFormat=audioInputStream.getFormat();
DataLine.Info info = new DataLine.Info(SourceDataLine.class,audioFormat);
if (!AudioSystem.isLineSupported(info)){
System.out.println("不支持DataLine");
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.start();
while (playThread != null){
try{
if((numBytesRead=audioInputStream.read(data)) == -1){//从输入流中读数据到data
break;
}
int numBytesRemaining=numBytesRead;
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){
try{ //帧数*一帧字节数,并将long型强制转换为int,不支持太大文件的播放.
audioFormat=audioInputStream.getFormat();
audioBytes=new byte[(int)(audioInputStream.getFrameLength()*audioFormat.getFrameSize())];
audioInputStream.read(audioBytes); //读入到audioBytes字节数组
}catch(Exception e){
System.out.println(e.toString());
repaint();
return;
}
}
int w=getSize().width;
int h=getSize().height-20;
int[] audioData=null;//将byte数组数据转换为int数组数据,便于绘制.
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奇字节LAB作低位字节处理
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次方
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 + -