Git Product home page Git Product logo

audio-waveform's Introduction

audio-waveform (for Android)


##What #####Show audio file's waveform, not spectrum. #####This lib based on ringdroid, but only contains WaveformView and related classes.
##How

  • Add this to your build.gradle
    compile 'com.github.derlio.waveform:library:1.0.3@aar'
  • Use SimpleWaveformView in your layout
        <com.github.derlio.waveform.SimpleWaveformView
            android:id="@+id/waveform"
            android:layout_width="match_parent"
            android:layout_height="144dp"
            app:waveformColor="#fb6155"
            app:indicatorColor="@android:color/holo_green_dark"
        />

app:waveformColor is the waveform line's color, app:indicatorColor is the current playing indicator's color.

  • Then get it from Activity, and prepare your audio file
final File file = new File(dir, "qudali.mp3");
final SoundFile soundFile = SoundFile.create(file.getPath(), new SoundFile.ProgressListener() {

                        int lastProgress = 0;

                        @Override
                        public boolean reportProgress(double fractionComplete) {
                            final int progress = (int) (fractionComplete * 100);
                            if (lastProgress == progress) {
                                return true;
                            }
                            lastProgress = progress;
                            Log.i(TAG, "LOAD FILE PROGRESS:" + progress);
                            
                            return true;
                        }
                    });

Make sure below codes should not be in the Main Thread. User SoundFile.ProgressListener to get file load progress, param fractionComplete is from 0.0 to 1.0, and return true means to continue decode, return false will abort the decode.

  • Then use
mWaveformView.setAudioFile(soundFile);
mWaveformView.invalidate();

to set the audio file to WaveformView. It does work.

  • If you want to show current playing indicator, just implements SimpleWaveformView.WaveformListener, use below codes in onWaveformDraw.
int now = mPlayer.getCurrentPosition();
mWaveformView.setPlaybackPosition(now);

This library is just satisfied my current situation. It has much more works to do. Hope you can help me~

audio-waveform's People

Contributors

derlio avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

audio-waveform's Issues

java.lang.NullPointerException: Attempt to invoke virtual method 'int com.github.derlio.waveform.soundfile.SoundFile.getSampleRate()' on a null object reference

@derlio

I get this error

 E/AndroidRuntime: FATAL EXCEPTION: main
                                                                           Process: com.studiosoapps.studioso, PID: 18253
                                                                           java.lang.NullPointerException: Attempt to invoke virtual method 'int com.github.derlio.waveform.soundfile.SoundFile.getSampleRate()' on a null object reference
                                                                               at com.github.derlio.waveform.SimpleWaveformView.setAudioFile(SimpleWaveformView.java:74)
                                                                               at com.studiosoapps.studioso.recordings.RecordedAudioListener$9$2.run(RecordedAudioListener.java:355)
                                                                               at android.os.Handler.handleCallback(Handler.java:751)
                                                                               at android.os.Handler.dispatchMessage(Handler.java:95)
                                                                               at android.os.Looper.loop(Looper.java:154)
                                                                               at android.app.ActivityThread.main(ActivityThread.java:6776)
                                                                               at java.lang.reflect.Method.invoke(Native Method)
                                                                               at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1520)
                                                                               at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1410)

this is my code

package com.studiosoapps.studioso.recordings;


import android.media.AudioManager;
import android.media.MediaPlayer;

import android.os.Environment;
import android.os.Handler;

import android.support.annotation.NonNull;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Button;
import android.widget.SeekBar;
import android.widget.Toast;

import com.github.derlio.waveform.SimpleWaveformView;
import com.github.derlio.waveform.soundfile.SoundFile;
import com.google.android.gms.tasks.OnFailureListener;
import com.google.android.gms.tasks.OnSuccessListener;
import com.google.firebase.auth.FirebaseAuth;
import com.google.firebase.storage.FileDownloadTask;
import com.google.firebase.storage.FirebaseStorage;
import com.google.firebase.storage.StorageReference;
import com.studiosoapps.studioso.R;

import java.io.File;
import java.io.IOException;
import static com.crashlytics.android.Crashlytics.TAG;

public class RecordedAudioListener extends AppCompatActivity implements MediaPlayer.OnPreparedListener, SimpleWaveformView.WaveformListener {

//    public static ArrayList<Object> urlName = new ArrayList<>();
    public static String fileName;
    public static String urlName;
    public static String urlNameOrg;
    public static String urlNameNew;
    private SimpleWaveformView mWaveformView;



