Java课程设计音乐播放器设计.docx

上传人:b****7 文档编号:8808544 上传时间:2023-02-01 格式:DOCX 页数:36 大小:1.88MB
下载 相关 举报
Java课程设计音乐播放器设计.docx_第1页
第1页 / 共36页
Java课程设计音乐播放器设计.docx_第2页
第2页 / 共36页
Java课程设计音乐播放器设计.docx_第3页
第3页 / 共36页
Java课程设计音乐播放器设计.docx_第4页
第4页 / 共36页
Java课程设计音乐播放器设计.docx_第5页
第5页 / 共36页
点击查看更多>>
下载资源
资源描述

Java课程设计音乐播放器设计.docx

《Java课程设计音乐播放器设计.docx》由会员分享,可在线阅读,更多相关《Java课程设计音乐播放器设计.docx(36页珍藏版)》请在冰豆网上搜索。

Java课程设计音乐播放器设计.docx

Java课程设计音乐播放器设计

程序设计课程设计

综合实验

 

音乐播放器

 

班级:

指导老师:

组员:

 

2014年12月2日

1程序功能描述

音乐播放器是一种用于播放各种音乐文件的多媒体播放软件。

我们以酷狗音乐播放器的操作界面为原型,设计一个实现播放、搜索、下载歌曲的Java音乐播放器。

此音乐播放器支持音乐格式较少,只有MID、WMA、MP3。

最后,为音乐播放器置入一些游戏,增强播放器的娱乐性。

 

2开发环境描述

IDE:

Eclipse(Luna)、netbeans

JDK:

1.8

图片处理:

Photoshop

 

3开发技术介绍

1)JavaSound:

JavaSoundAPI是JavaSE平台提供底层的处理声音接口。

使用JavaSoundAPI可以实现各种基于声音的应用,例如声音录制、音乐播放、音乐编辑等。

同时其还提供了第三方的扩展接口(SPI),实现各种音乐格式的解码与转码。

 

2)JavaZoom:

为了支持MP3的播放,必须为JavaSound扩展MP3的SPI支持库。

开源项目JavaZoom正是提供了一个兼容JavaSound的纯Java解码器。

引用:

jl1.0.1.jar、mp3spi1.9.5.jar、tritonus_share.jar

 

3)Jaudiotagger:

开源项目Jaudiotagger提供一个Java类库用于编辑音频文件的tag信息(附有此音频的歌手、标题、专辑、音轨长度等的信息)。

引用:

jaudiotagger-2.0.3.jar

 

4)Jsoup:

Jsoup是一款Java的HTML解析器,可直接解析某个URL地址、HTML文本内容。

它提供了一套非常省力的API。

引用:

jsoup-1.8.1.jar

 

5)Substance:

Swing自带提供了几种lookandfeel类,然而要设计一个非常精美的GUI界面,却相当麻烦。

使用javasubstance可以很简单地实现。

Substance里面有很多现成的非常漂亮的皮肤。

引用:

substance.jar

 

4详细设计

4.1功能模块划分

按结构化设计方法,划分出四个功能模块:

歌曲列表、播放控制、搜索及音乐库。

此四个模块正好对应酷狗用户界面的四部分。

酷狗音乐播放器如下:

Figure4.1.1Kugou

 

程序构建的包

main:

主入口

ui、ui.tool:

用户界面及其使用的一些工具类

song:

包含有歌曲、歌词信息的类

player:

播放相关的类

search:

搜索相关的类

 

程序结构图如下:

Figure4.1.2程序结构图

 

4.2用户界面设计

窗体(Frame):

窗体初始大小为975*670;内容面板(ContentPane)由播放面板(PlayPanel)、歌曲列表面板(PlayListPanel)、搜索面板(SearchPanel)、展示面板(ShowPanel)构成,内容面板的布局采用的是BoxLayout+Box,PlayListPanel和SearchPanel对应都绑定了一个工具条(ButtonToolBar)

程序引用了外包Substance设计观感

 

4.2.1歌曲列表面板

PlayListPanel由一个工具条(ButtonToolBarextendsJToolBar)、JPanel构成,其中JPanel采用CardLayout布局,JPanel加入了3个歌曲列表面板(SongListPanelextendsJScrollPanel)、1个应用面板(JScrollPanel)利用工具条的按钮切换显示面板

