How to get buffer size from played audio file and Encode to PCM data for FFT class processing(Android)?


#1

I want to make a spectrum analyzer from a played audio file. Before it, i’ve tried to make a spectrum analyzer from MIC input and here’s the part of the code:

   

private class RecordAudio extends AsyncTask<Void, double[], Void> {

            @Override

            protected Void doInBackground(Void... params) {

    

                if(isCancelled()){

                    return null;

                }

    

                //try {

                int bufferSize = AudioRecord.getMinBufferSize(frequency, channelConfiguration, audioEncoding);

                AudioRecord audioRecord = new AudioRecord(

                        MediaRecorder.AudioSource.MIC, frequency, channelConfiguration, audioEncoding, bufferSize);

                short[] buffer = new short[blockSize];

                double[] toTransform = new double[blockSize];

    

                try {

                    audioRecord.startRecording();

                }

                catch (IllegalStateException e) {

                    Log.e("Recording Failed", e.toString());

                }

                    while (started) {

                        int bufferReadResult = audioRecord.read(buffer, 0, blockSize);

                        for (int i = 0; i < blockSize && i < bufferReadResult; i++) {

                            toTransform[i] = (double) buffer[i] / 32768.0; // signed 16 bit

                        }

                        transformer.ft(toTransform);

                        publishProgress(toTransform);

    

                        //Log.e("AudioRecord", "Recording Failed");

                        //return null;

                    }

                    //return null;

    

                return null;

            }

    

    

    

            protected void onProgressUpdate(double[]... toTransform) {

                canvas.drawColor(Color.BLACK);

                for (int i = 0; i < toTransform[0].length; i++) {

                    int x;

                    x = i;

                    int downy = (int) (100 - (toTransform[0][i] * 10));

                    int upy = 100;

                    canvas.drawRect(x * 5, downy, x * 5 + 4, upy, paint);

                    //canvas.drawLine(x, downy, x, upy, paint);

                    imageView.invalidate();

                }

            }

From that code, I think that the FFT class needs the PCM data that we get from encoding sound input from the MIC. Now, how can I get the buffer size from played audio file and encode it to PCM? Can I use mediaCodec class?

I tried this code for my audio player :

public class PlayAudioExample extends ListActivity {

        private static final int UPDATE_FREQUENCY = 500;

        private static final int STEP_VALUE = 4000;

        

        private MediaCursorAdapter mediaAdapter = null;

        private TextView selelctedFile = null;

        private SeekBar seekbar = null;

        private MediaPlayer player = null;

        private ImageButton playButton = null;

        private ImageButton prevButton = null;

        private ImageButton nextButton = null;

        

        private boolean isStarted = true;

        private String currentFile = "";

        private boolean isMoveingSeekBar = false;

        

        private final Handler handler = new Handler();

        

        private final Runnable updatePositionRunnable = new Runnable() {

                public void run() {

                        updatePosition();

                }

        };

        

        @Override

    public void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.main);

        

        selelctedFile = (TextView)findViewById(R.id.selectedfile);

        seekbar = (SeekBar)findViewById(R.id.seekbar);

        playButton = (ImageButton)findViewById(R.id.play);

        prevButton = (ImageButton)findViewById(R.id.prev);

        nextButton = (ImageButton)findViewById(R.id.next);

        

        player = new MediaPlayer();

        

        player.setOnCompletionListener(onCompletion);

        player.setOnErrorListener(onError);

        seekbar.setOnSeekBarChangeListener(seekBarChanged);

        