    private Button buttonPlayStop;
    private SeekBar seekBar;
//    private static final String TAG = "RecordedAudioListener";

    private MediaPlayer mediaPlayer;
    //path to the audio file
    private String mediaFile;



    FirebaseStorage storage = FirebaseStorage.getInstance();
    String UID = FirebaseAuth.getInstance().getUid();

    //https://www.sitepoint.com/a-step-by-step-guide-to-building-an-android-audio-player-app/
    private final Handler handler = new Handler();

    // Here i override onCreate method.
    //
    // setContentView() method set the layout that you will see then
    // the application will starts
    //
    // initViews() method i create to init views components.

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_recorded_audio_listener);
//https://www.hrupin.com/2010/12/simple-android-mp3-media-player/comment-page-1
        urlNameOrg = RecordedAudioViewer.urlReturn();
        fileName = RecordedAudioViewer.nameReturn();
        Log.d(TAG, "onCreate: urlNameOrg " + urlNameOrg);
//        urlNameOrg = urlNameOrg.substring(0, urlNameOrg.indexOf("=") - 1);
        urlNameNew = urlNameOrg.replace("{DownloadURL=","");
        urlName = urlNameNew.replace("}","");

        Log.d(TAG, "onCreate: urlName " + urlName);
        Log.d(TAG, "onCreate: urlNameOrg new " + urlNameOrg);
        Log.d(TAG, "onCreate: fileName "+ fileName);

        StorageReference httpsReference = storage.getReferenceFromUrl(String.valueOf(urlName));
//        File localFile = null;
//        try {
//            localFile = File.createTempFile("videos", "mp4");
//        } catch (IOException e) {
//            e.printStackTrace();
//        }
        File directory = new File(Environment.getExternalStorageDirectory().getAbsolutePath(), "Studioso");
        File file = new File(Environment.getExternalStorageDirectory().getAbsolutePath(), "Studioso" + "/" + fileName);

        Log.d(TAG, "createDir: Dir == " + directory);
        Log.d(TAG, "createDir: file dir == " + file);
        if (!directory.exists() || !directory.isDirectory()) {
            directory.mkdirs();
            Toast.makeText(RecordedAudioListener.this, "Media file not ready", Toast.LENGTH_SHORT).show();
            Log.d(TAG, "createDir: making directory");
//            if ( buttonPlayStop != null ) buttonPlayStop.setEnabled(false);

            httpsReference.getFile(directory).addOnSuccessListener(new OnSuccessListener<FileDownloadTask.TaskSnapshot>() {
                @Override
                public void onSuccess(FileDownloadTask.TaskSnapshot taskSnapshot) {
                    // Local temp file has been created
                    Log.d(TAG, "createDir: Downloading files complete");
                }
            }).addOnFailureListener(new OnFailureListener() {
                @Override
                public void onFailure(@NonNull Exception exception) {
                    // Handle any errors
                    Log.d(TAG, "createDir: Downloading files failure");
                }
            });
        }
        else if (directory.exists() && !file.exists() ) {
//            if ( buttonPlayStop != null ) buttonPlayStop.setEnabled(false);
            Toast.makeText(RecordedAudioListener.this, "Media file not ready", Toast.LENGTH_SHORT).show();
            Log.d(TAG, "createDir: Downloading files");
            httpsReference.getFile(directory).addOnSuccessListener(new OnSuccessListener<FileDownloadTask.TaskSnapshot>() {
                @Override
                public void onSuccess(FileDownloadTask.TaskSnapshot taskSnapshot) {
                    // Local temp file has been created
                    Log.d(TAG, "createDir: Downloading files complete");
                }
            }).addOnFailureListener(new OnFailureListener() {
                @Override
                public void onFailure(@NonNull Exception exception) {
                    // Handle any errors
                    Log.d(TAG, "createDir: Downloading files failure");
                }
            });



        }
        else {
            Log.d(TAG, "createDir: files are there");
            Toast.makeText(RecordedAudioListener.this, "Media file not ready", Toast.LENGTH_SHORT).show();
//            if ( buttonPlayStop != null ) buttonPlayStop.setEnabled(false);
        }

        mediaFile = directory + "/" + fileName;



        initViews();
        mWaveformView = (SimpleWaveformView) findViewById(R.id.waveform);
        mWaveformView.setWaveformListener(this);

    }


    // This method set the setOnClickListener and method for it (buttonClick())
    private void initViews() {

//        buttonPlayStop.setOnClickListener(new View.OnClickListener() {@Override public void onClick(View v) {buttonClick();}});

//       mediaPlayer = MediaPlayer.create(this,  Uri.parse(mediaFile));

        mediaPlayer = new MediaPlayer();
        mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
        try {
            mediaPlayer.setDataSource(mediaFile);
//            mediaPlayer.setDataSource(getApplication(),Uri.parse(mediaFile));
//                mediaPlayer.setOnPreparedListener(this);
            mediaPlayer.setOnPreparedListener(this);
            mediaPlayer.prepareAsync();
            Log.d(TAG, "initViews: mediaPlayer input file set  " + mediaFile);
        } catch (IOException e) {
            e.printStackTrace();
        }

//        seekBar.setMax(mediaPlayer.getDuration());
//        seekBar.setOnTouchListener(new View.OnTouchListener() {
//            @Override
//            public boolean onTouch(View v, MotionEvent event) {
//                seekChange(v);
//                return false;
//            }
//        });
    }
