在每个listview项中绘制自定义WaveForm视图

时间:2016-08-22 05:19:16

标签: android listview audio

我在做什么

  • 我有多个音频文件在listview中播放。
  • 在每个列表视图项上,我正在该位置绘制特定音频文件的自定义波形。
  • 每个音频文件首先由Meta Data reader读取,然后将其转换为波形视图。

我的问题是什么。

  • 波形仅在最后一个列表项上生成View rest all都是空视图。此外,每个声音文件的波形仅在最后一个列表项视图中生成。

以下是我的代码

波形视图类

public class WaveformView extends View {
    public interface WaveformListener {
        public void waveformTouchStart(float x);

        public void waveformTouchMove(float x);

        public void waveformTouchEnd();

        public void waveformFling(float x);

        public void waveformDraw();
    }


    // Colors
    private Paint mGridPaint;
    private Paint mSelectedLinePaint;
    private Paint mUnselectedLinePaint;
    private Paint mUnselectedBkgndLinePaint;
    private Paint mBorderLinePaint;
    private Paint mPlaybackLinePaint;
    private Paint mTimecodePaint;

    private SoundFile mSoundFile;
    private int[] mLenByZoomLevel;
    private double[][] mValuesByZoomLevel;
    private double[] mZoomFactorByZoomLevel;
    private int[] mHeightsAtThisZoomLevel;
    private int mZoomLevel;
    private int mNumZoomLevels;
    private int mSampleRate;
    private int mSamplesPerFrame;
    private int mOffset;
    private int mSelectionStart;
    private int mSelectionEnd;
    private int mPlaybackPos;
    private float mDensity;
    private float mInitialScaleSpan;
    private WaveformListener mListener;
    private GestureDetector mGestureDetector;
    private ScaleGestureDetector mScaleGestureDetector;
    private boolean mInitialized;
      Color color;
    int totalLines = 0;
    MainActivity mainActivity;


    public WaveformView(Context context, AttributeSet attrs) {
        super(context, attrs);

        // We don't want keys, the markers get these
        setFocusable(false);

        mGridPaint = new Paint();
        mGridPaint.setAntiAlias(false);
        mGridPaint.setColor(
                getResources().getColor(R.color.grid_line));
        mSelectedLinePaint = new Paint();
        mSelectedLinePaint.setAntiAlias(false);
        mSelectedLinePaint.setColor(
                getResources().getColor(R.color.waveform_selected));
        mUnselectedLinePaint = new Paint();
        mUnselectedLinePaint.setAntiAlias(false);
        mUnselectedLinePaint.setColor(
                getResources().getColor(R.color.waveform_unselected));
        mUnselectedBkgndLinePaint = new Paint();
        mUnselectedBkgndLinePaint.setAntiAlias(false);
        mUnselectedBkgndLinePaint.setColor(
                getResources().getColor(
                        R.color.selection_border));
        mBorderLinePaint = new Paint();
        mBorderLinePaint.setAntiAlias(true);
        mBorderLinePaint.setStrokeWidth(1.5f);
        mBorderLinePaint.setPathEffect(
                new DashPathEffect(new float[]{3.0f, 2.0f}, 0.0f));
        mBorderLinePaint.setColor(
                getResources().getColor(R.color.selection_border));
        mPlaybackLinePaint = new Paint();
        mPlaybackLinePaint.setAntiAlias(false);
        mPlaybackLinePaint.setColor(
                getResources().getColor(R.color.playback_indicator));
        mTimecodePaint = new Paint();
        mTimecodePaint.setTextSize(12);
        mTimecodePaint.setAntiAlias(true);
        mTimecodePaint.setColor(
                getResources().getColor(R.color.timecode));
        mTimecodePaint.setShadowLayer(
                2, 1, 1,
                getResources().getColor(R.color.timecode_shadow));

        mGestureDetector = new GestureDetector(
                context,
                new GestureDetector.SimpleOnGestureListener() {
                    public boolean onFling(
                            MotionEvent e1, MotionEvent e2, float vx, float vy) {
                        mListener.waveformFling(vx);
                        return true;
                    }
                });

        mSoundFile = null;
        mLenByZoomLevel = null;
        mValuesByZoomLevel = null;
        mHeightsAtThisZoomLevel = null;
        mOffset = 0;
        mPlaybackPos = -1;
        mSelectionStart = 0;
        mSelectionEnd = 0;
        mDensity = 1.0f;
        mInitialized = false;
    }


