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 }
- android声音传感器编程
- Android传感器编程入门
- Android传感器编程入门
- Android传感器编程入门
- Android传感器编程入门
- Android传感器编程入门
- Android传感器编程入门
- Android传感器高级编程
- Android传感器编程入门
- Android传感器编程入门
- 《Android传感器高级编程》
- Android:传感器编程
- android 传感器编程
- Android 方位传感器 (传感器编程合集)
- Android的传感器编程小结
- Android的传感器编程小结
- Android的传感器编程小结
- Android传感器编程学习笔记
- c# 3.0新特性 隐式类型
- AndroidManifest.xml文件解析
- android用户界面之TabHost教程实例汇总
- startx analyze
- ASP.NET性能优化之负载均衡
- android声音传感器编程
- html文字滚动代码
- 遮罩层样式
- 提高代码可读性: 命名技术
- 屏蔽视频网站广告
- Linux下安装MySQL管理工具MySQL Administrator和MySQL Query Browser
- 监控WebLogic 8.x的解决方案(监控应用服务器系列文章三)
- QT+OpenGL读取显示图片
- C#创建Windows Service(Windows 服务)基础教程