//
//    public void startPlayProgressUpdater() {
//
//        seekBar.setProgress(mediaPlayer.getCurrentPosition());
//            if (mediaPlayer.isPlaying()) {
//
//                Runnable notification = new Runnable() {
//                    public void run() {
//                        startPlayProgressUpdater();
//                    }
//                };
////                handler.postDelayed(notification, 1000);
//            } else {
//                if (mediaPlayer != null) {
//                    mediaPlayer.pause();
//                }
////                buttonPlayStop.setText("Play");
////                seekBar.setProgress(0);
//            }
//
//    }

    // This is event handler thumb moving event
    private void seekChange(View v){
        if(mediaPlayer.isPlaying()){
            SeekBar sb = (SeekBar)v;
            mediaPlayer.seekTo(sb.getProgress());
        }
    }

    // This is event handler for buttonClick event
    private void buttonClick(){
        if (buttonPlayStop.getText() == "Play") {
            buttonPlayStop.setText("Pause");
            try{
                mediaPlayer.start();
//                startPlayProgressUpdater();
                updateSeek();
                Log.d(TAG, "buttonClick: mediaPlayer Started sucessfully");
            }catch (IllegalStateException e) {
                mediaPlayer.pause();
                Log.d(TAG, "buttonClick: mediaPlayer failed IllegalStatus ");
            }
        }else {
            mediaPlayer.pause();
            buttonPlayStop.setText("Play");

        }
    }

            @Override
            public void onPrepared(MediaPlayer mp) {
                // Do something. For example: playButton.setEnabled(true);
//                buttonPlayStop.setEnabled(true);

                        buttonPlayStop = (Button) findViewById(R.id.ButtonPlayStop);
                        buttonPlayStop.setOnClickListener(new View.OnClickListener() {
                            @Override
                            public void onClick(View v) {
                                buttonClick();
                            }
                        });
                        buttonPlayStop.setText("Play");

//                mediaPlayer.start();
                doTheWave();
                Toast.makeText(RecordedAudioListener.this, "Media file downloaded and ready to play", Toast.LENGTH_LONG).show();
                Log.d(TAG, "mediaPlayer: mediaPlayer ready");
                mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
                    @Override
                    public void onCompletion(MediaPlayer mediaPlayer) {
                        mediaPlayer.stop();
                        mediaPlayer.release();
                        mediaPlayer = null;
                    }
                });


                new Thread(new Runnable() {
                    public void run() {
                        seekBar = (SeekBar) findViewById(R.id.SeekBar01);
                        seekBar.setMax(mediaPlayer.getDuration());

                        seekBar.setOnTouchListener(new View.OnTouchListener() {
                            @Override
                            public boolean onTouch(View v, MotionEvent event) {
                                seekChange(v);
                                return false;
                            }
                        });
                    }
                }).start();

            }
    @Override
    public void onDestroy() {
        super.onDestroy();
        if (mediaPlayer != null) {
            mediaPlayer.stop();
            mediaPlayer.release();
            mediaPlayer = null;
        }
    }

    private void updateSeek() {

        new Thread(new Runnable() {
            public void run() {
                Log.d(TAG, "updateSeek: while loop will run"); //note this isn't in loop because of performance
                while (mediaPlayer.isPlaying()) {

                    seekBar.setProgress(mediaPlayer.getCurrentPosition());
                    if (!mediaPlayer.isPlaying()) {
                        break;
                    }
                }
            }
        }).start();

    }

    @Override
    public void onWaveformDraw() {
        if (mediaPlayer.isPlaying()) {
            updateDisplay();
        }

    }

    private synchronized void updateDisplay() {
        if (mediaPlayer.isPlaying() && mediaPlayer != null) {
            int now = mediaPlayer.getCurrentPosition();
            mWaveformView.setPlaybackPosition(now);
        }
//
//        mWaveformView.setParameters(mStartPos, mEndPos, mOffset);
//        mWaveformView.invalidate();

    }
    private void doTheWave() {
        new Thread(new Runnable() {
            public void run() {
                try {
                    File dir = Environment.getExternalStorageDirectory();
                    final File withDir = new File(dir, "Studioso");
                    final File file = new File(withDir, fileName);

                    final SoundFile soundFile = SoundFile.create(file.getPath(), new SoundFile.ProgressListener() {

                        int lastProgress = 0;


                        @Override
                        public boolean reportProgress(double fractionComplete) {
                            final int progress = (int) (fractionComplete * 100);
                            if (lastProgress == progress) {
                                return true;
                            }
                            lastProgress = progress;
                            Log.i(TAG, "LOAD FILE PROGRESS:" + progress);

                            return true;
                        }
                    });

                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            DisplayMetrics metrics = new DisplayMetrics();
                            getWindowManager().getDefaultDisplay().getMetrics(metrics);

                            mWaveformView.setAudioFile(soundFile);

//                            mWaveformView.invalidate();
                        }
                    });

                } catch (IOException e) {
                    e.printStackTrace();
                } catch (SoundFile.InvalidInputException e) {
                    e.printStackTrace();
                }

            }
        }).start();
    }
}

