本文來自http://blog.csdn.net/hellogv/ ,引用必須註明出處!
早就有人通過PC聲卡的輸入(麥克風孔)來做模擬示波器,但是用手機來實現的比較少。用J2ME的MMAPI實現模擬示波器,具體效果稍遜於智能機,因爲智能機可以實時讀取麥克風輸入流,而J2ME還需要有短暫的緩衝構成了阻塞,不過,實現出來玩一下還是足夠了。
先貼出效果圖:
左圖是程序在WTK運行的結果,右圖是Audition讀取音頻輸入口的波形,信號源是一個經過信號放大的壓力傳感器。
程序使用NetBeans + LWUIT類庫,接下來貼出全部代碼:
view plaincopy to clipboardprint?
import com.sun.lwuit.Command;
import com.sun.lwuit.Display;
import com.sun.lwuit.Form;
import com.sun.lwuit.events.ActionEvent;
import com.sun.lwuit.events.ActionListener;
import com.sun.lwuit.layouts.BorderLayout;
import java.io.ByteArrayOutputStream;
import javax.microedition.media.Manager;
import javax.microedition.media.Player;
import javax.microedition.media.control.RecordControl;
/**
* @author 張國威
*/
public class Frm_MainMenu extends javax.microedition.midlet.MIDlet implements ActionListener {
public Form form ;
private Command cmdExit = new Command("退出", 1);
private ThreadReceive threadReceive =new ThreadReceive();//接收數據線程
private Cmp_Wave cmp_HeartWave=null;
private Player capturePlayer = null;
private RecordControl recordControl = null;
private ByteArrayOutputStream bos = new ByteArrayOutputStream();
public void startApp() {
Display.init(this);
form = new Form();//達到全屏的效果
cmp_HeartWave=new Cmp_Wave(form.getHeight(),form.getWidth());
form.getStyle().setBgImage(null);//本窗體不需要背景
form.addCommand(cmdExit);
form.setCommandListener(this);
form.setLayout(new BorderLayout());
//設置畫板控件
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)
throw new Exception("No RecordControl available");
recordControl.setRecordStream(bos);
} else {
throw new Exception("Capture Audio Player is not available");
}
} catch (Exception e) {}
threadReceive.start();//開始啓動線程
}
/*
* byte轉爲int的函數,因爲JAVA的byte範圍從-127~127
*/
public static int unsignedByteToInt(byte b) {
return (int) b & 0xFF;
}
class ThreadReceive extends Thread {
private boolean isRuning=true;//默認線程內部while循環可以執行
public void StopThread()
{
isRuning=false;
}
public void run(){
//*************************************************************
//繪製波形數據
//*************************************************************
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();
//由於採集頻率太高,手機不能完全顯示,所以需要通過均值濾波來降低分辨率
int Zoom_out=200;//縮小200倍
int[] bits=new int[bos.toByteArray().length/Zoom_out];
for(int i=0,total=0,index=0;i<bos.toByteArray().length;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);
bos.reset();
}
capturePlayer.stop();
capturePlayer.close();
} catch (Exception e) {}
}
}
public void actionPerformed(ActionEvent arg0) {
Command command=arg0.getCommand();
if(command==cmdExit)//退出程序
notifyDestroyed();
}
protected void pauseApp() {}
protected void destroyApp(boolean arg0) {}
}
import com.sun.lwuit.Command;
import com.sun.lwuit.Display;
import com.sun.lwuit.Form;
import com.sun.lwuit.events.ActionEvent;
import com.sun.lwuit.events.ActionListener;
import com.sun.lwuit.layouts.BorderLayout;
import java.io.ByteArrayOutputStream;
import javax.microedition.media.Manager;
import javax.microedition.media.Player;
import javax.microedition.media.control.RecordControl;
/**
* @author 張國威
*/
public class Frm_MainMenu extends javax.microedition.midlet.MIDlet implements ActionListener {
public Form form ;
private Command cmdExit = new Command("退出", 1);
private ThreadReceive threadReceive =new ThreadReceive();//接收數據線程
private Cmp_Wave cmp_HeartWave=null;
private Player capturePlayer = null;
private RecordControl recordControl = null;
private ByteArrayOutputStream bos = new ByteArrayOutputStream();
public void startApp() {
Display.init(this);
form = new Form();//達到全屏的效果
cmp_HeartWave=new Cmp_Wave(form.getHeight(),form.getWidth());
form.getStyle().setBgImage(null);//本窗體不需要背景
form.addCommand(cmdExit);
form.setCommandListener(this);
form.setLayout(new BorderLayout());
//設置畫板控件
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)
throw new Exception("No RecordControl available");
recordControl.setRecordStream(bos);
} else {
throw new Exception("Capture Audio Player is not available");
}
} catch (Exception e) {}
threadReceive.start();//開始啓動線程
}
/*
* byte轉爲int的函數,因爲JAVA的byte範圍從-127~127
*/
public static int unsignedByteToInt(byte b) {
return (int) b & 0xFF;
}
class ThreadReceive extends Thread {
private boolean isRuning=true;//默認線程內部while循環可以執行
public void StopThread()
{
isRuning=false;
}
public void run(){
//*************************************************************
//繪製波形數據
//*************************************************************
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();
//由於採集頻率太高,手機不能完全顯示,所以需要通過均值濾波來降低分辨率
int Zoom_out=200;//縮小200倍
int[] bits=new int[bos.toByteArray().length/Zoom_out];
for(int i=0,total=0,index=0;i<bos.toByteArray().length;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);
bos.reset();
}
capturePlayer.stop();
capturePlayer.close();
} catch (Exception e) {}
}
}
public void actionPerformed(ActionEvent arg0) {
Command command=arg0.getCommand();
if(command==cmdExit)//退出程序
notifyDestroyed();
}
protected void pauseApp() {}
protected void destroyApp(boolean arg0) {}
}
以下代碼爲畫波形圖的代碼:
view plaincopy to clipboardprint?
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
import com.sun.lwuit.Component;
import com.sun.lwuit.Container;
import com.sun.lwuit.Graphics;
import com.sun.lwuit.Image;
import com.sun.lwuit.layouts.BorderLayout;
/**
*
* @author Administrator
*/
public class Cmp_Wave extends Container{
private Image imgWaveCanvas;//波形圖畫板,圖形畫在圖像上,再不斷地貼圖到屏幕
private int height; //自己定義的畫板高度 getHeight()
private int width; //自己定義的畫板寬度 getWidth()
private int old_xPos=-1;//位置初始化
private int old_yPos=-1;//位置初始化
private Component cmpWaveCanvas;//顯示波形控件
private int[] point=null;//每次收到的point數組
public Cmp_Wave(int canvasHeight,int canvasWidth)
{
super.setLayout(new BorderLayout());
super.addComponent(BorderLayout.CENTER,WaveCanvas(canvasHeight,canvasWidth));//波形顯示在中間
}
private Component WaveCanvas(int canvasHeight,int canvasWidth)
{
height=canvasHeight;
width=canvasWidth;
//-------初始化波形畫板圖像
imgWaveCanvas=Image.createImage(width, height);
//-------初始化波形畫板控件,在控件上繪製波形畫板圖像
cmpWaveCanvas=new Component(){
public void paint(Graphics g) {
//在內存中繪製波形圖
Graphics canvas=imgWaveCanvas.getGraphics();
if(point==null)//如果point還沒初始化
return;//不執行下面語句
for(int i=0;i<point.length;i++)
{
if(old_xPos>=width //如果xPos超過屏幕寬度
|| old_xPos==-1) //如果PaintVerticalWave是第一次運行
{
old_xPos=0;//歸零畫圖
old_yPos=height/2;//中心點畫圖
canvas.setColor(0x444444);//設置背景色
canvas.fillRect(0, 0, width, height);
}
int new_yPosPoint=point[i] ;
canvas.setColor(0xCCCCCC);//線條色
canvas.drawLine(old_xPos,old_yPos,old_xPos+1,new_yPosPoint);
old_xPos++;
old_yPos=new_yPosPoint;
}
//把內存中的波形圖畫到控件上
g.drawImage(imgWaveCanvas, 0, 0);
}
};
cmpWaveCanvas.setFocusPainted(false);
cmpWaveCanvas.setFocusable(false);
return cmpWaveCanvas;
}
public void UpdateVerticalWave(int []yPos) {
//更新繪圖數組
int []tmpPos=new int[yPos.length];//臨時數組,只取原數組的waveN分之一
for(int i=0,ii=0;i<tmpPos.length;i++,ii+=1)
tmpPos[i]=yPos[ii];
point=tmpPos;
//重新繪圖
cmpWaveCanvas.repaint();
}
}
本文來自CSDN博客,轉載請標明出處:http://blog.csdn.net/hellogv/archive/2010/08/27/5842657.aspx