SourceDataLine跳过指定的字节数(JavaSound)

时间:2018-04-09 03:26:37

标签: java audio javasound

由于某些原因,我需要使用SourceDataLine代替Clip来播放我的程序中的音频。可以很容易地将framePosition(我想跳过)分配给Clip,但SourceDataLine没有这个方便的API。

我想使用AudioInputStream.skip(n),其中n是要跳过的请求字节数。但我不知道如何正确设置n,如果我想跳过1.25秒。我怎样才能做到这一点?

我的代码来自site(MP3 player sample) 请检查功能in.skip()

中的stream
public class AudioFilePlayer {

public static void main(String[] args) {
    final AudioFilePlayer player = new AudioFilePlayer ();
    player.play("something.mp3");
}

public void play(String filePath) {
    final File file = new File(filePath);

    try (final AudioInputStream in = getAudioInputStream(file)) {

        final AudioFormat outFormat = getOutFormat(in.getFormat());
        final Info info = new Info(SourceDataLine.class, outFormat);

        try (final SourceDataLine line =
                 (SourceDataLine) AudioSystem.getLine(info)) {

            if (line != null) {
                line.open(outFormat);
                line.start();
                stream(getAudioInputStream(outFormat, in), line);
                line.drain();
                line.stop();
            }
        }

    } catch (UnsupportedAudioFileException 
           | LineUnavailableException 
           | IOException e) {
        throw new IllegalStateException(e);
    }
}

private AudioFormat getOutFormat(AudioFormat inFormat) {
    final int ch = inFormat.getChannels();
    final float rate = inFormat.getSampleRate();
    return new AudioFormat(PCM_SIGNED, rate, 16, ch, ch * 2, rate, false);
}

private void stream(AudioInputStream in, SourceDataLine line) 
    throws IOException {
    in.skip(proper number); //There is my question
    final byte[] buffer = new byte[65536];
    for (int n = 0; n != -1; n = in.read(buffer, 0, buffer.length)) {
        line.write(buffer, 0, n);
    }
}}

1 个答案:

答案 0 :(得分:1)

每个AudioInputStream都有一个AudioFormat对象,您可以通过format()方法获取该对象。要找出1.25秒的字节数,您需要计算1.25秒的帧数和帧的大小:

AudioFormat format = audioInputStream.format();
float b = format.getFrameSize() * format.getFrameRate() * 1.25f;
// round to nearest full frame
long n = (b/format.getFrameSize())*format.getFrameSize();
long skipped = audioInputStream.skip(b);
// you might want to check skipped to see whether the
// requested number of bytes was indeed skipped.

解释:

  • Frame 是所有频道的完整示例。因此,如果你有一个立体声信号,一个帧是左右两个样本。
  • FrameSize 是用于帧的字节数。对于CD质量,这将是每个通道2个字节,即每帧4个字节(在立体声的情况下)。
  • FrameRate 是每秒的帧数。
  • 由于您不应拆分框架,因此必须将其舍入到整个框架。

请注意,上面的代码假设您有PCM编码的音频。如果您还有其他内容,请先使用pcmStream = AudioSystem.getAudioInputStream(AudioFormat.Encoding.PCM_SIGNED, audioInputStream)等内容转码为PCM。