    public boolean hasSoundFile() {
        return mSoundFile != null;
    }

    public void setSoundFile(SoundFile soundFile) {
        mSoundFile = soundFile;
        mSampleRate = mSoundFile.getSampleRate();
        mSamplesPerFrame = mSoundFile.getSamplesPerFrame();
        computeDoublesForAllZoomLevels();
        mHeightsAtThisZoomLevel = null;
    }

    /**
     * Called once when a new sound file is added
     */
    private void computeDoublesForAllZoomLevels() {
        int numFrames = mSoundFile.getNumFrames();
        int[] frameGains = mSoundFile.getFrameGains();
        double[] smoothedGains = new double[numFrames];
        if (numFrames == 1) {
            smoothedGains[0] = frameGains[0];
        } else if (numFrames == 2) {
            smoothedGains[0] = frameGains[0];
            smoothedGains[1] = frameGains[1];
        } else if (numFrames > 2) {
            smoothedGains[0] = (double)(
                    (frameGains[0] / 2.0) +
                            (frameGains[1] / 2.0));
            for (int i = 1; i < numFrames - 1; i++) {
                smoothedGains[i] = (double)(
                        (frameGains[i - 1] / 3.0) +
                                (frameGains[i    ] / 3.0) +
                                (frameGains[i + 1] / 3.0));
            }
            smoothedGains[numFrames - 1] = (double)(
                    (frameGains[numFrames - 2] / 2.0) +
                            (frameGains[numFrames - 1] / 2.0));
        }

        // Make sure the range is no more than 0 - 255
        double maxGain = 1.0;
        for (int i = 0; i < numFrames; i++) {
            if (smoothedGains[i] > maxGain) {
                maxGain = smoothedGains[i];
            }
        }
        double scaleFactor = 1.0;
        if (maxGain > 255.0) {
            scaleFactor = 255 / maxGain;
        }

        // Build histogram of 256 bins and figure out the new scaled max
        maxGain = 0;
        int gainHist[] = new int[256];
        for (int i = 0; i < numFrames; i++) {
            int smoothedGain = (int)(smoothedGains[i] * scaleFactor);
            if (smoothedGain < 0)
                smoothedGain = 0;
            if (smoothedGain > 255)
                smoothedGain = 255;

            if (smoothedGain > maxGain)
                maxGain = smoothedGain;

            gainHist[smoothedGain]++;
        }

        // Re-calibrate the min to be 5%
        double minGain = 0;
        int sum = 0;
        while (minGain < 255 && sum < numFrames / 20) {
            sum += gainHist[(int)minGain];
            minGain++;
        }

        // Re-calibrate the max to be 99%
        sum = 0;
        while (maxGain > 2 && sum < numFrames / 100) {
            sum += gainHist[(int)maxGain];
            maxGain--;
        }

        // Compute the heights
        double[] heights = new double[numFrames];
        double range = maxGain - minGain;
        for (int i = 0; i < numFrames; i++) {
            double value = (smoothedGains[i] * scaleFactor - minGain) / range;
            if (value < 0.0)
                value = 0.0;
            if (value > 1.0)
                value = 1.0;
            heights[i] = value * value;
        }

        mNumZoomLevels = 5;
        mLenByZoomLevel = new int[5];
        mZoomFactorByZoomLevel = new double[5];
        mValuesByZoomLevel = new double[5][];

        // Level 0 is doubled, with interpolated values
        mLenByZoomLevel[0] = numFrames * 2;
        mZoomFactorByZoomLevel[0] = 2.0;
        mValuesByZoomLevel[0] = new double[mLenByZoomLevel[0]];
        if (numFrames > 0) {
            mValuesByZoomLevel[0][0] = 0.5 * heights[0];
            mValuesByZoomLevel[0][1] = heights[0];
        }
        for (int i = 1; i < numFrames; i++) {
            mValuesByZoomLevel[0][2 * i] = 0.5 * (heights[i - 1] + heights[i]);
            mValuesByZoomLevel[0][2 * i + 1] = heights[i];
        }

        // Level 1 is normal
        mLenByZoomLevel[1] = numFrames;
        mValuesByZoomLevel[1] = new double[mLenByZoomLevel[1]];
        mZoomFactorByZoomLevel[1] = 1.0;
        for (int i = 0; i < mLenByZoomLevel[1]; i++) {
            mValuesByZoomLevel[1][i] = heights[i];
        }

        // 3 more levels are each halved
        for (int j = 2; j < 5; j++) {
            mLenByZoomLevel[j] = mLenByZoomLevel[j - 1] / 2;
            mValuesByZoomLevel[j] = new double[mLenByZoomLevel[j]];
            mZoomFactorByZoomLevel[j] = mZoomFactorByZoomLevel[j - 1] / 2.0;
            for (int i = 0; i < mLenByZoomLevel[j]; i++) {
                mValuesByZoomLevel[j][i] =
                        0.5 * (mValuesByZoomLevel[j - 1][2 * i] +
                                mValuesByZoomLevel[j - 1][2 * i + 1]);
            }
        }

        if (numFrames > 5000) {
            mZoomLevel = 3;
        } else if (numFrames > 1000) {
            mZoomLevel = 2;
        } else if (numFrames > 300) {
            mZoomLevel = 1;
        } else {
            mZoomLevel = 0;
        }

        mInitialized = true;
    }

