在响亮的声音android应用振动

时间:2014-12-28 12:34:28

标签: android audio

我是Android应用程序开发的新手,我正在尝试在android studio上开发一个应用程序,它为聋人提供识别超过指定阈值的大声音的能力。如果声音高于指定的阈值,应用程序应实时监听环境并振动。

我已经使用AudioRecord类将周围的声音录制到16BIT PCM的缓冲区中,然后将数据读入数组(Byte [])。我不确定如何将16BIT,2字节,样本转换为十进制值,以便我可以将其与阈值进行比较。我也遇到了运行时错误,并在互联网上搜索了答案,但找不到任何答案。

这是我的MainActivity:

    import android.content.Context;
import android.media.AudioFormat;
import android.media.AudioRecord;
import android.media.MediaRecorder;
import android.os.Vibrator;
import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;

import java.io.IOException;


public class MainActivity extends ActionBarActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Button vib = (Button) findViewById(R.id.button);
        LoudSoundDetector action = new LoudSoundDetector();
        vib.setOnClickListener(action);
    }


    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();

        //noinspection SimplifiableIfStatement
        if (id == R.id.action_settings) {
            return true;
        }

        return super.onOptionsItemSelected(item);
    }


    public class MyVibrator {

        public Vibrator vibrator;

        public void vibrate1() {
            Toast.makeText(getBaseContext(), "Vibration test", Toast.LENGTH_LONG).show();
            long pattern[] = {0,100,200,300,400};
            vibrator = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
            vibrator.vibrate(pattern,0);
        }
    }


    public class LoudSoundDetector implements View.OnClickListener{

        private int amplitudeThreshold = 65;

        int checkThreshold(){
            return amplitudeThreshold;
        }

        @Override
        public void onClick(View v) {
            // TODO Auto-generated method stub
            Listener lsn = new Listener();
            try {
                lsn.listen();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }


    }

    public class Listener{
        int audioSource = MediaRecorder.AudioSource.MIC;
        int samplingRate = 44100; /* in Hz*/
        @SuppressWarnings("deprecation")
        int channelConfig = AudioFormat.CHANNEL_CONFIGURATION_MONO;
        int audioFormat = AudioFormat.ENCODING_PCM_16BIT;
        int bufferSize = AudioRecord.getMinBufferSize(samplingRate, channelConfig, audioFormat);
        boolean isRecording = false;


        public void listen() throws IOException{

            AudioRecord recorder = new AudioRecord(audioSource, samplingRate, channelConfig, audioFormat, bufferSize);
            recorder.startRecording();
            isRecording = true;


            //capture data and compare threshold
            int readBytes=0;
            do{
                byte[] data = null;
                readBytes = recorder.read(data, 0, bufferSize);

                if(AudioRecord.ERROR_INVALID_OPERATION != readBytes){

                    int sampleVal = 0;
                    for(int i=0;i<data.length; i+=2)
                        sampleVal = data[i] + data[i+1];
                    float db = (float) (20 * Math.log10(Math.abs(sampleVal)/32768));
                    LoudSoundDetector lsd = new LoudSoundDetector();

                    if(db>=lsd.checkThreshold()){

                        MyVibrator mVib = new MyVibrator();
                        mVib.vibrate1();
                    }

                }


            }while(isRecording);


        }


    }
}

和日志猫:

12-28 14:23:51.192  12962-12962/com.rayan.graduationtest E/AndroidRuntime﹕ FATAL EXCEPTION: main
java.lang.NullPointerException
        at com.rayan.graduationtest.MainActivity$Listener.listen(MainActivity.java:122)
        at com.rayan.graduationtest.MainActivity$LoudSoundDetector.onClick(MainActivity.java:80)
        at android.view.View.performClick(View.java:4432)
        at android.view.View$PerformClick.run(View.java:18339)
        at android.os.Handler.handleCallback(Handler.java:725)
        at android.os.Handler.dispatchMessage(Handler.java:92)
        at android.os.Looper.loop(Looper.java:137)
        at android.app.ActivityThread.main(ActivityThread.java:5283)
        at java.lang.reflect.Method.invokeNative(Native Method)
        at java.lang.reflect.Method.invoke(Method.java:511)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1102)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:869)
        at dalvik.system.NativeStart.main(Native Method)

1 个答案:

答案 0 :(得分:0)

抛出异常是因为某个对象为null,找出使用调试器的对象是null并尝试从那里开始解决问题。在你的情况下我怀疑你设置data数组null是问题,你应该把它初始化为一个长度为buffersize的空数组,即

byte[] data = new byte[buffersize];

关于获取样本值的问题,您构建样本值的方式(仅通过添加它们)是错误的,您必须执行与已完成的HERE类似的操作来获取样本来自bytes.Or你可以使用read(short[] audioData, int offsetInShorts, int sizeInShorts)而不是read(byte[] audioData, int offsetInBytes, int sizeInBytes)方法让你的生活更简单,并直接从AudioRecord对象接收样本16Bit未缩放的样本值,这意味着你需要做的就是将短值除以32768以得到实际样本值(这将是介于-1和1之间的数字)。

我也想知道你打算如何进行响度比较,你得到的最大分贝值是0db,所以与65db相比会导致错误的结果。