[讨论] 通过J2ME的录音功能实现简易示波器

soso   2010-8-27 14:20 楼主
本文来自http://blog.csdn.net/hellogv/ ,引用必须注明出处!      

早就有人通过PC声卡的输入(麦克风孔)来做模拟示波器,但是用手机来实现的比较少。用J2ME的MMAPI实现模拟示波器,具体效果稍逊于智能机,因为智能机可以实时读取麦克风输入流,而J2ME还需要有短暂的缓冲构成了阻塞,不过,实现出来玩一下还是足够了。
先贴出效果图:
0_1282873729tsKL.gif.jpeg
左图是程序在WTK运行的结果,右图是Audition读取音频输入口的波形,信号源是一个经过信号放大的压力传感器。
程序使用NetBeans + LWUIT类库,接下来贴出全部代码:
  1. import com.sun.lwuit.Command;
  2. import com.sun.lwuit.Display;
  3. import com.sun.lwuit.Form;
  4. import com.sun.lwuit.events.ActionEvent;
  5. import com.sun.lwuit.events.ActionListener;
  6. import com.sun.lwuit.layouts.BorderLayout;
  7. import java.io.ByteArrayOutputStream;
  8. import javax.microedition.media.Manager;
  9. import javax.microedition.media.Player;
  10. import javax.microedition.media.control.RecordControl;

  11. /**
  12. * @author 张国威
  13. */
  14. public class Frm_MainMenu extends javax.microedition.midlet.MIDlet implements ActionListener {
  15.     public Form form ;
  16.     private  Command cmdExit = new Command("退出", 1);
  17.     private ThreadReceive threadReceive =new ThreadReceive();//接收数据线程
  18.     private Cmp_Wave cmp_HeartWave=null;
  19.     private Player capturePlayer = null;
  20.     private RecordControl recordControl = null;
  21.     private ByteArrayOutputStream bos = new ByteArrayOutputStream();
  22.     public void startApp() {
  23.         Display.init(this);
  24.         
  25.         form = new Form();//达到全屏的效果
  26.         cmp_HeartWave=new Cmp_Wave(form.getHeight(),form.getWidth());
  27.         form.getStyle().setBgImage(null);//本窗体不需要背景
  28.         form.addCommand(cmdExit);
  29.         form.setCommandListener(this);
  30.         form.setLayout(new BorderLayout());
  31.         //设置画板控件
  32.         form.addComponent(BorderLayout.CENTER,cmp_HeartWave);//添加控件
  33.         form.show();
  34.         try {
  35.           capturePlayer = Manager.createPlayer("capture://audio?rate=8000&bits=8&channels=1");//PCM,8位,8kH
  36.           if (capturePlayer != null) {
  37.             capturePlayer.realize();
  38.             recordControl = (RecordControl) capturePlayer
  39.                 .getControl("javax.microedition.media.control.RecordControl");
  40.             if (recordControl == null)
  41.               throw new Exception("No RecordControl available");
  42.             recordControl.setRecordStream(bos);
  43.           } else {
  44.             throw new Exception("Capture Audio Player is not available");
  45.           }
  46.         } catch (Exception e) {}
  47.         threadReceive.start();//开始启动线程
  48.   }
  49. /*
  50. * byte转为int的函数,因为JAVA的byte范围从-127~127
  51. */
  52. public static int unsignedByteToInt(byte b) {
  53.     return (int) b & 0xFF;
  54.     }
  55. class ThreadReceive extends Thread {
  56.       private boolean isRuning=true;//默认线程内部while循环可以执行
  57.       public void StopThread()
  58.       {
  59.           isRuning=false;
  60.       }
  61.       public void run(){
  62.           //*************************************************************
  63.           //绘制波形数据
  64.           //*************************************************************
  65.           try {
  66.               capturePlayer.start();
  67.               while(isRuning)
  68.               {
  69.                   recordControl = (RecordControl) capturePlayer.getControl("javax.microedition.media.control.RecordControl");
  70.                   recordControl.setRecordStream(bos);
  71.                   recordControl.startRecord();
  72.                   Thread.sleep(25);//停顿25ms录音
  73.                   recordControl.stopRecord();
  74.                   recordControl.commit();
  75.                   //由于采集频率太高,手机不能完全显示,所以需要通过均值滤波来降低分辨率
  76.                   int Zoom_out=200;//缩小200倍
  77.                   int[] bits=new int[bos.toByteArray().length/Zoom_out];
  78.                   for(int i=0,total=0,index=0;i
  79.                   {
  80.                       total=total+unsignedByteToInt(bos.toByteArray()[i]);
  81.                       if(i%Zoom_out==0 && i!=0)
  82.                       {
  83.                           bits[index]=total/Zoom_out;
  84.                           total=0;
  85.                           index++;
  86.                       }
  87.                   }
  88.                   cmp_HeartWave.UpdateVerticalWave(bits);
  89.                   bos.reset();
  90.               }
  91.               capturePlayer.stop();
  92.               capturePlayer.close();
  93.           } catch (Exception e) {}
  94.       }
  95.   }
  96.     public void actionPerformed(ActionEvent arg0) {
  97.         Command command=arg0.getCommand();
  98.         if(command==cmdExit)//退出程序
  99.             notifyDestroyed();
  100.     }
  101.     protected void pauseApp() {}
  102.     protected void destroyApp(boolean arg0) {}

  103. }
以下代码为画波形图的代码:
  1. /*
  2. * To change this template, choose Tools | Templates
  3. * and open the template in the editor.
  4. */
  5. import com.sun.lwuit.Component;
  6. import com.sun.lwuit.Container;
  7. import com.sun.lwuit.Graphics;
  8. import com.sun.lwuit.Image;
  9. import com.sun.lwuit.layouts.BorderLayout;
  10. /**
  11. *
  12. * @author Administrator
  13. */
  14. public class Cmp_Wave extends Container{
  15.    private Image imgWaveCanvas;//波形图画板,图形画在图像上,再不断地贴图到屏幕
  16.    private int height; //自己定义的画板高度 getHeight()
  17.    private int width; //自己定义的画板宽度 getWidth()
  18.    private int old_xPos=-1;//位置初始化
  19.    private int old_yPos=-1;//位置初始化
  20.    private Component cmpWaveCanvas;//显示波形控件
  21.    private int[] point=null;//每次收到的point数组
  22.    public Cmp_Wave(int canvasHeight,int canvasWidth)
  23.    {
  24.        super.setLayout(new BorderLayout());
  25.        super.addComponent(BorderLayout.CENTER,WaveCanvas(canvasHeight,canvasWidth));//波形显示在中间
  26.    }
  27.    private Component WaveCanvas(int canvasHeight,int canvasWidth)
  28.   {
  29.       height=canvasHeight;
  30.       width=canvasWidth;
  31.       //-------初始化波形画板图像
  32.       imgWaveCanvas=Image.createImage(width, height);
  33.       //-------初始化波形画板控件,在控件上绘制波形画板图像
  34.       cmpWaveCanvas=new Component(){
  35.             public void paint(Graphics g) {
  36.                 //在内存中绘制波形图
  37.                 Graphics canvas=imgWaveCanvas.getGraphics();
  38.                
  39.                 if(point==null)//如果point还没初始化
  40.                     return;//不执行下面语句
  41.                 for(int i=0;i
  42.                 {
  43.                     if(old_xPos>=width //如果xPos超过屏幕宽度
  44.                     || old_xPos==-1) //如果PaintVerticalWave是第一次运行
  45.                     {
  46.                         old_xPos=0;//归零画图
  47.                         old_yPos=height/2;//中心点画图
  48.                         canvas.setColor(0x444444);//设置背景色
  49.                         canvas.fillRect(0, 0, width, height);
  50.                     }
  51.                     int new_yPosPoint=point[i] ;
  52.                     canvas.setColor(0xCCCCCC);//线条色
  53.                     canvas.drawLine(old_xPos,old_yPos,old_xPos+1,new_yPosPoint);
  54.                     old_xPos++;
  55.                     old_yPos=new_yPosPoint;
  56.                 }
  57.                 //把内存中的波形图画到控件上
  58.                 g.drawImage(imgWaveCanvas, 0, 0);
  59.             }
  60.       };      
  61.       cmpWaveCanvas.setFocusPainted(false);
  62.       cmpWaveCanvas.setFocusable(false);
  63.       return cmpWaveCanvas;
  64.   }
  65.    public void UpdateVerticalWave(int []yPos) {
  66.        //更新绘图数组
  67.        int []tmpPos=new int[yPos.length];//临时数组,只取原数组的waveN分之一
  68.        for(int i=0,ii=0;i
  69.            tmpPos[i]=yPos[ii];
  70.        point=tmpPos;
  71.        //重新绘图
  72.        cmpWaveCanvas.repaint();
  73.    }
  74. }
加油!在电子行业默默贡献自己的力量!:)

回复评论 (2)

顶一个,不过没有这么好的手机
zhouyuannian#126.com(#换成@)有问题交流
点赞  2010-8-27 16:27

好唉,这给示波器提出了另一类途径,那就是手机编程

http://shop34182318.taobao.com/ https://shop436095304.taobao.com/?spm=a230r.7195193.1997079397.37.69fe60dfT705yr
点赞  2010-9-28 06:32
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 京公网安备 11010802033920号
    写回复