Figure4.2.11歌曲目录

歌曲列表面板(SongListPanel)-列表的实现:

利用JTree实现二级目录。

顾名思义,JTree是树状元件,它由众多节点构成,其中JTree需要一个根节点(root)。

关于节点,我们用可派生节点DefaultMutableTreeNode类(implementsTreeNode)即这种节点可以做“树干”也可以做“叶子”

 

1)利用一个节点构建一个JTree,该节点为根节点,即一级节点

其实我们要实现的歌曲列表是3级节点:

根节点、歌曲目录、歌曲文件,这里我们需要隐藏点根节点:

tree.setRootVisible(false);否则我们将看到3层目录

 

2)根节点加入节点歌曲目录节点(rootNode.add(aNode))

第2级节点为歌曲目录,可派生歌曲节点:

节点(TreeNode)的其中一个构造器是接受Object对象userObject

JTree是以节点的toString方法返回的字符串显示节点,而节点的toString是由UserObjcet的toString决定,所以用String来构建歌曲目录节点即可

 

3)歌曲目录节点应该有一个计算当前歌曲数目并在目录中显示的方法

目录节点计算其的子节点数,并更新到目录名

 

4)歌曲目录节点加入歌曲文件节点

加入方法与上面一样。

这里每个歌曲(File)是一个节点,不可派生子节点

上面说到每个节点在JTree显示的字符串,都是由该节点的UserObject.toString()决定,File的toString返回的是该文件的路径,

这里我们重写DefaultMutableTreeNode的toString让它返回歌曲名,所以构造了SongNode类(extendsDefaultMutableTreeNode)

 

5)弹出菜单

再做下面各种操作前,需要一个使用载体,我们利用弹出菜单来实现

Figure4.2.12弹出菜单

6)移除歌曲目录

因为用户只能选中第2、3级节点,这里需要判断当前选中的是第几级节点:

获取选中的路径TreePathpath=tree.getSelectionPath()(如果path==null可以不往下执行),通过path.getPathCount()来判断,第3级节点是返回值是3。

如果是第3级节点,需获得它的上级节点(即歌曲目录)

获取末端组件DefaultMutableTreeNodenode=(DefaultMutableTreeNode)path.getLastPathComponent()

获取上级节点DefaultMutableTreeNodeaList=node.getParent()

如果是第2级节点,可直接获取选中路径的末端组件

aList=(DefaultMutableTreeNode)path.getLastPathComponent();

这样保证都从歌曲目录节点操作,

再按以下次序进行判断:

1.如果当前目录是默认目录,不移除,可以通过当前节点在根节点的位置判断root.getIndex(aList)

2.如果当前目录含有歌曲,进行提示是否移除,可以获取该目录节点的子节点数目(getChildCount)或者该节点是否为“叶子”(isLeaf)

3.如果当前目录播放着歌曲,终止播放,这里后面再叙述。

4.最后移除,aList.removeFromParent();

 

7)清空歌曲目录

与移除目录类似,最后清空使用的方法aList.removeAllChildren();

 

8)删除歌曲

可以参考移除目录的实现,需要注意的是,要保证当前选中的节点是第3级节点,即歌曲文件,是第2级节点就不往下操作,删除方法同样是aSong.removeFromParent()

9)获取音频文件

通过JFileChooser打开个对话框,获取外部文件,并给其安装过滤器。

过滤器过滤出的格式为mid,mp3,wav

选择文件分为两种模式,1获取多个音频文件,2获取一个文件夹。

需设置JFileChooser的选择模式setFileSelectionMode(intparam)

关于第2种模式,获取了文件夹后,也要给文件夹进行过滤操作(直接判断或者安装过滤器)这里的过滤器是抽象类FileFilter,这里定义了一个AFilter(extendsFileFilter)

最后将这些files加入目录节点即可

 

10)鼠标右击选中当前节点

给JTree注册MouseListener.,先判断是否鼠标右击,再取与点击点坐标最近的节点tree.getPathForLocation(intx,inty)

应用面板(AppPanel)的实现:

应用面板用JScrollPane,加入多个按钮,一个按钮对应着Expandsion包附加的小游戏程序(Expandsion包导出游戏程序后,被删除)

 

以上,歌曲列表面板界面基本实现,注意每次对JTree操作后,请更新JTree的状态,tree.updateUI(),否则有可能出现Bug。

在我们实现歌曲播放面板操作功能时,与歌曲列表面板进行交互,会再往列表面板添加功能。

 

4.2.2播放控制面板

PlayPanel由于JavaSwing布局复杂,我们可以用Eclipse的WindowBuilder或者netbeans的Matisse可视化构建

PlayPanel由以下组件构成

标签:

歌曲名(songNameLabel)当前播放进度时间(currentTimeCountLabel)

当前播放歌曲总时间(audioTotalTimeLabel)

按钮:

上一首(backPlay)下一首(frontPlay)播放(Play)静音(voiceControl)

下载(download)标记(mark)分享(share)

这里用到的按钮,都用到图片;为简化代码,构建一个IconButton来定义上面的按钮

其它:

组合框(JComboBox)mode控制播放模式

滑块条(JSlider)voiceAdjust控制音量

进度条(TimeProgressBar)这里用到的进度条timerProgressBar由于要计时,所以也构建一个TimeProgressBar

Figure4.2.21播放控制面板

 

4.2.3搜索及展示面板

SearchPanel/ShowPanel的布局可以参考PlayListPanel,这里说下折叠面板效果的实现(下图选中的按钮)

折叠:

SearchPanel/ShowPanel均设不可见,再设置Frame的大小和刷新。

展开:

给Frame注册窗体状态监听器,如果用户按了最大化按钮,会产生一个事件给监听器,这里判断当前窗体的新状态是否为最大化,然后与折叠操作类似。

(也可以不用“最大化”按钮判断,可以设置一个新按钮作事件源)

Figure4.2.31搜索及展示面板

 

4.3播放功能实现

播放面板功能主要由BasicPlayer、HigherPlayer、TimeProgressBar,BasicPlayer实现的是底层操作(播放、暂停、继续播放、终止、获取音频总时间等)。

HigherPlayer(extendsBasicPlayer)处理面板间的交互,面板与BasicPlayer的交互。

TimeProgressBar绑定了一个Timer,作计时功能。

4.3.1播放歌曲

为实现播放功能,我们这里用了JavaSoundAPI,它可以实现各种基于声音的应用。

JavaSoundAPI的输入/输出相当于IO流,TargetDataLine/SourceDataLine接口对应输入/输出设备,要得到这个设备的对象,需要设备信息:

它是输入还是输出设备,它处理的音频数据格式-即编码格式,不是“WAV/MP3”等文件格式

AudioSystem在此过程中起着工厂类的作用

这里先关注SourceDataLine如何实现播放功能:

BasicPlayer中关于播放的属性

privateAudioInputStreamaudioInputStream;

publicSourceDataLinesourceDataLine;

publicURLaudio;

publicThreadplayThread;

1)获取audioURL

回到SongListPanel,在JTree已注册的MouseListener里增加响应mouseClicked的处理,进行判断,选取第3级节点。

HigherPlayer在load方法里获取这节点的userObect(即File),再转成URL,这里在HigherPlayer,议保存这个节点,因为节点很容易获取它所在的列表节点。

2)从指定的URL获取音频输入流及音频编码格式

先获取音频输入流AudioSystem.getAudioInputStream(audio),再获取其音频编码格式audioInputStream.getFormat()

Javax.Sound默认支持的编码格式有PCM_SIGNED、PCM_UNSIGNED、ALAW、ULAW,对于这些编码格式我们都不这么了解,只知道WAV与MID采用的是PCM_SIGNED

当要播放MP3档时,这里会报异常,因为Javax.Sound并不支持MPEG1L3编码(MP3采用此格式编码)

3)将MPEG1L3编码转换成PCM_SIGNED

首先要扩展Javax.Sound的解码能力,之后再进行转码。

Javax.Sound除了有实现声音处理的API外,同时它以SPI(服务提供接口)为基础,实现各种音乐格式的解码与转码,SPI以插件形式扩展了音频处理的能力,SPI随程序启动而被启动。

