
使用Java实现音频播放:
本文将通过设计和构建一个支持实时MP3,WAV和Ogg音频格式解码/播放的Java音乐播放器,来解释使用JavaSound API编写音频处理程序的想法和一般过程.
台式机的性能日益提高,Java虚拟机的优化技术也在不断取得突破,所有这些使得使用Java处理实时信号成为可能. 在本文中,通过设计和构建支持实时MP3,WAV和Ogg音频格式解码/回放的Java音乐播放器,描述了使用JavaSound API编写音频处理程序的想法和一般过程.
JavaSound是一个小型的低级API,它支持数字音频和MIDI数据的记录/回放. 在JDK 1.3.0之前,JavaSound是标准的Java扩展API,但是从Java 2.版本1.3.0开始,JavaSound包含在JDK中. 由于Java具有跨平台(操作系统和硬件平台)的特性,因此基于JavaSound的音频处理程序(包括本文中的程序)可以在实现Java 1.3+的任何系统上运行,而无需安装任何支持软件.
首先,JavaSound的体系结构
JDK的当前Java Sound API与Java Media Framework(JMF,Java Media Framework)一起发布. 主页位于java.sun.com/products/java-media/jmf/,适用于JDK 1.1和更高版本. 除了JDK实现的JavaSound API外,还有一个Tritonus开源JavaSound实现,其主页位于.
图1描述了JavaSound API的体系结构. 虚线表示Sun的JavaSound标准定义的API调用. 上面的虚线表示我们编写音频处理程序时要调用的API. JavaSound API包含在javax.sound.sampled和javax.sound.midi包中. 两条虚线之间的部分是JavaSound API的具体实现.

图1: JavaSound架构
就像上面用虚线指示的API具有统一的标准一样,在所有JavaSound实现中,图1中用虚线指示的SPI(服务提供商接口)也是统一的. SPI的作用是以插件形式提供自定义扩展模块. 只要我们提供与SPI兼容的插件扩展模块,我们就可以扩展音频处理程序的功能,而无需更改API. SPI包含在java.sound.sampled.spi和javax.sound.midi.spi包中.
例如,如果有一个只能播放WAV文件的程序,只要我们添加一个支持MP3文件解码的插件模块,就可以在此播放器程序中添加MP3播放器而无需更改其中的任何代码行播放器程序. 能力.
第二,JavaSound混合的原理
图2说明了JavaSound混合器的原理. 在处理输入音频的应用程序中,对于来自各种音频输入端口(例如麦克风,CD播放器,磁带播放器等)的信号,我们可以使用混音器控制输入混音,直到它们到达TargetDataLine,最后获得数字音频通过程序中的TargetDataLine输入流.

图2: JavaSound混音器
同样,在处理输出音频的应用程序中,混合器用于混合SourceDataLine中的一系列数据,并且处理后的信号可以输出到各种输出端口,例如扬声器和耳机. SourceDataLine是可以写入音频信号数字流的设备. 例如,我们可以从WAV文件读取内容并将其写入SourceDataLine,然后通过扬声器输出.
输入到调音台的信号可以来自剪辑. Clip是一种包含完整音频数据流或缓冲在内存中的完整音频数据流的设备. 在某些需要重复播放音乐片段的情况下,例如游戏中的背景音乐,编辑非常有用.
图3描述了JavaSound API中一些常用的类,接口及其关系. 图3所示的所有类和接口都是通过基本接口Line统一的. Line接口用于关闭/打开设备,注册事件器,并提供一些用于调节声音效果的对象,例如用于调节音量的对象. AudioSystem在JavaSound系统中充当工厂类的角色,提供了一系列静态方法. 我们使用这些静态方法来获取JavaSound系统默认配置的资源(所谓的静态方法是在直接调用方法的情况下不会创建AudioSystem实例的那些方法. )



