java sound api_Java Sound API

Java Sound API是javaSE平台提供底层的(low-level)处理声音接口。

例外,java也提供了简单的实用的高层媒体接口(higher-level) - JMF(Java Media Framework)。

Java Sound API 将需要处理的数字音频分为:simpled-audio和midi,

分别提供Package来处理它们:

javax.sound.simpled

javax.sound.midi

同时SOUND API还提供了第三方的扩展接口:

javax.sound.simpled.spi

javax.sound.midi.spi

*注:spi : service provider interface

Sampled Audio

采样音频(simpled-audio)不仅包含从模拟信号采样来的数字音频,还包括电脑合成的。

称作digital-audio更为合适。

为了能够让设备播放采样声音,程序需要处理 audio input, output device, audio data buffers。

还有混音处理(mix multiple streams of audio into one stream)。

SOUND API 可以使用3种方式传输声音数据:stream, buffered fashion, in-memory unbuffered fashion。

第三种方式适合数据量不大,能够一次载入的所有数据的情形。这样,声音的响应较快,循环和随机定位也会很简单。

使用SOUND API播放声音至少需要3样东西:

lformatted audio data,

la mixer,

la line.

Mixer

调音台

technically the Mixer itself is also a kind of Line

Line

音频数据管道。

Clip extends Line

将需要播放的音频数据装载进来。

preloads audio data from a sound file into clips

A Clip is a data line into which audio data can be loaded prior to playback. Because the data is

pre-loaded rather than streamed, the clip‘s duration is known before playback, and you can choose any

starting position in the media. Clips can be looped, meaning that upon playback, all the data between two

specified loop points will repeat a specified number of times, or indefinitely.

SourceDataLine extends Line

accept real-time stream of audio data

feed audio to the Mixer

A SourceDataLine receives audio data for playback. It provides methods for writing data to the

source data line‘s buffer for playback, and for determining how much data the line is prepared to receive

without blocking.

TargetDataLine

A TargetDataLine receives audio data from a mixer. Commonly, the mixer has captured audio data

from a port such as a microphone; it might process or mix this captured audio before placing the data in

the target data line‘s buffer. The TargetDataLine interface provides methods for reading the data

from the target data line‘s buffer and for determining how much data is currently available for reading.

Port extends Line

simple Line

Line接口的继承关系图

361273_1.png

AudioSystem

AudioSystem提供音频资源的访问服务。

通过AudioSystem,可以知道什么样的资源可以被识别。

可从AudioSystem获得的资源:

lMixers, AudioSystem类可以提供一张已经安装的Mixer列表

lLines

lFormat conversions

lFiles and streams

Mixer的获得

Mixer.Info

AudioSystem.getMixerInfo():Mixer.Info

可以获得一张Mixer信息列表。

每个Mixer.Info包含如下关键信息:

lName

lVersion

lVendor

lDescription

我机器上的Mixer列表,WinXP,JDK_1.4.2

[INFO 0]

INFO.NAME:Java Sound Audio Engine

INFO.VERSION:1.0

INFO.VERDOR:Sun Microsystems

INFO.DESCRIPTION:Software mixer and synthesizer

[INFO 1]

INFO.NAME:Microsoft ?ù??????÷

INFO.VERSION:Unknown Version

INFO.VERDOR:Unknown Vendor

INFO.DESCRIPTION:No details available

[INFO 2]

INFO.NAME:Realtek AC97 Audio

INFO.VERSION:Unknown Version

INFO.VERDOR:Unknown Vendor

INFO.DESCRIPTION:No details available

[INFO 3]

INFO.NAME:Realtek AC97 Audio

INFO.VERSION:5.10

INFO.VERDOR:Unknown Vendor

INFO.DESCRIPTION:Unknown Description

获取Mixer

AudioSystem.getMixer( MixerInfo ):Mixer

如果只从Mixer.Info提供的信息无法确定需要的Mixer,

不妨创建出所有的Mixer,使用时检查它们的能力,使用合适那个。

