如何使用 Java 声音缓冲和播放来自 OGG 文件的声音数据
How to buffer and play sound data from OGG files with Java Sound
我正在尝试使用 Java Sound(使用 MP3SPI and VorbisSPI)从 WAV、MP3 和 OGG 文件中读取音频数据,将其存储到字节数组中,以便稍后播放从那里。为此,我使用如下代码:
public Sound loadSound(File file){
AudioInputStream baseStream = AudioSystem.getAudioInputStream(file);
AudioFormat baseFormat = baseStream.getFormat();
AudioFormat decodedFormat = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED,
baseFormat.getSampleRate(),
16,
baseFormat.getChannels(),
baseFormat.getChannels() * 2,
baseFormat.getSampleRate(),
false);
AudioInputStream decodedStream = AudioSystem.getAudioInputStream(decodedFormat, baseStream);
// Buffer audio data from audio stream
ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
byte[] buffer = new byte[4096];
int nBytesRead = 0;
while (nBytesRead != -1) {
nBytesRead = decodedStream.read(buffer, 0, buffer.length);
// Write read bytes to out stream
byteOut.write(buffer);
}
// close streams and cleanup
byte[] samples = byteOut.toByteArray();
return new Sound(samples,decodedFormat);
}
Sound class 基本上是一对(byte[] 样本,AudioFormat 格式)。完成后,我尝试按如下方式读取和播放字节数组:
public void play(Sound sound) {
InputStream source = new ByteArrayInputStream(sound.getSamples());
AudioFormat format = sound.getFormat();
// use a short, 100ms (1/10th sec) buffer for real-time changes to the sound stream
int bufferSize = format.getFrameSize()
* Math.round(format.getSampleRate() / 10);
byte[] buffer = new byte[bufferSize];
// create a line to play to
SourceDataLine line;
try {
DataLine.Info info
= new DataLine.Info(SourceDataLine.class, format);
line = (SourceDataLine) AudioSystem.getLine(info);
line.open(format, bufferSize);
} catch (LineUnavailableException ex) {
ex.printStackTrace();
return;
}
// start the line
line.start();
// copy data to the line
try {
int numBytesRead = 0;
while (numBytesRead != -1) {
numBytesRead
= source.read(buffer, 0, buffer.length);
if (numBytesRead != -1) {
line.write(buffer, 0, numBytesRead);
}
}
} catch (IOException ex) {
ex.printStackTrace();
} catch (ArrayIndexOutOfBoundsException ex2) {
}
// wait until all data is played, then close the line
line.drain();
line.close();
}
WAV 和 MP3 都可以正常播放,但 OGG 播放失真且速度变慢,就好像格式不对一样。如果有人能指出为什么会这样,我会很高兴。
注意:我通过使用 FileInputStream 将整个音频文件加载为字节数组,然后通过数组上的 ByteArrayInputStream 使用 AudioInputStream 播放它来解决问题。但是,通过这种方式,字节数组保存编码数据而不是解码数据:实际上,对我来说差别不大,但我很好奇为什么以前的方法对 OGG 不起作用。
感谢所有尝试回答的人。
问题出在 loadSound
中,其中 nBytesRead
return 值未在以下 write
调用中使用。 read
函数不需要 return 请求的全部字节数。事实上,如果解码器可以沿着其自然边界打破事物,它可能会使解码器更易于实现。这可能就是 ogg 解码器正在做的事情。此外,如果未使用 return 值,则 very read 调用不太可能 return 确切请求的大小。
byte[] buffer = new byte[4096];
int nBytesRead = 0;
while (nBytesRead != -1) {
nBytesRead = decodedStream.read(buffer, 0, buffer.length);
// Write read bytes to out stream
byteOut.write(buffer, 0, nBytesRead);
// ^^^^^^^^^^^^^
}
我正在尝试使用 Java Sound(使用 MP3SPI and VorbisSPI)从 WAV、MP3 和 OGG 文件中读取音频数据,将其存储到字节数组中,以便稍后播放从那里。为此,我使用如下代码:
public Sound loadSound(File file){
AudioInputStream baseStream = AudioSystem.getAudioInputStream(file);
AudioFormat baseFormat = baseStream.getFormat();
AudioFormat decodedFormat = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED,
baseFormat.getSampleRate(),
16,
baseFormat.getChannels(),
baseFormat.getChannels() * 2,
baseFormat.getSampleRate(),
false);
AudioInputStream decodedStream = AudioSystem.getAudioInputStream(decodedFormat, baseStream);
// Buffer audio data from audio stream
ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
byte[] buffer = new byte[4096];
int nBytesRead = 0;
while (nBytesRead != -1) {
nBytesRead = decodedStream.read(buffer, 0, buffer.length);
// Write read bytes to out stream
byteOut.write(buffer);
}
// close streams and cleanup
byte[] samples = byteOut.toByteArray();
return new Sound(samples,decodedFormat);
}
Sound class 基本上是一对(byte[] 样本,AudioFormat 格式)。完成后,我尝试按如下方式读取和播放字节数组:
public void play(Sound sound) {
InputStream source = new ByteArrayInputStream(sound.getSamples());
AudioFormat format = sound.getFormat();
// use a short, 100ms (1/10th sec) buffer for real-time changes to the sound stream
int bufferSize = format.getFrameSize()
* Math.round(format.getSampleRate() / 10);
byte[] buffer = new byte[bufferSize];
// create a line to play to
SourceDataLine line;
try {
DataLine.Info info
= new DataLine.Info(SourceDataLine.class, format);
line = (SourceDataLine) AudioSystem.getLine(info);
line.open(format, bufferSize);
} catch (LineUnavailableException ex) {
ex.printStackTrace();
return;
}
// start the line
line.start();
// copy data to the line
try {
int numBytesRead = 0;
while (numBytesRead != -1) {
numBytesRead
= source.read(buffer, 0, buffer.length);
if (numBytesRead != -1) {
line.write(buffer, 0, numBytesRead);
}
}
} catch (IOException ex) {
ex.printStackTrace();
} catch (ArrayIndexOutOfBoundsException ex2) {
}
// wait until all data is played, then close the line
line.drain();
line.close();
}
WAV 和 MP3 都可以正常播放,但 OGG 播放失真且速度变慢,就好像格式不对一样。如果有人能指出为什么会这样,我会很高兴。
注意:我通过使用 FileInputStream 将整个音频文件加载为字节数组,然后通过数组上的 ByteArrayInputStream 使用 AudioInputStream 播放它来解决问题。但是,通过这种方式,字节数组保存编码数据而不是解码数据:实际上,对我来说差别不大,但我很好奇为什么以前的方法对 OGG 不起作用。 感谢所有尝试回答的人。
问题出在 loadSound
中,其中 nBytesRead
return 值未在以下 write
调用中使用。 read
函数不需要 return 请求的全部字节数。事实上,如果解码器可以沿着其自然边界打破事物,它可能会使解码器更易于实现。这可能就是 ogg 解码器正在做的事情。此外,如果未使用 return 值,则 very read 调用不太可能 return 确切请求的大小。
byte[] buffer = new byte[4096];
int nBytesRead = 0;
while (nBytesRead != -1) {
nBytesRead = decodedStream.read(buffer, 0, buffer.length);
// Write read bytes to out stream
byteOut.write(buffer, 0, nBytesRead);
// ^^^^^^^^^^^^^
}