即我们只要给程序引入MP3的SPI支持库,这里用到的第3方支持库是JavaZoom,

获取其中的jl1.0.jar、mp3spil1.9.5.jar、tritonus_share.jar

因为程序解码能力扩展,所以上面不再报异常,接着往下转码

//MPEG1L3转PCM_SIGNED

if(audioFormat.getEncoding()!

=AudioFormat.Encoding.PCM_SIGNED){

audioFormat=newAudioFormat(AudioFormat.Encoding.PCM_SIGNED,

audioFormat.getSampleRate(),16,

audioFormat.getChannels(),

audioFormat.getChannels()*2,

audioFormat.getSampleRate(),false);

audioInputStream=AudioSystem.getAudioInputStream(audioFormat,

audioInputStream);

}

这里将audioFormataudioInputStream分别转换成PCM_SIGNED,对于此转码方法,我们作了搬运工

4)获取输出设备信息及对象

//根据上面的音频格式获取输出设备信息

DataLine.Infoinfo=newInfo(SourceDataLine.class,audioFormat);

//获取输出设备对象

sourceDataLine=(SourceDataLine)AudioSystem.getLine(info);

这里sourceDataLineextendsLine

5)打开输出数据管道并进行IO操作

打开输出管道sourceDataLine.open();

允许此管道执行数据I/OsourceDataLine.start();

到这里,我们从输入流读入数据,再将数据写入输出管道(输出管道会先进入混频器,再进入到端口,这里我们不管混频器,只要知道数据输入到扬声器)

最后,我们应该设置一个独立线程(playThread)启动播放过程,否则主线程会在播放结束前阻塞。

 

4.3.2暂停及继续播放

为BasicPlayer加入属性:

publicbooleanIsPause=true;//是否为暂停状态

publicbooleanNeedContinue;//当播放同一首歌曲是否继续播放状态

1)暂停

这里IsPause初始为true,是为了后面Play按钮控制使用的

上面我们用到了playTread线程启动播放,那么“暂停”只要让此线程进入阻塞状态即可,“继续播放”则是唤醒线程。

playTread线程执行过程需要占有锁旗标,只要让它释放此锁旗标就达到暂停效果

这个锁旗标(Oject)我们设为BasicPlayer这个对象本身。

(其实随便一个对象也可以)

记住wait(),notify()要在同步块中使用,synchronized(BasicPlayer.this){},否则报异常

在音频数据的I/O读写循环中,设置一个控制标记(IsPause),true时,进入暂停:

BasicPlayer.this.wait();NeedContinue=true;

 

这里不需要设置IsPause为false,我们play按钮是如下判断,当前状态是暂停,则播放,当前是播放(即不是暂停),则暂停。

 

2)继续播放

当用户点击相同的歌曲,或者暂停后,再点击play按钮时,继续播放:

方法与暂停播放相对

3)终止当前歌曲播放和播放新选中歌曲功能

BasicPlayer增加属性:

publicbooleanIsComplete;

终止当前播放:

即是销毁当前播放线程

如果当前歌曲播放完成,即线程run完,线程自动销毁

如果当前歌曲播放中,播放新歌曲,我们手工销毁当前播放线程,并初始化IsPause、NeedContinue、IsComplete,之后启动新线程播放新歌曲。

我们需要在HigherPlayer里记录当前播放的歌曲与加载的歌曲,判断两者是否是同一首歌曲。

如果这里用stop也有可能会产生Bug,不安全,我们想要终止当前线程,不一定要销毁,有点强暴,我们让线程执行完就可以,加入新标记booleanIsEnd,True时,完成这个线程(return)。

这样播放新歌曲时,过渡平滑些

4)Play按钮状态

上面说到的方法:

都是用于播放面板Play按钮的功能操作

点击Play按钮的5种状态:

1.载入歌曲为null时,没什么都不做

2.当前没播放歌曲,播放载入歌曲

3.当前播放着歌曲,让它暂停

4.当前播放歌曲已暂停,如果加载歌曲没变,让它继续播放

5.不管当前播放歌曲是否暂停,如果加载歌曲与播放歌曲不同,终止当前播放歌曲线程,播放载入歌曲

 

4.3.3音量控制

输出设备对象sourceDataLine有获取各种控制的方法

