3

So this code records audio into a wav file that is stored in the emulated storage. How can I then take this wav file and get an array of the raw audio data?

The code would go down in the buttonDecode section where it says: //read raw data from wav file

package com.example.wesle.noisemachine;

import android.content.Intent;
import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.AudioRecord;
import android.net.Uri;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.media.MediaPlayer;
import android.media.MediaRecorder;
import android.os.Environment;
import android.widget.Toast;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.*;

public class ReceiveScreen extends AppCompatActivity {

    private Button buttonStart, buttonStop, buttonDecode, buttonPlay;
    private String filePath;

    private static final int RECORDER_BPP = 16;
    private static final String AUDIO_RECORDER_FILE_EXT_WAV = ".wav";
    private static final String AUDIO_RECORDER_FOLDER = "AudioRecorder";
    private static final String AUDIO_RECORDER_TEMP_FILE = "record_temp.raw";
    private static final int RECORDER_SAMPLERATE = 44100;
    private static final int RECORDER_CHANNELS = AudioFormat.CHANNEL_IN_STEREO;
    private static final int RECORDER_AUDIO_ENCODING = AudioFormat.ENCODING_PCM_16BIT;
    short[] audioData;

    private AudioRecord recorder = null;
    private int bufferSize = 0;
    private Thread recordingThread = null;
    private boolean isRecording = false;
    Complex[] fftTempArray;
    Complex[] fftArray;
    int[] bufferData;
    int bytesRecorded;

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


        //final MediaPlayer wavRecording = MediaPlayer.create(this, "/storage/emulated/0");
        buttonStart = (Button) findViewById(R.id.buttonStart);
        buttonStop = (Button) findViewById(R.id.buttonStop);
        buttonPlay = (Button) findViewById(R.id.buttonPlay);
        buttonDecode = (Button) findViewById(R.id.buttonDecode);
        buttonStop.setEnabled(false);
        buttonDecode.setEnabled(false);
        buttonPlay.setEnabled(false);
        //outputFile = Environment.getExternalStorageDirectory().getAbsolutePath() + "/recording.3gp";
        //System.out.println(outputFile);

        bufferSize = AudioRecord.getMinBufferSize
                (RECORDER_SAMPLERATE,RECORDER_CHANNELS,RECORDER_AUDIO_ENCODING)*3;
        audioData = new short [bufferSize];


        buttonStart.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                buttonStart.setEnabled(false);
                buttonDecode.setEnabled(false);
                buttonPlay.setEnabled(false);
                recorder = new AudioRecord(MediaRecorder.AudioSource.MIC,
                        RECORDER_SAMPLERATE,
                        RECORDER_CHANNELS,
                        RECORDER_AUDIO_ENCODING,
                        bufferSize);
                int i = recorder.getState();
                if (i==1)
                    recorder.startRecording();

                isRecording = true;

                recordingThread = new Thread(new Runnable() {
                    @Override
                    public void run() {
                        writeAudioDataToFile();
                    }
                }, "AudioRecorder Thread");

                recordingThread.start();

                buttonStop.setEnabled(true);

