int numBytesRead; //Cache the number of bytes we have read while (recording) { //Read in some data from the line //Read will return -1 if it encounters errors if((numBytesRead = line.read(data, 0, bufferLengthInBytes)) == -1) { break; }
//Once we read in the data, we'll write it to an //audio output stream out.write(data, 0, numBytesRead); } */ /*
//Convert the output stream back to a byte[] byte[] audioBytes = out.toByteArray();
//Make a ByteArrayInputStream from the byte[] ByteArrayInputStream bais = new ByteArrayInputStream(audioBytes);
//Request an AudioInputStream from the AudioSystem //passing in the byte stream, audio format, and length audioInputStream = new AudioInputStream(bais, format, audioBytes.length/frameSizeInBytes);
AIFC AIFF AU SND WAV 我们需要提供输出文件和文件类型常量。 我们将假设调用方法将为我们指定 AudioFileFormat.Type 类. 下面是 save 方法的代码:
public boolean saveToFile(File file, AudioFileFormat.Type fileType) throws Exception { //Reset to the beginning of the captured data audioInputStream.reset();
//Notify if an error has occurred return (AudioSystem.write(audioInputStream, fileType, file) == -1); }
1.获得输出的途径 SourceDataLine line=AudioSystem.getLine()2.constuct a sound format AudioFormat format = ... 这个format许要和你采集是的format一致 3.open line line.open(format) 4.line.writeByte(byte[] b)具体的可以看sun的sound api 详情http://java.sun.com/products/java-media/sound/index.html这样采集的是输入吗?我没试过,以前想写这方面东西是找了很多资料
IAudioRecorder 接口非常象播放音频中演示的 IAudioPlayer,但它用于录制而不是回放。
与 IAudioPlayer 一样,IAudioRecorder 接口仅包含很通用的方法(例如,startRecording、stopRecording 和 save),
因此简化了使用并封装了特定于 Java Sound 的功能。
虽然关于播放音频的一章与关于录制的本章之间有许多相似之处,但在实现方面却有许多很重要的不同之处。
首先,没有简单的对象能象 Clip 简单地播放音频那样来录制声音。
结果,我们不得不直接同 I/O 流、线路、字节数组和音频数据转换等打交道。
在 AudioPlayer 示例中,我们学习了如何从给定的声音文件中检索音频格式。
然而在 AudioRecorder(IAudioRecorder 的基本实现)中,我们控制用于录制实际音频的设置。
由于一旦录制了音频就难以更改音频格式,所以这需要更多地关注音频设置。
每当需要弄清音频术语或概念时,请您参考数字音频速成课程。
*/
/*
接口 第 2 页(共12 页)
下面介绍 AudioRecorder 接口。AudioRecorder 接口与 AudioPlayer 之间有一点不同,
不同之处在于这个类需要考虑音频格式。对于 AudioPlayer,根据从读入的音频数据中检索的格式,
从 AudioSystem 类检索线路。
然而,在音频录制时,AudioRecorder 将控制录制音频所用的格式。
下面是 AudioRecorder 接口代码:
*/
public interface IAudioRecorder
{
/* start recording */
public void startRecording();
/* stop recording */
public void stopRecording();
/* reset all audio buffers, clear recording */
public void reset();
/* set AudioFormat used to record the audio */
public void setAudioFormat();
/* retrieve audio format used to record the audio */
public AudioFormat getAudioFormat();
/* set the default audio format, non-compressed
CD-quality settings */
public void setDefaultAudioFormat();
/* save the cached recording to a file */
public boolean
saveToFile(File file, AudioFileFormat.Type fileType);
}
/*
标准音频设置 第 3 页(共12 页)
对于缺省 AudioFormat,我们将使用 CD 音频设置和 WAV 文件格式以使示例简单。
下面是缺省音频格式的规范:
编码:带正负号的 PCM
采样率:44.1 kHz(CD 音质)
采样大小:16 位或两个 8 位字节(CD 音质)
声道数:两个或立体声(CD 音质)
帧大小:32 位或 4 字节(16 位采样大小 * 2 声道 = 每字节 32 位/8 位每字节 = 4 字节)
帧速率:44.1 kHz(采样率)
大尾数法:否
接下来,我们将为 IAudioRecorder 接口中的缺省音频格式声明 public static final 变量。下面是格式:
*/
public static final AudioFormat DEFAULT_AUDIO_FORMAT = new AudioFormat
(
//Encoding
AudioFormat.Encoding.PCM_SIGNED,
//Sample rate
44100f,
//Sample size in bytes
2,
//Number of channels
2,
//Frame size
4,
//Frame rate
44100f,
//Big endian
false
);
/*
除了我们必须实例化一个 AudioFormat 对象,而不是从 AudioInputStream 检索它之外,
检索输入 Line 的过程与检索 Clip 的过程相同。要检索一个输入 Line,请完成下列步骤:
实例化 AudioFormat 对象。
实例化 DataLine.Info 对象,该对象引用适当的 AudioFormat 并指定请求的 Line 类型。
从 AudioSystem 请求 Line。
与 AudioPlayer 示例相同,我们将请求一个 TargetDataLine 实例来接收音频输入而不是直接实例化 TargetDataLine。
在有了 TargetDataLine 实例之后,需要打开它以完成初始化。
与回放示例相同,AudioSystem 类返回一个缺少内容的容器。
另外,AudioRecorder 被设计成除非被覆盖,否则使用 DEFAULT_AUDIO_FORMAT。
下面是代码:
*/
//Create a DataLine.Info object with a TargetDataLine and the default format
DataLine.Info info = new DataLine.Info(TargetDataLine.class, format);
//Request the line from the AudioSystem
line = (TargetDataLine) AudioSystem.getLine(info);
//Open the line to complete the instantiation
line.open(format, line.getBufferSize());
/*
TargetDataLine 中的读方法 第 5 页(共12 页)
一旦提供了音频,我们就需要使用 TargetDataLine 接口中的 read 方法读取并储存音频数据。
让我们查看 read 方法以了解如何捕获音频输入:
public int read(byte[] b, int offset, int length)
byte[] b:音频数据输入被写入这个 byte[]。
状态 int 是由 read 方法返回的,因此必须传入 byte[] 以使它只具有单个返回类型。
int offset:指定数组内的偏移量以开始写音频。
当在缓冲区中已有数据并且您想将新数据添加到已有数据的结尾时,可以使用偏移量。
对于我们简单的音频录制器用途,偏移量将始终为零。
这将新捕获的音频数据放在缓冲区的开始处。
int length:指定从音频输入读取的字节数。在从输入读取 length 个字节以前,该方法会一直阻塞。
因此,read 方法应该在其自己的线程中执行;否则,将冻结该接口。
假设 AudioRecorder 被正确线程化(但我不会详细讨论线程化,因为它超出本教程的范围)。
检查示例源代码(可以在参考资料中获取)以了解更多信息。
*/
/*
准备检索的字节数组 第 6 页(共12 页)
首先,我们需要计算传入 read 方法中的 byte 数组的大小。这是通过下列计算完成的:
//Frame size
int frameSizeInBytes = format.getFrameSize();
//The number of frames = the size of the buffer
int bufferLengthInFrames = line.getBufferSize() / 8;
//Number of frames * frame size = total bytes
int bufferLengthInBytes = bufferLengthInFrames * frameSizeInBytes;
//Make a new byte[] the size of the AudioBuffer
byte[] data = new byte[bufferLengthInBytes];
接下来,我们实例化一个输出流以将 byte 数组写入。
用这种方法,如果我们进行后续读取,则可以写入到输出流而不需要为数据管理编写更多代码。
ByteArrayOutputStream out = new ByteArrayOutputStream();
*/
/*
读取音频数据并对其进行高速缓存 第 7 页(共12 页)
现在,我们已经准备好读入音频。可以通过调用 TargetDataLine 中的 read 方法读取音频数据。
read 方法在 while 循环中,因此我们可以连续地录制而不用创建一个非常大的 byte[]。
从 TargetDataLine 中读取的数据将被写到 ByteArrayOutputStream 进行存储。
如果 read 方法返回 -1(表示错误),则我们还需要执行检查以中断循环。
下面是代码:
int numBytesRead; //Cache the number of bytes we have read
while (recording)
{
//Read in some data from the line
//Read will return -1 if it encounters errors
if((numBytesRead = line.read(data, 0, bufferLengthInBytes)) == -1)
{
break;
}
//Once we read in the data, we'll write it to an
//audio output stream
out.write(data, 0, numBytesRead);
}
*/
/*
将 ByteArrayOutputStream 转换成 AudioInputStream 第 8 页(共12 页)
接下来,我们将把 ByteArrayOutputStream 转换成 AudioInputStream。这样做有两个原因:
将音频保存到一个文件
将音频缓冲区保存到文件之前回放它
下面是用于转换的代码:
//Convert the output stream back to a byte[]
byte[] audioBytes = out.toByteArray();
//Make a ByteArrayInputStream from the byte[]
ByteArrayInputStream bais = new ByteArrayInputStream(audioBytes);
//Request an AudioInputStream from the AudioSystem
//passing in the byte stream, audio format, and length
audioInputStream =
new AudioInputStream(bais, format, audioBytes.length/frameSizeInBytes);
*/
/*
将音频缓冲区保存到文件 第 9 页(共12 页)
既然我们已经有了 AudioInputStream,则我们可以调用 AudioSystem 中的 write 方法以将缓冲区保存到文件。
在保存该文件之前,我们需要指定 AudioFileFormat。AudioFileFormat 包含下列信息:
AudioFormat
AudioFileFormat.Type
AudioFileFormat.Type 是 AudioFileFormat 的一个内部类,它定义下列文件类型的全局常量:
AIFC
AIFF
AU
SND
WAV
我们需要提供输出文件和文件类型常量。
我们将假设调用方法将为我们指定 AudioFileFormat.Type 类.
下面是 save 方法的代码:
public boolean saveToFile(File file, AudioFileFormat.Type fileType)
throws Exception
{
//Reset to the beginning of the captured data
audioInputStream.reset();
//Notify if an error has occurred
return (AudioSystem.write(audioInputStream, fileType, file) == -1);
}
*/
/*
支持的文件类型 第 10 页(共12 页)
AudioFileFormat.Type 常量对应的文件类型不是保证受支持的。
您可以通过使用 isFileTypeSupported(AudioFileFormat.Type type) 方法询问 AudioSystem 类来确定受支持的文件类型。
*/
/*
回放音频缓冲区 第 11 页(共12 页)
这个资料谈及的是如何从输入音频流中捕获音频数据,我非常想从输出的音频流中捕获音频数据,也就是说当任意 一个播放软件在播放音乐的时候,我把它发往声卡的音频流截获。暂不结贴,期待更多信息。请大家共同探讨!
SourceDataLine line=AudioSystem.getLine()2.constuct a sound format
AudioFormat format = ...
这个format许要和你采集是的format一致
3.open line
line.open(format)
4.line.writeByte(byte[] b)具体的可以看sun的sound api 详情http://java.sun.com/products/java-media/sound/index.html这样采集的是输入吗?我没试过,以前想写这方面东西是找了很多资料
import java.io.IOException;
import java.util.ArrayList;import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.FloatControl;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.SourceDataLine;
import javax.sound.sampled.UnsupportedAudioFileException;public class SoundPlayer {
private String filename;
private Position curPosition;
private final int EXTERNAL_BUFFER_SIZE = 524288; // 128Kb
enum Position {
LEFT, RIGHT, NORMAL
};
public SoundPlayer(String wavfile) {
filename = wavfile;
curPosition = Position.NORMAL;
}
public SoundPlayer(String wavfile, Position p) {
filename = wavfile;
curPosition = p;
}
public void run() {
File soundFile = new File(filename);
if (!soundFile.exists()) {
System.err.println("Wave file not found: " + filename);
return;
}
AudioInputStream audioInputStream = null;
try {
audioInputStream = AudioSystem.getAudioInputStream(soundFile);
} catch (UnsupportedAudioFileException e1) {
e1.printStackTrace();
return;
} catch (IOException e1) {
e1.printStackTrace();
return;
}
AudioFormat format = audioInputStream.getFormat();
SourceDataLine auline = null;
DataLine.Info info = new DataLine.Info(SourceDataLine.class, format);
try {
auline = (SourceDataLine) AudioSystem.getLine(info);
auline.open(format);
} catch (LineUnavailableException e) {
e.printStackTrace();
return;
} catch (Exception e) {
e.printStackTrace();
return;
}
if (auline.isControlSupported(FloatControl.Type.PAN)) {
FloatControl pan = (FloatControl) auline
.getControl(FloatControl.Type.PAN);
if (curPosition == Position.RIGHT)
pan.setValue(1.0f);
else if (curPosition == Position.LEFT)
pan.setValue(-1.0f);
}
auline.start();
int nBytesRead = 0;
byte[] abData = new byte[EXTERNAL_BUFFER_SIZE]; try {
while (nBytesRead != -1) {
nBytesRead = audioInputStream.read(abData, 0, abData.length);
if (nBytesRead >= 0)
auline.write(abData, 0, nBytesRead);
}
} catch (Exception e) {
e.printStackTrace();
return;
} finally {
auline.drain();
auline.close();
}
}
public static void main(String args[]){
SoundPlayer a=new SoundPlayer(文件地址);
a.run();
}
}