通过J2ME的录音功能实现简易示波器

               

本文来自http://blog.****.net/hellogv/ ,引用必须注明出处!      

       早就有人通过PC声卡的输入(麦克风孔)来做模拟示波器,但是用手机来实现的比较少。用J2ME的MMAPI实现模拟示波器,具体效果稍逊于智能机,因为智能机可以实时读取麦克风输入流,而J2ME还需要有短暂的缓冲构成了阻塞,不过,实现出来玩一下还是足够了。

先贴出效果图:

通过J2ME的录音功能实现简易示波器

左图是程序在WTK运行的结果,右图是Audition读取音频输入口的波形,信号源是一个经过信号放大的压力传感器。

程序使用NetBeans + LWUIT类库,接下来贴出全部代码:

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) {}}

 

以下代码为画波形图的代码:

/* * 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();   }}  

           

再分享一下我老师大神的人工智能教程吧。零基础!通俗易懂!风趣幽默!还带黄段子!希望你也加入到我们人工智能的队伍中来!https://blog.****.net/jiangjunshow