如何在声音输入上触发振动?

时间:2016-02-22 13:28:21

标签: android audio mediarecorder vibrate android-vibration

我正在尝试创建一个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() 的线程内创建处理程序。有什么建议吗?

4 个答案:

答案 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);