私は音声(音)レベルの視覚化を表示しながら音声を録音するためのアンドロイドアプリケーションを作成する必要があります。Android:音声レベルの視覚化による音声の録音
私はすでにオーディオレコーディングアプリケーションを作成しましたが、サウンドレベルの視覚化を追加することはできません。どうしたらいいですか?
私に寄付の提案やサンプルのチュートリアルのリンクやコードを教えてください。
私は音声(音)レベルの視覚化を表示しながら音声を録音するためのアンドロイドアプリケーションを作成する必要があります。Android:音声レベルの視覚化による音声の録音
私はすでにオーディオレコーディングアプリケーションを作成しましたが、サウンドレベルの視覚化を追加することはできません。どうしたらいいですか?
私に寄付の提案やサンプルのチュートリアルのリンクやコードを教えてください。
は、このリンクをチェックしてください: http://code.google.com/p/android-labs/source/browse/trunk/NoiseAlert/src/com/google/android/noisealert/SoundMeter.java
をそれは/ dev/nullにオーディオを記録し、ボリュームをチェックします。 しかし、録音したサウンドを維持するためにファイル名を変更することはできます。
MediaRecorder
クラスを使用しており、ピーク振幅に基づくビジュアライゼーションがOKの場合は、getMaxAmplitude()メソッドを使用して、「最後の呼び出し以降にサンプリングされた絶対最大振幅」を連続的にポーリングできます。
あなたのアプリのグラフィカルボリュームバーのどれだけが点灯し、設定されているかを決定するインデックスに振幅をスケールダウンします。
このようなxml activity_recording.xmlを作成します。
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="180dp"
android:layout_alignParentBottom="true"
android:background="#231f20" >
<ali.visualiser.VisualizerView
android:id="@+id/visualizer"
android:layout_width="220dp"
android:layout_height="75dp"
android:layout_centerHorizontal="true"
android:layout_margin="5dp" />
<TextView
android:id="@+id/txtRecord"
android:layout_width="wrap_content"
android:layout_height="40dp"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:layout_marginBottom="25dp"
android:gravity="center"
android:text="Start Recording"
android:textColor="@android:color/white"
android:textSize="30sp" />
</RelativeLayout>
以下のようにカスタムビジュアライザビューを作成します。
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<Float> 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<Float>(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<files.length; i++) {
if(files[i].isDirectory()) {
}
else {
files[i].delete();
}
}
}
return true;
}
@Override
protected void onDestroy() {
super.onDestroy();
releaseRecorder();
}
// updates the visualizer every 50 milliseconds
Runnable updateVisualizer = new Runnable() {
@Override
public void run() {
if (isRecording) // if we are already recording
{
// get the current amplitude
int x = recorder.getMaxAmplitude();
visualizerView.addAmplitude(x); // update the VisualizeView
visualizerView.invalidate(); // refresh the VisualizerView
// update in 40 milliseconds
handler.postDelayed(this, REPEAT_INTERVAL);
}
}
};
}
結果
これは、それがどのように見えるかです:予想通り https://www.youtube.com/watch?v=BoFG6S02GH0
それが最後に到達する、アニメーションは継続:グラフの始まりを消去します。
許可を追加することを忘れないでください。使用許諾android:name = "android.permission.RECORD_AUDIO" />
あなたは、またはあなたのソリューションを使用している誰かが、動作中の例のスクリーンショットを追加しました – vedant1811
これは動作しません。録音を開始するときに録音を開始しないでください。停止するときに例外があります。私を助けてください。例外は以下の通りです –
私はアリの答えが好きですが、ここでははるかに優れた簡単なバージョンです。
RecordingActivityを起動してフルスクリーンに設定しましたが、レイアウトリソースを作成したり、ビューをどこにでも追加することができます。
RecordingActivity with Fullscreen View
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);
}
}
あなたのソリューションは完璧です。私はちょうどこれを追加するだけで、ユーザーがレコードボタンをクリックするたびにビジュアライザをリフレッシュし、最初から再描画したいと思います。私は多くの解決策を試しましたが、うまくいかなかった、あなたが私を助けてくれますか? –
サンプルコードはありますか? – user1972690
サンプルコードはありません。しかし、そのほとんどは、簡単なAndroid UIのコーディングのように思えるでしょう。 [あなたは定期的に実行する](ハンドラ)を開始します(http://stackoverflow.com/questions/6242268/repeat-a-task-with-a-time-delay/6242292#6242292)、 'getMaxAmplitude'メソッドを呼び出します。あなたの 'MediaRecorder'は現在のピークレベルを取得し、新しいピークレベルに基づいてボリュームバーを含む' View'を更新し、最後に[postInvalidate]を実行します(http://stackoverflow.com/questions/5521596/what- does-postinvalidate-do)を使用して、変更されたビューが再描画されるように要求します。 – Michael
@Michaelこれは非常に意味があるようですが、Visualizerの初期化にはどのaudioSession IDを使用するのか不明です。 –