本文标签: Android提高
上次简单地介绍了《AudioRecord和AudioTrack的使用》,这次就结合SurfaceView实现一个Android版的手机模拟信号示波器(PS:以前也讲过J2ME版的手机示波器)。最近物联网炒得很火,作为手机软件开发者,如何在不修改手机硬件电路的前提下实现与第三方传感器结合呢?麦克风就是一个很好的ADC接口,通过麦克风与第三方传感器结合,再在软件里对模拟信号做相应的处理,就可以提供更丰富的传感化应用。
先来看看本文程序运行的效果图(屏幕录像速度较慢,真机实际运行起来会更加流畅):
本文程序使用8000hz的采样率,对X轴方向绘图的实时性要求较高,如果不降低X轴的分辨率,程序的实时性较差,因此程序对X轴数据缩小区间为8倍~16倍。由于采用16位采样,因此Y轴数据的高度相对于手机屏幕来说也偏大,程序也对Y轴数据做缩小,区间为1倍~10倍。在SurfaceView的OnTouchListener方法里加入了波形基线的位置调节,直接在SurfaceView控件上触摸即可控制整体波形偏上或偏下显示。
main.xml源码如下:
ClsOscilloscope.java是实现示波器的类库,包含AudioRecord操作线程和SurfaceView绘图线程的实现,两个线程同步操作,代码如下:
testOscilloscope.java是主程序,控制UI和ClsOscilloscope,代码如下:
ClsOscilloscope clsOscilloscope=new ClsOscilloscope();
static final int frequency = 8000;//分辨率
static final int channelConfiguration = AudioFormat.CHANNEL_CONFIGURATION_MONO;
static final int audioEncoding = AudioFormat.ENCODING_PCM_16BIT;
static final int xMax = 16;//X轴缩小比例最大值,X轴数据量巨大,容易产生刷新延时
static final int xMin = 8;//X轴缩小比例最小值
static final int yMax = 10;//Y轴缩小比例最大值
static final int yMin = 1;//Y轴缩小比例最小值
int recBufSize;//录音最小buffer大小
AudioRecord audioRecord;
Paint mPaint;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
//录音组件
recBufSize = AudioRecord.getMinBufferSize(frequency,
channelConfiguration, audioEncoding);
audioRecord = new AudioRecord(MediaRecorder.AudioSource.MIC, frequency,
channelConfiguration, audioEncoding, recBufSize);
//按键
btnStart = (Button) this.findViewById(R.id.btnStart);
btnStart.setOnClickListener(new ClickEvent());
btnExit = (Button) this.findViewById(R.id.btnExit);
btnExit.setOnClickListener(new ClickEvent());
//画板和画笔
sfv = (SurfaceView) this.findViewById(R.id.SurfaceView01);
sfv.setOnTouchListener(new TouchEvent());
mPaint = new Paint();
mPaint.setColor(Color.GREEN);// 画笔为绿色
mPaint.setStrokeWidth(1);// 设置画笔粗细
//示波器类库
clsOscilloscope.initOscilloscope(xMax/2, yMax/2, sfv.getHeight()/2);
//缩放控件,X轴的数据缩小的比率高些
zctlX = (ZoomControls)this.findViewById(R.id.zctlX);
zctlX.setOnZoomInClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if(clsOscilloscope.rateX>xMin)
clsOscilloscope.rateX--;
setTitle("X轴缩小"+String.valueOf(clsOscilloscope.rateX)+"倍"
+","+"Y轴缩小"+String.valueOf(clsOscilloscope.rateY)+"倍");
}
});
zctlX.setOnZoomOutClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if(clsOscilloscope.rateX<xMax)
clsOscilloscope.rateX++;
setTitle("X轴缩小"+String.valueOf(clsOscilloscope.rateX)+"倍"
+","+"Y轴缩小"+String.valueOf(clsOscilloscope.rateY)+"倍");
}
});
zctlY = (ZoomControls)this.findViewById(R.id.zctlY);
zctlY.setOnZoomInClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if(clsOscilloscope.rateY>yMin)
clsOscilloscope.rateY--;
setTitle("X轴缩小"+String.valueOf(clsOscilloscope.rateX)+"倍"
+","+"Y轴缩小"+String.valueOf(clsOscilloscope.rateY)+"倍");
}
});
zctlY.setOnZoomOutClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if(clsOscilloscope.rateY<yMax)
clsOscilloscope.rateY++;
setTitle("X轴缩小"+String.valueOf(clsOscilloscope.rateX)+"倍"
+","+"Y轴缩小"+String.valueOf(clsOscilloscope.rateY)+"倍");
}
});
}
@Override
protected void onDestroy() {
super.onDestroy();
android.os.Process.killProcess(android.os.Process.myPid());
}
/**
* 按键事件处理
* @author GV
*
*/
class ClickEvent implements View.OnClickListener {
@Override
public void onClick(View v) {
if (v == btnStart) {
clsOscilloscope.baseLine=sfv.getHeight()/2;
clsOscilloscope.Start(audioRecord,recBufSize,sfv,mPaint);
} else if (v == btnExit) {
clsOscilloscope.Stop();
}
}
}
/**
* 触摸屏动态设置波形图基线
* @author GV
*
*/
class TouchEvent implements OnTouchListener{
@Override
public boolean onTouch(View v, MotionEvent event) {
clsOscilloscope.baseLine=(int)event.getY();
return true;
}
}
}
声明: 本文由( 张飞不张,文采横飞 )原创编译,转载请保留链接: Android提高第十一篇之模拟信号示波器
Linux系统与内核学习群:194051772
WP建站技术学习交流群:194062106
[e01]以前看过lwuit的,android的性能更好哟!
2010-11-24 14:14[e01]好东西
2010-11-24 14:18太牛B 了.
2010-11-24 14:20[e01]
不错,加油啊。[e01]
2010-11-24 14:22[e01]哥的必须顶
2010-11-24 14:28被逼顶了一下[e01]
2010-11-24 14:43回复 goodlinux:
2010-11-24 15:56下次去深圳,吃穷你….
回复 hellogv:看完楼上的评论,我感觉好笑,因为断句不同给读者的感受亦不同。
2010-11-24 19:52高人啊~~~
2010-11-24 20:38深入浅出..注释合理…[e01][e01][e01][e01][e01]
2010-11-24 21:32载道名师课堂点评:深入浅出,注释合理,android开发性能非常的好,我支持你…….[e01]
2010-11-25 09:26[e01]
高手, 顶一下. 有机会来上海请你吃饭!!
2010-11-25 09:44回复 certificate:
2010-11-25 09:47我不在上海….现在南京,年底准备回广东工作,呵呵
回复 hellogv:高手到哪都可以, 对上海有兴趣不?
2010-11-25 10:07我知道有一个公司不错 http://www.broadcom.com 可以试试.
回复 certificate:
2010-11-25 10:20也有比较好的上海公司给我offer,不过我是广东人,呵呵
呵呵, 人个有志.
2010-11-25 10:29无论如何, 只要来上海 请你吃饭是没有问题的.[e04]
[e01]
2010-11-25 10:49[e01]
2010-11-25 11:13lz模拟器上怎么看不到波段啊
2010-11-25 11:21回复 emike:
2010-11-25 11:22AudioRecord不能在模拟器上用,必须要在真机上面试
回复 WolfMvP:恩,中国文化博大精深啊![e04]
2010-11-25 12:35原来楼主在南京啊,我请你吃饭!
2010-11-25 16:35有没有人请我吃饭啊
2010-11-26 10:23回复 andyzhchy:
2010-11-26 10:44…………………………
很强大[e01]
2010-11-26 11:40[e01]android很有前途
2010-11-26 12:02记下先,有时间过来看[e01]
2010-11-26 17:11请问在真机测试没有?[e08] 有的机器不行的
2010-11-27 01:03楼主很厉害啊[e01]
2010-11-30 09:51回复 zxciop110:
2010-11-30 10:49AudioRecord只能在真机上用的,我测试的手机是XT720
[e01]
2010-11-30 14:13[e03]强悍。。。
2010-12-02 16:49回复 goodlinux:被什么顶了一下?[e07]
2010-12-14 16:30HTC G6真机测试下来没有波形,不知道为什么
2010-12-21 00:02[e01]
2010-12-29 15:19[e01]先谢谢楼主,正好用的到,不过楼主好像忘了贴mainfest.xml,mic权限要设置,刚刚调试了好长时间不出图像啊.android.permission.RECORD_AUDIO
2011-03-14 17:39[e04]
如果說要把y軸振福調小還有其他方式嗎,
audioEncoding = AudioFormat.ENCODING_PCM_16BIT
我在這邊改成8BIT 在模擬器上跑就會出現錯誤了16BIT還可以,是因為音效卡本身的編碼方式造成的嗎??
[e07]
2011-04-19 12:18正在学习, 好声羡慕楼主的工夫。关于AudioRecord不能在模拟器上用, 请楼主看看下面连接。 本人新手, 看不出所以。 又没有真机。 不能在模拟器上用, 实在是赶着急。
http://www.dyteq.com/2ndquest/?p=102e08
2011-04-19 16:25回复 license2005:似乎你可以在模拟器上跑。 和板主说法是否矛盾。 我非常想在模拟器上试试,恳请解释一下。
2011-04-21 09:37回复 you_sun:试一试
2011-04-21 09:39回复 license2005:似乎你可以在模拟器上跑。 和板主说法是否矛盾。 我非常想在模拟器上试试,恳请解释一下
2011-04-21 09:40回复 you_sun:也許是因為硬體的關西 有些用到AudioRecord的我這邊也是無法在模擬器上運作,我反而比較想了解,如果在實機上跑是否會很不流暢,電腦跟手機處理速度差很多,不知道有沒有人可以說一下在實機上跑的感想?
2011-04-21 13:16回复 hellogv:我真机上试也没有啊..
2011-04-23 15:43回复 license2005:非常感谢回复,也就是说, 你的确是可以在你的硬体环境下跑模拟信号示波器了。如果可以,我也想试试。遇到问题还会请教, 多谢了。
2011-04-23 16:19回复 you_sun:
2011-04-23 17:08我这个例子就是在真机下面跑并且截图录屏的
想請問一下為什麼取樣率如果不是8k就不能執行呢???我是在電腦上測試的,在手機上可行嗎[e07]
2011-04-25 21:03回复 license2005:
2011-04-25 23:14必须用真机
回复 hellogv:我試過把取樣率改成10000在真機下跑卻還是沒辦法,而前一篇的助聽器那邊的頻率是用44100卻可以執行,我是在三星Galaxy Tab(P1000)下嘗試的。
2011-04-26 10:09回复 hellogv:所以版主可以在更動任何分辨率下在真機執行囉?[e07]
2011-04-26 10:11回复 hellogv:版主我測試過了ok了 您的blog真是一個好學習的地方
2011-04-26 21:53深入浅出,android开发性能好
2011-04-27 18:20版主您好 如果是要顯示聲音檔案的波形開如何做呢[e07]
2011-04-30 19:23回复 license2005:
2011-04-30 19:35如果是wave/PCM的话就直接读取,如果是MP3的话就先解码在再读取波形
问一句外行话, 可以在Android Tablet上实现吗?
2011-05-09 02:35回复 Moon_Night:和谐啊
2011-05-09 23:12回复 you_sun:
2011-05-10 06:29可以的
回复 hellogv:我准备去买一个t-mobile comet, 99.99$, 具说是华为的, 从来没用过android, 请内行人给多多指点, 多谢。
2011-05-10 15:15报告大家一个好消息, 我成功了. 我上星期专门为试这个程序买了一个手机, Huawei, U8150 IDEOS, 试了一星期, 终于见到了波形. 我真是太高兴了. 我想跟大家说, 好好干, 会成功的.
2011-05-19 12:38感谢tingshuai的提示, 对于我最后成功起到关键作用.
问个菜问题, 我在sdcard录音的文件如何上传到计算机. 计算机上看不到sdcard. 我在网上找了半天, 也没有答案.
2011-05-19 14:16很不好意思, 我把USB设成debug mode 了, 所以看不见USB Storage, 刚刚玩了几天android, 见笑了.
2011-05-19 15:55版主您好:
2011-06-27 19:34我目前已經有.pcm檔,我想在您的ClsOscilloscope這程式中,绘制指定区域那邊,加入檔案讀取,並將它繪製出來,可是一直實現不了,希望版主能提供一點方法幫助…..[e06]
回复 license2005:
2011-06-27 19:37。。。。。。。。。。。。
回复 hellogv:版主我繼續研究!!對程式概念還是很差><[e08]
2011-06-27 19:54回复 license2005:
2011-06-27 23:15先了解是8位的PCM还是16位的PCM吧
回复 hellogv:格式是一樣的16BIT 取樣率:8000,是否是需要先將檔案轉成數據流的形式,在將數據流(buffer)繪出,如果需要將檔案轉成數據流的方式,這部分不曉得該如何實現了…..[e08]
2011-06-28 00:35模拟器上是可以实现的,只要需添加一下模拟器对record的支持,然后在androidmanifest.xml添加权限访问即可。
2011-08-03 11:48版主你好,我想做一个音乐播放器在播放音乐的时候显示其波形图,不知您能否指点下?多谢啦!持续关注中~~~
2011-08-10 10:33版主我修改了你的程序,但是不知道为什么我的X轴无法改变,能指点一下吗?
2011-08-14 14:57我的QQ号是378532514
请问楼主,如果是从一个真实的示波器中输出的一个正弦信号 怎么将其在android模拟出示波器上显示,是通过手机的usb口还是耳机接口?
2011-08-30 14:57[reply]marenjun0611[/reply]
2011-08-30 21:31USB就是数字信号了,当然是麦克风,麦克风采集的是模拟信号,同时要注意采集的分辨率
[reply]hellogv[/reply]
2011-08-31 08:36要是通过usb的话,在android里面加一个A/D转换行不行?
[reply]marenjun0611[/reply]
2011-08-31 09:19也可以,不过麻烦些而已
请问楼主做过语音识别吗?就是预先录入一些声音,保存起来,以后用户说出声音就执行命令,不知道能不能做到,求解,谢谢!
2011-09-23 21:14[reply]winhjm[/reply]
2011-09-25 17:07没有
[reply]winhjm[/reply]
2011-10-04 10:12你看看Android的api示例程序,里面有个语音识别的demo,可以参考下。
请问,楼主,如果我从信号发生器输出一个正弦信号,接到耳机接口作为输入信号,要在示波器上显示,也是用audioRecor来处理吗? 能不能稍微指点一下
2011-10-08 19:56[reply]marenjun0611[/reply]
2011-10-08 21:00audioRecord就是一个ADC
牛人,谢谢啦
2011-10-12 01:09请问大哥有什么办法可以实现android手机和pc通过蓝牙socket通信吗?
2011-10-12 01:10[reply]zb235[/reply]
2011-10-12 09:30就是SPP这个虚拟串口协议啊
[reply]hellogv[/reply]
2011-10-14 10:19从MIC口输入一个数字信号,经过程序的D/A转换,可以达到相同的效果吗
[reply]wdqfzy[/reply]
2011-10-14 11:17请教一下怎么添加模拟器对recording的支持?
[reply]marenjun0611[/reply]
2011-10-14 22:39用真机吧
请问,楼主,我如果想让画图在自己指定的一个区域内画,然后屏幕的其余部分添加一些示波器常用的按钮之类的,用RelativeLayout可以实现吗
2011-10-27 16:01[reply]marenjun0611[/reply]
2011-10-27 20:13不一定用RelativeLayout,其他Layout也可以的
楼主,请教你个事情,用android系统我如果想用usb口来接收波形,做一个示波器来显示,实现的难度大吗?
2011-11-22 18:25[reply]marenjun0611[/reply]
2011-11-22 22:59用USB口接收,那就是数字信号了,你要想好发送端怎么处理
[reply]hellogv[/reply]
2011-11-23 19:19是的,发送端发送的是调制后的数字信号,在用usb口接收做示波器方面,楼主能不能给给点思路 谢了
顶
2011-12-12 13:33请教~~~请问文中使用audioRecorder采集出来的数据使用AudioFormat.ENCODING_PCM_16BIT编码,是否表示采集后read到int bufferReadResult = audioRecord.read(buffer, 0,recBufSize);的short[] buffer中的数据就是pcm数据呢?以8KHZ的采样频率,
2012-02-17 16:17short[] buffer中的每一个short代表一个脉冲信号,所以一秒的话会有8000个short类型的数据?那么这个信号是否可以直接拿去做分帧、加窗、FFT等接下来的信号处理了呀?
信号处理方便我不太懂,还请博主指点一二哇,非常感谢!
[reply]jj6335[/reply]
2012-02-17 22:0716位信号可以直接去做信号分析,8位的要另外补偿
[reply]hellogv[/reply]
2012-02-20 10:43那么我每次从其中read出来的short数组,有8192长,是否就是在一秒钟所采到的8000个点呀?
[reply]jj6335[/reply]
2012-02-20 22:57嗯
hello,你的东西写得不错,但是我在真机上打开程序后没有看见波形,按了开始了,是不是还要什么操作或者配置等,我正在弄流量统计的动态图,每一次传入的是long型,请问怎么做到你这样的效果呢
2012-02-21 19:50[reply]abcxob[/reply]
2012-02-22 08:07你把本文代码完整地作为工程文件跑一次,别做任何修改
[reply]abcxob[/reply]
2012-02-22 14:49可以了,效果还可以,不是特别流畅,我cpu800,楼主,我看过你有一篇是写surfaceview双缓冲的,你这里可以用上吗,,波形的界面有明显的重画,如果能做到像心电图那样的效果那就太好了,呵呵,还是很感谢楼主的分享精神
[reply]abcxob[/reply]
2012-02-22 14:51在真机上没有显示波形的同学,基本都是没有加.android.permission.RECORD_AUDIO,加上去就可以了
向楼主请教下,我想给后面加个坐标背景,用什么方法比较好
2012-02-23 12:39我这个问题大发了,如果原样照抄,提示@override错误,把@override删除了吧,报错倒是不报了,但是一运行就程序自动关闭。唉,版主大大,这叫我如何是好
2012-04-23 19:39[reply]abcxob[/reply]
2012-04-23 20:00您好,你能把这个程序的APK发给我么,我编译完运行不了,检查了N遍,摆脱。
[reply]abcxob[/reply]
2012-04-23 20:01如果你有幸看到,我的邮箱是330865911@qq.com
[reply]a330865911[/reply]
2012-04-24 16:31注册了Activity没
[reply]hellogv[/reply]完全照抄,可是运行不了。一运行,就报错误关闭。 我在XML文件里已经注册过Activity了。而且也加了AudioRcord的访问权限了。不知什么原因。而且是复制粘贴得。求解?
2012-04-25 18:25[reply]hellogv[/reply]
2012-04-28 09:24弄了2天,注册完Activity,android.permission.RECORD_AUDIO也已经申请了,程序总算是正常安装上了。但是出现一个新问题,点开始没反应,而且他是竖屏而不是横屏,如果我设置自动调整横竖屏,并且把屏幕横过来,程序就自动关闭,在模拟机上按Ctrl+F11的话也会程序自动关闭。。我到底哪里弄错了。/。唉。
[reply]hellogv[/reply]
2012-04-30 20:17哈哈,这次终于弄好了,有波形,但是他还是竖屏的,怎么把它弄成横过来的
[reply]a330865911[/reply]
2012-05-02 14:01用真机,别用虚拟机
[reply]hellogv[/reply]
2012-05-02 18:14把android.os.Process.killProcess(android.os.Process.myPid()); 这句删除,再注册一下Activity就行了!
楼主,你好,请教一问题:为了节省绘图的点数,每次在保存上一次绘图上仅绘制最新一个点(曲线动态延伸),该如何实现?请教!谢谢!
2012-05-02 19:12楼主大大 很犀利呀 !这么早 就研究这么复杂的问题 向楼主大大致敬
2012-07-04 09:56楼主,我想请问一下
2012-07-17 10:31楼主,我想请问一下,问什么我插了耳机(带麦克风的那种)之后,对手机自带的麦克风说话,这个模拟示波器还是会有反应
2012-07-17 10:32我现在再做一个Android手机示波器,用来显示脉搏波传感器的波形,传感器通过USB与手机相连,但不知道如何获取传感器传来的数字信号,求指教!
2012-08-14 17:30