Thursday 10 March 2016

Audio Visualization for A Simple Android Recorder

In this post Im going to extent an app from my previous post A Simple Android Recorder by adding a visualization to it so the first thing to do would be create a class named MyVisualiser and coppy the following code to it.
You can download the entire code here.

MyVisualiser.java

package avinash.pet.project.androidrecorder;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.View;


public class MyVisualizer extends View{

    private Paint mForePaint = new Paint();
    private byte[] mBytes;
    private float[] mPoints;
    private Rect mRect = new Rect();

    public MyVisualizer(Context context) {
        super(context);
        initialize();
    }
    public MyVisualizer(Context context, AttributeSet attrs) {
        super(context, attrs);
        initialize();
    }
    public MyVisualizer(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initialize();
    }

    void initialize(){
        mBytes=null;
        mForePaint.setStrokeWidth(1f);
        mForePaint.setAntiAlias(true);
        mForePaint.setColor(Color.rgb(0, 128, 255));
    }

    public void updateVisualizer(byte[] bytes) {
        mBytes = bytes;
        invalidate();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        if (mBytes == null) {
            return;
        }

        if (mPoints == null || mPoints.length < mBytes.length * 4) {
            mPoints = new float[mBytes.length * 4];
        }

        mRect.set(0, 0, getWidth(), getHeight());

        for (int i = 0; i < mBytes.length - 1; i++) {
            mPoints[i * 4] = mRect.width() * i / (mBytes.length - 1);
            mPoints[i * 4 + 1] = mRect.height() / 2 + ((byte) (mBytes[i] + 128)) * (mRect.height() / 2) / 128;
            mPoints[i * 4 + 2] = mRect.width() * (i + 1) / (mBytes.length - 1);
            mPoints[i * 4 + 3] = mRect.height() / 2 + ((byte) (mBytes[i + 1] + 128)) * (mRect.height() / 2) / 128;
        }

        canvas.drawLines(mPoints, mForePaint);
    }

}

now make some changes to the xml file activity_main.xml to add the Visualizer view to it as follows

activity_main.xml

<LinearLayout 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:orientation="vertical"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".MainActivity">

    <avinash.pet.project.androidrecorder.MyVisualizer
        android:id="@+id/visualizer"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_weight="1"/>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <Button            android:id="@+id/btntoggelRec"
            android:layout_width="0dp"
            android:layout_height="80dp"
            android:layout_weight="1"
            android:text="Record"
            android:textAppearance="?android:attr/textAppearanceLarge"
            android:textStyle="bold" />

        <Button
            android:id="@+id/btnPlayRec"
            android:layout_width="0dp"
            android:layout_height="80dp"
            android:layout_weight="1"
            android:text="Play"
            android:textAppearance="?android:attr/textAppearanceLarge"
            android:textStyle="bold" />
    </LinearLayout>

</LinearLayout>

The layout should look like the following Image

 

the last thing is the Java code in the MainActivity

MainActivity.java

package avinash.pet.project.androidrecorder;

import android.media.MediaPlayer;
import android.media.MediaRecorder;
import android.media.audiofx.Visualizer;
import android.os.Environment;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;

import java.io.IOException;

public class MainActivity extends AppCompatActivity {

    private MediaRecorder audioRecorder;
    private boolean mIsRecording;
    private boolean isRecording;
    private boolean isPlaying;
    private MediaPlayer player;
    private MyVisualizer visualizerView;
    private Visualizer mVisualizer;
    private MediaPlayer.OnCompletionListener completeListener;

    @Override    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        final Button record = (Button) findViewById(R.id.btntoggelRec);
        final Button playBack = (Button) findViewById(R.id.btnPlayRec);
        visualizerView = (MyVisualizer) findViewById(R.id.visualizer);

        // set recording boolean flag to false        isRecording = false;
        // set playing flag to false        isPlaying = false;

        //get the output file where you want the recording to be stored
        final String outputFile = Environment.getExternalStorageDirectory().getAbsolutePath() + "/recording.3gp";

        // step 1 : setup MediaRecorder        audioRecorder = new MediaRecorder();
        audioRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
        audioRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
        audioRecorder.setAudioEncoder(MediaRecorder.OutputFormat.AMR_NB);
        audioRecorder.setOutputFile(outputFile);
        // End step 1
        //step 2 : setup recording start/stop
        record.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (isRecording) {
                    Toast.makeText(MainActivity.this, "Recording Stoped", Toast.LENGTH_SHORT).show();
                    audioRecorder.stop();
                    audioRecorder.release();
                    isRecording = false;
                    playBack.setEnabled(true);
                    ((Button) v).setText("Record");


                } else {
                    try {
                        Toast.makeText(MainActivity.this, "Recording Started", Toast.LENGTH_SHORT).show();
                        audioRecorder.prepare();
                        audioRecorder.start();
                        isRecording = true;
                        ((Button) v).setText("Stop");
                        playBack.setEnabled(false);
                    } catch (Exception ex) {
                        Toast.makeText(MainActivity.this, "Recording Error", Toast.LENGTH_SHORT).show();
                    }
                }
            }
        });
        // end of step 2
        // step 3 : setup playback start/Stop
        playBack.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (isPlaying) {
                    player.stop();
                    player.release();
                    isPlaying = false;
                    record.setEnabled(true);
                    mVisualizer.setEnabled(false);
                    ((Button) v).setText("Play");
                } else {

                    try {
                        record.setEnabled(false);
                        player = new MediaPlayer();
                        player.setDataSource(outputFile);
                        player.setOnCompletionListener(completeListener);
                        player.prepare();
                        setupVisualizerFxAndUI();
                        player.start();
                        mVisualizer.setEnabled(true);
                        isPlaying = true;
                        ((Button) v).setText("Stop");
                        Toast.makeText(MainActivity.this, "PlayBack Started", Toast.LENGTH_SHORT).show();
                    } catch (IOException e) {
                        e.printStackTrace();
                        Toast.makeText(MainActivity.this, "No recording to play please record first", Toast.LENGTH_SHORT).show();
                    }
                }
            }
        });

        completeListener = new MediaPlayer.OnCompletionListener() {
            @Override
            public void onCompletion(MediaPlayer mp) {
                player.stop();
                player.release();
                isPlaying = false;
                record.setEnabled(true);
                mVisualizer.setEnabled(false);
                playBack.setText("Play");
            }
        };

    }

    private void setupVisualizerFxAndUI() {

        // Create the Visualizer object and attach it to our media player.        mVisualizer = new Visualizer(player.getAudioSessionId());
        mVisualizer.setCaptureSize(Visualizer.getCaptureSizeRange()[1]);
        mVisualizer.setDataCaptureListener(
                new Visualizer.OnDataCaptureListener() {
                    public void onWaveFormDataCapture(Visualizer visualizer, byte[] bytes, int samplingRate) {
                        visualizerView.updateVisualizer(bytes);
                    }

                    public void onFftDataCapture(Visualizer visualizer,
                                                 byte[] bytes, int samplingRate) {
                    }
                }, Visualizer.getMaxCaptureRate() / 2, true, false);
    }


}

Also make sure that you have added permissions in the manifest files as in the previous post A Simple Android Recorder.
You can download the entire code here.

Well you are all set to build the app and check it for yourself.

No comments:

Post a Comment