例如,你可能需要一个Mixer,能够将混音好的数据同时写入一定数目的目标数据管道(TargetDataLine).

使用Mixer.getMaxLines(Line.Info info):int来了解Mixer的输出能力。info就是指定的TargetDataLine

获得指定类型Line

2种方法获得Line

l直接由AudioSystem获得,AudioSystem.getLine( Line.Info ):Line

l由Mixer获得

从AudioSystem直接获得Line

static Line AudioSystem.getLine( Line.Info )

不同于Mixer.Info,Line.Info不是文本信息,而是Line的类信息。

Line.Info是抽象类,所以使用它的子类DataLine.Info,Port.Info。

下面是通过Line.Info获得Line的示例:

TargetDataLine line;

DataLine.Info info = new DataLine.Info(TargetDataLine.class,

format); // format is an AudioFormat object

if (!AudioSystem.isLineSupported(info)) {

// Handle the error.

}

// Obtain and open the line.

try {

line = (TargetDataLine) AudioSystem.getLine(info);

line.open(format);

} catch (LineUnavailableException ex) {

// Handle the error.

//...

}

Port.Info定义一系列静态的Port.Info对象,MICROPHONE,SPEAKER,etc.

从Mixer获得Line

getSourceDataLine()

getTargetDataLine()

getLine()

AudioSystem对象模型

361273_2.png

AudioPermission

音频资源访问许可。

利用JAVA-SOUND-API播放声音

可以使用2种Line来播放声音,Clip,SourceDataLine。

Clip一次载入需要播放的声音资源,而SourceDataLine以流的方式传输声音数据。

使用Clip

当使用getLine()获得Clip后,还要保证其他的程序在你播放前不能获取它,调用open()方法独占它:

void open( AudioInputStream stream );

void open( AudioFormat, byte[] data, int offset, int bufferSize );

Clip默认从音频的开头开始播放,除非使用setFramePosition(),setMicroSecondPosition()设定其他位置。

Clip.start()播放,Clip.stop()暂停。

getLevel(),获得声音高度。

isActive(),Clip是否正在播放。

使用SourceDataLine

open(AudioFormat),打开source dataLine,但不指定数据,使用默认的buffer size。

open(AudioFormat, bufferSize),指定buffer size.

合理设置buffer size,保证开始载入的延时能够被接受,又尽量减少IO访问。

open()之后,调用start()容许SourceDataLine一有数据就开始播放,使用write()不停的输入数据。

void write( byte[] b, int offset, int length );

SourceDataLine开始播放后,向Mixer传输数据,当Mixer开始向target传输数据时,SourceDataLine产生一个START事件。

这是SourceDataLine被认为是活动的(active)。

isRunning()表明Line是否start()了。

isActive()表明Line是否开始播放。

write()方法向buffer size中写入数据,如果buffer已满,还剩下一些数据,该方法会阻塞;否则,是不阻塞的。

可以使用DataLine.available()知道buffer size还能写入多少数据。

事实上,可以另开线程去使用write(),而不用考虑阻塞的问题。

drain()方法在所有数据播放完后返回。

所有在写完数据后,调用drain(),到它返回时再是否Line。

line.write(b, offset, numBytesToWrite);

//this is the final invocation of write

line.drain();

line.stop();

line.close();

line = null;

flush()清空buffer中的剩余数据,Line在stop时才能调用。

有如下情形,Line会产生STOP事件:

l调用drain()

l调用stop()

l调用flush()

l输出完旧的数据,而新的数据未到时。

STOP事件意味着isActive()返回false.

start()调用之后,isRunning()都会返回true,知道stop()被调用。它不是依据STOP事件产生返回值的。

而isActive()是依据START和STOP事件的。

监视Line的状态

使用LineListener响应Line的事件。

void Line.addLineListener( LineListener );

当调用open(),close(),start(),stop()会产生OPEN,CLOSE,START,STOP事件。

多个Line同步播放

有些Mixer提供方便的同步功能,对一组Lines使用open(),close(),start(),stop(),保证它们的同步。

可以使用如下方法,检查Mixer是否支持同步功能:

