Android录音时指针摆动的实现
来源:互联网 发布:怎样在淘宝上入驻商家 编辑:程序博客网 时间:2024/06/10 04:37
本文中实现录音时候、指针摆动的功能主要是参考SoundRecorder的。主要是其中的VUMeter类,VUMeter是通过Recorder.getMaxAmplitude()的值计算,画出指针的偏移摆动。
下面直接上代码:
VUMeter类:
package hfut.geron.record;import hfut.geron.memorybook.R;import android.content.Context;import android.graphics.Canvas;import android.graphics.Color;import android.graphics.Paint;import android.graphics.drawable.Drawable;import android.util.AttributeSet;import android.view.View;public class VUMeter extends View { static final float PIVOT_RADIUS = 3.5f; static final float PIVOT_Y_OFFSET = 10f; static final float SHADOW_OFFSET = 2.0f; static final float DROPOFF_STEP = 0.18f; static final float SURGE_STEP = 0.35f; static final long ANIMATION_INTERVAL = 70; Paint mPaint, mShadow; float mCurrentAngle; RecordHelper mRecorder; public VUMeter(Context context) { super(context); init(context); } public VUMeter(Context context, AttributeSet attrs) { super(context, attrs); init(context); } void init(Context context) { Drawable background = context.getResources().getDrawable(R.drawable.record_bg2); setBackgroundDrawable(background); mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); mPaint.setColor(Color.WHITE); mShadow = new Paint(Paint.ANTI_ALIAS_FLAG); mShadow.setColor(Color.argb(60, 0, 0, 0)); mRecorder = null; mCurrentAngle = 0; } public void setRecorder(RecordHelper recorder) { mRecorder = recorder; invalidate(); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); final float minAngle = (float)Math.PI/8; final float maxAngle = (float)Math.PI*7/8; float angle = minAngle; if (mRecorder != null) angle += (float)(maxAngle - minAngle)*mRecorder.getMaxAmplitude()/32768; if (angle > mCurrentAngle) mCurrentAngle = angle; else mCurrentAngle = Math.max(angle, mCurrentAngle - DROPOFF_STEP); mCurrentAngle = Math.min(maxAngle, mCurrentAngle); float w = getWidth(); float h = getHeight(); float pivotX = w/2; float pivotY = h - PIVOT_RADIUS - PIVOT_Y_OFFSET; float l = h*4/5; float sin = (float) Math.sin(mCurrentAngle); float cos = (float) Math.cos(mCurrentAngle); float x0 = pivotX - l*cos; float y0 = pivotY - l*sin; canvas.drawLine(x0 + SHADOW_OFFSET, y0 + SHADOW_OFFSET, pivotX + SHADOW_OFFSET, pivotY + SHADOW_OFFSET, mShadow); canvas.drawCircle(pivotX + SHADOW_OFFSET, pivotY + SHADOW_OFFSET, PIVOT_RADIUS, mShadow); canvas.drawLine(x0, y0, pivotX, pivotY, mPaint); canvas.drawCircle(pivotX, pivotY, PIVOT_RADIUS, mPaint); if (mRecorder != null) postInvalidateDelayed(ANIMATION_INTERVAL); }}
录音类:RecordHelper.java
package hfut.geron.record;import java.io.File;import java.io.IOException;import java.text.SimpleDateFormat;import android.content.Context;import android.media.MediaPlayer;import android.media.MediaPlayer.OnCompletionListener;import android.media.MediaPlayer.OnErrorListener;import android.media.MediaRecorder;import android.util.Log;public class RecordHelper implements OnCompletionListener, OnErrorListener{ private MediaRecorder mRecorder ; private String record_path; public static final int IDLE_STATE = 0; //空闲状态 public static final int RECORDING_STATE = 1; //录音状态 int mState = IDLE_STATE; //状态标示,默认是空闲状态 public static final int NO_ERROR = 0; public static final int SDCARD_ACCESS_ERROR = 1; public static final int INTERNAL_ERROR = 2; public interface OnStateChangedListener { public void onStateChanged(int state); public void onError(int error); } OnStateChangedListener mOnStateChangedListener = null; public void setOnStateChangedListener(OnStateChangedListener listener) { mOnStateChangedListener = listener; } public void startRecording(int outputfileformat, String suffix, Context context) { Log.d("Infor", "start..."); stopRecording(); if(CommonUtils.isSdCardAvailable()){ File audioRecPath = new File(CommonUtils.RECORD_PATH);//判断存储音频的文件夹是否存在,如果不存在则进行创建操作 if(!audioRecPath.exists()){ audioRecPath.mkdir(); } if(audioRecPath != null ){ //创建临时文件,以Record_开头 SimpleDateFormat sDateFormat = new SimpleDateFormat("yyyyMMdd_hhmmss"); String record_name = "Record_"+sDateFormat.format(new java.util.Date()); File audioRecFile; try {audioRecFile = File.createTempFile(record_name, suffix, audioRecPath); } catch (IOException e) {// TODO Auto-generated catch block setError(SDCARD_ACCESS_ERROR); return;} mRecorder= new MediaRecorder();//设置采样的音频源为麦克风mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);//设置输出文件格式 mRecorder.setOutputFormat(MediaRecorder.OutputFormat.DEFAULT); //设置音频的编码方式 mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT); //设置输出文件 Log.d("Infor", audioRecFile.getAbsolutePath()); record_path= audioRecFile.getAbsolutePath(); mRecorder.setOutputFile(audioRecFile.getAbsolutePath()); try{ mRecorder.prepare(); }catch(IOException e){ setError(INTERNAL_ERROR); mRecorder.reset(); mRecorder.release(); mRecorder = null; return; } //开始录音 if(this.mState==RecordHelper.IDLE_STATE){ mRecorder.start(); setState(RECORDING_STATE); } } } else{ Log.d("Infor", "error,内存卡打不开。。。"); setError(SDCARD_ACCESS_ERROR); } } public void stopRecording() { if (mRecorder == null) return; mRecorder.stop(); mRecorder.release(); mRecorder = null; setState(IDLE_STATE); } void setState(int state){//设置状态 if (state == mState) return; mState = state; signalStateChanged(mState); } public int getMaxAmplitude() {//得到录音的振幅 if (mState != RECORDING_STATE) return 0; return mRecorder.getMaxAmplitude(); } //实现对自定义接口OnStateChangedListener的两个方法调用的条件 private void signalStateChanged(int state) { if (mOnStateChangedListener != null) mOnStateChangedListener.onStateChanged(state); } private void setError(int error) { if (mOnStateChangedListener != null) mOnStateChangedListener.onError(error); } public String getPath(){ return record_path; } /*继承接口方法*/ public boolean onError(MediaPlayer mp, int what, int extra) {// TODO Auto-generated method stubreturn true;}public void onCompletion(MediaPlayer mp) {// TODO Auto-generated method stub}}
RecordActivity:
package hfut.geron.memorybook.onebook;import java.io.File;import hfut.geron.memorybook.R;import hfut.geron.record.CommonUtils;import hfut.geron.record.RecordHelper;import hfut.geron.record.RecordHelper.OnStateChangedListener;import hfut.geron.record.VUMeter;import android.app.Activity;import android.app.Dialog;import android.content.Context;import android.content.DialogInterface;import android.content.Intent;import android.media.MediaRecorder;import android.os.Bundle;import android.os.Handler;import android.os.Message;import android.os.PowerManager;import android.os.PowerManager.WakeLock;import android.util.Log;import android.view.View;import android.view.View.OnClickListener;import android.widget.ImageButton;import android.widget.TextView;import android.widget.Toast;public class RecordActivity extends Activity implements OnClickListener, OnStateChangedListener { private TextView record_text_time; private ImageButton record_btn_begin,record_btn_end; private VUMeter mVUMeter;//VUMeter类是通过mRecorder.getMaxAmplitude()的值计算,画出指针的偏移摆动 WakeLock mWakeLock;//用WakeLock请求休眠锁,让其不会休眠 private String time; private RecordHelper mRecordHelper;//录音类,实现录音功能 private int s1=0; private int s2=0; private int m1=0; private int m2=0; private final static int RECORD_ISOVER = 1; private final static int SDCARD_ACCESS_ERROR=2; private final static int NOTES_RECORD=1; private Handler time_handler= new Handler(); private Runnable runnable = new Runnable(){public void run() {// TODO Auto-generated method stubif(s1==10){s2++;s1=0;}if(s2==6){s2=0;m1++;}if(m1==10){m1=0;m2++;}time=""+m2+m1+":"+s2+s1;record_text_time = (TextView) findViewById(R.id.record_text_time);record_text_time.setText(time);s1++;time_handler.postDelayed(runnable, 1000);} }; @Overrideprotected void onCreate(Bundle savedInstanceState) {// TODO Auto-generated method stubsuper.onCreate(savedInstanceState);this.setContentView(R.layout.recordialog);PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);mWakeLock = pm.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK,"SoundRecorder");//请求休眠锁mRecordHelper = new RecordHelper();mRecordHelper.setOnStateChangedListener(this);mVUMeter = (VUMeter)this.findViewById(R.id.record_VUMeter);mVUMeter.setRecorder(mRecordHelper);record_text_time = (TextView)this.findViewById(R.id.record_text_time);record_btn_begin = (ImageButton)this.findViewById(R.id.record_btn_begin);record_btn_end= (ImageButton)this.findViewById(R.id.record_btn_end);record_btn_begin.setOnClickListener(this);record_btn_end.setOnClickListener(this);record_btn_begin.setId(1);record_btn_end.setId(2);}public void onClick(View v) {// TODO Auto-generated method stubint id=v.getId();switch(id){case 1: //录音开始time_handler.post(runnable);Log.d("Infor", "录音开始...");mRecordHelper.startRecording(MediaRecorder.OutputFormat.DEFAULT, ".amr", this);record_btn_end.setClickable(true);record_btn_begin.setClickable(false); break;case 2: //录音结束record_btn_begin.setClickable(true);time_handler.removeCallbacks(runnable);s1=s2=m1=m2=0;Log.d("Infor", "录音关闭...");mRecordHelper.stopRecording();showDialog(RECORD_ISOVER);break;}}public void onStateChanged(int state) {// TODO Auto-generated method stubLog.d("Infor", "录音状态发生改变");if (state == RecordHelper.RECORDING_STATE) {mWakeLock.acquire(); // 录音的时候让其不休眠} else {if (mWakeLock.isHeld())mWakeLock.release();}}public void onError(int error) {// TODO Auto-generated method stubLog.d("Infor", "error:"+error);this.showDialog(error);}@Overrideprotected Dialog onCreateDialog(int id) {// TODO Auto-generated method stubswitch(id){case RECORD_ISOVER:Log.d("Infor", "here");return CommonUtils.getDialog(this, "提示", "确定要保存该录音音频文件吗?", 0,"是", "否", new DialogInterface.OnClickListener() {public void onClick(DialogInterface dialog, int which) {// TODO Auto-generated method stubLog.d("Infor", "保存该录音音频");Toast.makeText(RecordActivity.this, "录音文件保存成功...", Toast.LENGTH_SHORT).show(); Intent intent = new Intent(RecordActivity.this,NoteActivity.class); intent.putExtra("recordpath", mRecordHelper.getPath()); RecordActivity.this.setResult(NOTES_RECORD, intent); RecordActivity.this.finish();}}, new DialogInterface.OnClickListener() {public void onClick(DialogInterface dialog, int which) {// TODO Auto-generated method stub//删除之前的录音文件Log.d("Infor", "取消保存该录音音频");record_text_time.setText("00:00");Log.d("Infor", "PATH:"+mRecordHelper.getPath());File file = new File(mRecordHelper.getPath());if(file.exists()){Log.d("Infor", "存在");try{file.delete();}catch(Exception e){Log.d("Infor", "删除不了");}}}});case SDCARD_ACCESS_ERROR:return CommonUtils.getDialog(this, "提示", "无法读取内存卡..", 0, "是", null, new DialogInterface.OnClickListener(){public void onClick(DialogInterface dialog, int which) {// TODO Auto-generated method stubRecordActivity.this.finish();}}, null);default:return null;}}}
结果截图:
要点:
1、该程序中使用了用WakeLock请求休眠锁,让其不会休眠。这样能保证录音过程中屏幕常亮。
2、该程序中主要使用VUMeter,自定义该类,VUMeter类是通过mRecorder.getMaxAmplitude()的值计算,画出指针的偏移摆动。
3、RecordHelper类中定义了一个接口OnStateChangedListener ,定义如下
public interface OnStateChangedListener {
public void onStateChanged(int state);
public void onError(int error);
}
并在RecordHelper类中实例化该接口并set,如下:
OnStateChangedListener mOnStateChangedListener = null;
public void setOnStateChangedListener(OnStateChangedListener listener) {
mOnStateChangedListener = listener;
}
定义在何种情况下使用该接口中的两个方法:
//实现对自定义接口OnStateChangedListener的两个方法调用的条件
private void signalStateChanged(int state) {
if (mOnStateChangedListener != null)
mOnStateChangedListener.onStateChanged(state);
}
private void setError(int error) {
if (mOnStateChangedListener != null)
mOnStateChangedListener.onError(error);
}
在RecordActivity类中就可以继承该接口
class RecordActivity extends Activity implements OnStateChangedListener{}
并
mRecordHelper = new RecordHelper();
mRecordHelper.setOnStateChangedListener(this);
- Android录音时指针摆动的实现
- Android录音时指针摆动的实现
- Android录音时指针摆动的实现
- Android录音时指针摆动的实现(附源码)
- Android录音时指针摆动的实现(附源码)
- Android录音时指针摆动的实现(附源码)
- Android录音时指针摆动的实现(附源码)
- Android 摆动的球体
- Android 摆动的球体
- Android 摆动的球体
- android录音功能的实现
- android录音功能的实现
- android 录音功能的实现
- Android实现录音的功能
- android控件摆动摇动晃动效果实现
- css3 实现自由摆动的立方体
- Android 录音、播放功能的实现
- Android 实现能够暂停的录音功能
- 使用sprintf 的常见问题
- 关于VC串口通信不能添加MSCOMM控件的解决办法
- UIControl IOS控件编程—IOS开发
- 判断一年是否是闰年。
- ORACLE 启动与关闭
- Android录音时指针摆动的实现
- html input 只读
- 打印九九乘法表 JAVA
- Java中各种文件路径的表示
- javascript操作URL函数
- python学习笔记一
- UITableViewController显示UIToolbar
- cookie小节二—购物车
- 什么是32位汇编的flat平坦内存模式