图3: 常用的JavaSound类
顺便说一下,在JavaSound的默认配置的当前(JDK 1.4)实现中,输入声音来自本地声卡的麦克风,并且声音被输出到本地声卡的扬声器. 应该说,当前实现的对端口和混音器的JavaSound支持并不完美,但是对于许多应用程序,包括本文中的音乐播放器,JavaSound配置的默认实现就足够了.
三,音频数据和存储格式
采样的音频数据,即从TargetDataLine输入的数据或从SourceDataLine输出的数据必须符合音频格式标准. 音频数据格式选项由AudioFormat类封装. 主要选项包括: 编码方法,可以是PCM(脉冲代码调制,脉冲代码调制),MP3等;频道数;采样率;帧频;
音频数据可以多种格式保存到磁盘. 在JavaSound参考实现中,直接支持的文件格式包括WAV(Windows),AIFF(主要由Apple Macintosh使用)和AU(主要由UNIX使用). 音频文件的格式由AudioFileFormat类指定.
并非所有的音频数据格式都可以保存为任何音频文件格式(或从音频文件播放),具体取决于平台和操作系统的类型. 为简单起见,本文中的播放器仅考虑包含PCM单声道或立体声数据的WAV文件. 这是当前流行的音频数据/文件格式组合,通常用于CD质量的音频数据. 压缩的音频数据(例如MP3和Ogg Vorbis)通常具有自己的特殊存储格式(例如.MP3和.OGG),并且通常不以WAV / AIFF / AU格式存储.
四款设计音乐播放器
我们要编写的音乐播放器(图4)由表1中所示的几类组成. 鉴于事实是,通常需要大量代码来构建用户界面,而这些代码通常可以由IDE自动生成,以下仅是一些关键GUI元素的简要介绍,不会给出完整的代码.


图4: 播放器的用户界面
播放器的用户界面主要由带有菜单的JFrame框架,名为filenamesList的JList和几个JButton组成. 该框架具有私有的TestBase成员,其实例在GUIInit()方法的末尾使用pBase = new TestBase()语句进行初始化.
表1


用户界面中的按钮是使用类似于以下代码的代码创建的,其中addBttnIconText()是一种私有方法,将图标放置在按钮的文本标签上方. Java程序的用户界面与Windows界面非常不同. 建议读者使用Java开发工具随附的图标,或从Java图标库中下载它们(例如).

