Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/361.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何使用Java声音缓冲和播放OGG文件中的声音数据_Java_Audio_Buffer_Javasound_Ogg - Fatal编程技术网

如何使用Java声音缓冲和播放OGG文件中的声音数据

如何使用Java声音缓冲和播放OGG文件中的声音数据,java,audio,buffer,javasound,ogg,Java,Audio,Buffer,Javasound,Ogg,我正在尝试使用Java声音(带和)从WAV、MP3和OGG文件中读取音频数据,将其存储到字节数组中,以便以后在那里播放。为此,我使用如下代码: public Sound loadSound(File file){ AudioInputStream baseStream = AudioSystem.getAudioInputStream(file); AudioFormat baseFormat = baseStream.getFormat(); AudioFormat dec

我正在尝试使用Java声音(带和)从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);
}
声音类基本上是(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播放它。然而,通过这种方式,字节数组保存的是编码的数据而不是解码的数据:实际上,对我来说没有太大的区别,但我很好奇为什么之前的方法对OGG不起作用。
感谢所有尝试回答的人。

问题在于
loadSound
中,在下面的
write
调用中没有使用
nBytesRead
返回值。
read
函数不需要返回请求的完整字节数。事实上,如果解码器能够打破其自然边界,那么它可能会使解码器更易于实现。这可能就是ogg解码器正在做的事情。此外,如果未使用返回值,则每次读取调用都不太可能返回准确的请求大小

            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);
                //                    ^^^^^^^^^^^^^
            }

可能不相关,但您应该在
字节输出中使用
nBytesRead
。write
调用。read返回的字节可能少于4096字节,在这种情况下,您将向输出流写入垃圾。这几乎保证会发生在最后一个缓冲区上。这似乎起到了作用!谢谢@jaket:)太好了,我会写下来作为你可以接受的答案。