any advice I don't know why this error is happening?

Crashes on using WaveformView in a RecyclerView

CrashLog:

java.lang.NullPointerException: Attempt to read from null array
        at com.github.derlio.waveform.WaveformView.onDraw(WaveformView.java:384)
        at android.view.View.draw(View.java:17099)
        at android.view.View.updateDisplayListIfDirty(View.java:16081)
        at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:3750)
        at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:3730)
        at android.view.View.updateDisplayListIfDirty(View.java:16044)
        at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:3750)
        at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:3730)
        at android.view.View.updateDisplayListIfDirty(View.java:16044)
        at android.view.View.draw(View.java:16865)
        at android.view.ViewGroup.drawChild(ViewGroup.java:3766)
        at androidx.recyclerview.widget.RecyclerView.drawChild(RecyclerView.java:4820)
        at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3552)
        at android.view.View.draw(View.java:17102)
        at androidx.recyclerview.widget.RecyclerView.draw(RecyclerView.java:4219)
        at android.view.View.updateDisplayListIfDirty(View.java:16081)
        at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:3750)
        at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:3730)
        at android.view.View.updateDisplayListIfDirty(View.java:16044)
        at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:3750)
        at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:3730)
        at android.view.View.updateDisplayListIfDirty(View.java:16044)
        at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:3750)
        at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:3730)
        at android.view.View.updateDisplayListIfDirty(View.java:16044)
        at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:3750)
        at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:3730)
        at android.view.View.updateDisplayListIfDirty(View.java:16044)
        at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:3750)
        at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:3730)
        at android.view.View.updateDisplayListIfDirty(View.java:16044)
        at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:3750)
        at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:3730)
        at android.view.View.updateDisplayListIfDirty(View.java:16044)
        at android.view.ThreadedRenderer.updateViewTreeDisplayList(ThreadedRenderer.java:666)
        at android.view.ThreadedRenderer.updateRootDisplayList(ThreadedRenderer.java:672)
        at android.view.ThreadedRenderer.draw(ThreadedRenderer.java:780)
        at android.view.ViewRootImpl.draw(ViewRootImpl.java:2840)
        at android.view.ViewRootImpl.performDraw(ViewRootImpl.java:2648)
        at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:2255)
        at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1290)
        at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:6399)
        at android.view.Choreographer$CallbackRecord.run(Choreographer.java:873)
        at android.view.Choreographer.doCallbacks(Choreographer.java:685)
        at android.view.Choreographer.doFrame(Choreographer.java:621)
        at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:859)
        at android.os.Handler.handleCallback(Handler.java:754)
        at android.os.Handler.dispatchMessage(Handler.java:95)
        at android.os.Looper.loop(Looper.java:165)
        at android.app.ActivityThread.main(ActivityThread.java:6375)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:912)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:802)

This does not seem to be a problem with SimpleWaveformView but it does not allow setting the Sound file asynchronously.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.