我正在尝试使用可以检测钢琴频率的应用。 我已经看到了这个
How to calculate sound frequency in android?
FFT类:https://github.com/fjfdeztoro/fftpack
并使用示例代码 https://github.com/sommukhopadhyay/FFTBasedSpectrumAnalyzer/tree/master/
这是我的代码:
package com.somitsolutions.android.spectrumanalyzer;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Point;
import android.media.AudioFormat;
import android.media.AudioRecord;
import android.media.MediaRecorder;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.view.Display;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup.LayoutParams;
import android.view.ViewGroup.MarginLayoutParams;
import android.view.Window;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import ca.uol.aig.fftpack.RealDoubleFFT;
public class SoundRecordAndAnalysisActivity extends Activity implements OnClickListener{
//code by yu-che
int display_width = 600;//the result of display_width/5 and display_width/50 must be integer
int frequency = 44100;
//code by yu-che
int channelConfiguration = AudioFormat.CHANNEL_IN_MONO;
//origin code
//int channelConfiguration = AudioFormat.CHANNEL_CONFIGURATION_MONO;
int audioEncoding = AudioFormat.ENCODING_PCM_16BIT;
AudioRecord audioRecord;
private RealDoubleFFT transformer;
int blockSize;// = 256;
Button startStopButton;
boolean started = false;
boolean CANCELLED_FLAG = false;
RecordAudio recordTask;
ImageView imageViewDisplaySpectrum;
MyImageView imageViewScale;
Bitmap bitmapDisplaySpectrum;
Canvas canvasDisplaySpectrum;
Paint paintSpectrumDisplay;
SoundRecordAndAnalysisActivity mainActivity;
LinearLayout main;
int width;
int height;
int left_Of_BitmapScale;
int left_Of_DisplaySpectrum;
private final static int ID_BITMAPDISPLAYSPECTRUM = 1;
private final static int ID_IMAGEVIEWSCALE = 2;
TextView tv;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Display display = getWindowManager().getDefaultDisplay();
//Point size = new Point();
//display.get(size);
//code by yu-che
Point size = new Point();
display.getSize(size);
width = size.x;
height = size.y;
//origin code
//width = display.getWidth();
//height = display.getHeight();
blockSize = 8196;
}
@Override
public void onWindowFocusChanged (boolean hasFocus) {
//left_Of_BitmapScale = main.getC.getLeft();
MyImageView scale = (MyImageView)main.findViewById(ID_IMAGEVIEWSCALE);
ImageView bitmap = (ImageView)main.findViewById(ID_BITMAPDISPLAYSPECTRUM);
left_Of_BitmapScale = scale.getLeft();
left_Of_DisplaySpectrum = bitmap.getLeft();
}
private class RecordAudio extends AsyncTask<Void, double[], Boolean> {
@Override
protected Boolean doInBackground(Void... params) {
int bufferSize = AudioRecord.getMinBufferSize(frequency,
channelConfiguration, audioEncoding);
audioRecord = new AudioRecord(
MediaRecorder.AudioSource.DEFAULT, frequency,
channelConfiguration, audioEncoding, bufferSize);
int bufferReadResult;
short[] buffer = new short[blockSize];
double[] toTransform = new double[blockSize];
try {
audioRecord.startRecording();
} catch (IllegalStateException e) {
Log.e("Recording failed", e.toString());
}
while (started) {
if (isCancelled() || (CANCELLED_FLAG == true)) {
started = false;
//publishProgress(cancelledResult);
Log.d("doInBackground", "Cancelling the RecordTask");
break;
} else {
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);
}
}
return true;
}
@Override
protected void onProgressUpdate(double[]...progress) {
Log.e("RecordingProgress", "Displaying in progress");
Log.d("Test:", Integer.toString(progress[0].length));
if (width > 512) {
int i = 0;
int intensity = 0;
double scale =0;
while (true){
//scale = 1600/(2000/50)*(display_width/50);
//canvasDisplaySpectrum.drawLine((int)scale, 150, (int)scale,150-50 , paintSpectrumDisplay);
if ( 0 == i){
intensity = (int)(progress[0][0]* progress[0][0]);
canvasDisplaySpectrum.drawLine(0, 150, 0,150-intensity , paintSpectrumDisplay);
i++;
} else if ( (blockSize-1) == i) {
intensity = (int)(progress[0][(blockSize-1)]* progress[0][(blockSize-1)]);
scale = (i/2+0.5)*frequency/(blockSize-1)/(2000/50)*(display_width/50);
canvasDisplaySpectrum.drawLine((int)scale, 150, (int)scale,150-intensity , paintSpectrumDisplay);
break;
} else{
intensity = (int)(progress[0][i]*progress[0][i]+ progress[0][(i+1)]*progress[0][(i+1)]);
scale = (i/2+0.5)*frequency/(blockSize-1)/(2000/50)*(display_width/50);
canvasDisplaySpectrum.drawLine((int)scale, 150, (int)scale,150-intensity , paintSpectrumDisplay);
i = i +2;
}
}
/*
for (int i = 0; i < progress[0].length; i++) {
//int x = 2 * i;
//int downy = (int) (150 - (progress[0][i] * 10));
//int upy = 150;
//canvasDisplaySpectrum.drawLine(x, downy, x, upy, paintSpectrumDisplay);
canvasDisplaySpectrum.drawLine(0, 120, 0, 150, paintSpectrumDisplay);
canvasDisplaySpectrum.drawLine(display_width/50*10, 170, display_width/50*10, 150, paintSpectrumDisplay);
}
*/
imageViewDisplaySpectrum.invalidate();
} else {
for (int i = 0; i < progress[0].length; i++) {
int x = i;
int downy = (int) (150 - (progress[0][i] * 10));
int upy = 150;
canvasDisplaySpectrum.drawLine(x, downy, x, upy, paintSpectrumDisplay);
}
imageViewDisplaySpectrum.invalidate();
}
}
@Override
protected void onPostExecute(Boolean result) {
super.onPostExecute(result);
try{
audioRecord.stop();
}
catch(IllegalStateException e){
Log.e("Stop failed", e.toString());
}
canvasDisplaySpectrum.drawColor(Color.BLACK);
imageViewDisplaySpectrum.invalidate();
}
}
protected void onCancelled(Boolean result){
try{
audioRecord.stop();
}
catch(IllegalStateException e){
Log.e("Stop failed", e.toString());
}
/* //recordTask.cancel(true);
Log.d("FFTSpectrumAnalyzer","onCancelled: New Screen");
Intent intent = new Intent(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_HOME);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
*/
}
public void onClick(View v) {
if (started == true) {
//started = false;
CANCELLED_FLAG = true;
//recordTask.cancel(true);
try{
audioRecord.stop();
}
catch(IllegalStateException e){
Log.e("Stop failed", e.toString());
}
startStopButton.setText("Start");
canvasDisplaySpectrum.drawColor(Color.BLACK);
}
else {
started = true;
CANCELLED_FLAG = false;
startStopButton.setText("Stop");
recordTask = new RecordAudio();
recordTask.execute();
}
}
//code by yu-che
/*
static SoundRecordAndAnalysisActivity getMainActivity(){
return mainActivity;
}
*/
public void onStop(){
super.onStop();
/* try{
audioRecord.stop();
}
catch(IllegalStateException e){
Log.e("Stop failed", e.toString());
}*/
recordTask.cancel(true);
Intent intent = new Intent(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_HOME);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
}
public void onStart(){
super.onStart();
main = new LinearLayout(this);
main.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT,android.view.ViewGroup.LayoutParams.MATCH_PARENT));
main.setOrientation(LinearLayout.VERTICAL);
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
transformer = new RealDoubleFFT(blockSize);
imageViewDisplaySpectrum = new ImageView(this);
if(width > 512){
bitmapDisplaySpectrum = Bitmap.createBitmap((int)512,(int)300,Bitmap.Config.ARGB_8888);
}
else{
bitmapDisplaySpectrum = Bitmap.createBitmap((int)256,(int)150,Bitmap.Config.ARGB_8888);
}
LinearLayout.LayoutParams layoutParams_imageViewScale = null;
//Bitmap scaled = Bitmap.createScaledBitmap(bitmapDisplaySpectrum, 320, 480, true);
canvasDisplaySpectrum = new Canvas(bitmapDisplaySpectrum);
//canvasDisplaySpectrum = new Canvas(scaled);
paintSpectrumDisplay = new Paint();
paintSpectrumDisplay.setColor(Color.GREEN);
imageViewDisplaySpectrum.setImageBitmap(bitmapDisplaySpectrum);
if(width >512){
//imageViewDisplaySpectrum.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.FILL_PARENT,LinearLayout.LayoutParams.WRAP_CONTENT));
LinearLayout.LayoutParams layoutParams_imageViewDisplaySpectrum=new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
((MarginLayoutParams) layoutParams_imageViewDisplaySpectrum).setMargins(100, 600, 0, 0);
imageViewDisplaySpectrum.setLayoutParams(layoutParams_imageViewDisplaySpectrum);
layoutParams_imageViewScale= new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
//layoutParams_imageViewScale.gravity = Gravity.CENTER_HORIZONTAL;
((MarginLayoutParams) layoutParams_imageViewScale).setMargins(100, 20, 0, 0);
}
else if ((width >320) && (width<512)){
LinearLayout.LayoutParams layoutParams_imageViewDisplaySpectrum=new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
((MarginLayoutParams) layoutParams_imageViewDisplaySpectrum).setMargins(60, 250, 0, 0);
//layoutParams_imageViewDisplaySpectrum.gravity = Gravity.CENTER_HORIZONTAL;
imageViewDisplaySpectrum.setLayoutParams(layoutParams_imageViewDisplaySpectrum);
//imageViewDisplaySpectrum.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.FILL_PARENT,LinearLayout.LayoutParams.WRAP_CONTENT));
layoutParams_imageViewScale=new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
((MarginLayoutParams) layoutParams_imageViewScale).setMargins(60, 20, 0, 100);
//layoutParams_imageViewScale.gravity = Gravity.CENTER_HORIZONTAL;
}
else if (width < 320){
/*LinearLayout.LayoutParams layoutParams_imageViewDisplaySpectrum=new LinearLayout.LayoutParams(LinearLayout.LayoutParams.FILL_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT);
((MarginLayoutParams) layoutParams_imageViewDisplaySpectrum).setMargins(30, 100, 0, 100);
imageViewDisplaySpectrum.setLayoutParams(layoutParams_imageViewDisplaySpectrum);*/
imageViewDisplaySpectrum.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,LinearLayout.LayoutParams.WRAP_CONTENT));
layoutParams_imageViewScale=new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT);
//layoutParams_imageViewScale.gravity = Gravity.CENTER;
}
imageViewDisplaySpectrum.setId(ID_BITMAPDISPLAYSPECTRUM);
main.addView(imageViewDisplaySpectrum);
imageViewScale = new MyImageView(this);
imageViewScale.setLayoutParams(layoutParams_imageViewScale);
imageViewScale.setId(ID_IMAGEVIEWSCALE);
//imageViewScale.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.FILL_PARENT,LinearLayout.LayoutParams.WRAP_CONTENT));
main.addView(imageViewScale);
tv=new TextView(this);
tv.setText("frequency");
tv.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,LinearLayout.LayoutParams.WRAP_CONTENT));
startStopButton = new Button(this);
startStopButton.setText("Start");
startStopButton.setOnClickListener(this);
startStopButton.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,LinearLayout.LayoutParams.WRAP_CONTENT));
main.addView(startStopButton);
main.addView(tv);
setContentView(main);
mainActivity = this;
}
@Override
public void onBackPressed() {
super.onBackPressed();
try{
audioRecord.stop();
}
catch(IllegalStateException e){
Log.e("Stop failed", e.toString());
}
recordTask.cancel(true);
Intent intent = new Intent(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_HOME);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
}
@Override
protected void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
try{
audioRecord.stop();
}
catch(IllegalStateException e){
Log.e("Stop failed", e.toString());
}
recordTask.cancel(true);
Intent intent = new Intent(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_HOME);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
}
//Custom Imageview Class
//底下的座標軸
public class MyImageView extends ImageView {
Paint paintScaleDisplay;
Bitmap bitmapScale;
Canvas canvasScale;
public MyImageView(Context context) {
super(context);
// TODO Auto-generated constructor stub
if(width >display_width){
bitmapScale = Bitmap.createBitmap(display_width,50,Bitmap.Config.ARGB_8888);
}
else{
bitmapScale = Bitmap.createBitmap(256,50,Bitmap.Config.ARGB_8888);
}
//坐標軸
paintScaleDisplay = new Paint();
paintScaleDisplay.setColor(Color.BLUE);
paintScaleDisplay.setStyle(Paint.Style.FILL);
canvasScale = new Canvas(bitmapScale);
setImageBitmap(bitmapScale);
invalidate();
}
@Override
protected void onDraw(Canvas canvas)
{
// TODO Auto-generated method stub
super.onDraw(canvas);
if(width > 512){
canvasScale.drawLine(0, 30, display_width, 30, paintScaleDisplay);
for(int i = 0,j = 0; i< display_width; i=i+display_width/5, j++){
for (int k = i; k<(i+display_width/5); k=k+display_width/50){
canvasScale.drawLine(k, 30, k, 23, paintScaleDisplay);
}
canvasScale.drawLine(i, 40, i, 20, paintScaleDisplay);
String text = Integer.toString(j*400) + " Hz";
canvasScale.drawText(text, i, 45, paintScaleDisplay);
}
canvas.drawBitmap(bitmapScale, 0, 0, paintScaleDisplay);
}
else if ((width >320) && (width<512)){
canvasScale.drawLine(0, 30, 0 + 256, 30, paintScaleDisplay);
for(int i = 0,j = 0; i<256; i=i+64, j++){
for (int k = i; k<(i+64); k=k+8){
canvasScale.drawLine(k, 30, k, 25, paintScaleDisplay);
}
canvasScale.drawLine(i, 40, i, 25, paintScaleDisplay);
String text = Integer.toString(j) + " KHz";
canvasScale.drawText(text, i, 45, paintScaleDisplay);
}
canvas.drawBitmap(bitmapScale, 0, 0, paintScaleDisplay);
}
else if (width <320){
canvasScale.drawLine(0, 30, 256, 30, paintScaleDisplay);
for(int i = 0,j = 0; i<256; i=i+64, j++){
for (int k = i; k<(i+64); k=k+8){
canvasScale.drawLine(k, 30, k, 25, paintScaleDisplay);
}
canvasScale.drawLine(i, 40, i, 25, paintScaleDisplay);
String text = Integer.toString(j) + " KHz";
canvasScale.drawText(text, i, 45, paintScaleDisplay);
}
canvas.drawBitmap(bitmapScale, 0, 0, paintScaleDisplay);
}
}
}
}
但是当频率低于A3(220Hz)时。
根本无法抓住。只是抓住了它的泛音。
我尝试更改采样率和阻止,但我没有得到更好的结果。
我的代码有问题吗?或者我找不到一些细节? 有人可以教我,我会受到赞赏&gt;。&lt;
答案 0 :(得分:0)
峰值幅度频率估计器不是音高检测器/估计器。所以不正确的结果与代码无关。除了它是OP目的的错误算法选择。