当用户单击按钮时,与该按钮相对应的xxxClick()事件处理函数开始执行. 播放器中有5个按钮视频播放器jar版,并且有5个相应的事件句柄: playClick(“播放”按钮),stopClick(“停止”按钮),pauseClick(“暂停”按钮),prevClick(“后退”按钮),nextClick( “前进按钮).
例如,当单击“播放”按钮时,playClick()句柄首先获取在JList中选择的文件,然后在TestBase实例中调用playFile()辅助方法以播放该文件. playClick()句柄的代码如下所示. 请注意,连接音乐文件及其所在目录的方法与操作系统无关.
1.void playClick(ActionEvent e){
2.String fileToPlay =(String)filenamesList.getSelectedValue();
4.pBase.playFile(searchDir +
5.System.getProperty(“ file.separator”)+ fileToPlay);
stopClick()和pauseClick()方法分别在TestBase中调用stop()和pause()方法. prevClick()和nextClick()句柄的任务要复杂一些. 首先,他们调用TestBase中的stop()方法来停止当前的播放操作,然后在JList中选择当前项目的上一个或下一个项目,最后调用playClick()来播放新选择的音乐文件,如下所示.
01.void prevClick(ActionEvent e){
03.filenamesList.setSelectedIndex(filenamesList.getSelectedIndex()-1);
06.void nextClick(ActionEvent e){
08.filenamesList.setSelectedIndex(((filenamesList.getSelectedIndex()+ 1)
09.%curPlayListLength);
五,播放音乐
TestBase类包含主要的播放逻辑. 例如,当用户单击“播放”按钮时,TestBase类中的play()方法开始执行.
play()方法首先确认播放器当前已终止而不是暂停. 然后,它检查这是否是第一个对play()的调用: 如果是,它将创建一个playerThread线程. 我们使用单独的线程播放音乐,因此无论播放器正在读取文件,解码还是将音频数据输出到扬声器,用户界面始终可操作.
启动线程后,play()方法将锁定静态同步同步对象,将stopd标志设置为false,然后通知等待线程(playerThread线程将在开始之前向静态同步对象等待提醒通知)播放音乐文件).
playerThread线程启动后,其run()方法开始运行. 该线程执行while循环,直到threadExit标志变为true. 在while循环中,线程首先等待“开始播放”信号(当用户单击“播放”按钮时),然后播放音乐. 表2列出了描述播放器状态及其含义的各种符号.



playMusic()方法使用JavaSound API播放当前选定的文件. 首先,您需要通过AudioSystem类获取AudioInputStream. 然后,使用AudioInputStream的getFormat()获得音频数据的格式. 在此基础上,我们尝试通过getLine()方法获得支持此格式的SourceDataLine. 如果要播放WAV文件,现在我们已解压缩了PCM格式的音频数据,则可以开始使用线对象播放音频.
1.ais = AudioSystem.getAudioInputStream(新文件(fileToPlay));
4.baseFormat = ais.getFormat();
5.line = getLine(baseFormat);
如果音频数据为压缩格式,例如MP3或Ogg,则必须首先将MP3 / Ogg转换解码为PCM. 解码主要包括三个步骤:
1. 创建解压缩结果的自定义AudioFormat(PCM编码),但保留与原始压缩流相同的采样率和通道信息.
2. 创建一个AudioInputStream,将原始AudioInputStream转换为新的AudioFormat格式.
3. 获取处理解码格式的SourceDataLine.
如下:
01.AudioFormat encodedFormat =新的AudioFormat(
02.AudioFormat.Encoding.PCM_SIGNED,
03.baseFormat.getSampleRate(),
05.baseFormat.getChannels(),
06.baseFormat.getChannels()* 2,
07.baseFormat.getSampleRate(),
09.ais = AudioSystem.getAudioInputStream(decodedFormat,ais);
10.line = getLine(decodedFormat);

getLine()方法的返回值是与参数中指定的AudioFormat兼容的SourceDataLine. 如果无法获得兼容的SourceDataLine,则getLine()返回null. 在getLine()方法中,我们首先创建并填充一个DataLine.Info结构,调用AudioSystem.getLine()方法,然后将信息结构传递给AudioSystem类工厂.
01.private SourceDataLine getLine(AudioFormat audioFormat){
03.DataLine.Info info =新的DataLine.Info(SourceDataLine.class,
06.res =(SourceDataLine)AudioSystem.getLine(info);
07.res.open(audioFormat);
在准备好AudioInputStream和SourceDataLine之后,playMusic()的其余任务已经非常简单: 使用循环从AudioInputStream读取数据,然后写入SourceDataLine.
01.int inBytes = 0;
02.while(((inBytes!= -1)&&(!stopped)&&(!threadExit)){
04.inBytes = ais.read(audioData,0,BUFFER_SIZE);
06.catch(IOException e){e.printStackTrace();}
08.int outBytes = line.write(audioData,0,inBytes);
10.if(已暂停)waitforSignal();
六,支持更多音频格式
假定所有.java文件都已在test目录中准备好,请执行javac * .java进行顺利编译,并执行java test.TestPlayer以启动图1中的播放器. 但是现在播放器只能播放有限的文件,因为JDK实现的JavaSound仅支持WAV,AIFF和AU. 但是,只要下载并安装相应的插件Jar文件,我们就可以使用JavaSound SPI向播放器添加对MP3和Ogg Vorbis的支持.
可以从JavaCraft()下载Java版本的Vorbis. 最新版本是0.0.12. JOrbis还有一个SPI包装器,这对于在JavaSound下透明运行是必要的,可以从JavaSound下载. VorbisSPI的最新版本是0.7.
为了支持MP3,JavaZoom还提供了与JavaSound兼容的纯Java,称为JavaLayer(),最新版本为0.2.0. 请注意,您要下载JavaLayer的J2SE版本,请勿下载J2ME版本.
解压缩下载的文件视频播放器jar版,并将所有Jar文件放在播放器所在的目录中. 使用以下命令启动播放器: java -classpath. ;. \ Jogg-0.0.5.jar;. \ Jorbis-0.0.12.jar;. \ Jl020.jar;. \ mp3sp.jar;. \ Vorbisspi0.6 .jar test.TestPlayer. 如果您下载的版本不同,则应相应更改启动命令. 将SPI扩展添加到播放器的类路径后,JavaSound将在运行时自动使用它们.
了解原理之后,可以参考学习MpegAudioSPI1.9.4,那里有很多地方可以学习和学习;
本文来自电脑杂谈,转载请注明本文网址:
https://www.pc-fly.com/a/bofangqi/article-178537-1.html
被发现核潜艇已经没有纯在的意义
十年96到06年