        Cursor cursor = getContentResolver().query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, null, null, null, null);

        

        if(null != cursor)

        {

                cursor.moveToFirst();

        

                mediaAdapter = new MediaCursorAdapter(this, R.layout.listitem, cursor);

                

                setListAdapter(mediaAdapter);

                

                playButton.setOnClickListener(onButtonClick);

                nextButton.setOnClickListener(onButtonClick);

                prevButton.setOnClickListener(onButtonClick);

        }

    }

    

    @Override

        protected void onListItemClick(ListView list, View view, int position, long id) {

                super.onListItemClick(list, view, position, id);

                

                currentFile = (String) view.getTag();

                

                startPlay(currentFile);

        }

    

        @Override

        protected void onDestroy() {

                super.onDestroy();

                

                handler.removeCallbacks(updatePositionRunnable);

                player.stop();

                player.reset();

                player.release();

    

                player = null;

        }

    

        private void startPlay(String file) {

                Log.i("Selected: ", file);

                

                selelctedFile.setText(file);

                seekbar.setProgress(0);

                                

                player.stop();

                player.reset();

                

                try {

                        player.setDataSource(file);

                        player.prepare();

                        player.start();

                } catch (IllegalArgumentException e) {

                        e.printStackTrace();

                } catch (IllegalStateException e) {

                        e.printStackTrace();

                } catch (IOException e) {

                        e.printStackTrace();

                }

                

                seekbar.setMax(player.getDuration());

                playButton.setImageResource(android.R.drawable.ic_media_pause);

                

                updatePosition();

                

                isStarted = true;

        }

        

        private void stopPlay() {

                player.stop();

                player.reset();

                playButton.setImageResource(android.R.drawable.ic_media_play);

                handler.removeCallbacks(updatePositionRunnable);

                seekbar.setProgress(0);

                

                isStarted = false;

        }

        

        private void updatePosition(){

                handler.removeCallbacks(updatePositionRunnable);

                

                seekbar.setProgress(player.getCurrentPosition());

                

                handler.postDelayed(updatePositionRunnable, UPDATE_FREQUENCY);

        }

    

        private class MediaCursorAdapter extends SimpleCursorAdapter{

    

                public MediaCursorAdapter(Context context, int layout, Cursor c) {

                        super(context, layout, c, 

                                        new String[] { MediaStore.MediaColumns.DISPLAY_NAME, MediaStore.MediaColumns.TITLE, MediaStore.Audio.AudioColumns.DURATION},

                                        new int[] { R.id.displayname, R.id.title, R.id.duration });

                }

    

                @Override

                public void bindView(View view, Context context, Cursor cursor) {

                        TextView title = (TextView)view.findViewById(R.id.title);

                        TextView name = (TextView)view.findViewById(R.id.displayname);

                        TextView duration = (TextView)view.findViewById(R.id.duration);

                        

                        name.setText(cursor.getString(

                                        cursor.getColumnIndex(MediaStore.MediaColumns.DISPLAY_NAME)));

                        

                        title.setText(cursor.getString(

                                        cursor.getColumnIndex(MediaStore.MediaColumns.TITLE)));

    

                        long durationInMs = Long.parseLong(cursor.getString(

                                        cursor.getColumnIndex(MediaStore.Audio.AudioColumns.DURATION)));

                        

                        double durationInMin = ((double)durationInMs/1000.0)/60.0;

                        

                        durationInMin = new BigDecimal(Double.toString(durationInMin)).setScale(2, BigDecimal.ROUND_UP).doubleValue(); 

    

                        duration.setText("" + durationInMin);

                        

                        view.setTag(cursor.getString(cursor.getColumnIndex(MediaStore.MediaColumns.DATA)));

                }

    

                @Override

                public View newView(Context context, Cursor cursor, ViewGroup parent) {

                        LayoutInflater inflater = LayoutInflater.from(context);

                        View v = inflater.inflate(R.layout.listitem, parent, false);

                        

                        bindView(v, context, cursor);

                        

                        return v;

                }

    }

        

        private View.OnClickListener onButtonClick = new View.OnClickListener() {

                

                @Override

                public void onClick(View v) {

                        switch(v.getId())

                        {

                                case R.id.play:

                                {

                                        if(player.isPlaying())

                                        {

                                                handler.removeCallbacks(updatePositionRunnable);

                                                player.pause();

                                                playButton.setImageResource(android.R.drawable.ic_media_play);

                                        }

                                        else

                                        {

                                                if(isStarted)

                                                {

                                                        player.start();

                                                        playButton.setImageResource(android.R.drawable.ic_media_pause);

                                                        

                                                        updatePosition();

                                                }

                                                else

                                                {

                                                        startPlay(currentFile);

                                                }

                                        }

                                        

                                        break;

                                }

                                case R.id.next:

                                {

                                        int seekto = player.getCurrentPosition() + STEP_VALUE;

                                        

                                        if(seekto > player.getDuration())

                                                seekto = player.getDuration();

                                        

                                        player.pause();

                                        player.seekTo(seekto);

                                        player.start();

                                        

                                        break;

                                }

                                case R.id.prev:

                                {

                                        int seekto = player.getCurrentPosition() - STEP_VALUE;

                                        

                                        if(seekto < 0)

                                                seekto = 0;

                                        

                                        player.pause();

                                        player.seekTo(seekto);

                                        player.start();

                                        

                                        break;

                                }

                        }

                }

        };

        

        private MediaPlayer.OnCompletionListener onCompletion = new MediaPlayer.OnCompletionListener() {

                

                @Override

                public void onCompletion(MediaPlayer mp) {

                        stopPlay();

                }

        };

        

        private MediaPlayer.OnErrorListener onError = new MediaPlayer.OnErrorListener() {

                

                @Override

                public boolean onError(MediaPlayer mp, int what, int extra) {

                        // returning false will call the OnCompletionListener

                        return false;

                }

        };

        

        private SeekBar.OnSeekBarChangeListener seekBarChanged = new SeekBar.OnSeekBarChangeListener() {

                @Override

                public void onStopTrackingTouch(SeekBar seekBar) {

                        isMoveingSeekBar = false;

                }

                

                @Override

                public void onStartTrackingTouch(SeekBar seekBar) {

                        isMoveingSeekBar = true;

                }

                

                @Override

                public void onProgressChanged(SeekBar seekBar, int progress,boolean fromUser) {

                        if(isMoveingSeekBar)

                        {

                                player.seekTo(progress);

                        

                                Log.i("OnSeekBarChangeListener","onProgressChanged");

                        }

                }

        };

    }

Really need help

Thanks :slight_smile:


#2

Hello Pras,

Thanks for getting in touch. It sounds really interesting what you are trying to achieve with your app! I’m afraid I do not have any experience in working with audio files in Android. Here at ShinobiControls we currently are not performing any development work with audio file processing and as such, I do not believe we are best placed to advise you. I have noticed however that you also have a post on StackOverflow. In my experience I have found this to be an excellent forum on which many helpful developers frequently visit. I think your question is much more likely to be answered using this forum than the ShinobiControls forum. This forum tends to focus on more (ShinobiControls) product specific queries. 

I am sorry I have not been able to be any further help but I do sincerely wish you the best of luck with your application!

Thanks and kind regards,

Kai.


#3

No Problem :slight_smile:

I’ve found the solution and now still try modify my app. Anyway, what kind of development usually performed at ShinobiControl? May be next time I’ll ask question with a match subject :slight_smile:


#4

Greetings Program!

I had to Google what a spectrum analyzer was; basically a graph of data but sounds like a pretty cool app smiley lol.

Although I work with iOS, I got lost with your question just from the subject  smiley eek because the forum generally has questions regarding issues with the controls themselves; the developer has the data but the control isn’t working or wants to be able to do something specific with the data and doesn’t know how, etc.

In your case, you were looking for a way to get the data and hadn’t tackled presenting it in the chart yet  smiley wink. But now that you have the data, how’s the implementation with the ShinobiChart going?

Wg