2015-01-29 4 views
3

Я работаю над приложением Android, где мне нужно рассчитать амплитуду звука в реальном времени. На данный момент я использую MediaPlayer для воспроизведения трека. Есть ли способ вычислить его амплитуду в реальном времени во время игры?Как рассчитать амплитуду звука в реальном времени (android)

Вот мой код:

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; 
} 
+0

Что такое 32768.0? – dberm22

+0

Так как мне нужно значение между 0-1, поэтому я делю его 32768 (32 байт) –

+0

Вы попробовали ответ здесь: http://stackoverflow.com/questions/17486222/animate-progressbar-by-getting-the-amplitude -of-mediaplayer –

ответ

2

Ваша проблема заключается в неправильной конвертации из 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 (после преобразования в double).

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); 
Смежные вопросы