通過J2ME的錄音功能實現簡易示波器

本文來自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

發佈了26 篇原創文章 · 獲贊 3 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章