免费色播,亚洲国产欧美国产第一区二区三区,毛片看,日本精品在线观看视频,国产成人精品一区二区免费视频,日本黄色免费网站,一级毛片免费

Android提高應(yīng)用篇之模擬信號(hào)示波器

來(lái)源:網(wǎng)絡(luò)

點(diǎn)擊:1956

A+ A-

所屬頻道:新聞中心

關(guān)鍵詞: Android手機(jī),模擬信號(hào)示波器

        本文結(jié)合SurfaceView實(shí)現(xiàn)一個(gè)Android版的手機(jī)模擬信號(hào)示波器(PS:以前也講過J2ME版的手機(jī)示波器)。最近物聯(lián)網(wǎng)炒得很火,作為手機(jī)軟件開發(fā)者,如何在不修改手機(jī)硬件電路的前提下實(shí)現(xiàn)與第三方傳感器結(jié)合呢?麥克風(fēng)就是一個(gè)很好的ADC接口,通過麥克風(fēng)與第三方傳感器結(jié)合,再在軟件里對(duì)模擬信號(hào)做相應(yīng)的處理,就可以提供更豐富的傳感化應(yīng)用。

        先來(lái)看看本文程序運(yùn)行的效果圖(屏幕錄像速度較慢,真機(jī)實(shí)際運(yùn)行起來(lái)會(huì)更加流暢):

     

           本文程序使用8000hz的采樣率,對(duì)X軸方向繪圖的實(shí)時(shí)性要求較高,如果不降低X軸的分辨率,程序的實(shí)時(shí)性較差,因此程序?qū)軸數(shù)據(jù)縮小區(qū)間為8倍~16倍。由于采用16位采樣,因此Y軸數(shù)據(jù)的高度相對(duì)于手機(jī)屏幕來(lái)說(shuō)也偏大,程序也對(duì)Y軸數(shù)據(jù)做縮小,區(qū)間為1倍~10倍。在SurfaceView的OnTouchListener方法里加入了波形基線的位置調(diào)節(jié),直接在SurfaceView控件上觸摸即可控制整體波形偏上或偏下顯示。

    main.xml源碼如下:

    view plaincopy to clipboardprint?
    <?xml version="1.0" encoding="utf-8"?> 
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
        android:orientation="vertical" android:layout_width="fill_parent" 
        android:layout_height="fill_parent"> 
        <LinearLayout android:id="@+id/LinearLayout01" 
            android:layout_height="wrap_content" android:layout_width="fill_parent" 
            android:orientation="horizontal"> 
            <Button android:layout_height="wrap_content" android:id="@+id/btnStart" 
                android:text="開始" android:layout_width="80dip"></Button> 
            <Button android:layout_height="wrap_content" android:text="停止" 
                android:id="@+id/btnExit" android:layout_width="80dip"></Button> 
            <ZoomControls android:layout_width="wrap_content" 
                android:layout_height="wrap_content" android:id="@+id/zctlX"></ZoomControls> 
            <ZoomControls android:layout_width="wrap_content" 
                android:layout_height="wrap_content" android:id="@+id/zctlY"></ZoomControls> 
        </LinearLayout> 
        <SurfaceView android:id="@+id/SurfaceView01" 
            android:layout_height="fill_parent" android:layout_width="fill_parent"></SurfaceView> 
    </LinearLayout> 
    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:orientation="vertical" android:layout_width="fill_parent"
     android:layout_height="fill_parent">
     <LinearLayout android:id="@+id/LinearLayout01"
      android:layout_height="wrap_content" android:layout_width="fill_parent"
      android:orientation="horizontal">
      <Button android:layout_height="wrap_content" android:id="@+id/btnStart"
       android:text="開始" android:layout_width="80dip"></Button>
      <Button android:layout_height="wrap_content" android:text="停止"
       android:id="@+id/btnExit" android:layout_width="80dip"></Button>
      <ZoomControls android:layout_width="wrap_content"
       android:layout_height="wrap_content" android:id="@+id/zctlX"></ZoomControls>
      <ZoomControls android:layout_width="wrap_content"
       android:layout_height="wrap_content" android:id="@+id/zctlY"></ZoomControls>
     </LinearLayout>
     <SurfaceView android:id="@+id/SurfaceView01"
      android:layout_height="fill_parent" android:layout_width="fill_parent"></SurfaceView>
    </LinearLayout>
     

    ClsOscilloscope.java是實(shí)現(xiàn)示波器的類庫(kù),包含AudioRecord操作線程和SurfaceView繪圖線程的實(shí)現(xiàn),兩個(gè)線程同步操作,代碼如下:

    view plaincopy to clipboardprint?
    package com.testOscilloscope;  
    import java.util.ArrayList;  
    import android.graphics.Canvas;  
    import android.graphics.Color;  
    import android.graphics.Paint;  
    import android.graphics.Rect;  
    import android.media.AudioRecord;  
    import android.view.SurfaceView;  
    public class ClsOscilloscope {  
        private ArrayList<short[]> inBuf = new ArrayList<short[]>();  
        private boolean isRecording = false;// 線程控制標(biāo)記  
        /** 
         * X軸縮小的比例 
         */ 
        public int rateX = 4;  
        /** 
         * Y軸縮小的比例 
         */ 
        public int rateY = 4;  
        /** 
         * Y軸基線 
         */ 
        public int baseLine = 0;  
        /** 
         * 初始化 
         */ 
        public void initOscilloscope(int rateX, int rateY, int baseLine) {  
            this.rateX = rateX;  
            this.rateY = rateY;  
            this.baseLine = baseLine;  
        }  
        /** 
         * 開始 
         *  
         * @param recBufSize 
         *            AudioRecord的MinBufferSize 
         */ 
        public void Start(AudioRecord audioRecord, int recBufSize, SurfaceView sfv,  
                Paint mPaint) {  
            isRecording = true;  
            new RecordThread(audioRecord, recBufSize).start();// 開始錄制線程  
            new DrawThread(sfv, mPaint).start();// 開始繪制線程  
        }  
        /** 
         * 停止 
         */ 
        public void Stop() {  
            isRecording = false;  
            inBuf.clear();// 清除  
        }  
        /** 
         * 負(fù)責(zé)從MIC保存數(shù)據(jù)到inBuf 
         *  
         * @author GV 
         *  
         */ 
        class RecordThread extends Thread {  
            private int recBufSize;  
            private AudioRecord audioRecord;  
            public RecordThread(AudioRecord audioRecord, int recBufSize) {  
                this.audioRecord = audioRecord;  
                this.recBufSize = recBufSize;  
            }  
            public void run() {  
                try {  
                    short[] buffer = new short[recBufSize];  
                    audioRecord.startRecording();// 開始錄制  
                    while (isRecording) {  
                        // 從MIC保存數(shù)據(jù)到緩沖區(qū)  
                        int bufferReadResult = audioRecord.read(buffer, 0,  
                                recBufSize);  
                        short[] tmpBuf = new short[bufferReadResult / rateX];  
                        for (int i = 0, ii = 0; i < tmpBuf.length; i++, ii = i  
                                * rateX) {  
                            tmpBuf[i] = buffer[ii];  
                        }  
                        synchronized (inBuf) {//  
                            inBuf.add(tmpBuf);// 添加數(shù)據(jù)  
                        }  
                    }  
                    audioRecord.stop();  
                } catch (Throwable t) {  
                }  
            }  
        };  
        /** 
         * 負(fù)責(zé)繪制inBuf中的數(shù)據(jù) 
         *  
         * @author GV 
         *  
         */  


        class DrawThread extends Thread {  
            private int oldX = 0;// 上次繪制的X坐標(biāo)  
            private int oldY = 0;// 上次繪制的Y坐標(biāo)  
            private SurfaceView sfv;// 畫板  
            private int X_index = 0;// 當(dāng)前畫圖所在屏幕X軸的坐標(biāo)  
            private Paint mPaint;// 畫筆  
            public DrawThread(SurfaceView sfv, Paint mPaint) {  
                this.sfv = sfv;  
                this.mPaint = mPaint;  
            }  
            public void run() {  
                while (isRecording) {  
                    ArrayList<short[]> buf = new ArrayList<short[]>();  
                    synchronized (inBuf) {  
                        if (inBuf.size() == 0)  
                            continue;  
                        buf = (ArrayList<short[]>) inBuf.clone();// 保存  
                        inBuf.clear();// 清除  
                    }  
                    for (int i = 0; i < buf.size(); i++) {  
                        short[] tmpBuf = buf.get(i);  
                        SimpleDraw(X_index, tmpBuf, rateY, baseLine);// 把緩沖區(qū)數(shù)據(jù)畫出來(lái)  
                        X_index = X_index + tmpBuf.length;  
                        if (X_index > sfv.getWidth()) {  
                            X_index = 0;  
                        }  
                    }  
                }  
            }  
            /** 
             * 繪制指定區(qū)域 
             *  
             * @param start 
             *            X軸開始的位置(全屏) 
             * @param buffer 
             *            緩沖區(qū) 
             * @param rate 
             *            Y軸數(shù)據(jù)縮小的比例 
             * @param baseLine 
             *            Y軸基線 
             */ 
            void SimpleDraw(int start, short[] buffer, int rate, int baseLine) {  
                if (start == 0)  
                    oldX = 0;  
                Canvas canvas = sfv.getHolder().lockCanvas(  
                        new Rect(start, 0, start + buffer.length, sfv.getHeight()));// 關(guān)鍵:獲取畫布  
                canvas.drawColor(Color.BLACK);// 清除背景  
                int y;  
                for (int i = 0; i < buffer.length; i++) {// 有多少畫多少  
                    int x = i + start;  
                    y = buffer[i] / rate + baseLine;// 調(diào)節(jié)縮小比例,調(diào)節(jié)基準(zhǔn)線  
                    canvas.drawLine(oldX, oldY, x, y, mPaint);  
                    oldX = x;  
                    oldY = y;  
                }  
                sfv.getHolder().unlockCanvasAndPost(canvas);// 解鎖畫布,提交畫好的圖像  
            }  
        }  

    package com.testOscilloscope;
    import java.util.ArrayList;
    import android.graphics.Canvas;
    import android.graphics.Color;
    import android.graphics.Paint;
    import android.graphics.Rect;
    import android.media.AudioRecord;
    import android.view.SurfaceView;
    public class ClsOscilloscope {
     private ArrayList<short[]> inBuf = new ArrayList<short[]>();
     private boolean isRecording = false;// 線程控制標(biāo)記
     /**
      * X軸縮小的比例
      */
     public int rateX = 4;
     /**
      * Y軸縮小的比例
      */
     public int rateY = 4;
     /**
      * Y軸基線
      */
     public int baseLine = 0;
     /**
      * 初始化
      */
     public void initOscilloscope(int rateX, int rateY, int baseLine) {
      this.rateX = rateX;
      this.rateY = rateY;
      this.baseLine = baseLine;
     }
     /**
      * 開始
      *
      * @param recBufSize
      *            AudioRecord的MinBufferSize
      */
     public void Start(AudioRecord audioRecord, int recBufSize, SurfaceView sfv,
       Paint mPaint) {
      isRecording = true;
      new RecordThread(audioRecord, recBufSize).start();// 開始錄制線程
      new DrawThread(sfv, mPaint).start();// 開始繪制線程
     }
     /**
      * 停止
      */
     public void Stop() {
      isRecording = false;
      inBuf.clear();// 清除
     }
     /**
      * 負(fù)責(zé)從MIC保存數(shù)據(jù)到inBuf
      *
      * @author GV
      *
      */
     class RecordThread extends Thread {
      private int recBufSize;
      private AudioRecord audioRecord;
      public RecordThread(AudioRecord audioRecord, int recBufSize) {
       this.audioRecord = audioRecord;
       this.recBufSize = recBufSize;
      }
      public void run() {
       try {
        short[] buffer = new short[recBufSize];
        audioRecord.startRecording();// 開始錄制
        while (isRecording) {
         // 從MIC保存數(shù)據(jù)到緩沖區(qū)
         int bufferReadResult = audioRecord.read(buffer, 0,
           recBufSize);
         short[] tmpBuf = new short[bufferReadResult / rateX];
         for (int i = 0, ii = 0; i < tmpBuf.length; i++, ii = i
           * rateX) {
          tmpBuf[i] = buffer[ii];
         }
         synchronized (inBuf) {//
          inBuf.add(tmpBuf);// 添加數(shù)據(jù)
         }
        }
        audioRecord.stop();
       } catch (Throwable t) {
       }
      }
     };
     /**
      * 負(fù)責(zé)繪制inBuf中的數(shù)據(jù)
      *
      * @author GV
      *
      */
     class DrawThread extends Thread {
      private int oldX = 0;// 上次繪制的X坐標(biāo)
      private int oldY = 0;// 上次繪制的Y坐標(biāo)
      private SurfaceView sfv;// 畫板
      private int X_index = 0;// 當(dāng)前畫圖所在屏幕X軸的坐標(biāo)
      private Paint mPaint;// 畫筆
      public DrawThread(SurfaceView sfv, Paint mPaint) {
       this.sfv = sfv;
       this.mPaint = mPaint;
      }
      public void run() {
       while (isRecording) {
        ArrayList<short[]> buf = new ArrayList<short[]>();
        synchronized (inBuf) {
         if (inBuf.size() == 0)
          continue;
         buf = (ArrayList<short[]>) inBuf.clone();// 保存
         inBuf.clear();// 清除
        }
        for (int i = 0; i < buf.size(); i++) {
         short[] tmpBuf = buf.get(i);
         SimpleDraw(X_index, tmpBuf, rateY, baseLine);// 把緩沖區(qū)數(shù)據(jù)畫出來(lái)
         X_index = X_index + tmpBuf.length;
         if (X_index > sfv.getWidth()) {
          X_index = 0;
         }
        }
       }
      }


      /**
       * 繪制指定區(qū)域
       *
       * @param start
       *            X軸開始的位置(全屏)
       * @param buffer
       *            緩沖區(qū)
       * @param rate
       *            Y軸數(shù)據(jù)縮小的比例
       * @param baseLine
       *            Y軸基線
       */
      void SimpleDraw(int start, short[] buffer, int rate, int baseLine) {
       if (start == 0)
        oldX = 0;
       Canvas canvas = sfv.getHolder().lockCanvas(
         new Rect(start, 0, start + buffer.length, sfv.getHeight()));// 關(guān)鍵:獲取畫布
       canvas.drawColor(Color.BLACK);// 清除背景
       int y;
       for (int i = 0; i < buffer.length; i++) {// 有多少畫多少
        int x = i + start;
        y = buffer[i] / rate + baseLine;// 調(diào)節(jié)縮小比例,調(diào)節(jié)基準(zhǔn)線
        canvas.drawLine(oldX, oldY, x, y, mPaint);
        oldX = x;
        oldY = y;
       }
       sfv.getHolder().unlockCanvasAndPost(canvas);// 解鎖畫布,提交畫好的圖像
      }
     }
    }
     

    testOscilloscope.java是主程序,控制UI和ClsOscilloscope,代碼如下:

    view plaincopy to clipboardprint?
    package com.testOscilloscope;  
    import android.app.Activity;  
    import android.graphics.Color;  
    import android.graphics.Paint;  
    import android.media.AudioFormat;  
    import android.media.AudioRecord;  
    import android.media.MediaRecorder;  
    import android.os.Bundle;  
    import android.view.MotionEvent;  
    import android.view.SurfaceView;  
    import android.view.View;  
    import android.view.View.OnTouchListener;  
    import android.widget.Button;  
    import android.widget.ZoomControls;  
    public class testOscilloscope extends Activity {  
        /** Called when the activity is first created. */ 
        Button btnStart,btnExit;  
        SurfaceView sfv;  
        ZoomControls zctlX,zctlY;  
          
        ClsOscilloscope clsOscilloscope=new ClsOscilloscope();  
          
        static final int frequency = 8000;//分辨率  
        static final int channelConfiguration = AudioFormat.CHANNEL_CONFIGURATION_MONO;  
        static final int audioEncoding = AudioFormat.ENCODING_PCM_16BIT;  
        static final int xMax = 16;//X軸縮小比例最大值,X軸數(shù)據(jù)量巨大,容易產(chǎn)生刷新延時(shí)  
        static final int xMin = 8;//X軸縮小比例最小值  
        static final int yMax = 10;//Y軸縮小比例最大值  
        static final int yMin = 1;//Y軸縮小比例最小值  
          
        int recBufSize;//錄音最小buffer大小  
        AudioRecord audioRecord;  
        Paint mPaint;  
        @Override 
        public void onCreate(Bundle savedInstanceState) {  
            super.onCreate(savedInstanceState);  
            setContentView(R.layout.main);  
            //錄音組件  
            recBufSize = AudioRecord.getMinBufferSize(frequency,  
                    channelConfiguration, audioEncoding);  
            audioRecord = new AudioRecord(MediaRecorder.AudioSource.MIC, frequency,  
                    channelConfiguration, audioEncoding, recBufSize);  
            //按鍵  
            btnStart = (Button) this.findViewById(R.id.btnStart);  
            btnStart.setOnClickListener(new ClickEvent());  
            btnExit = (Button) this.findViewById(R.id.btnExit);  
            btnExit.setOnClickListener(new ClickEvent());  
            //畫板和畫筆  
            sfv = (SurfaceView) this.findViewById(R.id.SurfaceView01);   
            sfv.setOnTouchListener(new TouchEvent());  
            mPaint = new Paint();    
            mPaint.setColor(Color.GREEN);// 畫筆為綠色    
            mPaint.setStrokeWidth(1);// 設(shè)置畫筆粗細(xì)   
            //示波器類庫(kù)  
            clsOscilloscope.initOscilloscope(xMax/2, yMax/2, sfv.getHeight()/2);  
              
            //縮放控件,X軸的數(shù)據(jù)縮小的比率高些  
            zctlX = (ZoomControls)this.findViewById(R.id.zctlX);  
            zctlX.setOnZoomInClickListener(new View.OnClickListener() {  
                @Override 
                public void onClick(View v) {  
                    if(clsOscilloscope.rateX>xMin)  
                        clsOscilloscope.rateX--;  
                    setTitle("X軸縮小"+String.valueOf(clsOscilloscope.rateX)+"倍" 
                            +","+"Y軸縮小"+String.valueOf(clsOscilloscope.rateY)+"倍");  
                }  
            });  
            zctlX.setOnZoomOutClickListener(new View.OnClickListener() {  
                @Override 
                public void onClick(View v) {  
                    if(clsOscilloscope.rateX<xMax)  
                        clsOscilloscope.rateX++;      
                    setTitle("X軸縮小"+String.valueOf(clsOscilloscope.rateX)+"倍" 
                            +","+"Y軸縮小"+String.valueOf(clsOscilloscope.rateY)+"倍");  
                }  
            });  
            zctlY = (ZoomControls)this.findViewById(R.id.zctlY);  
            zctlY.setOnZoomInClickListener(new View.OnClickListener() {  
                @Override 
                public void onClick(View v) {  
                    if(clsOscilloscope.rateY>yMin)  
                        clsOscilloscope.rateY--;  
                    setTitle("X軸縮小"+String.valueOf(clsOscilloscope.rateX)+"倍" 
                            +","+"Y軸縮小"+String.valueOf(clsOscilloscope.rateY)+"倍");  
                }  
            });  
              
            zctlY.setOnZoomOutClickListener(new View.OnClickListener() {  
                @Override 
                public void onClick(View v) {  
                    if(clsOscilloscope.rateY<yMax)  
                        clsOscilloscope.rateY++;      
                    setTitle("X軸縮小"+String.valueOf(clsOscilloscope.rateX)+"倍" 
                            +","+"Y軸縮小"+String.valueOf(clsOscilloscope.rateY)+"倍");  
                }  
            });  
        }  
        @Override 
        protected void onDestroy() {  
            super.onDestroy();  
            android.os.Process.killProcess(android.os.Process.myPid());  
        }  
          
        /** 
         * 按鍵事件處理 
         * @author GV 
         * 
         */ 
        class ClickEvent implements View.OnClickListener {  
            @Override 
            public void onClick(View v) {  
                if (v == btnStart) {  
                    clsOscilloscope.baseLine=sfv.getHeight()/2;  
                    clsOscilloscope.Start(audioRecord,recBufSize,sfv,mPaint);  
                } else if (v == btnExit) {  
                    clsOscilloscope.Stop();  
                }  
            }  
        }  
        /** 
         * 觸摸屏動(dòng)態(tài)設(shè)置波形圖基線 
         * @author GV 
         * 
         */ 
        class TouchEvent implements OnTouchListener{  
            @Override 
            public boolean onTouch(View v, MotionEvent event) {  
                clsOscilloscope.baseLine=(int)event.getY();  
                return true;  
            }  
              
        }  

    (審核編輯: 智匯小新)

    聲明:除特別說(shuō)明之外,新聞內(nèi)容及圖片均來(lái)自網(wǎng)絡(luò)及各大主流媒體。版權(quán)歸原作者所有。如認(rèn)為內(nèi)容侵權(quán),請(qǐng)聯(lián)系我們刪除。