文中的Android代碼主要是移植SoundRecorder的。主要是其中的VUMeter類,VUMeter是通過Recorder.getMaxAmplitude()的值計算,畫出指針的偏移擺動。下面直接上代碼
- /*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
- package com.android.soundrecorder;
-
- 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;
-
- Recorder 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.vumeter);
- 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(Recorder 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 && mRecorder.state() == Recorder.RECORDING_STATE)
- postInvalidateDelayed(ANIMATION_INTERVAL);
- }
- }
錄音類:RecordHelper.java
- package org.winplus.sh;
-
- import java.io.File;
- import java.io.IOException;
-
- import android.content.Context;
- import android.media.AudioManager;
- import android.media.MediaPlayer;
- import android.media.MediaRecorder;
- import android.media.MediaPlayer.OnCompletionListener;
- import android.media.MediaPlayer.OnErrorListener;
- import android.os.Bundle;
- import android.os.Environment;
-
- public class RecordHelper implements OnCompletionListener, OnErrorListener {
- static final String SAMPLE_PREFIX = "recording";
- static final String SAMPLE_PATH_KEY = "sample_path";
- static final String SAMPLE_LENGTH_KEY = "sample_length";
-
- public static final int IDLE_STATE = 0;
- public static final int RECORDING_STATE = 1;
- public static final int PLAYING_STATE = 2;
-
- 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 static final int IN_CALL_RECORD_ERROR = 3;
-
- public interface OnStateChangedListener {
- public void onStateChanged(int state);
- public void onError(int error);
- }
- OnStateChangedListener mOnStateChangedListener = null;
-
- long mSampleStart = 0; // time at which latest record or play operation started
- int mSampleLength = 0; // length of current sample
- File mSampleFile = null;
-
- MediaRecorder mRecorder = null;
- MediaPlayer mPlayer = null;
-
- public RecordHelper() {
- }
-
- public void saveState(Bundle recorderState) {
- recorderState.putString(SAMPLE_PATH_KEY, mSampleFile.getAbsolutePath());
- recorderState.putInt(SAMPLE_LENGTH_KEY, mSampleLength);
- }
-
- public int getMaxAmplitude() {
- if (mState != RECORDING_STATE)
- return 0;
- return mRecorder.getMaxAmplitude();
- }
-
- public void restoreState(Bundle recorderState) {
- String samplePath = recorderState.getString(SAMPLE_PATH_KEY);
- if (samplePath == null)
- return;
- int sampleLength = recorderState.getInt(SAMPLE_LENGTH_KEY, -1);
- if (sampleLength == -1)
- return;
-
- File file = new File(samplePath);
- if (!file.exists())
- return;
- if (mSampleFile != null
- && mSampleFile.getAbsolutePath().compareTo(file.getAbsolutePath()) == 0)
- return;
-
- delete();
- mSampleFile = file;
- mSampleLength = sampleLength;
-
- signalStateChanged(IDLE_STATE);
- }
-
- public void setOnStateChangedListener(OnStateChangedListener listener) {
- mOnStateChangedListener = listener;
- }
-
- public int state() {
- return mState;
- }
-
- public int progress() {
- if (mState == RECORDING_STATE || mState == PLAYING_STATE)
- return (int) ((System.currentTimeMillis() - mSampleStart)/1000);
- return 0;
- }
-
- public int sampleLength() {
- return mSampleLength;
- }
-
- public File sampleFile() {
- return mSampleFile;
- }
-
- /**
- * Resets the recorder state. If a sample was recorded, the file is deleted.
- */
- public void delete() {
- stop();
-
- if (mSampleFile != null)
- mSampleFile.delete();
-
- mSampleFile = null;
- mSampleLength = 0;
-
- signalStateChanged(IDLE_STATE);
- }
-
- /**
- * Resets the recorder state. If a sample was recorded, the file is left on disk and will
- * be reused for a new recording.
- */
- public void clear() {
- stop();
-
- mSampleLength = 0;
-
- signalStateChanged(IDLE_STATE);
- }
-
- public void startRecording(int outputfileformat, String extension, Context context) {
- stop();
-
- if (mSampleFile == null) {
- File sampleDir = Environment.getExternalStorageDirectory();
- if (!sampleDir.canWrite()) // Workaround for broken sdcard support on the device.
- sampleDir = new File("/sdcard/sdcard");
-
- try {
- mSampleFile = File.createTempFile(SAMPLE_PREFIX, extension, sampleDir);
- } catch (IOException e) {
- setError(SDCARD_ACCESS_ERROR);
- return;
- }
- }
-
- mRecorder = new MediaRecorder();
- mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
- mRecorder.setOutputFormat(outputfileformat);
- mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
- mRecorder.setOutputFile(mSampleFile.getAbsolutePath());
-
- // Handle IOException
- try {
- mRecorder.prepare();
- } catch(IOException exception) {
- setError(INTERNAL_ERROR);
- mRecorder.reset();
- mRecorder.release();
- mRecorder = null;
- return;
- }
- // Handle RuntimeException if the recording couldn't start
- try {
- mRecorder.start();
- } catch (RuntimeException exception) {
- AudioManager audioMngr = (AudioManager)context.getSystemService(Context.AUDIO_SERVICE);
- boolean isInCall = ((audioMngr.getMode() == AudioManager.MODE_IN_CALL) ||
- (audioMngr.getMode() == AudioManager.MODE_IN_COMMUNICATION));
- if (isInCall) {
- setError(IN_CALL_RECORD_ERROR);
- } else {
- setError(INTERNAL_ERROR);
- }
- mRecorder.reset();
- mRecorder.release();
- mRecorder = null;
- return;
- }
- mSampleStart = System.currentTimeMillis();
- setState(RECORDING_STATE);
- }
-
- public void stopRecording() {
- if (mRecorder == null)
- return;
-
- mRecorder.stop();
- mRecorder.release();
- mRecorder = null;
-
- mSampleLength = (int)( (System.currentTimeMillis() - mSampleStart)/1000 );
- setState(IDLE_STATE);
- }
-
- public void startPlayback() {
- stop();
-
- mPlayer = new MediaPlayer();
- try {
- mPlayer.setDataSource(mSampleFile.getAbsolutePath());
- mPlayer.setOnCompletionListener(this);
- mPlayer.setOnErrorListener(this);
- mPlayer.prepare();
- mPlayer.start();
- } catch (IllegalArgumentException e) {
- setError(INTERNAL_ERROR);
- mPlayer = null;
- return;
- } catch (IOException e) {
- setError(SDCARD_ACCESS_ERROR);
- mPlayer = null;
- return;
- }
-
- mSampleStart = System.currentTimeMillis();
- setState(PLAYING_STATE);
- }
-
- public void stopPlayback() {
- if (mPlayer == null) // we were not in playback
- return;
-
- mPlayer.stop();
- mPlayer.release();
- mPlayer = null;
- setState(IDLE_STATE);
- }
-
- public void stop() {
- stopRecording();
- stopPlayback();
- }
-
- public boolean onError(MediaPlayer mp, int what, int extra) {
- stop();
- setError(SDCARD_ACCESS_ERROR);
- return true;
- }
-
- public void onCompletion(MediaPlayer mp) {
- stop();
- }
-
- private void setState(int state) {
- if (state == mState)
- return;
-
- mState = state;
- signalStateChanged(mState);
- }
-
- private void signalStateChanged(int state) {
- if (mOnStateChangedListener != null)
- mOnStateChangedListener.onStateChanged(state);
- }
-
- private void setError(int error) {
- if (mOnStateChangedListener != null)
- mOnStateChangedListener.onError(error);
- }
- }
界面:
- package org.winplus.sh;
-
- import android.app.Activity;
- import android.content.Context;
- import android.media.MediaRecorder;
- import android.os.Bundle;
- 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.Button;
-
- public class SoundHandActivity extends Activity implements OnClickListener,
- RecordHelper.OnStateChangedListener {
-
- private static final String TAG = "SoundHandActivity";
-
- private VUMeter mVUMeter;
- private RecordHelper mRecorder;
-
- private Button btnStart;
- private Button btnStop;
-
- WakeLock mWakeLock;
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
- setupViews();
- }
-
- public void setupViews() {
-
- PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
- mWakeLock = pm.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK,
- "SoundRecorder");
- mRecorder = new RecordHelper();
- mRecorder.setOnStateChangedListener(this);
- mVUMeter = (VUMeter) findViewById(R.id.uvMeter);
- mVUMeter.setRecorder(mRecorder);
-
- btnStart = (Button) findViewById(R.id.button1);
- btnStop = (Button) findViewById(R.id.button2);
- btnStart.setOnClickListener(this);
- btnStop.setOnClickListener(this);
- }
-
- @Override
- public void onClick(View v) {
- switch (v.getId()) {
- case R.id.button1:
- mRecorder.startRecording(MediaRecorder.OutputFormat.AMR_NB, ".amr",
- this);
-
- break;
-
- case R.id.button2:
- mRecorder.stop();
- break;
- }
- }
-
- private void updateUi() {
- Log.e(TAG, "=======================updateUi");
-
- mVUMeter.invalidate();
- }
-
- @Override
- public void onStateChanged(int state) {
- if (state == RecordHelper.PLAYING_STATE
- || state == RecordHelper.RECORDING_STATE) {
- mWakeLock.acquire(); // we don't want to go to sleep while recording
- // or playing
- } else {
- if (mWakeLock.isHeld())
- mWakeLock.release();
- }
- updateUi();
- }
-
- @Override
- public void onError(int error) {
- // TODO Auto-generated method stub
-
- }
- }
OK,沒有什麼特別的。
Android錄音時指針擺動的實現源碼下載
免費下載地址在 http://linux.linuxidc.com/
用戶名與密碼都是www.linuxidc.com
具體下載目錄在 /2012年資料/5月/13日/Android錄音時指針擺動的實現(附源碼)/
更多Android相關信息見Android 專題頁面 http://www.linuxidc.com/topicnews.aspx?tid=11