How to trigger Vibration on Sound Input?

两盒软妹~` 提交于 2019-12-05 03:33:21
Ricardo

For your main problem, maybe you can check for the amplitude of the sound, and only vibrate if a minimum threshold has been reached. Something like this:

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;
    }
} 

For more information regarding the detection of sound level, please refer to the following:

Regarding the exception java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare(), that is happening because the Toast needs to run on the main thread of your app. If your Thread code (like an AsyncTask) is inside an Activity, you can try the following:

runOnUiThread(new Runnable() {
        @Override
        public void run() {
            //Call your Toast here
        }
    });

Otherwise, you need to somehow pass the conclusion of your method to the Activity for it to run the Toast.

EDIT:

If you want to use this from a Button, you could set its OnClickListener on your Activity's onCreate() call and execute the AsyncTask there. For example:

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.your_layout);
    Button button = (Button)findViewById(R.id.your_button_id);
    button.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            new DetectAmplitude().execute(new Void[]{});
        }
    });
}

I suggest you take a look at how AsyncTask works before using this in production code.

Espen Riskedal

You want to sample the audio, and analyze it immediately.

MediaRecorder seems to high level for this, it only captures to file. You probably want to use AudioRecorder instead, as it gives direct access to the input samples.

In order to detect a specific tone, you can use the Goertzel algorithm on the input samples. Here is a C++ implementation I did years ago that could serve as an example.

In order to detect any sound over a certain threshold, you can use Root Mean Square analysis on the input samples and make it trigger once the loudness reaches your threshold. Here is a Python example that reacts to loud noises from a microphone.

Try this:

Btn1.setOnClickListener(new View.OnClickListener() {

        @Override
        public void onClick(View v) {
            v.post(new Runnable() {

                @Override
                public void run() {

                    vibrate.vibrate(800);
                }
            });

        }
    });

You can try this:

    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);
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!