android声音传感器编程

来源:互联网 发布:潮州淘宝村 编辑:程序博客网 时间:2024/06/10 23:11

这篇日志整理了一些关于android声音传感器部分的处理的代码

代码收集整理自网络

主要原因是因为何畅最近在做的项目

帮他整理的

部分代码我加亮注释应该可读性还不错

排版始终有问题

不过不影响可读性

就算了

暂时就先这样了

下面是代码部分

有不懂的可以留言

也可以一起讨论交流

下面代码调用声音传感器

获取声音信号

从而获取音量数据

01 packageeoe.demo;
03 importandroid.media.AudioFormat;
04 importandroid.media.AudioRecord;
05 importandroid.media.MediaRecorder;
06 importandroid.util.Log;
08 publicclassRecordThreadextendsThread{
09 privateAudioRecordar;
10 privateint bs;
11 privatestaticintSAMPLE_RATE_IN_HZ = 8000;
12 privatebooleanisRun= false;
13 publicRecordThread(){
14 super();
15 bs = AudioRecord.getMinBufferSize(SAMPLE_RATE_IN_HZ,AudioFormat.CHANNEL_CONFIGURATION_MONO,AudioFormat.ENCODING_PCM_16BIT);
16 ar=newAudioRecord(MediaRecorder.AudioSource.MIC,SAMPLE_RATE_IN_HZ,AudioFormat.CHANNEL_CONFIGURATION_MONO,AudioFormat.ENCODING_PCM_16BIT, bs);
17 }
18 publicvoidrun(){
19 super.run();
20 ar.startRecording();
21 // 用于读取的
22 bufferbyte[]buffer=newbyte[bs];isRun=true;while (isRun){
23 intr=ar.read(buffer,0, bs);
24 intv=0;
25 // 将 buffer 内容取出,进行平方和运算
26 for (inti=0; i <buffer.length;i++){
27 // 这里没有做运算的优化,为了更加清晰的展示代码
28 v+=buffer[i]*buffer[i];
29 }
30 // 平方和除以数据总长度,得到音量大小。可以获取白噪声值,然后对实际采样进行标准化。
31 // 如果想利用这个数值进行操作,建议用 sendMessage 将其抛出,在 Handler 里进行处理。
32 Log.d(“spl”,String.valueOf(v/ (float)r));
33 }
34 ar.stop();
35 }
36 publicvoidpause(){
37 // 在调用本线程的 Activity 的 onPause 里调用,以便 Activity 暂停时释放麦克风
38 isRun=false;
39 }
40 publicvoidstart(){
41 // 在调用本线程的 Activity 的 onResume 里调用,以便 Activity 恢复后继续获取麦克风输入音量
42 if(!isRun){
43 super.start();
44 }
45 }
46
47 }

上面代码获取的是一段时间的音量平均值

适合用于编写一些靠吹气控制软件动作的软件

而何畅需要根据音量来生成图像

那么需要的是瞬时音量数据

改时间片段代码就可以了

鉴于这种运用相对少一些就不专门贴代码了

再贴一个示波器代码

本程序使用8000hz的采样率,对X轴方向绘图的实时性要求较高,如果不降低X轴的分辨率,程序的实时性较差,因此程序对X轴数据缩小区间为8倍~16倍。由于采用16位采样,因此Y轴数据的高度相对于手机屏幕来说也偏大,程序也对Y轴数据做缩小,区间为1倍~10倍。在SurfaceView的OnTouchListener方法里加入了波形基线的位置调节,直接在SurfaceView控件上触摸即可控制整体波形偏上或偏下显示。

main.xml源码如下:

01 <?xml version=”1.0″ encoding=”utf-8″?>
02 <LinearLayoutxmlns:android=“http://schemas.android.com/apk/res/android”
03     android:orientation=“vertical”android:layout_width=“fill_parent”
04     android:layout_height=“fill_parent”>
05     <LinearLayoutandroid:id=“@+id/LinearLayout01″
06         android:layout_height=“wrap_content” android:layout_width=“fill_parent”
07         android:orientation=“horizontal”>
08         <Button android:layout_height=“wrap_content”android:id=“@+id/btnStart”
09             android:text=“开始” android:layout_width=“80dip”></Button>
10         <Buttonandroid:layout_height=“wrap_content”android:text=“停止”
11             android:id=“@+id/btnExit” android:layout_width=“80dip”></Button>
12         <ZoomControls android:layout_width=“wrap_content”
13             android:layout_height=“wrap_content” android:id=“@+id/zctlX”></ZoomControls>
14         <ZoomControls android:layout_width=“wrap_content”
15             android:layout_height=“wrap_content”android:id=“@+id/zctlY”></ZoomControls>
16     </LinearLayout>
17     <SurfaceViewandroid:id=“@+id/SurfaceView01″
18         android:layout_height=“fill_parent” android:layout_width=“fill_parent”></SurfaceView>
19 </LinearLayout>

ClsOscilloscope.java是实现示波器的类库,包含AudioRecord操作线程和SurfaceView绘图线程的实现,两个线程同步操作,代码如下:

001 packagecom.testOscilloscope;
002 importjava.util.ArrayList;
003 importandroid.graphics.Canvas;
004 importandroid.graphics.Color;
005 importandroid.graphics.Paint;
006 importandroid.graphics.Rect;
007 importandroid.media.AudioRecord;
008 importandroid.view.SurfaceView;
009 publicclassClsOscilloscope{
010     privateArrayList<short[]>inBuf=newArrayList<short[]>();
011     privatebooleanisRecording=false;// 线程控制标记   
012     /** 
013      * X轴缩小的比例 
014      */
015     publicintrateX= 4;
016     /** 
017      * Y轴缩小的比例 
018      */
019     publicintrateY= 4;
020     /** 
021      * Y轴基线 
022      */
023     publicintbaseLine= 0;
024     /** 
025      * 初始化 
026      */
027     publicvoidinitOscilloscope(intrateX,intrateY,intbaseLine) {
028         this.rateX=rateX;
029         this.rateY=rateY;
030         this.baseLine=baseLine;
031     }
032     /** 
033      * 开始 
034      *  
035      * @param recBufSize 
036      *            AudioRecord的MinBufferSize 
037      */
038     publicvoidStart(AudioRecordaudioRecord,intrecBufSize,SurfaceViewsfv,
039             Paint mPaint) {
040         isRecording=true;
041         new RecordThread(audioRecord,recBufSize).start();// 开始录制线程   
042         new DrawThread(sfv,mPaint).start();// 开始绘制线程   
043     }
044     /** 
045      * 停止 
046      */
047     publicvoidStop(){
048         isRecording = false;
049         inBuf.clear();// 清除   
050     }
051     /** 
052      * 负责从MIC保存数据到inBuf 
053      *  
054      * @author GV 
055      *  
056      */
057     classRecordThreadextendsThread{
058         private intrecBufSize;
059         private AudioRecord audioRecord;
060         publicRecordThread(AudioRecordaudioRecord,intrecBufSize){
061             this.audioRecord=audioRecord;
062             this.recBufSize=recBufSize;
063         }
064         public voidrun(){
065             try{
066                 short[] buffer = newshort[recBufSize];
067                 audioRecord.startRecording();// 开始录制   
068                 while (isRecording) {
069                     // 从MIC保存数据到缓冲区   
070                     int bufferReadResult = audioRecord.read(buffer,0,
071                             recBufSize);
072                     short[] tmpBuf = newshort[bufferReadResult/rateX];
073                     for (inti=0,ii=0; i <tmpBuf.length;i++,ii= i
074                             * rateX) {
075                         tmpBuf[i]=buffer[ii];
076                     }
077                     synchronized (inBuf) {//   
078                         inBuf.add(tmpBuf);// 添加数据   
079                     }
080                 }
081                 audioRecord.stop();
082             } catch (Throwablet){
083             }
084         }
085     };
086     /** 
087      * 负责绘制inBuf中的数据 
088      *  
089      * @author GV 
090      *  
091      */
092     classDrawThreadextendsThread{
093         private intoldX=0;// 上次绘制的X坐标   
094         private intoldY=0;// 上次绘制的Y坐标   
095         privateSurfaceViewsfv;// 画板   
096         private intX_index=0;// 当前画图所在屏幕X轴的坐标   
097         private Paint mPaint;// 画笔   
098         public DrawThread(SurfaceViewsfv,PaintmPaint){
099             this.sfv=sfv;
100             this.mPaint=mPaint;
101         }
102         public voidrun(){
103             while (isRecording) {
104                 ArrayList<short[]>buf=newArrayList<short[]>();
105                 synchronized (inBuf) {
106                     if (inBuf.size()==0)
107                         continue;
108                     buf = (ArrayList<short[]>)inBuf.clone();// 保存   
109                     inBuf.clear();// 清除   
110                 }
111                 for (inti=0; i <buf.size();i++){
112                     short[] tmpBuf = buf.get(i);
113                     SimpleDraw(X_index,tmpBuf,rateY,baseLine);// 把缓冲区数据画出来   
114                     X_index = X_index+tmpBuf.length;
115                     if (X_index > sfv.getWidth()){
116                         X_index = 0;
117                     }
118                 }
119             }
120         }
121         /** 
122          * 绘制指定区域 
123          *  
124          * @param start 
125          *            X轴开始的位置(全屏) 
126          * @param buffer 
127          *            缓冲区 
128          * @param rate 
129          *            Y轴数据缩小的比例 
130          * @param baseLine 
131          *            Y轴基线 
132          */
133         void SimpleDraw(intstart,short[]buffer,intrate,intbaseLine) {
134             if (start == 0)
135                 oldX = 0;
136             Canvas canvas = sfv.getHolder().lockCanvas(
137                     new Rect(start,0,start+ buffer.length,sfv.getHeight()));// 关键:获取画布   
138             canvas.drawColor(Color.BLACK);// 清除背景   
139             int y;
140             for (inti=0; i <buffer.length;i++){// 有多少画多少   
141                 int x = i +start;
142                 y = buffer[i]/rate+ baseLine;// 调节缩小比例,调节基准线   
143                 canvas.drawLine(oldX,oldY,x,y,mPaint);
144                 oldX = x;
145                 oldY = y;
146             }
147             sfv.getHolder().unlockCanvasAndPost(canvas);// 解锁画布,提交画好的图像   
148         }
149     }
150 }