                Toast.makeText(getApplicationContext(), "Recording started", Toast.LENGTH_LONG).show();

            }
        });

        buttonStop.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                buttonStop.setEnabled(false);
                if (null != recorder){
                    isRecording = false;

                    int i = recorder.getState();
                    if (i==1)
                        recorder.stop();
                    recorder.release();

                    recorder = null;
                    recordingThread = null;
                }
                filePath = getFilename();
                copyWaveFile(getTempFilename(),filePath);
                deleteTempFile();

                Toast.makeText(getApplicationContext(), "Recording Completed", Toast.LENGTH_LONG).show();
                buttonStart.setEnabled(true);
                buttonPlay.setEnabled(true);
                buttonDecode.setEnabled(true);
            }
        });

        buttonPlay.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                buttonStart.setEnabled(false);
                buttonDecode.setEnabled(false);
                buttonPlay.setEnabled(false);
                Toast.makeText(getApplicationContext(), "Recording Playing", Toast.LENGTH_LONG).show();

                //play code
                File wavfile = new File(filePath);
                Uri myUri1 = Uri.fromFile(wavfile);
                final MediaPlayer mPlayer = new MediaPlayer();
                mPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);

                try {
                    mPlayer.setDataSource(getApplicationContext(), myUri1);
                } catch (IllegalArgumentException e) {
                    Toast.makeText(getApplicationContext(), "You might not set the URI correctly!", Toast.LENGTH_LONG).show();
                } catch (SecurityException e) {
                    Toast.makeText(getApplicationContext(), "You might not set the URI correctly!", Toast.LENGTH_LONG).show();
                } catch (IllegalStateException e) {
                    Toast.makeText(getApplicationContext(), "You might not set the URI correctly!", Toast.LENGTH_LONG).show();
                } catch (IOException e) {
                    e.printStackTrace();
                }

                try {
                    mPlayer.prepare();
                } catch (IllegalStateException e) {
                    Toast.makeText(getApplicationContext(), "You might not set the URI correctly!", Toast.LENGTH_LONG).show();
                } catch (IOException e) {
                    Toast.makeText(getApplicationContext(), "You might not set the URI correctly!", Toast.LENGTH_LONG).show();
                }

                mPlayer.start();

                buttonStart.setEnabled(true);
                buttonDecode.setEnabled(true);
                buttonPlay.setEnabled(true);
            }
        });

        buttonDecode.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                buttonStart.setEnabled(false);
                buttonDecode.setEnabled(false);
                buttonPlay.setEnabled(false);

                //read raw data from wav file

                buttonStart.setEnabled(true);
                buttonDecode.setEnabled(true);
                buttonPlay.setEnabled(true);
            }
        });

        //Code for the back button
        Button backbuttonR = (Button) findViewById(R.id.backbuttonR);
        backbuttonR.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                startActivity(new Intent(ReceiveScreen.this, MainActivity.class));
            }
        });

    }

    private String getFilename(){
        String filepath = Environment.getExternalStorageDirectory().getPath();
        File file = new File(filepath,AUDIO_RECORDER_FOLDER);
        System.out.println(file.getAbsolutePath() + "/" + System.currentTimeMillis() + AUDIO_RECORDER_FILE_EXT_WAV);
        if (!file.exists()) {
            file.mkdirs();
        }

        return (file.getAbsolutePath() + "/" + System.currentTimeMillis() + AUDIO_RECORDER_FILE_EXT_WAV);
    }

    private String getTempFilename() {
        String filepath = Environment.getExternalStorageDirectory().getPath();
        File file = new File(filepath,AUDIO_RECORDER_FOLDER);

        if (!file.exists()) {
            file.mkdirs();
        }

        File tempFile = new File(filepath,AUDIO_RECORDER_TEMP_FILE);

        if (tempFile.exists())
            tempFile.delete();

        return (file.getAbsolutePath() + "/" + AUDIO_RECORDER_TEMP_FILE);
    }

    private void writeAudioDataToFile() {
        byte data[] = new byte[bufferSize];
        String filename = getTempFilename();
        FileOutputStream os = null;

        try {
            os = new FileOutputStream(filename);
        } catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        int read = 0;
        if (null != os) {
            while(isRecording) {
                read = recorder.read(data, 0, bufferSize);
                if (read > 0){
                }

                if (AudioRecord.ERROR_INVALID_OPERATION != read) {
                    try {
                        os.write(data);
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }

            try {
                os.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    private void deleteTempFile() {
        File file = new File(getTempFilename());
        file.delete();
    }

    private void copyWaveFile(String inFilename,String outFilename){
        FileInputStream in = null;
        FileOutputStream out = null;
        long totalAudioLen = 0;
        long totalDataLen = totalAudioLen + 36;
        long longSampleRate = RECORDER_SAMPLERATE;
        int channels = 2;
        long byteRate = RECORDER_BPP * RECORDER_SAMPLERATE * channels/8;

        byte[] data = new byte[bufferSize];

        try {
            in = new FileInputStream(inFilename);
            out = new FileOutputStream(outFilename);
            totalAudioLen = in.getChannel().size();
            totalDataLen = totalAudioLen + 36;

            System.out.println("File size: " + totalDataLen);

            WriteWaveFileHeader(out, totalAudioLen, totalDataLen,
                    longSampleRate, channels, byteRate);

            while(in.read(data) != -1) {
                out.write(data);
            }

            in.close();
            out.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private void WriteWaveFileHeader(
            FileOutputStream out, long totalAudioLen,
            long totalDataLen, long longSampleRate, int channels,
            long byteRate) throws IOException
    {
        byte[] header = new byte[44];

        header[0] = 'R';  // RIFF/WAVE header
        header[1] = 'I';
        header[2] = 'F';
        header[3] = 'F';
        header[4] = (byte) (totalDataLen & 0xff);
        header[5] = (byte) ((totalDataLen >> 8) & 0xff);
        header[6] = (byte) ((totalDataLen >> 16) & 0xff);
        header[7] = (byte) ((totalDataLen >> 24) & 0xff);
        header[8] = 'W';
        header[9] = 'A';
        header[10] = 'V';
        header[11] = 'E';
        header[12] = 'f';  // 'fmt ' chunk
        header[13] = 'm';
        header[14] = 't';
        header[15] = ' ';
        header[16] = 16;  // 4 bytes: size of 'fmt ' chunk
        header[17] = 0;
        header[18] = 0;
        header[19] = 0;
        header[20] = 1;  // format = 1
        header[21] = 0;
        header[22] = (byte) channels;
        header[23] = 0;
        header[24] = (byte) (longSampleRate & 0xff);
        header[25] = (byte) ((longSampleRate >> 8) & 0xff);
        header[26] = (byte) ((longSampleRate >> 16) & 0xff);
        header[27] = (byte) ((longSampleRate >> 24) & 0xff);
        header[28] = (byte) (byteRate & 0xff);
        header[29] = (byte) ((byteRate >> 8) & 0xff);
        header[30] = (byte) ((byteRate >> 16) & 0xff);
        header[31] = (byte) ((byteRate >> 24) & 0xff);
        header[32] = (byte) (2 * 16 / 8);  // block align
        header[33] = 0;
        header[34] = RECORDER_BPP;  // bits per sample
        header[35] = 0;
        header[36] = 'd';
        header[37] = 'a';
        header[38] = 't';
        header[39] = 'a';
        header[40] = (byte) (totalAudioLen & 0xff);
        header[41] = (byte) ((totalAudioLen >> 8) & 0xff);
        header[42] = (byte) ((totalAudioLen >> 16) & 0xff);
        header[43] = (byte) ((totalAudioLen >> 24) & 0xff);

        out.write(header, 0, 44);
    }

    /*public class SoundPoolPlayer {
        private SoundPool mShortPlayer= null;
        private HashMap mSounds = new HashMap();

        public SoundPoolPlayer(Context pContext)
        {
            // setup Soundpool
            this.mShortPlayer = new SoundPool(4, AudioManager.STREAM_MUSIC, 0);


            mSounds.put(R.raw.<sound_1_name>, this.mShortPlayer.load(pContext, R.raw.<sound_1_name>, 1));
            mSounds.put(R.raw.<sound_2_name>, this.mShortPlayer.load(pContext, R.raw.<sound_2_name>, 1));
        }

        public void playShortResource(int piResource) {
            int iSoundId = (Integer) mSounds.get(piResource);
            this.mShortPlayer.play(iSoundId, 0.99f, 0.99f, 0, 0, 1);
        }

        // Cleanup
        public void release() {
            // Cleanup
            this.mShortPlayer.release();
            this.mShortPlayer = null;
        }
    }*/

    public static final class Complex {
        // The number stored is x+I*y.
        final private double x, y;
        // I don't want to allow anyone to access these numbers so I've labeled
        // them private.

        /** Construct a point from real and imaginary parts. */
        public Complex(double real_part, double imaginary_part) {
            x=real_part;
            y=imaginary_part;
        }

        /** Construct a real number. */
        public Complex(double real_part) {
            x=real_part;
            y=0;
        }

        // A static constructor.

        /** Construct a complex number from the given polar coordinates. */
        public static Complex fromPolar(double r, double theta) {
            return new Complex(r*Math.cos(theta), r*Math.sin(theta));
        }

        // Basic operations on Complex numbers.

        /** Return the real part. */
        public double re(){
            return x;
        }

        /** Return the imaginary part. */
        public double im(){
            return y;
        }

        /** Return the complex conjugate */
        public Complex conj() {
            return new Complex(x,-y);
        }

        /** Return the square of the absolute value. */
        public double absSquared() {
            return x*x+y*y;
        }

        /** Return the absolute value. */
        public double abs() {
            // The java.lang.Math package contains many useful mathematical functions,
            // including the square root function.
            return Math.sqrt(absSquared());
        }

        // ARITHMETIC

        /** Add a complex number to this one.
         *
         * @param z The complex number to be added.
         * @return A new complex number which is the sum.
         */
        public Complex add(Complex z) {
            return new Complex(x+z.x, y+z.y);
        }

        /** Subtract a complex number from this one.
         *
         * @param z The complex number to be subtracted.
         * @return A new complex number which is the sum.
         */
        public Complex minus(Complex z) {
            return new Complex(x-z.x, y-z.y);
        }

        /** Negate this complex number.
         *
         * @return The negation.
         */
        public Complex neg() {
            return new Complex(-x, -y);
        }

        /** Compute the product of two complex numbers
         *
         * @param z The complex number to be multiplied.
         * @return A new complex number which is the product.
         */
        public Complex mult(Complex z) {
            return new Complex(x*z.x-y*z.y, x*z.y+z.x*y);
        }

        /** Divide this complex number by a real number.
         *
         * @param q The number to divide by.
         * @return A new complex number representing the quotient.
         */
        public Complex div(double q) {
            return new Complex(x/q,y/q);
        }

        /** Return the multiplicative inverse. */
        public Complex inv() {
            // find the square of the absolute value of this complex number.
            double abs_squared=absSquared();
            return new Complex(x/abs_squared, -y/abs_squared);
        }

        /** Compute the quotient of two complex numbers.
         *
         * @param z The complex number to divide this one by.
         * @return A new complex number which is the quotient.
         */
        public Complex div(Complex z) {
            return mult(z.inv());
        }

        /** Return the complex exponential of this complex number. */
        public Complex exp() {
            return new Complex(Math.exp(x)*Math.cos(y),Math.exp(x)*Math.sin(y));
        }


        // FUNCTIONS WHICH KEEP JAVA HAPPY:

        /** Returns this point as a string.
         * The main purpose of this function is for printing the string out,
         * so we return a string in a (fairly) human readable format.
         */
        // The _optional_ override directive "@Override" below just says we are
        // overriding a function defined in a parent class. In this case, the
        // parent is java.lang.Object. All classes in Java have the Object class
        // as a superclass.
        @Override
        public String toString() {
            // Comments:
            // 1) "" represents the empty string.
            // 2) If you add something to a string, it converts the thing you
            // are adding to a string, and then concatentates it with the string.

            // We do some voodoo to make sure the number is displayed reasonably.
            if (y==0) {
                return ""+x;
            }
            if (y>0) {
                return ""+x+"+"+y+"*I";
            }
            // otherwise y<0.
            return ""+x+"-"+(-y)+"*I";
        }

        /** Return true if the object is a complex number which is equal to this complex number. */
        @Override
        public boolean equals(Object obj) {
            // Return false if the object is null
            if (obj == null) {
                return false;
            }
            // Return false if the object is not a Complex number
            if (!(obj instanceof Complex)) {
                return false;
            }

            // Now the object must be a Complex number, so we can convert it to a
            // Complex number.
            Complex other = (Complex) obj;

            // If the x-coordinates are not equal, then return false.
            if (x != other.x) {
                return false;
            }
            // If the y-coordinates are not equal, then return false.
            if (y != other.y) {
                return false;
            }
            // Both parts are equal, so return true.
            return true;
        }

        // Remark: In Java, we should really override the hashcode function
        // whenever we override the equals function. But, I don't want to
        // get into this for a light introduction to programming in java.
        // Hash codes are necessary for various of Java's collections. See HashSet for instance.
        // The following was generated by Netbeans.
        @Override
        public int hashCode() {
            int hash = 3;
            hash = 83 * hash + (int) (Double.doubleToLongBits(this.x) ^ (Double.doubleToLongBits(this.x) >>> 32));
            hash = 83 * hash + (int) (Double.doubleToLongBits(this.y) ^ (Double.doubleToLongBits(this.y) >>> 32));
            return hash;
        }
    }
}
Scott Stensland
  • 26,870
  • 12
  • 93
  • 104
Wes Summers
  • 87
  • 1
  • 12

1 Answers1

-1

This should work. There might be better way to concat the bytes from the input stream etc but it is a working exemple to improve. Hope it works. Instead of MediaPlayer I use AudioTrack. HOpe this will work for you.

    InputStream is = mContext.getResources().openRawResource(R.raw.bell);
    byte []musicBytes=new byte[512];
    byte []fullMusicBytes=new byte[512];
    byte []tempMusicBytes=new byte[512];

    try {
        while (is.available() > 0) {
            is.read(musicBytes);
            if(fullMusicBytes!=null)
            {
                tempMusicBytes = new byte[fullMusicBytes.length + musicBytes.length];
                System.arraycopy(fullMusicBytes, 0, tempMusicBytes, 0, fullMusicBytes.length);
                System.arraycopy(musicBytes, 0, tempMusicBytes, fullMusicBytes.length, musicBytes.length);
                fullMusicBytes=tempMusicBytes;
            }
            else
            {
                fullMusicBytes=musicBytes;
            }

        }
        is.close();
    }catch(Exception e)
    {

    }
    int buffsize = AudioTrack.getMinBufferSize(sr,
            AudioFormat.CHANNEL_OUT_STEREO, AudioFormat.ENCODING_PCM_16BIT);
    // create an audiotrack object
    AudioTrack audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC,
            sr, AudioFormat.CHANNEL_OUT_STEREO,
            AudioFormat.ENCODING_PCM_16BIT, buffsize,
            AudioTrack.MODE_STREAM);
    audioTrack.play();

    int buffNr=0;

    while(fullMusicBytes.length>=buffNr) {
        audioTrack.write(fullMusicBytes, buffNr, buffsize);
        buffNr+=buffsize;
    }
bajen micke
  • 309
  • 1
  • 7
  • 18
  • i believe so, im new to java so i dont know much, can i do signal processing with the byte[]? – Wes Summers Jun 24 '17 at 18:08
  • The bytearray is the soundbytes in a wavefile and they can be proccesed byte by byte. In stereosound every second byte in the Array is right and the other left or the otherway, dont remember. The bytearray of a wav file starts with some bytes of header info (samplerate, stereo/mono etc). The rest is sound – bajen micke Jun 24 '17 at 20:39
  • so how can i extract the raw data into a byte[] array? – Wes Summers Jun 26 '17 at 11:05
  • the first answer in this question shows how to convert a WAV-file to byte-array. https://stackoverflow.com/questions/10397272/wav-file-convert-to-byte-array-in-java – bajen micke Jun 26 '17 at 15:48
  • Sorry that was java. I don't know if it works the same in Android. I get back in a while. I have a old project where I used wav but I don't remember, gonna open it and see – bajen micke Jun 26 '17 at 15:49