    public boolean canZoomIn() {
        return (mZoomLevel > 0);
    }

    public void zoomIn() {
        if (canZoomIn()) {
            mZoomLevel--;
            mSelectionStart *= 2;
            mSelectionEnd *= 2;
            mHeightsAtThisZoomLevel = null;
            int offsetCenter = mOffset + getMeasuredWidth() / 2;
            offsetCenter *= 2;
            mOffset = offsetCenter - getMeasuredWidth() / 2;
            if (mOffset < 0)
                mOffset = 0;
            invalidate();
        }
    }

    public boolean canZoomOut() {
        return (mZoomLevel < mNumZoomLevels - 1);
    }

    public void zoomOut() {
        if (canZoomOut()) {
            mZoomLevel++;
            mSelectionStart /= 2;
            mSelectionEnd /= 2;
            int offsetCenter = mOffset + getMeasuredWidth() / 2;
            offsetCenter /= 2;
            mOffset = offsetCenter - getMeasuredWidth() / 2;
            if (mOffset < 0)
                mOffset = 0;
            mHeightsAtThisZoomLevel = null;
            invalidate();
        }
    }



    public void setParameters(int start, int end, int offset) {
        mSelectionStart = start;
        mSelectionEnd = end;
        mOffset = offset;
    }

    public int getStart() {
        return mSelectionStart;
    }

    public int getEnd() {
        return mSelectionEnd;
    }

    public int getOffset() {
        return mOffset;
    }

    public void setPlayback(int pos) {
        mPlaybackPos = pos;
    }

    public void setListener(WaveformListener listener) {
        mListener = listener;
    }

    public void recomputeHeights(float density) {
        mHeightsAtThisZoomLevel = null;
        mDensity = density;
        mTimecodePaint.setTextSize((int)(12 * density));

        invalidate();
    }


    protected void drawWaveformLine(Canvas canvas,
                                    int x, int y0, int y1,
                                    Paint paint) {
        canvas.drawLine(x, y0, x, y1, paint);
    }


    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        if (mSoundFile == null)
            return;

        if (mHeightsAtThisZoomLevel == null)
            computeIntsForThisZoomLevel();
        DisplayMetrics displaymetrics = getContext().getResources().getDisplayMetrics();
        int height = displaymetrics.heightPixels;
        int widths = displaymetrics.widthPixels;
        // Draw waveform
        int measuredWidth = getMeasuredWidth();
        int measuredHeight = getMeasuredHeight();
        int start = mOffset;
        int width = mHeightsAtThisZoomLevel.length - start;
        int ctr = measuredHeight / 2;


        totalLines = width;

        Log.e("wid",String.valueOf(width));
        Log.e("widCal",String.valueOf(mHeightsAtThisZoomLevel.length));
        Log.e("widstart",String.valueOf(start));


