Android根据音量大小绘制心电图(附源码)

前提:很久没有更新了,今天就为大家带来一个画布和SurfaceView的使用吧。(附源码资源)

需求:录制音频时有时候为了增加与用户的体验,我们需要增加与用户的交互,于是就有了录音动画。如下图


分析:录音动画有很多种,比如话筒式的,如微信语音和QQ语音,相对于简单一些,只需几张图片根据音量大小来回切换,这里就不多说了。还有就是类似于心电图,根据音量大小实现及时画出波形图,而这篇文章就能解决以上需求,好了,废话不多说,直接上代码。

首先我们需要建立一个简单的录音界面,如图

activity_test_surface_view.xml如下

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin" >

    <SurfaceView
        android:id="@+id/record_surfaceView"
        android:layout_width="match_parent"
        android:layout_height="100dp"
        android:layout_gravity="center_horizontal"
        android:background="@color/acoustic_wave_bg" />

    <Button
        android:layout_below="@id/record_surfaceView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="录音" 
        android:onClick="Record"
        />

</RelativeLayout>
接下来就是代码的实现了,首先获取视图和初始化画笔,代码如下

// 初始化视图
	private void initView() {
		sfv = (SurfaceView) findViewById(R.id.record_surfaceView);
		sfv.setZOrderOnTop(true);
		sfv.getHolder().setFormat(PixelFormat.TRANSLUCENT);
	}

	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_test_surface_view);
		initView();
		// 初始化画笔
		mPaint = new Paint();
		mPaint.setColor(getResources().getColor(R.color.maincolor));// 画笔为主色调
		mPaint.setStrokeWidth(4);// 设置画笔粗细
	}

做完这俩件事后就是录音的点击事件,具体可以查看以下代码,代码注释也很详细,如有不懂,可留言,我会及时回复

public void Record(View view) {
		baseLine = sfv.getHeight() / 2;
		if (mediarecord == null) {
                        //判断文件是否存在,如果存在则删除
			File file = new File("mnt/sdcard/a123" + ".m4a");
			if (file.exists()) {
				file.delete();
			}
                        //初始化<span style="font-family: Arial, Helvetica, sans-serif;">MediaRecorder</span>
			mediarecord = new MediaRecorder();
                        //设置<span style="font-family: Arial, Helvetica, sans-serif;">MediaRecorder的属性</span>
			mediarecord.setAudioSource(MediaRecorder.AudioSource.MIC);
			mediarecord.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
			mediarecord.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
			
			mediarecord.setOutputFile("mnt/sdcard/a123" + ".m4a");

			try {//准备
				mediarecord.prepare();
			} catch (IOException e) {
				Log.e("iii", "prepare() failed");
			}
                        //开始录制
			mediarecord.start();
			//开启画笔线程每0.2绘制一次
			sfvtimer = new Timer();
			sfvtimer.schedule(new TimerTask() {
				@Override
				public void run() {
					Message message = new Message();
					message.what = 1;
					mHandler.sendMessage(message);
				}
			}, 0, 200);
			// 录音
		} else {
			if (mediarecord != null) {
				mediarecord.stop();
				mediarecord.reset();
				mediarecord.release();
				mediarecord = null;
				sfvtimer.cancel();
				sfvtimer = null;
			}
		}
绘制线程代码如下

private final Handler mHandler = new Handler() {
		@Override
		public void handleMessage(Message msg) {
			// TODO Auto-generated method stub
			updateMicStatus();
		}
	};

updateMicStatus()方法如下:

if (mediarecord != null) {
			double ratio = (double) mediarecord.getMaxAmplitude() / BASE;
			int db = 0;// 分贝
			if (ratio > 1)
				db = (int) (20 * Math.log10(ratio)) - 50;
			if (db < 0)
				db = 0;
			x.add(-db);//保存音频分贝大小,根据X里的值绘制一段完整的波浪线
			if (x.size() > sfv.getWidth() / divider) {
				x.remove(0);//如果长达超出了屏幕宽度则删除第一个数据
			}
			SimpleDraw(x, baseLine);
		}


绘制画板如下:

if (rateY == 0) {
			rateY = 200 / sfv.getHeight();
			baseLine = sfv.getHeight() / 2;
		}
		Canvas canvas = sfv.getHolder().lockCanvas(
				new Rect(0, 0, sfv.getWidth(), sfv.getHeight()));// 关键:获取画布

		canvas.drawColor(getResources().getColor(R.color.acoustic_wave_bg));// 清除背景
		int start = sfv.getWidth() - buf.size() * divider;
		int py = baseLine;
		if (buf.size() > 0)
			py += buf.get(0) / rateY;
		int y;
		canvas.drawLine(0, baseLine, start - divider, baseLine, mPaint);
		for (int i = 0; i < buf.size(); i++) {
			y = buf.get(i) / rateY + baseLine;// 调节缩小比例,调节基准线
			canvas.drawLine(start + (i - 1) * divider, py, start + i * divider,
					y, mPaint);
			py = y;
		}
		sfv.getHolder().unlockCanvasAndPost(canvas);// 解锁画布,提交画好的图像
完成到这里就可以实现录音心电图了,效果图如下




不懂得可以留言或者自己下载资源慢慢研究,如有不足,希望大家指出,共同讨论,进步


发布了16 篇原创文章 · 获赞 19 · 访问量 4万+

猜你喜欢

转载自blog.csdn.net/pengguichu/article/details/51867403