如何实时计算音频幅度(android)

时间:2015-01-29 12:53:45

标签: java android audio media-player

我正在使用Android应用,我需要实时计算音频幅度。截至目前,我正在使用MediaPlayer来播放曲目。有没有办法在播放时实时计算其幅度?

这是我的代码:

int counterPlayer = 0;
static double[] drawingBufferForPlayer = new double[100];
private byte[] mBytes;
private byte[] mFFTBytes;
private Visualizer mVisualizer;

public void link(final MediaPlayer player)
{
    if(player == null)
    {
        throw new NullPointerException("Cannot link to null MediaPlayer");
    }

    // Create the Visualizer object and attach it to our media player.
    mVisualizer = new Visualizer(player.getAudioSessionId());
    mVisualizer.setCaptureSize(Visualizer.getCaptureSizeRange()[1]);
    //mVisualizer.setMeasurementMode(Visualizer.MEASUREMENT_MODE_PEAK_RMS);

    // Pass through Visualizer data to VisualizerView
    Visualizer.OnDataCaptureListener captureListener = new Visualizer.OnDataCaptureListener()
    {
        @Override
        public void onWaveFormDataCapture(Visualizer visualizer, byte[] bytes,
                                          int samplingRate)
        {
            updateVisualizer(bytes);
        }

        @Override
        public void onFftDataCapture(Visualizer visualizer, byte[] bytes,
                                     int samplingRate)
        {
            updateVisualizerFFT(bytes);
        }
    };

    mVisualizer.setDataCaptureListener(captureListener,
            Visualizer.getMaxCaptureRate() / 2, true, true);
    // Enabled Visualizer and disable when we're done with the stream
    mVisualizer.setEnabled(true);
    player.setOnCompletionListener(new MediaPlayer.OnCompletionListener()
    {
        @Override
        public void onCompletion(MediaPlayer mediaPlayer)
        {
            mVisualizer.setEnabled(false);
        }
    });
}
public void updateVisualizer(byte[] bytes) {

    int t = calculateRMSLevel(bytes);
    Visualizer.MeasurementPeakRms measurementPeakRms = new Visualizer.MeasurementPeakRms();
    int x = mVisualizer.getMeasurementPeakRms(measurementPeakRms);
    mBytes = bytes;
}

/**
 * Pass FFT data to the visualizer. Typically this will be obtained from the
 * Android Visualizer.OnDataCaptureListener call back. See
 * {@link android.media.audiofx.Visualizer.OnDataCaptureListener#onFftDataCapture }
 * @param bytes
 */
public void updateVisualizerFFT(byte[] bytes) {
    int t = calculateRMSLevel(bytes);
    mFFTBytes = bytes;
}
public int calculateRMSLevel(byte[] audioData) {
    //System.out.println("::::: audioData :::::"+audioData);
    double amplitude = 0;
    for (int i = 0; i < audioData.length; i++) {
        amplitude += Math.abs((double) (audioData[i] / 32768.0));
    }
    amplitude = amplitude / audioData.length;
    //Add this data to buffer for display
    if (counterPlayer < 100) {
        drawingBufferForPlayer[counterPlayer++] = amplitude;
    } else {
        for (int k = 0; k < 99; k++) {
            drawingBufferForPlayer[k] = drawingBufferForPlayer[k + 1];
        }
        drawingBufferForPlayer[99] = amplitude;
    }

    updateBufferDataPlayer(drawingBufferForPlayer);
    setDataForPlayer(100,100);

    return (int)amplitude;
}

3 个答案:

答案 0 :(得分:4)

您的问题在于将16位样本的不正确转换为双精度。首先,您需要将两个相邻字节转换为int,然后将转换转换为double。例如

double amplitude = 0;
for (int i = 0; i < audioData.length/2; i++) {
    double y = (audioData[i*2] | audioData[i*2+1] << 8) / 32768.0
    // depending on your endianness:
    // double y = (audioData[i*2]<<8 | audioData[i*2+1]) / 32768.0
    amplitude += Math.abs(y);
}
amplitude = amplitude / audioData.length / 2;

请注意,您的代码和我的答案都假设有一个数据通道。如果您有多个通道,则需要小心分离振幅,因为数据将交错L,R,L,R(转换为双精度后)。

答案 1 :(得分:1)

你试过那个solution吗?

// Calc amplitude for this waveform
float accumulator = 0;
for (int i = 0; i < data.bytes.length - 1; i++) {
  accumulator += Math.abs(data.bytes[i]);
}

float amp = accumulator/(128 * data.bytes.length);

答案 2 :(得分:0)