        if (width > measuredWidth)
            width = measuredWidth;


        Log.e("measured",String.valueOf(measuredWidth));


        // Draw grid
        double onePixelInSecs = pixelsToSeconds(1);
        boolean onlyEveryFiveSecs = (onePixelInSecs > 1.0 / 50.0);
        double fractionalSecs = mOffset * onePixelInSecs;
        int integerSecs = (int) fractionalSecs;
        int i = 0;
        while (i < width) {
            i++;
            fractionalSecs += onePixelInSecs;
            int integerSecsNew = (int) fractionalSecs;
            if (integerSecsNew != integerSecs) {
                integerSecs = integerSecsNew;
                if (!onlyEveryFiveSecs || 0 == (integerSecs % 5)) {
                    canvas.drawLine(i, 0, i, measuredHeight, mGridPaint);
                }
            }
        }

        // Draw waveform
        for ( i = 0; i < width; i++) {
            Paint paint;

            if (i + start >= mSelectionStart &&
                    i + start < mSelectionEnd) {
                paint = mSelectedLinePaint;
             //   paint.setColor(color);
            } else {
                drawWaveformLine(canvas, ((widths/width)*i), 0, measuredHeight,
                        mUnselectedBkgndLinePaint);
                paint = mUnselectedLinePaint;
            }
            drawWaveformLine(
                    canvas, ((widths/width)*i),
                    ctr - mHeightsAtThisZoomLevel[start + i],
                    ctr + 1 + mHeightsAtThisZoomLevel[start + i],
                    paint);


            if (i + start <= mPlaybackPos) {
                Paint mPaint = new Paint(paint);
                mPaint.setColor(Color.RED);
                drawWaveformLine(
                        canvas, ((widths/width)*i),
                        ctr - mHeightsAtThisZoomLevel[start + i],
                        ctr + 1 + mHeightsAtThisZoomLevel[start + i],
                        mPaint);

            }

             if (i + start == mPlaybackPos) {
                Paint mPaints = new Paint(paint);
                mPaints.setColor(Color.RED);
                drawWaveformLine(
                        canvas, ((widths / width) * i),
                        ctr - mHeightsAtThisZoomLevel[start + i],
                        ctr + 1 + mHeightsAtThisZoomLevel[start + i],
                        mPaints);
            }

        if (mListener != null) {
            mListener.waveformDraw();
        }
    }}
   private void computeIntsForThisZoomLevel() {
        int halfHeight = (getMeasuredHeight() / 2) - 1;
        mHeightsAtThisZoomLevel = new int[mLenByZoomLevel[mZoomLevel]];
        for (int i = 0; i < mLenByZoomLevel[mZoomLevel]; i++) {
            mHeightsAtThisZoomLevel[i] =
                    (int)(mValuesByZoomLevel[mZoomLevel][i] * halfHeight);
        }
    }

}

CustomAdapter类

