Implementation of an improved analog signal oscilloscope for Android _android

Source: Internet
Author: User

The previous simple introduction of the Android program in the development of the use of Audiorecord and Audiotrack, this time combined with Surfaceview to achieve an Android version of the phone analog signal oscilloscope. Recently the Internet of Things is very hot, as a mobile phone software developers, how to do not modify the phone hardware circuit under the premise of integration with third-party sensors it? The microphone is a good ADC interface, through the microphone and third-party sensors, and then in the software to do the corresponding processing of analog signals, can provide a richer sensor applications.

Let's take a look at the effect of the program running (screen video screenshot is slow, the real machine will actually run very smooth):

This procedure uses the 8000hz sampling rate, to the X axis drawing real-time request is high, if does not reduce the X axis resolution, the program's real time is poor, therefore the program to the X axis data reduction interval is 8 times times ~16 times. Because of the use of 16-bit sampling, so the y-axis data height relative to the phone screen is also large, the program also to the y-axis data to shrink, the interval is 1 time times ~10 times. In the Ontouchlistener method of Surfaceview, the position adjustment of the waveform baseline is added, and the Surfaceview control can control the overall waveform deviation or the lower display.

Main.xml source code is as follows:

<?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" 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=" Stop "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>

The

Clsoscilloscope.java is the class library that implements the oscilloscope, contains the implementation of the Audiorecord operation thread and Surfaceview drawing thread, and two threads synchronize the code as follows:

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;//Thread Control token/** * x axis zoom/public int ratex = 4;
 /** * Y-axis zoom/public int ratey = 4;
 /** * Y-Axis baseline */public int baseLine = 0;
 /** * Initialize/public void initoscilloscope (int ratex, int ratey, int baseLine) {This.ratex = Ratex;
 This.ratey = Ratey;
 This.baseline = BaseLine; /** * Start * * @param recbufsize * Audiorecord minbuffersize/public void start (Audiorecord Audiorecord, in
 T recbufsize, Surfaceview SFV, Paint mpaint) {isrecording = true;
 New Recordthread (Audiorecord, Recbufsize). Start ()//Begin recording Thread new Drawthread (SFV, Mpaint). Start () ()//Begin drawing Thread}/** * Stop*/public void Stop () {isrecording = false; Inbuf.clear ()//clear}/** * Responsible for saving data from mic to INBUF * * @author GV */class Recordthread extends Thread {private in
 T 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 ()//Start recording while (isrecording) {//Save data from mic to buffer 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);//Add Data}} audiorecord.stop ();
 The catch (Throwable t) {}}}; /** * is responsible for drawing data in Inbuf * * @author GV */class Drawthread extends Thread {private int oldx = 0;//last drawn x coordinates Priva Te int Oldy= 0;//last-drawn y-coordinate private surfaceview sfv;//artboard private int x_index = 0;//coordinates of the screen X axis of the current drawing the private Paint mpaint;//Brush Publ
  IC 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 ()//Save Inbuf.clear ();//clear} for (int i = 0; i < buf.size (); i++)
   {short[] tmpbuf = Buf.get (i);
   Simpledraw (X_index, Tmpbuf, Ratey, baseLine);//Draw out the buffer data X_index = X_index + tmpbuf.length;
   if (X_index > Sfv.getwidth ()) {x_index = 0;       /** * Draw the specified range * * @param start * x-axis position (full screen) * @param buffer * Buffer * @param rate *  Y-Axis Data reduction ratio * @param baseLine * y-axis baseline/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 ());/key: Get Canvas Canvas.drawcolor (Col Or.
  black);/clear background int y;
  for (int i = 0; i < buffer.length i++) {//How many to draw int x = i + start;
  y = buffer[i]/rate + baseline;//Adjust the scaling down, adjust the baseline Canvas.drawline (OLDX, Oldy, X, Y, mpaint);
  OLDX = x;
  Oldy = y;

 } sfv.getholder (). Unlockcanvasandpost (canvas);//unlock canvas, submit painted Image}}}

The

Testoscilloscope.java is the main program that controls the UI and Clsoscilloscope, and the code is as follows:

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; The public class Testoscilloscope extends activity {/** called the ' when the ' is the ' The activity ' is the ' the '
 Xit
  Surfaceview SFV;
  
  Zoomcontrols zctlx,zctly;
  
 Clsoscilloscope clsoscilloscope=new Clsoscilloscope ();
 static final int frequency = 8000;//Resolution static final int channelconfiguration = Audioformat.channel_configuration_mono;
 static final int audioencoding = Audioformat.encoding_pcm_16bit; static final int xmax = 16;//x axis reduced proportional maximum, large x-axis data, easy to create refresh delay static final int xmin = 8;//x Axis Shrink-ratio minimum static final int ymax = 10 ;Y-axis zoom max static final int ymin = 1;//y axis reduced proportional minimum int recbufsize;//recording minimum buffer size Audiorecord audiorecord;
  Paint Mpaint;
    @Override public void OnCreate (Bundle savedinstancestate) {super.oncreate (savedinstancestate);
    Setcontentview (R.layout.main);
 Recording module recbufsize = audiorecord.getminbuffersize (Frequency, channelconfiguration, audioencoding); Audiorecord = new Audiorecord (MediaRecorder.AudioSource.MIC, Frequency, channelconfiguration, audioencoding,
 Recbufsize);
 Button btnstart = (button) This.findviewbyid (R.id.btnstart);
 Btnstart.setonclicklistener (New Clickevent ());
 Btnexit = (Button) This.findviewbyid (r.id.btnexit);
 Btnexit.setonclicklistener (New Clickevent ()); 
 Artboards and brushes SFV = (surfaceview) This.findviewbyid (R.ID.SURFACEVIEW01);
    Sfv.setontouchlistener (new TouchEvent ()); 
    Mpaint = new Paint (); Mpaint.setcolor (Color.green);//Brush is green mpaint.setstrokewidth (1);//Set Brush thickness/oscilloscope class Library Clsoscilloscope.initoscillo Scope (XMAX/2, YMAX/2, sfv.getheIght ()/2);
 Scaling controls, the x-axis data is reduced by a higher ratio zctlx = (zoomcontrols) This.findviewbyid (R.ID.ZCTLX); Zctlx.setonzoominclicklistener (New View.onclicklistener () {@Override public void OnClick (View v) {if Clsoscillosco
  Pe.ratex>xmin) clsoscilloscope.ratex--; Settitle ("x-axis Shrink" +string.valueof (Clsoscilloscope.ratex) + "times" + "," + "y-axis shrink" +string.valueof (clsoscilloscope.ratey) + "Times"
  );
 }
 }); Zctlx.setonzoomoutclicklistener (New View.onclicklistener () {@Override public void OnClick (View v) {if Clsoscillosc 
  Ope.ratex<xmax) clsoscilloscope.ratex++; Settitle ("x-axis Shrink" +string.valueof (Clsoscilloscope.ratex) + "times" + "," + "y-axis shrink" +string.valueof (clsoscilloscope.ratey) + "Times"
  );
 }
 });
 zctly = (zoomcontrols) This.findviewbyid (r.id.zctly); Zctly.setonzoominclicklistener (New View.onclicklistener () {@Override public void OnClick (View v) {if Clsoscillosco
  Pe.ratey>ymin) clsoscilloscope.ratey--; Settitle ("x-axis Shrink" +string.valueof (Clsoscilloscope.ratex) + "times" + "," + "y-axis shrink" +string.valueOf (Clsoscilloscope.ratey) + "Times");
 
 }
 }); Zctly.setonzoomoutclicklistener (New View.onclicklistener () {@Override public void OnClick (View v) {if Clsoscillosc 
  Ope.ratey<ymax) clsoscilloscope.ratey++; Settitle ("x-axis Shrink" +string.valueof (Clsoscilloscope.ratex) + "times" + "," + "y-axis shrink" +string.valueof (clsoscilloscope.ratey) + "Times"
  );
  }
 });
 } @Override protected void OnDestroy () {Super.ondestroy ();
 Android.os.Process.killProcess (Android.os.Process.myPid ()); /** * Key Event processing * @author GV */class Clickevent implements View.onclicklistener {@Override public void onclic
  K (View v) {if (v = = btnstart) {clsoscilloscope.baseline=sfv.getheight ()/2;
  Clsoscilloscope.start (Audiorecord,recbufsize,sfv,mpaint);
  else if (v = = btnexit) {clsoscilloscope.stop ();  /** * Touch screen dynamically set waveform baseline * @author GV * * */class TouchEvent implements ontouchlistener{@Override public boolean
  Ontouch (View V, motionevent event) {clsoscilloscope.baseline= (int) event.gety (); RetUrn true; }
 }
}

I hope this article will help readers to develop the Android project.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.