android声音传感器编程

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

代码收集整理自网络

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

帮他整理的

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

排版始终有问题

不过不影响可读性

就算了

暂时就先这样了

下面是代码部分

有不懂的可以留言

也可以一起讨论交流

下面代码调用声音传感器

获取声音信号

从而获取音量数据

01 package eoe . demo;
03 import android.media.AudioFormat;
04 import android.media.AudioRecord;
05 import android.media.MediaRecorder;
06 import android.util.Log;
08 public class RecordThread extends Thread {
09 private AudioRecord ar;
10 private int bs;
11 private static int SAMPLE_RATE_IN_HZ = 8000;
12 private boolean isRun = false;
13 public RecordThread() {
14 super();
15 bs = AudioRecord . getMinBufferSize( SAMPLE_RATE_IN_HZ , AudioFormat . CHANNEL_CONFIGURATION_MONO , AudioFormat . ENCODING_PCM_16BIT);
16 ar = new AudioRecord( MediaRecorder . AudioSource . MIC , SAMPLE_RATE_IN_HZ , AudioFormat . CHANNEL_CONFIGURATION_MONO , AudioFormat . ENCODING_PCM_16BIT , bs);
17 }
18 public void run() {
19 super . run();
20 ar . startRecording();
21 // 用于读取的
22 buffer byte [] buffer = new byte [bs ]; isRun = true; while ( isRun) {
23 int r = ar . read( buffer , 0 , bs);
24 int v = 0;
25 // 将 buffer 内容取出,进行平方和运算
26 for ( int i = 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 public void pause() {
37 // 在调用本线程的 Activity 的 onPause 里调用,以便 Activity 暂停时释放麦克风
38 isRun = false;
39 }
40 public void start() {
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 <LinearLayout xmlns:android= “http://schemas.android.com/apk/res/android”
03     android:orientation= “vertical” android:layout_width= “fill_parent”
04     android:layout_height= “fill_parent” >
05     <LinearLayout android: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         <Button android: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     <SurfaceView android:id= “@+id/SurfaceView01″
18         android:layout_height= “fill_parent” android:layout_width= “fill_parent” ></SurfaceView>
19 </LinearLayout>

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

001 package com . testOscilloscope;
002 import java.util.ArrayList;
003 import android.graphics.Canvas;
004 import android.graphics.Color;
005 import android.graphics.Paint;
006 import android.graphics.Rect;
007 import android.media.AudioRecord;
008 import android.view.SurfaceView;
009 public class ClsOscilloscope {
010     private ArrayList < short []> inBuf = new ArrayList < short []>();
011     private boolean isRecording = false; // 线程控制标记   
012     /** 
013      * X轴缩小的比例 
014      */
015     public int rateX = 4;
016     /** 
017      * Y轴缩小的比例 
018      */
019     public int rateY = 4;
020     /** 
021      * Y轴基线 
022      */
023     public int baseLine = 0;
024     /** 
025      * 初始化 
026      */
027     public void initOscilloscope( int rateX , int rateY , int baseLine) {
028         this . rateX = rateX;
029         this . rateY = rateY;
030         this . baseLine = baseLine;
031     }
032     /** 
033      * 开始 
034      *  
035      * @param recBufSize 
036      *            AudioRecord的MinBufferSize 
037      */
038     public void Start( AudioRecord audioRecord , int recBufSize , SurfaceView sfv ,
039             Paint mPaint) {
040         isRecording = true;
041         new RecordThread( audioRecord , recBufSize ). start(); // 开始录制线程   
042         new DrawThread( sfv , mPaint ). start(); // 开始绘制线程   
043     }
044     /** 
045      * 停止 
046      */
047     public void Stop() {
048         isRecording = false;
049         inBuf . clear(); // 清除   
050     }
051     /** 
052      * 负责从MIC保存数据到inBuf 
053      *  
054      * @author GV 
055      *  
056      */
057     class RecordThread extends Thread {
058         private int recBufSize;
059         private AudioRecord audioRecord;
060         public RecordThread( AudioRecord audioRecord , int recBufSize) {
061             this . audioRecord = audioRecord;
062             this . recBufSize = recBufSize;
063         }
064         public void run() {
065             try {
066                 short [] buffer = new short [ recBufSize ];
067                 audioRecord . startRecording(); // 开始录制   
068                 while ( isRecording) {
069                     // 从MIC保存数据到缓冲区   
070                     int bufferReadResult = audioRecord . read( buffer , 0 ,
071                             recBufSize);
072                     short [] tmpBuf = new short [ bufferReadResult / rateX ];
073                     for ( int i = 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 ( Throwable t) {
083             }
084         }
085     };
086     /** 
087      * 负责绘制inBuf中的数据 
088      *  
089      * @author GV 
090      *  
091      */
092     class DrawThread extends Thread {
093         private int oldX = 0; // 上次绘制的X坐标   
094         private int oldY = 0; // 上次绘制的Y坐标   
095         private SurfaceView sfv; // 画板   
096         private int X_index = 0; // 当前画图所在屏幕X轴的坐标   
097         private Paint mPaint; // 画笔   
098         public DrawThread( SurfaceView sfv , Paint mPaint) {
099             this . sfv = sfv;
100             this . mPaint = mPaint;
101         }
102         public void run() {
103             while ( isRecording) {
104                 ArrayList < short []> buf = new ArrayList < short []>();
105                 synchronized ( inBuf) {
106                     if ( inBuf . size() == 0)
107                         continue;
108                     buf = ( ArrayList < short []>) inBuf . clone(); // 保存   
109                     inBuf . clear(); // 清除   
110                 }
111                 for ( int i = 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( int start , short [] buffer , int rate , int baseLine) {
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 ( int i = 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 package com . testOscilloscope;
002 import android.app.Activity;
003 import android.graphics.Color;
004 import android.graphics.Paint;
005 import android.media.AudioFormat;
006 import android.media.AudioRecord;
007 import android.media.MediaRecorder;
008 import android.os.Bundle;
009 import android.view.MotionEvent;
010 import android.view.SurfaceView;
011 import android.view.View;
012 import android.view.View.OnTouchListener;
013 import android.widget.Button;
014 import android.widget.ZoomControls;
015 public class testOscilloscope extends Activity {
016     /** Called when the activity is first created. */
017     Button btnStart , btnExit;
018     SurfaceView sfv;
019     ZoomControls zctlX , zctlY;
020
021     ClsOscilloscope clsOscilloscope = new ClsOscilloscope();
022
023     static final int frequency = 8000; //分辨率   
024     static final int channelConfiguration = AudioFormat . CHANNEL_CONFIGURATION_MONO;
025     static final int audioEncoding = AudioFormat . ENCODING_PCM_16BIT;
026     static final int xMax = 16; //X轴缩小比例最大值,X轴数据量巨大,容易产生刷新延时   
027     static final int xMin = 8; //X轴缩小比例最小值   
028     static final int yMax = 10; //Y轴缩小比例最大值   
029     static final int yMin = 1; //Y轴缩小比例最小值   
030
031     int recBufSize; //录音最小buffer大小   
032     AudioRecord audioRecord;
033     Paint mPaint;
034     @Override
035     public void onCreate( Bundle savedInstanceState) {
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( new ClickEvent());
046         btnExit = ( Button) this . findViewById( R . id . btnExit);
047         btnExit . setOnClickListener( new ClickEvent());
048         //画板和画笔   
049         sfv = ( SurfaceView) this . findViewById( R . id . SurfaceView01);
050         sfv . setOnTouchListener( new TouchEvent());
051         mPaint = new Paint();
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( new View . OnClickListener() {
060             @Override
061             public void onClick( View v) {
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( new View . OnClickListener() {
069             @Override
070             public void onClick( View v) {
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( new View . OnClickListener() {
079             @Override
080             public void onClick( View v) {
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( new View . OnClickListener() {
089             @Override
090             public void onClick( View v) {
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     protected void onDestroy() {
100         super . onDestroy();
101         android . os . Process . killProcess( android . os . Process . myPid());
102     }
103
104     /** 
105      * 按键事件处理 
106      * @author GV 
107      * 
108      */
109     class ClickEvent implements View . OnClickListener {
110         @Override
111         public void onClick( View v) {
112             if ( v == btnStart) {
113                 clsOscilloscope . baseLine = sfv . getHeight ()/ 2;
114                 clsOscilloscope . Start( audioRecord , recBufSize , sfv , mPaint);
115             } else if ( v == btnExit) {
116                 clsOscilloscope . Stop();
117             }
118         }
119     }
120     /** 
121      * 触摸屏动态设置波形图基线 
122      * @author GV 
123      * 
124      */
125     class TouchEvent implements OnTouchListener {
126         @Override
127         public boolean onTouch( View v , MotionEvent event) {
128             clsOscilloscope . baseLine =( int) event . getY();
129             return true;
130         }
131
132     }
133 }
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值