Android 流畅的音频波形

问题描述

我正在开发音乐应用。现在我需要实现如下图所示的内容

enter image description here

在我的搜索中,我遇到了以下似乎可以正常工作的代码。 (当然,我对它的功能有些怀疑)

public class PlayerVisualizerView extends View {

/**
 * constant value for Height of the bar
 */
public static final int VISUALIZER_HEIGHT = 28;

/**
 * bytes array converted from file.
 */
private byte[] bytes;

/**
 * Percentage of audio sample scale
 * Should updated dynamically while audioPlayer is played
 */
private float denseness;

private float last = 0;

/**
 * Canvas painting for sample scale,filling played part of audio sample
 */
private Paint playedStatePainting = new Paint();
/**
 * Canvas painting for sample scale,filling not played part of audio sample
 */
private Paint notPlayedStatePainting = new Paint();

private int width;
private int height;

public PlayerVisualizerView(Context context) {
    super(context);
    init();
}

public PlayerVisualizerView(Context context,@Nullable AttributeSet attrs) {
    super(context,attrs);
    init();
}

private void init() {
    bytes = null;

    playedStatePainting.setstrokeWidth(1f);
    playedStatePainting.setAntiAlias(true);
    playedStatePainting.setColor(ContextCompat.getColor(getContext(),R.color.colorPrimaryRipple));
    notPlayedStatePainting.setstrokeWidth(1f);
    notPlayedStatePainting.setAntiAlias(true);
    notPlayedStatePainting.setColor(ContextCompat.getColor(getContext(),R.color.colorAmber_A400));
}

/**
 * update and redraw Visualizer view
 */
public void updateVisualizer(byte[] bytes) {
    this.bytes = bytes;
    invalidate();
}

/**
 * Update player percent. 0 - file not played,1 - full played
 *
 * @param percent
 */
public void updatePlayerPercent(float percent) {
    denseness = (int) Math.ceil((percent * width) / 100 );
    if (denseness <= 0) {
        denseness = 0;
    } else if (denseness > width) {
        denseness = width;
    }
    if(percent != last)
    {
        Log.e("UpdateUI",percent + "");
        last = percent;
        invalidate();
    }
}

@Override
protected void onLayout(boolean changed,int left,int top,int right,int bottom) {
    super.onLayout(changed,left,top,right,bottom);
    width = getMeasuredWidth();
    height = getMeasuredHeight();
}

@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    if (bytes == null || width == 0) {
        return;
    }
    float totalBarsCount = width / dp(3);
    if (totalBarsCount <= 0.1f) {
        return;
    }
    byte value;
    int samplesCount = (bytes.length * 8 / 5);
    float samplesPerBar = samplesCount / totalBarsCount;
    float barCounter = 0;
    int nextBarNum = 0;

    int y = (height - dp(VISUALIZER_HEIGHT)) / 2;
    int barNum = 0;
    int lastBarNum;
    int drawBarCount;

    for (int a = 0; a < samplesCount; a++) {
        if (a != nextBarNum) {
            continue;
        }
        drawBarCount = 0;
        lastBarNum = nextBarNum;
        while (lastBarNum == nextBarNum) {
            barCounter += samplesPerBar;
            nextBarNum = (int) barCounter;
            drawBarCount++;
        }

        int bitPointer = a * 5;
        int byteNum = bitPointer / Byte.SIZE;
        int byteBitOffset = bitPointer - byteNum * Byte.SIZE;
        int currentByteCount = Byte.SIZE - byteBitOffset;
        int nextByteRest = 5 - currentByteCount;
        value = (byte) ((bytes[byteNum] >> byteBitOffset) & ((2 << (Math.min(5,currentByteCount) - 1)) - 1));
        if (nextByteRest > 0) {
            value <<= nextByteRest;
            value |= bytes[byteNum + 1] & ((2 << (nextByteRest - 1)) - 1);
        }

        for (int b = 0; b < drawBarCount; b++) {
            int x = barNum * dp(3);
            float left = x;
            float top = y + dp(VISUALIZER_HEIGHT - Math.max(1,VISUALIZER_HEIGHT * value / 31.0f));
            float right = x + dp(2);
            float bottom = y + dp(VISUALIZER_HEIGHT);
            if (x < denseness && x + dp(2) < denseness) {
                canvas.drawRect(left,bottom,notPlayedStatePainting);
            } else {
                canvas.drawRect(left,playedStatePainting);
                if (x < denseness) {
                    canvas.drawRect(left,notPlayedStatePainting);
                }
            }
            barNum++;
        }
    }
}

public int dp(float value) {
    if (value == 0) {
        return 0;
    }
    return (int) Math.ceil(getContext().getResources().getdisplayMetrics().density * value);
}

问题是什么?

使用大型音频文件(超过 2 MB)时,它运行缓慢。这个问题在 RecyclerView 内部使用时尤为明显。

你觉得上面的代码有什么问题需要优化吗?

如果您引入了库或其他代码片段。

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)