2012-02-17 4 views
3

Следующий код показывает график, но мне нужна частота звука. Я пытаюсь записать голос и получить частоту в реальном времени, чтобы я мог играть на фортепиано или на гитаре и находить частоту.Получить звуковую частоту с помощью Android FFT

public class AudioProcessing extends Activity implements OnClickListener { 

int frequency = 8000; 
int channelConfiguration = AudioFormat.CHANNEL_CONFIGURATION_MONO; 
int audioEncoding = AudioFormat.ENCODING_PCM_16BIT; 

private RealDoubleFFT transformer; 
int blockSize = 256; 

Button startStopButton; 
boolean started = false; 

RecordAudio recordTask; 

ImageView imageView; 
Bitmap bitmap; 
Canvas canvas; 
Paint paint; 

@Override 
public void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.main); 

    startStopButton = (Button) this.findViewById(R.id.StartStopButton); 
    startStopButton.setOnClickListener(this); 

    transformer = new RealDoubleFFT(blockSize); 

    imageView = (ImageView) this.findViewById(R.id.ImageView01); 
    bitmap = Bitmap.createBitmap((int) 256, (int) 100, 
      Bitmap.Config.ARGB_8888); 
    canvas = new Canvas(bitmap); 
    paint = new Paint(); 
    paint.setColor(Color.GREEN); 
    imageView.setImageBitmap(bitmap); 
} 



private class RecordAudio extends AsyncTask<Void, double[], Void> { 
    @Override 
    protected Void doInBackground(Void... params) { 
     try { 
      int bufferSize = AudioRecord.getMinBufferSize(frequency, 
        channelConfiguration, audioEncoding); 

      AudioRecord audioRecord = new AudioRecord(
        MediaRecorder.AudioSource.MIC, frequency, 
        channelConfiguration, audioEncoding, bufferSize); 

      short[] buffer = new short[blockSize]; 
      double[] toTransform = new double[blockSize]; 

      audioRecord.startRecording(); 

      while (started) { 
       int bufferReadResult = audioRecord.read(buffer, 0, 
         blockSize); 

       for (int i = 0; i < blockSize && i < bufferReadResult; i++) { 
        toTransform[i] = (double) buffer[i]/32768.0; // signed 
        // 16 
        // bit 
       } 

       transformer.ft(toTransform); 

       publishProgress(toTransform); 
      } 

      audioRecord.stop(); 
     } catch (Throwable t) { 
      Log.e("AudioRecord", "Recording Failed"); 
     } 

     return null; 
    } 

    protected void onProgressUpdate(double[]... toTransform) { 
     canvas.drawColor(Color.BLACK); 

     for (int i = 0; i < toTransform[0].length; i++) { 
      int x = i; 
      int downy = (int) (100 - (toTransform[0][i] * 10)); 
      int upy = 100; 

      canvas.drawLine(x, downy, x, upy, paint); 
     } 
     imageView.invalidate(); 
    } 
} 

public void onClick(View v) { 
    if (started) { 
     started = false; 
     startStopButton.setText("Start"); 
     recordTask.cancel(true); 
    } else { 
     started = true; 
     startStopButton.setText("Stop"); 
     recordTask = new RecordAudio(); 
     recordTask.execute(); 
    } 
} 
    } 

Как я могу получить частоту от этого кода?

ответ

3

Ваш код FFT не дает вам частоты. Он дает вам множество комплексных значений на множестве разных частот. И может быть ошибка в коде, если вы просто смотрите на «реальный» или косинусный компонент результата FFT вместо векторной величины каждого сложного компонента.

Каждый элемент вашего массива toTransform [i] после FFT дает вам комплексное значение для частот вокруг или рядом (i * sampleRate/blockSize). Вы можете найти максимумы величин этого массива для оценки приблизительной частоты, при которой величина была наибольшей. Вы также можете интерполировать максимумы, чтобы улучшить эту частотную оценку.

Но если вы ищете оценку высоты тона (например, гитарной ноты), это может сильно отличаться от оценки частоты пиков. Возможно, вам захочется взглянуть на некоторые алгоритмы оценки шага.