boolean isSynchronizationSupported( Line[] lines, boolean maintainSync )

第二个参数表明同步精度,是采样同步,还是只是start(),stop()保持同步,并不维护播放过程同步。

AudioFormat

音频采样的格式,不是音频文件的格式。

l编码技术,一般都是PCM( pulse code modulation )

l声道数目(1,单声道;2,双声道;等等)

l采样频率sample rate

l样本的位数number of bits per sample

l帧速率Frame rate

lFrame Size in bytes

lByte Order( big-endian or little-endian )

AudioFileFormat:

音频文件格式。

The file type( WAV,AIFF,etc )

The file length in bytes

The length, in frames, of the audio data contained in the file

An AudioFormat that specifies data format of the audio data in the file

AudioInputStream extends InputStream

无须考虑文件的格式,就能操作Samples。

读取音频文件

AudioSystem提供2中方法读取音频文件:

l根据音频文件中音频数据的格式信息

l使用一个指定了音频数据格式的流

使用如下方法获得音频文件中音频数据的格式信息:

static AudioFileFormat getAudioFileFormat(File);

static AudioFileFormat getAudioFileFormat(InputStream);

static AudioFileFormat getAudioFileFormat(URL);

利用如下方法获得第二种方法提到的音频数据流:

static AudioInputStream getAudioInputStream(File)

static AudioInputStream getAudioInputStream(InputStream)

static AudioInputStream getAudioInputStream(URL)

读取音频文件数据的步骤:

1)获得AudioInputStream对象

2)创建一个字节数组,存放一次读入的数据块

3)不断地从audio流中读入数据,播放或处理数据。

示例代码如下:

int totalFramesRead = 0;

File fileIn = new File(somePathName);

// somePathName is a pre-existing string whose value was

// based on a user selection.

try {

AudioInputStream audioInputStream =

AudioSystem.getAudioInputStream(fileIn);

int bytesPerFrame =

audioInputStream.getFormat().getFrameSize();

// Set an arbitrary buffer size of 1024 frames.

int numBytes = 1024 * bytesPerFrame;

byte[] audioBytes = new byte[numBytes];

try {

int numBytesRead = 0;

int numFramesRead = 0;

// Try to read numBytes bytes from the file.

while ((numBytesRead =

audioInputStream.read(audioBytes)) != -1) {

// Calculate the number of frames actually read.

numFramesRead = numBytesRead / bytesPerFrame;

totalFramesRead += numFramesRead;

// Here, do something useful

// with the audio data that‘s

// now in the audioBytes array...

}

} catch (Exception ex) {

// Handle the error...

}

} catch (Exception e) {

// Handle the error...

}

写音频文件

通过下列方法知道AudioSystem支持哪些音频文件格式写入:

static boolean isFileTypeSupported( AudioFileFormat.Type,AudioInputStream );

static AudioFileFormat.Type[] getAudioFileTypes();

static AudioFileFormat.Type[] getAudioFileTypes(AudioInputStream);

利用AudioSystem.write()方法向文件写入指定格式的音频数据:

static int write( AudioInputStream, AudioFileFormat.Type, File );

文件或数据格式转换

“Java Sound Programmer Guide” – chapter 7

Audio File Format Convertion

Audio Data Format Convertion

PCM

PCM脉冲编码调制是Pulse Code Modulation的缩写。

PCM通过抽样、量化、编码三个步骤将连续变化的模拟信号转换为数字编码。

PCM是数字音频中最佳的保真水准,近似看成“无损”编码。

PCM编码的优点是音质好,缺点是数据量大。

JAVA SOUND API对于其它编码格式,在播放前都会转换成PCM格式。

DAC:digital-to-analog converter,数模转换器

Decibel:分贝。pl.decibels

PAN:声象,该通道信号在左右音箱之间的立体声位置。

GAIN:增益

REVERB:数字混响。

Acoustics:声学

资源

《Java Sound programmer guide》

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/245098.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

取pi的前8位的解压密码_两种方式实现取16位变量的高低8位, 不严谨对比