public class CustomWavePlayAdapter extends BaseAdapter implements WaveformView.WaveformListener {

ViewHolder holder;
Context mContext;
SoundFile mSoundFile;
boolean mLoadingKeepGoing;
boolean mFinishActivity;
String mTitle, mArtist;
Handler handler = new Handler();
Button pla, pause;
MediaPlayer mediaPlayer;
boolean ismIsPlaying;
int k = 0;
int j = 0;
TextView tv;
boolean runningWave = false;
ArrayList<String> mFilePath;
int totalLinesInWave = 0;
int count =0;
int myPos = 0;
private float mDensity;
private File mFile;
private String mFilename;
private long mLoadingLastUpdateTime;
private ProgressDialog mProgressDialog;
private Thread mLoadSoundFileThread;
private Thread mRecordAudioThread;
private Thread mSaveSoundFileThread;
private boolean mIsPlaying;
private SamplePlayer mPlayer;
private String mInfoContent;
private int mWidth;
private int mMaxPos;
private int mStartPos;
private int mEndPos;
private boolean mStartVisible;
private boolean mEndVisible;
private int mLastDisplayedStartPos;
private int mLastDisplayedEndPos;
private int mOffset;
private int mOffsetGoal;
private int mFlingVelocity;
private int mPlayStartMsec;
private int mPlayEndMsec;
private Handler mHandler;
private Handler myHandler = new Handler();

public CustomWavePlayAdapter(Context mContext, ArrayList<String> mfilePath){

    this.mContext = mContext;
    this.mFilePath = mfilePath;
}

@Override
public int getCount() {
    return mFilePath.size();

}

@Override
public Object getItem(int position) {
    return position;
}

@Override
public long getItemId(int position) {
    return 0;
}

@Override
public void waveformTouchStart(float x) {

}

@Override
public void waveformTouchMove(float x) {

}

@Override
public void waveformTouchEnd() {

}

@Override
public void waveformFling(float x) {

}

@Override
public void waveformDraw() {
    mWidth = holder.waveformView.getMeasuredWidth();
    if (mOffsetGoal != mOffset) {
        // updateDisplay();
    } else if (mIsPlaying) {
        //   updateDisplay();
    } else if (mFlingVelocity != 0) {
        //     updateDisplay();
    }
}

@Override
public View getView(final int position, View convertView, ViewGroup parent) {


    if (convertView == null) {

        holder = new ViewHolder();
        mHandler = new Handler();

        LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(
                Activity.LAYOUT_INFLATER_SERVICE);

        convertView = inflater.inflate(R.layout.sound_files_items, null);
        holder.waveformView = (WaveformView) convertView.findViewById(R.id.waveformList);
        holder.button = (Button) convertView.findViewById(R.id.playList);

        convertView.setTag(holder);
        myPos = position;

        final Uri uri = Uri.parse(mFilePath.get(position));
        mediaPlayer = new MediaPlayer();


        loadGui();
        loadFromFile(position);
        holder.button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                runningWave = true;
                if (!mediaPlayer.isPlaying())
                {
                    Log.e("adapter array",String.valueOf(uri));
                    mediaPlayer = MediaPlayer.create(mContext, uri);
                    //                mediaPlayer.prepare();
                    Toast.makeText(mContext, String.valueOf(position), Toast.LENGTH_SHORT).show();
                    mediaPlayer.start();
                    Log.e("length", String.valueOf(holder.waveformView.totalLines));

                }
                ismIsPlaying = true;

                if (mediaPlayer.isPlaying()) {
                    playWaveAnimation(k);
                }

            }
        });
  }


    return convertView;
}

private void loadGui() {
    DisplayMetrics metrics = new DisplayMetrics();
    WindowManager windowManager = (WindowManager) mContext
            .getSystemService(Context.WINDOW_SERVICE);
    windowManager.getDefaultDisplay().getMetrics(metrics);
    mDensity = metrics.density;
    holder.waveformView.setListener(this);

   if (mSoundFile != null && !holder.waveformView.hasSoundFile()) {
        holder.waveformView.setSoundFile(mSoundFile);
        holder.waveformView.recomputeHeights(mDensity);

    }

}

