Получите частоту звука с 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();
}
}
}
Как я могу получить частоту из этого кода?
1 ответ
Ваш код FFT не дает вам частоту. Это дает вам массив сложных значений на кучу разных частот. И в вашем коде может быть ошибка, если вы просто смотрите на "реальный" или косинусный компонент результата БПФ, а не на векторную величину каждого сложного компонента.
Каждый элемент вашего массива toTransform[i] после БПФ дает комплексное значение для частот около или около (i * sampleRate / blockSize). Вы можете найти максимумы величин этого массива, чтобы оценить приблизительную частоту, при которой величина была наибольшей. Вы также можете интерполировать максимумы, чтобы улучшить эту оценку частоты.
Но если вы ищете оценку высоты тона (например, ноты гитары), она может сильно отличаться от оценки пиковой частоты. Возможно, вы захотите взглянуть на некоторые алгоритмы оценки высоты тона.