testOscilloscope.java是主程序,控制UI和ClsOscilloscope,代码如下:

001 packagecom.testOscilloscope;
002 importandroid.app.Activity;
003 importandroid.graphics.Color;
004 importandroid.graphics.Paint;
005 importandroid.media.AudioFormat;
006 importandroid.media.AudioRecord;
007 importandroid.media.MediaRecorder;
008 importandroid.os.Bundle;
009 importandroid.view.MotionEvent;
010 importandroid.view.SurfaceView;
011 importandroid.view.View;
012 importandroid.view.View.OnTouchListener;
013 importandroid.widget.Button;
014 importandroid.widget.ZoomControls;
015 publicclasstestOscilloscopeextendsActivity{
016     /** Called when the activity is first created. */
017     ButtonbtnStart,btnExit;
018     SurfaceViewsfv;
019     ZoomControlszctlX,zctlY;
020
021     ClsOscilloscopeclsOscilloscope=newClsOscilloscope();
022
023     staticfinalintfrequency=8000;//分辨率   
024     staticfinalintchannelConfiguration=AudioFormat.CHANNEL_CONFIGURATION_MONO;
025     staticfinalintaudioEncoding =AudioFormat.ENCODING_PCM_16BIT;
026     staticfinalintxMax = 16;//X轴缩小比例最大值,X轴数据量巨大,容易产生刷新延时   
027     staticfinalintxMin = 8;//X轴缩小比例最小值   
028     staticfinalintyMax = 10;//Y轴缩小比例最大值   
029     staticfinalintyMin = 1;//Y轴缩小比例最小值   
030
031     intrecBufSize;//录音最小buffer大小   
032     AudioRecordaudioRecord;
033     PaintmPaint;
034     @Override
035     publicvoidonCreate(BundlesavedInstanceState){
036         super.onCreate(savedInstanceState);
037         setContentView(R.layout.main);
038         //录音组件   
039         recBufSize = AudioRecord.getMinBufferSize(frequency,
040                 channelConfiguration, audioEncoding);
041         audioRecord = new AudioRecord(MediaRecorder.AudioSource.MIC,frequency,
042                 channelConfiguration, audioEncoding, recBufSize);
043         //按键   
044         btnStart = (Button)this.findViewById(R.id.btnStart);
045         btnStart.setOnClickListener(newClickEvent());
046         btnExit = (Button)this.findViewById(R.id.btnExit);
047         btnExit.setOnClickListener(newClickEvent());
048         //画板和画笔   
049         sfv = (SurfaceView)this.findViewById(R.id.SurfaceView01);
050         sfv.setOnTouchListener(newTouchEvent());
051         mPaint = newPaint();
052         mPaint.setColor(Color.GREEN);// 画笔为绿色     
053         mPaint.setStrokeWidth(1);// 设置画笔粗细    
054         //示波器类库   
055         clsOscilloscope.initOscilloscope(xMax/2,yMax/2,sfv.getHeight()/2);
056
057         //缩放控件,X轴的数据缩小的比率高些   
058         zctlX = (ZoomControls)this.findViewById(R.id.zctlX);
059         zctlX.setOnZoomInClickListener(newView.OnClickListener(){
060             @Override
061             public voidonClick(Viewv){
062                 if(clsOscilloscope.rateX>xMin)
063                     clsOscilloscope.rateX–;
064                 setTitle(“X轴缩小”+String.valueOf(clsOscilloscope.rateX)+“倍”
065                         +“,”+“Y轴缩小”+String.valueOf(clsOscilloscope.rateY)+“倍”);
066             }
067         });
068         zctlX.setOnZoomOutClickListener(newView.OnClickListener(){
069             @Override
070             publicvoidonClick(Viewv){
071                 if(clsOscilloscope.rateX<xMax)
072                     clsOscilloscope.rateX++;
073                 setTitle(“X轴缩小”+String.valueOf(clsOscilloscope.rateX)+“倍”
074                         +“,”+“Y轴缩小”+String.valueOf(clsOscilloscope.rateY)+“倍”);
075             }
076         });
077         zctlY = (ZoomControls)this.findViewById(R.id.zctlY);
078         zctlY.setOnZoomInClickListener(newView.OnClickListener(){
079             @Override
080             publicvoidonClick(Viewv){
081                 if(clsOscilloscope.rateY>yMin)
082                     clsOscilloscope.rateY–;
083                 setTitle(“X轴缩小”+String.valueOf(clsOscilloscope.rateX)+“倍”
084                         +“,”+“Y轴缩小”+String.valueOf(clsOscilloscope.rateY)+“倍”);
085             }
086         });
087
088         zctlY.setOnZoomOutClickListener(newView.OnClickListener(){
089             @Override
090             publicvoidonClick(Viewv){
091                 if(clsOscilloscope.rateY<yMax)
092                     clsOscilloscope.rateY++;
093                 setTitle(“X轴缩小”+String.valueOf(clsOscilloscope.rateX)+“倍”
094                         +“,”+“Y轴缩小”+String.valueOf(clsOscilloscope.rateY)+“倍”);
095             }
096         });
097     }
098     @Override
099     protectedvoidonDestroy(){
100         super.onDestroy();
101         android.os.Process.killProcess(android.os.Process.myPid());
102     }
103
104     /** 
105      * 按键事件处理 
106      * @author GV 
107      * 
108      */
109     classClickEventimplementsView.OnClickListener{
110         @Override
111         public voidonClick(Viewv){
112             if (v == btnStart) {
113                 clsOscilloscope.baseLine=sfv.getHeight()/2;
114                 clsOscilloscope.Start(audioRecord,recBufSize,sfv,mPaint);
115             }elseif (v==btnExit){
116                 clsOscilloscope.Stop();
117             }
118         }
119     }
120     /** 
121      * 触摸屏动态设置波形图基线 
122      * @author GV 
123      * 
124      */
125     classTouchEventimplementsOnTouchListener{
126         @Override
127         public booleanonTouch(Viewv,MotionEventevent){
128             clsOscilloscope.baseLine=(int)event.getY();
129             return true;
130         }
131
132     }
133 }
原创粉丝点击