我正在尝试创建一个Android应用程序,我在其中过滤一个特定频率的蜂鸣声并使手机振动。
我正在从移动设备的MIC中获取输入并使用MediaRecorder类,通过使用此类,我可以录制,保存和播放输入。现在,只要有哔哔声或任何声音,我就需要我的手机振动。
输入是通过电线连接到手机的耳机插孔,所以我知道只有一个频率输入。
我有一个按钮,点击开始录制。 我已经拥有振动并在我的清单文件中记录的权限。
record.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
try {
isRecording=true;
myAudioRecorder.prepare();
myAudioRecorder.start();
...
}
我也尝试搜索互联网,发现类似的问题here,但我找不到任何正确的答案。
但是,我可以点击另一个按钮让手机振动,这是一段代码,
Vibrator vibrate;
vibrate = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
Btn1.setOnClickListener(new View.OnClickListener()
{
@Override
public void onClick(View v) {
vibrate.vibrate(800);
}
}
我试过在recorder.start()中调用振动器;功能但这使手机即使在没有声音时也会振动。 我也试过从this question获得帮助,所以每当有沉默时,手机都不应该振动,但是我感到困惑,我知道应该有一个布尔值,当有声音并让手机振动时才会生效,但我无法将此逻辑放入代码中。 请让我知道在这种情况下我该怎么办?我应该在哪个方向搜索?
更新 我找到了this用于显示输入声音振幅的进度条,它工作正常我试图让手机在缓冲区有一些值时振动,现在它振动甚至当振幅为零时,我猜这是因为每次振动都会产生噪音,导致手机振动。由于 java.lang.RuntimeException,我无法通过TOAST检查函数:无法在未调用Looper.prepare() 的线程内创建处理程序。有什么建议吗?
答案 0 :(得分:6)
对于您的主要问题,也许您可以检查声音的振幅,并且只有在达到最小阈值时才会振动。像这样:
private class DetectAmplitude extends AsyncTask<Void, Void, Void> {
private MediaRecorder mRecorder = null;
private final static int MAX_AMPLITUDE = 32768;
//TODO: Investigate what is the ideal value for this parameter
private final static int MINIMUM_REQUIRED_AVERAGE = 5000;
@Override
protected Void doInBackground(Void... params) {
Boolean soundStarted = true;
if (mRecorder == null) {
mRecorder = new MediaRecorder();
mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
mRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
mRecorder.setOutputFile("/dev/null");
try {
mRecorder.prepare();
} catch (IllegalStateException e) {
soundStarted = false;
Log.e(TAG, "Could not detect background noise. Error preparing recorder: " + e.getMessage());
} catch (IOException e) {
soundStarted = false;
Log.e(TAG, "Could not detect background noise. Error preparing recorder: " + e.getMessage());
}
try {
mRecorder.start();
} catch (RuntimeException e) {
Log.e(TAG, "Could not detect background noise. Error starting recorder: " + e.getMessage());
soundStarted = false;
mRecorder.release();
mRecorder = null;
}
}
if (soundStarted) {
// Compute a simple average of the amplitude over one
// second
int nMeasures = 100;
int sumAmpli = 0;
mRecorder.getMaxAmplitude(); // First call returns 0
int n = 0;
for (int i = 0; i < nMeasures; i++) {
if (mRecorder != null) {
int maxAmpli = mRecorder.getMaxAmplitude();
if (maxAmpli > 0) {
sumAmpli += maxAmpli;
n++;
}
} else {
return null;
}
try {
Thread.sleep(1000 / nMeasures);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
mRecorder.stop();
mRecorder.release();
mRecorder = null;
final float avgAmpli = (float) sumAmpli / n;
if (avgAmpli > MINIMUM_REQUIRED_AVERAGE) {
//TODO: Vibrate the device here
}
}
return null;
}
}
有关声级检测的更多信息,请参阅以下内容:
关于异常java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
,这种情况正在发生,因为Toast
需要在应用的主线程上运行。如果您的Thread
代码(如AsyncTask
)位于Activity
内,您可以尝试以下操作:
runOnUiThread(new Runnable() {
@Override
public void run() {
//Call your Toast here
}
});
否则,您需要以某种方式将方法的结论传递给Activity
,以便运行Toast
。
编辑:
如果您想在Button
中使用此功能,可以在OnClickListener
的{{1}}来电中设置Activity
并在那里执行onCreate()
。例如:
AsyncTask
我建议您在生产代码中使用之前先查看how AsyncTask works。
答案 1 :(得分:1)
您想对音频进行采样,并立即进行分析。
MediaRecorder对此似乎很高级,它只捕获到文件。您可能希望使用AudioRecorder,因为它可以直接访问输入样本。
为了检测特定音调,您可以在输入样本上使用Goertzel algorithm。这是我多年前做过的C++ implementation,可以作为一个例子。
为了检测超过特定阈值的任何声音,您可以对输入样本使用Root Mean Square分析,并在响度达到阈值时触发。这是一个Python example,可以对麦克风产生的大声噪音作出反应。
答案 2 :(得分:0)
试试这个:
Btn1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
v.post(new Runnable() {
@Override
public void run() {
vibrate.vibrate(800);
}
});
}
});
答案 3 :(得分:0)
你可以试试这个:
Handler handler;
Runnable r;
handler = new Handler();
r = new Runnable() {
public void run() {
Vibrator vib = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
vib.vibrate(500);
handler.postDelayed(r, 1000);
}
};
handler.post(r);