Android:带语音级可视化的音频录制

我需要一个创建一个Android应用程序,用于录制语音,同时显示语音(声音)级别的可视化。

我已经创建了一个录音应用程序,但我无法添加声级可视化。 我该怎么做?

请有人帮我提供建议或示例教程链接或代码。

像这样创建一个xml activity_recording.xml。

     

创建一个自定义visualizerView,如下所示。

 package ali.visualiser; import java.util.ArrayList; import java.util.List; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.util.AttributeSet; import android.view.View; public class VisualizerView extends View { private static final int LINE_WIDTH = 1; // width of visualizer lines private static final int LINE_SCALE = 75; // scales visualizer lines private List amplitudes; // amplitudes for line lengths private int width; // width of this View private int height; // height of this View private Paint linePaint; // specifies line drawing characteristics // constructor public VisualizerView(Context context, AttributeSet attrs) { super(context, attrs); // call superclass constructor linePaint = new Paint(); // create Paint for lines linePaint.setColor(Color.GREEN); // set color to green linePaint.setStrokeWidth(LINE_WIDTH); // set stroke width } // called when the dimensions of the View change @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { width = w; // new width of this View height = h; // new height of this View amplitudes = new ArrayList(width / LINE_WIDTH); } // clear all amplitudes to prepare for a new visualization public void clear() { amplitudes.clear(); } // add the given amplitude to the amplitudes ArrayList public void addAmplitude(float amplitude) { amplitudes.add(amplitude); // add newest to the amplitudes ArrayList // if the power lines completely fill the VisualizerView if (amplitudes.size() * LINE_WIDTH >= width) { amplitudes.remove(0); // remove oldest power value } } // draw the visualizer with scaled lines representing the amplitudes @Override public void onDraw(Canvas canvas) { int middle = height / 2; // get the middle of the View float curX = 0; // start curX at zero // for each item in the amplitudes ArrayList for (float power : amplitudes) { float scaledHeight = power / LINE_SCALE; // scale the power curX += LINE_WIDTH; // increase X by LINE_WIDTH // draw a line representing this item in the amplitudes ArrayList canvas.drawLine(curX, middle + scaledHeight / 2, curX, middle - scaledHeight / 2, linePaint); } } } 

创建RecordingActivity类,如下所示。

包ali.visualiser;

 import java.io.File; import java.io.IOException; import android.app.Activity; import android.media.MediaRecorder; import android.media.MediaRecorder.OnErrorListener; import android.media.MediaRecorder.OnInfoListener; import android.os.Bundle; import android.os.Environment; import android.os.Handler; import android.view.View; import android.view.View.OnClickListener; import android.widget.TextView; public class RecordingActivity extends Activity { public static final String DIRECTORY_NAME_TEMP = "AudioTemp"; public static final int REPEAT_INTERVAL = 40; private TextView txtRecord; VisualizerView visualizerView; private MediaRecorder recorder = null; File audioDirTemp; private boolean isRecording = false; private Handler handler; // Handler for updating the visualizer // private boolean recording; // are we currently recording? @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_recording); visualizerView = (VisualizerView) findViewById(R.id.visualizer); txtRecord = (TextView) findViewById(R.id.txtRecord); txtRecord.setOnClickListener(recordClick); audioDirTemp = new File(Environment.getExternalStorageDirectory(), DIRECTORY_NAME_TEMP); if (audioDirTemp.exists()) { deleteFilesInDir(audioDirTemp); } else { audioDirTemp.mkdirs(); } // create the Handler for visualizer update handler = new Handler(); } OnClickListener recordClick = new OnClickListener() { @Override public void onClick(View v) { if (!isRecording) { // isRecording = true; txtRecord.setText("Stop Recording"); recorder = new MediaRecorder(); recorder.setAudioSource(MediaRecorder.AudioSource.MIC); recorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP); recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB); recorder.setOutputFile(audioDirTemp + "/audio_file" + ".mp3"); OnErrorListener errorListener = null; recorder.setOnErrorListener(errorListener); OnInfoListener infoListener = null; recorder.setOnInfoListener(infoListener); try { recorder.prepare(); recorder.start(); isRecording = true; // we are currently recording } catch (IllegalStateException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } handler.post(updateVisualizer); } else { txtRecord.setText("Start Recording"); releaseRecorder(); } } }; private void releaseRecorder() { if (recorder != null) { isRecording = false; // stop recording handler.removeCallbacks(updateVisualizer); visualizerView.clear(); recorder.stop(); recorder.reset(); recorder.release(); recorder = null; } } public static boolean deleteFilesInDir(File path) { if( path.exists() ) { File[] files = path.listFiles(); if (files == null) { return true; } for(int i=0; i 

结果

它的外观如下: https : //www.youtube.com/watch?v = BoFG6S02GH0

当它到达结尾时,animation按预期继续:擦除图形的开头。

我喜欢阿里的回答,但这里的版本更简单,性能更好。

我启动了我的RecordingActivity并将其设置为全屏,但您可以创建布局资源或在任何地方添加视图。

使用全屏视图录制活动

 public class RecordingActivity extends Activity { private VisualizerView visualizerView; private MediaRecorder recorder = new MediaRecorder(); private Handler handler = new Handler(); final Runnable updater = new Runnable() { public void run() { handler.postDelayed(this, 1); int maxAmplitude = recorder.getMaxAmplitude(); if (maxAmplitude != 0) { visualizerView.addAmplitude(maxAmplitude); } } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_recording); visualizerView = (VisualizerView) findViewById(R.id.visualizer); try { recorder.setAudioSource(MediaRecorder.AudioSource.MIC); recorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP); recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB); recorder.setOutputFile("/dev/null"); recorder.prepare(); recorder.start(); } catch (IllegalStateException | IOException ignored) { } } @Override protected void onDestroy() { super.onDestroy(); handler.removeCallbacks(updater); recorder.stop(); recorder.reset(); recorder.release(); } @Override public void onWindowFocusChanged(boolean hasFocus) { super.onWindowFocusChanged(hasFocus); handler.post(updater); } } 