获取当前输出设备对象的浮点控制器对象,类型为总音量控制sourceDataLine.getControl(FloatControl.Type.MASTER_GAIN);

然后通过floatVoiceControl.setValue()/getValue(),设置/获取当前音量(db)音量大概范围为-80F~6F默认为0F

通过一个滑块组件(JSlider)设置其值

 

4.3.4播放模式

1)上一首/下一首

获取当前歌曲节点的位置(通过其父节点获取的),再指向上一个/下一个,然后加载此歌曲节点,手工触发play按钮

2)单曲播放、循环等模式

因为是播放完,之后进行播放模式操作,给BasicPlayer增加属性booleanIsComplete,判断当前是否播放完。

因为线程播放期间,一直阻塞,所以在线程最后设置IsComplte=true;

组合框获取当前模式的值,进行判断。

在当前歌曲播完后,这里可以先触发一下play按钮,成暂停状态,设置IsPause为true,等待下次播放,随后进行播放模式操作选择,这个与节点所在的位置有关。

 

4.3.5时间进度条

要想实现进度条,需要得到当前播放歌曲的播放时长,再通过一个计时器,设置进度条的值。

1)获取歌曲播放时长

每个音频文件都要个文件头记录音频信息(作者、采样率、时长等),引用外包jaudiotagger.jar解析音频,步骤如下:

获取音频文件

//AudioFileIO是org.jaudiotagger.audio包的类

AudioFilefile=newAudioFileIO.read(newFile(URI));

获取音频文件头

AudioHeaderaudioHeader=file.getAudioHeader();

获取音频总长度

inttimelength=audioHeader.getTrackLength();

这里的timelength是秒计,之后将timelength转成“0:

00”格式即可。

需要更新播放面板(PlayPanel)的当前歌曲总时间标签(audioTotalTimeLabel)

2)计时及更新进度条

这里构建了一个TimeProgressBar(extendsJProgressBar),其中绑定了一个计时器Timer

当播放歌曲前,更新初始化TimeProgressBar的状态(TimeProgressBar的两个最值为0,timelength),重置Timer,启动Timer。

暂停歌曲时,Timer阻塞。

继续播放时,Timer唤醒。

Timer对应有个线程,执行一次(或定期重复执行)它的任务Task。

Timer.schedule(TimerTasktask,longdelay,longperiod)。

给Timer安排一个任务,从指定延迟时间(delay)后执行task,之后按间隔时间(period这里是1s)执行。

每次执行Task,更新TimeProgressBar的值和当前播放进度时间标签currentTimeCountLabel,当计时时间等于当前歌曲播放时长时,终止Timer,放弃所有任务,Timer.cancel(),当本次任务会执行完。

暂停/继续播放时,可以参考歌曲的处理,来处理Timer,Timer也共享IsPause,最后也是阻塞/唤醒计时线程。

4.4歌词展示实现

4.4.1加载歌词文件

加载歌词文件的方式,我们分为两种方式

1.在加入歌曲文件时,直接判断歌曲文件所在目录是否有对应的歌词文件,同名判断(隐式加入)

2.用户方加入歌词文件(显式加入)

这里加入方法为歌曲文件一样,打开文件对话框让用户选择。

获取歌词文件数组后,与歌曲文件匹配:

为了进行匹配,我们需要记录下当前程序已加载的歌曲(Listsonglist),在程序加入歌曲时,把这些歌曲文件加入到集合即可。

删除歌曲时,集合也要将其删除

之后对加入的歌词文件进行匹配(同名匹配):

利用JDK8的新特性,可以将songlist转成数据流,挑选出满足条件(是否同名)的数据组成子集合,子集合中的元素即是与此歌词匹配的歌曲。

 

4.4.2解析歌词文件

观察下面的歌词文件(lrc),其实lrc是一种遵循特殊规范的文本文件

[ar:

陈奕迅]

[ti:

k歌之王]

[00:

13.32]我唱得不够动人你别皱眉

[00:

19.89]我愿意和你约定至死

它包含信息有歌手([ar:

])、标题([ti:

])、专辑([al:

])、歌词(时间-歌词键值对)

从Filelrc读取每一行

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 初中教育

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1