使用JLayer将MP3解码为PCM以检测振幅

时间:2013-09-21 23:09:59

标签: java mp3 javasound pcm javax.sound.sampled

背景:我正在使用JLayer来播放MP3文件。我试图分析MP3中不同的幅度/音频电平。通过我的分析,我想确定MP3开始和结束时的沉默持续时间。另外,当正在播放MP3时,我想要一个图形来显示音频电平(如视觉声波)。

问题:为了进行有效分析,我需要能够分析原始PCM数据。目前,我正在分析通过AudioInputStream检索到的字节[]并发送到SourceDataLinePCM是短[]而不是byte [],这意味着我没有得到完整的数据。

我正在使用Root-Mean SquareRMS)来确定音量级别。

处理byte []的回放代码:

AudioInputStream in = null;
AudioFile af = null; //Custom class which holds some data about mp3.
SourceDataLine line = null;

// Set current audio file.
af = musicPlaylist.get(0);

line = (SourceDataLine) AudioSystem.getLine(af.getLineInfo());
line.open(af.getAudioFormat());
line.start();

in = getAudioInputStream(af.getAudioFormat(), af.getAudioStream());

int bR = playbackBufferSize;

final byte[] buffer = new byte[bR];
int n = 0;
while (playMedia) {
    if ((n = in.read(buffer, 0, buffer.length)) == -1) {
        break;
    }

    if (line != null) {
        line.write(buffer, 0, n);

        int amp = (int) Math
                .ceil((rmsAudioLevel(decode(buffer)) / 32767) * 100);
        mainScreen.setAmpDisplayLevel(amp, String.valueOf(amp));
        mainScreen.updateGraph(amp);
    }
}

基本上:当我播放PCM时,如何在现场解码MP3数据,以便我可以显示音量级别,从而检测到静音?

1 个答案:

答案 0 :(得分:1)

首先,你得到缓冲区[]中的所有PCM数据。但您可能必须将字节组合成PCM数据。您的音频格式将告诉您正在使用多少位编码。最常见的是16位,但有时会显示24位或32位数据。对于16位数据,您附加两个连续的字节来构建short。两个字节的顺序取决于格式是little-endian还是big-endian。我注意到这个屏幕的右边,在“相关”列中,是一个链接:如何从wav文件中获取PCM数据 - 该链接或其他类似应该为您提供所需代码的示例。 / p>

第二个问题,我不认为在单独的buffer []数组上进行RMS是完全正确的。我可能错了。我认为它更像是移动平均线,其中一个缓冲区[]开头的一些数据应该包含前一个缓冲区末尾的一些数据[]。公式是否要求您“返回”或“平均”超过N个帧?如果是这样,您将希望保留先前的缓冲区[],以适应N量跨越两帧的情况。并且您将遍历当前缓冲区[],一次一个“帧”(或将缓冲区[]交给一个实际执行此操作的子程序。