视图类的onDraw方法应该尽可能快。

 public class VisualizerView extends View { private static final int MAX_AMPLITUDE = 32767; private float[] amplitudes; private float[] vectors; private int insertIdx = 0; private Paint pointPaint; private Paint linePaint; private int width; private int height; public VisualizerView(Context context, AttributeSet attrs) { super(context, attrs); linePaint = new Paint(); linePaint.setColor(Color.GREEN); linePaint.setStrokeWidth(1); pointPaint = new Paint(); pointPaint.setColor(Color.BLUE); pointPaint.setStrokeWidth(1); } @Override protected void onSizeChanged(int width, int h, int oldw, int oldh) { this.width = width; height = h; amplitudes = new float[this.width * 2]; // xy for each point across the width vectors = new float[this.width * 4]; // xxyy for each line across the width } /** * modifies draw arrays. cycles back to zero when amplitude samples reach max screen size */ public void addAmplitude(int amplitude) { invalidate(); float scaledHeight = ((float) amplitude / MAX_AMPLITUDE) * (height - 1); int ampIdx = insertIdx * 2; amplitudes[ampIdx++] = insertIdx; // x amplitudes[ampIdx] = scaledHeight; // y int vectorIdx = insertIdx * 4; vectors[vectorIdx++] = insertIdx; // x0 vectors[vectorIdx++] = 0; // y0 vectors[vectorIdx++] = insertIdx; // x1 vectors[vectorIdx] = scaledHeight; // y1 // insert index must be shorter than screen width insertIdx = ++insertIdx >= width ? 0 : insertIdx; } @Override public void onDraw(Canvas canvas) { canvas.drawLines(vectors, linePaint); canvas.drawPoints(amplitudes, pointPaint); } } 

如果您正在使用MediaRecorder类并且基于峰值幅度的可视化是可以的,则可以使用getMaxAmplitude()方法连续轮询“自上次调用以来采样的最大绝对振幅”。
将该幅度缩放到一个索引中,该索引确定您的应用程序的图形音量条中有多少点亮并且您已设置。

请检查以下链接: http : //code.google.com/p/android-labs/source/browse/trunk/NoiseAlert/src/com/google/android/noisealert/SoundMeter.java

它将音频记录到/ dev / null,并检查音量。 但您可以更改文件名以保留录制的声音。