private void loadFromFile(int position) {
    mFilename = mFilePath.get(position);

    Log.e("check count", String.valueOf(count++) + ":" + String.valueOf(myPos)  + ":" + mFilename);

    mFile = new File(mFilename);

    SongMetadataReader metadataReader = new SongMetadataReader(mContext, mFilename);
    mTitle = metadataReader.mTitle;
    mArtist = metadataReader.mArtist;

    String titleLabel = mTitle;
    if (mArtist != null && mArtist.length() > 0) {
        titleLabel += " - " + mArtist;
    }
  //  setTitle(titleLabel);

    mLoadingLastUpdateTime = getCurrentTime();
    mLoadingKeepGoing = true;
    mFinishActivity = false;
    mProgressDialog = new ProgressDialog( mContext);
    mProgressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
    mProgressDialog.setTitle("Loading...");
    mProgressDialog.setCancelable(false);
    mProgressDialog.setOnCancelListener(
            new DialogInterface.OnCancelListener() {
                public void onCancel(DialogInterface dialog) {
                    mLoadingKeepGoing = false;
                    mFinishActivity = true;
                }
            });
 //   mProgressDialog.show();

    final SoundFile.ProgressListener listener =
            new SoundFile.ProgressListener() {
                public boolean reportProgress(double fractionComplete) {
                    long now = getCurrentTime();
                    if (now - mLoadingLastUpdateTime > 100) {
                        mProgressDialog.setProgress(
                                (int) (mProgressDialog.getMax() * fractionComplete));
                        mLoadingLastUpdateTime = now;
                    }
                    return mLoadingKeepGoing;
                }
            };

    // Load the sound file in a background thread
    mLoadSoundFileThread = new Thread() {
        public void run() {
            try {
                mSoundFile = SoundFile.create(mFile.getAbsolutePath(), listener);

                if (mSoundFile == null) {
                    mProgressDialog.dismiss();
                    String name = mFile.getName().toLowerCase();
                    String[] components = name.split("\\.");
                    String err;
                    if (components.length < 2) {
                        err = mContext.getResources().getString(
                                R.string.no_extension_error);
                    } else {
                        err = mContext.getResources().getString(
                                R.string.bad_extension_error) + " " +
                                components[components.length - 1];
                    }
                    final String finalErr = err;
                    Runnable runnable = new Runnable() {
                        public void run() {
                            showFinalAlert(new Exception(), finalErr);
                        }
                    };
                    mHandler.post(runnable);
                    return;
                }
                mPlayer = new SamplePlayer(mSoundFile);
            } catch (final Exception e) {
                mProgressDialog.dismiss();
                e.printStackTrace();
                mInfoContent = e.toString();
              /*  runOnUiThread(new Runnable() {
                    public void run() {

                    }
                });*/

                Runnable runnable = new Runnable() {
                    public void run() {
                        showFinalAlert(e, mContext.getResources().getText(R.string.read_error));
                    }
                };
                mHandler.post(runnable);
                return;
            }
            mProgressDialog.dismiss();
            if (mLoadingKeepGoing) {
                Runnable runnable = new Runnable() {
                    public void run() {
                        finishOpeningSoundFile();

                    }
                };
                mHandler.post(runnable);
            } else if (mFinishActivity) {

            }
        }
    };
    mLoadSoundFileThread.start();

}

private void finishOpeningSoundFile() {
    holder.waveformView.setSoundFile(mSoundFile);
    holder.waveformView.recomputeHeights(mDensity);

}

private void showFinalAlert(Exception e, CharSequence message) {
    CharSequence title;
    if (e != null) {
        Log.e("Ringdroid", "Error: " + message);
        Log.e("Ringdroid", getStackTrace(e));
        title = mContext.getResources().getText(R.string.alert_title_failure);
     //   setResult(RESULT_CANCELED, new Intent());
    } else {
        Log.v("Ringdroid", "Success: " + message);
        title = mContext.getResources().getText(R.string.alert_title_success);
    }

    new AlertDialog.Builder(mContext)
            .setTitle(title)
            .setMessage(message)
            .setPositiveButton(
                    R.string.alert_ok_button,
                    new DialogInterface.OnClickListener() {
                        public void onClick(DialogInterface dialog,
                                            int whichButton) {
                            ((Activity)mContext).finish();
                        }
                    })
            .setCancelable(false)
            .show();
}

private long getCurrentTime() {
    return System.nanoTime() / 1000000;
}

private String getStackTrace(Exception e) {
    StringWriter writer = new StringWriter();
    e.printStackTrace(new PrintWriter(writer));
    return writer.toString();
}

public void playWaveAnimation(int i) {
    k = i;

    final int intervalTime = 60;


    totalLinesInWave = holder.waveformView.totalLines;

    handler.postDelayed(new Runnable() {
        @Override
        public void run() {

            if (runningWave){

                //Display Data here
                if (k < totalLinesInWave ) {
                    holder.waveformView.setPlayback(k);
                    holder.waveformView.invalidate();
                    playWaveAnimation(++k);
                    Log.e("k value", String.valueOf(k));
                }

                if (k==totalLinesInWave){
                    k = 0;
                    runningWave = false;
                }



            }
        }
    }, intervalTime);
}

public void pauseWaveAnimation(int s) {

    j = s;
    if (j < totalLinesInWave) {

        Log.e("j value in pause",String.valueOf(j));
        holder.waveformView.setPlayback(j);
        holder.waveformView.invalidate();


    }
}

0 个答案:

没有答案