早就有人通過PC聲卡的輸入(麥克風孔)來做模擬示波器,但是用手機來實現的比較少。用J2ME的MMAPI實現模擬示波器,具體效果稍遜于智能機,因為智能機可以實時讀取麥克風輸入流,而J2ME還需要有短暫的緩沖構成了阻塞,不過,實現出來玩一下還是足夠了。
先貼出效果圖:
左圖是程序在WTK運行的結果,右圖是Audition讀取音頻輸入口的波形,信號源是一個經過信號放大的壓力傳感器。
程序使用NetBeans + LWUIT類庫,接下來貼出全部代碼:
importcom.sun.lwuit.Command;
importcom.sun.lwuit.Display;
importcom.sun.lwuit.Form;
importcom.sun.lwuit.events.ActionEvent;
importcom.sun.lwuit.events.ActionListener;
importcom.sun.lwuit.layouts.BorderLayout;
importjava.io.ByteArrayOutputStream;
importjavax.microedition.media.Manager;
importjavax.microedition.media.Player;
importjavax.microedition.media.control.RecordControl;
/**
*@author張國威
*/
publicclassFrm_MainMenuextendsjavax.microedition.midlet.MIDletimplementsActionListener{
publicFormform;
privateCommandcmdExit=newCommand("退出",1);
privateThreadReceivethreadReceive=newThreadReceive();//接收數據線程
privateCmp_Wavecmp_HeartWave=null;
privatePlayercapturePlayer=null;
privateRecordControlrecordControl=null;
privateByteArrayOutputStreambos=newByteArrayOutputStream();
publicvoidstartApp(){
Display.init(this);
form=newForm();//達到全屏的效果
cmp_HeartWave=newCmp_Wave(form.getHeight(),form.getWidth());
form.getStyle().setBgImage(null);//本窗體不需要背景
form.addCommand(cmdExit);
form.setCommandListener(this);
form.setLayout(newBorderLayout());
//設置畫板控件
form.addComponent(BorderLayout.CENTER,cmp_HeartWave);//添加控件
form.show();
try{
capturePlayer=Manager.createPlayer("capture://audio?rate=8000&bits=8&channels=1");//PCM,8位,8kH
if(capturePlayer!=null){
capturePlayer.realize();
recordControl=(RecordControl)capturePlayer
.getControl("javax.microedition.media.control.RecordControl");
if(recordControl==null)
thrownewException("NoRecordControlavailable");
recordControl.setRecordStream(bos);
}else{
thrownewException("CaptureAudioPlayerisnotavailable");
}
}catch(Exceptione){}
threadReceive.start();//開始啟動線程
}
/*
*byte轉為int的函數,因為JAVA的byte范圍從-127~127
*/
publicstaticintunsignedByteToInt(byteb){
return(int)b&0xFF;
}
classThreadReceiveextendsThread{
privatebooleanisRuning=true;//默認線程內部while循環(huán)可以執(zhí)行
publicvoidStopThread()
{
isRuning=false;
}
publicvoidrun(){
//*************************************************************
//繪制波形數據
//*************************************************************
try{
capturePlayer.start();
while(isRuning)
{
recordControl=(RecordControl)capturePlayer.getControl("javax.microedition.media.control.RecordControl");
recordControl.setRecordStream(bos);
recordControl.startRecord();
Thread.sleep(25);//停頓25ms錄音
recordControl.stopRecord();
recordControl.commit();
//由于采集頻率太高,手機不能完全顯示,所以需要通過均值濾波來降低分辨率
intZoom_out=200;//縮小200倍
int[]bits=newint[bos.toByteArray().length/Zoom_out];
for(inti=0,total=0,index=0;i
{
total=total+unsignedByteToInt(bos.toByteArray()[i]);
if(i%Zoom_out==0&&i!=0)
{
bits[index]=total/Zoom_out;
total=0;
index++;
}
}
cmp_HeartWave.UpdateVerticalWave(bits);