Zookeeper
Let's take a look at the program running in this article (the screen recording speed is slow, and the real machine runs more smoothly ):
In this article, the program uses the 8000hz sampling rate, which requires a high real-time performance for the x-axis drawing. If the resolution of the x-axis is not reduced, the program's real-time performance is poor. Therefore, the program reduces the x-axis data range by 8 times ~ 16 times. Because the 16-bit sampling is used, the height of the Y-axis data is also larger than that of the mobile phone screen, and the program also reduces the y-axis data, with a range of 1 ~ 10 times. The position adjustment of the waveform baseline is added to the OnTouchListener method of SurfaceView. You can directly touch the SurfaceView control to control the overall display of the waveform to the top or bottom.
The source code of main. xml is as follows:
ClsOscilloscope. java is the class library that implements the oscilloscope, including the implementation of the AudioRecord operation thread and the SurfaceView drawing thread. The Code is 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 inBuf = new ArrayList (); private boolean isRecording = false; // thread control mark/*** scale down the X axis */public int rateX = 4;/*** scale down the Y axis */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 * MinBufferSize of AudioRecord */public void Start (AudioRecord audioRecord, int recBufSize, SurfaceView sfv, Paint mPaint) {isRecording = true; new RecordThread (audioRecord, recBufSize ). start (); // start recording thread new DrawThread (sfv, mPaint ). start (); // start drawing thread}/*** Stop */public void Stop () {isRecording = false; inBuf. clear (); // clear}/*** saves data from MIC to 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 (); // 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 () ;}catch (Throwable t ){}}}; /*** plot data in inBuf ** @ author GV **/class DrawThread extends Thread {private int oldX = 0; // last drawn X coordinate private int oldY = 0; // last drawn Y coordinate private SurfaceView sfv; // artboard private int X_index = 0; // The coordinate private Paint mPaint on the X axis of the screen where the current drawing is located; // brush public DrawThread (SurfaceView sfv, Paint mPaint) {this. sfv = sfv; this. mPaint = mPaint;} public void run () {while (isRecording) {ArrayList buf = new ArrayList (); synchronized (inBuf) {if (inBuf. size () = 0) continue; buf = (ArrayList) 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); // draws the buffer data X_index = X_index + tmpBuf. length; if (X_index> sfv. getWidth () {X_index = 0 ;}}}/*** draw the position starting from the X axis of the specified area ** @ param start * (full screen) * @ param buffer * @ param rate * Ratio of Y-axis data reduction * @ 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. drawColor (Color. BLACK); // clear the background int y; for (int I = 0; I <buffer. length; I ++) {// The number of int x = I + start; y = buffer [I]/rate + baseLine; // adjust the zoom-in ratio, adjust the baseline canvas. drawLine (oldX, oldY, x, y, mPaint); oldX = x; oldY = y;} sfv. getHolder (). unlockCanvasAndPost (canvas); // unlock the canvas and submit the painted image }}}
TestOscilloscope. java is the main program that controls the UI and ClsOscilloscope. 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; public class testOscilloscope extends Activity {/** Called when the activity is first created. */Button btnStart, btnExit; SurfaceView sfv; ZoomControls zctlX, zctlY; ClsOscilloscope Limit = new limit (); 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; // The maximum ratio of the X axis to be scaled down. the X axis has a large amount of data and is prone to a refresh delay of static final int xMin = 8; // The minimum scale-down ratio of the X axis is static final int yMax = 10; // the maximum scale-down ratio of the Y axis is static final int yMin = 1; // the minimum scale-down ratio of the Y axis is int recBufSize; // minimum buffer size of the recording 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); // press btnStart = (Button) this. findViewById (R. id. btnStart); btnStart. setOnClickListener (new ClickEvent (); btnExit = (Button) this. findViewById (R. id. btnExit); btnExit. setOnClickListener (new ClickEvent (); // canvas and brush sfv = (SurfaceView) this. findViewById (R. id. surfaceView01); sfv. setOnTouchListener (new TouchEvent (); mPaint = new Paint (); mPaint. setColor (Color. GREEN); // the paint brush is GREEN mPaint. setStrokeWidth (1); // set the paint brush width // The oscilloscope class library clsOscilloscope. initOscilloscope (xMax/2, yMax/2, sfv. getHeight ()/2); // scaling control, 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 ("Narrowing the X axis" + String. valueOf (clsOscilloscope. rateX) + "times" + "," + "" + String. valueOf (clsOscilloscope. rateY) + "times") ;}}); zctlX. setOnZoomOutClickListener (new View. onClickListener () {@ Override public void onClick (View v) {if (clsOscilloscope. rateX
YMin) clsOscilloscope. rateY --; setTitle ("Narrowing the X axis" + String. valueOf (clsOscilloscope. rateX) + "times" + "," + "" + String. valueOf (clsOscilloscope. rateY) + "times") ;}}); zctlY. setOnZoomOutClickListener (new View. onClickListener () {@ Override public void onClick (View v) {if (clsOscilloscope. rateY