程序如下&#xff0c;第一种方式是强制指针转换&#xff0c;再取结构体成员&#xff1b;第二种方式是简单的移位。前面这种写法得考虑大小端序, 后者不用管.#include <stdio.h>#define hi8(x) ((( struct { unsigned char l; unsigned char h; } *)(&x))->h) …

java实现的小程序_Java实现 微信小程序 + 消息推送

实现效果&#xff1a;下面要显示五个字段接下来&#xff0c;参照官方文档&#xff0c;一步步实现&#xff1a;一、官方给出请求示例、返回示例二、根据上面编写实体类(1)请求参数Datapublic class SendTemplateReq {/*** 接收者(用户)的 openid*/private String touser;/*** 所…

vb excel 整行删除_Excel中常用的批量处理都不掌握,那就真的Out了

针对一些有规律&#xff0c;能批量处理的数据&#xff0c;必须采用批量处理的方法&#xff0c;否则对于工作效率就会有很大的影响。今天我们来学习的内容是Excel中的6个批量处理技巧。一、Excel批量技巧&#xff1a;批量求和。目的&#xff1a;按照“季度”和“产品”两个维度计…

eclipse找不到dynamic_Eclipse Juno在Dynamic Web Project中没有JSP(但其他...

简短的问题是,在创建动态Web项目(1.6 jdk)时,我可以看到要创建的所有文件类型,但jsp没有选项.当我检查文件关联时添加到那里,没有可供选择的JSP编辑器.稍微长一点的版本是我只想编辑JSP文件,我安装了Juno EE版本,它说安装了Web工具平台,一切正常.然而,虽然一切正常,但文件关联中…

exe编辑器_【小功能】Unreal Editor中调用exe

后续文章更新移步→微信公众号“虚幻社区”&#xff08;mantra-xhsq&#xff09;&#xff0c;您的支持是我创作的动力。在程序界混&#xff0c;哪能碰上不改需求的策划 --Mantra最近遇到了一个奇葩的需求&#xff0c;在Unreal Editor的Toolbar中添加一个快捷键&#xff0c;可以…

java bitset用途_BitSet的用法

1&#xff0c;BitSet类大小可动态改变, 取值为true或false的位集合。用于表示一组布尔标志。此类实现了一个按需增长的位向量。位 set 的每个组件都有一个 boolean 值。用非负的整数将 BitSet 的位编入索引。可以对每个编入索引的位进行测试、设置或者清除。通过逻辑与、逻辑或…

html select选择事件_按键精灵的Html系列命令实战讲解

金猪脚本(原飞猪脚本)以按键精灵教学为主,涉及UiBot&#xff0c;Python,Lua等脚本编程语言,教学包括全自动办公脚本,游戏辅助脚本,引流脚本,网页脚本,安卓脚本,IOS脚本,注册脚本,点赞脚本,阅读脚本以及网赚脚本等各个领域。想学习按键精灵的朋友可以添加金猪脚本粉丝交流群:554…

java多线程意义_Java多线程学习之多线程的概念及意义

Java的线程机制&#xff0c;则是由执行程序表示的单一进程创建的任务(拗口&#xff01;)&#xff0c;注意&#xff0c;是在单一进程里面创建多个任务&#xff0c;不同于操作系统分叉外部进程。由于所有的任务在同一个进程内&#xff0c;任务之间会相互干涉(例如操作同样的对象&…

java 验证码_java学习之web基础(6):使用Response的输出流在页面输出验证码

package 输出并且我们可以写一个简单的网页&#xff0c;来实现点击更新验证码<!DOCTYPE html>

java socket编程实现聊天程序_java Socket编程 聊天程序 服务器端和客户端

[java]代码库package com.gufengxiachen.sthreadchatapp;/*** author GUXIA*/import java.io.BufferedReader;import java.io.DataInputStream;import java.io.DataOutputStream;import java.io.InputStream;import java.io.InputStreamReader;import java.io.OutputStream;imp…

电商前台模板中文html5_跨境电商平台上产品如何上传?虾皮新版批量上传工具使用指南分享...

大家好&#xff0c;这里是天师跨境&#xff0c;今天来为电商新人们解答一下关于如何在跨境电商平台上上传产品的疑惑&#xff0c;顺便介绍一下虾皮跨境平台的新版批量上传工具是如何使用的。在跨境电商平台上开店的新手们在入驻成功后&#xff0c;一般最先面临的问题就是上传产…

移动端 关闭浏览器事件_前端开发中什么是移动端点透事件?

点透事件&#xff1a;是指两个元素其中一个元素具有默认的点击事件&#xff0c;当我们让不具有点击事件的元素隐藏起来&#xff0c;会触发另一个元素的点击事件&#xff0c;这种行为被称之为点透事件。如下图所示&#xff1a;当我们给div元素添加touchstart事件让div元素隐藏起…

java web 线程数_Java Web应用调优线程池

最简单的单线程我们先从基础开始。无论使用哪种应用服务器或者框架(如Tomcat、Jetty等)&#xff0c;他们都有类似的基础实现。Web服务的基础是套接字(socket)&#xff0c;套接字负责监听端口&#xff0c;等待TCP连接&#xff0c;并接受TCP连接。一旦TCP连接被接受&#xff0c;即…

清除浏览器缓存之后为什么还是显示旧的html页面_Web缓存控制策略详解

管理Web缓存的最常用和最有效的方法之一是通过Cache-Control HTTP标头&#xff0c;由于此标头适用于Web页面的缓存&#xff0c;这意味着我们页面上的所有内容都可以具有非常精细化的缓存策略。通过各种自定义策略&#xff0c;我们控制的策略就可以变得非常复杂和强大。Cache-Co…

js二维数组_Javascript数组

数组的概念&#xff1a;引用类型的对象。本质&#xff1a;内存中存储多个数据的空间&#xff0c;再取个名字。数据结构&#xff1a;数据结构不同&#xff0c;擅长的操作不同。数组特点&#xff1a;便于数据的查找与维护。数组的创建&#xff1a;方法1&#xff1a;var 数组名【元…

java jtextfield 事件_JAVA JTextField事件处理

初学JAVA&#xff0c;笔记&#xff1a;package windows;import javax.swing.*;import java.awt.*;import java.awt.event.*;class WindowFlow extends JFrame implements ActionListener{private static final long serialVersionUID 1L;JTextField text1,text2;WindowFlow(St…

js封装函数_JavaScript基础-如何封装函数来改变元素的位置

点击右上方红色按钮关注“小郑搞码事”&#xff0c;每天都能学到知识&#xff0c;搞懂一个问题&#xff01;大家好&#xff01;我是/小郑搞码事/的小郑今天给大家分享JavaScript的基础知识-改变元素的位置。没错&#xff0c;用JS实现过动画的同学都应该了解一点&#xff0c;简单…

python查找指定字符所在行号_python查找字符串中某个字符

本文收集整理关于python查找字符串中某个字符的相关议题&#xff0c;使用内容导航快速到达。内容导航&#xff1a;Q1&#xff1a;Python里统计一个字符串中另一个字符串的个数答案为3(用正则)&#xff1a;1234>>>importre>>>sabababab>>>len(re.fin…

java jai create 方法_使用JAI扩展Java Image的功能

Java Image功能一直都在增强&#xff0c;但是向磁盘写一个图像文件或者返回一个PNG或JPEG依然比较难实现。但是我们可以使用Java Advanced Imaging(JAI)API来解决这个问题。JAI可以从SUN的Java站点下载&#xff0c;它包含在JDK 1.4的javax.imageio包中。要安装JAI&#xff0c;你…

python实现rm_python winrm模块使用

使用session方法###import winrmswinrm.Session(http://10.10.60.14:5985/wsman,auth(administrator,password))rs.run_ps(dir)rs.run_cmd(cd /d d: & test.bat)print r.std_outprint r.std_err使用Protocol方法###import winrmconn winrm.Protocol(endpointhttp://10.10…