Skip to content

Instantly share code, notes, and snippets.

@junlincao
Created September 11, 2018 11:36
Show Gist options
  • Save junlincao/2f7f2a1e47d9858ecf338390f655f31c to your computer and use it in GitHub Desktop.
Save junlincao/2f7f2a1e47d9858ecf338390f655f31c to your computer and use it in GitHub Desktop.
pcm voice wave view
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
/**
*
* @author CJL
* @since 2018/9/11
**/
public class PcmWaveView extends View {
private WaveData mData;
private int pcmBit = 16;
private int waveByteLen;
private float amplitudeMultiple = 2f;
private Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
public PcmWaveView(Context context) {
this(context, null, 0);
}
public PcmWaveView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public PcmWaveView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
setSample(16000);
mPaint.setColor(Color.RED);
}
public void setSample(int sample) {
mData = new WaveData(sample);
postInvalidate();
}
public void setPcmBit(int bit) {
if (bit != 8 && bit != 16) {
throw new IllegalArgumentException("only support 8bit or 16bit");
}
this.pcmBit = bit;
postInvalidate();
}
public void setAmplitudeMultiple(float multiple) {
this.amplitudeMultiple = multiple;
postInvalidate();
}
public void updateWaveData(byte[] bytes, int offset, int len) {
waveByteLen = bytes.length;
mData.addData(bytes, offset, len);
postInvalidate();
}
public void setWaveColor(int color) {
mPaint.setColor(color);
postInvalidate();
}
@Override
protected void onDraw(Canvas canvas) {
if (getWidth() <= 0) {
return;
}
int height = getHeight();
byte[] data = mData.getFrameData();
int maxP = 1 << pcmBit;
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(1);
int lastX = 0;
int lastY = 0;
if (pcmBit == 16) {
int showByteCount = Math.max(waveByteLen, getWidth()) * 2;
float xStep = getWidth() * 2f / showByteCount;
for (int i = 0; i < showByteCount; i += 2) {
int idx = data.length - showByteCount + i;
short wv = (short) (getShort(data, idx) * amplitudeMultiple);
int y = height / 2 - height * wv / maxP;
int x = (int) (i * xStep);
canvas.drawLine(lastX, lastY, x, y, mPaint);
lastX = x;
lastY = y;
}
} else {
int showByteCount = Math.max(waveByteLen, getWidth());
float xStep = getWidth() / showByteCount;
for (int i = 0; i < showByteCount; i++) {
int idx = data.length - showByteCount + i;
int wv = (int) (data[idx] * amplitudeMultiple);
int y = height / 2 - height * wv / maxP;
int x = (int) (i * xStep);
canvas.drawLine(lastX, lastY, x, y, mPaint);
lastX = x;
lastY = y;
}
}
}
private short getShort(byte[] bytes, int pos) {
return (short) ((bytes[pos + 1] << 8) | (bytes[pos] & 0xff));
}
private short getShort(byte b0, byte b1) {
return (short) ((b1 << 8) | (b0 & 0xff));
}
/**
* wave data, new data saved at tail of cache
*/
static class WaveData {
private final byte[] data1;
private final byte[] data2;
private boolean useData1 = true;
private int dataOffset;
WaveData(int sample) {
data1 = new byte[sample];
data2 = new byte[sample];
dataOffset = sample;
}
void addData(byte[] bytes, int offset, int len) {
final int dataLen = data1.length;
if (len > dataLen) {
Log.e("---", "add data len > sample size!!!!");
len = dataLen;
}
if (dataOffset >= len) {
if (useData1) {
System.arraycopy(data1, dataOffset, data2, dataOffset - len, dataLen - dataOffset);
System.arraycopy(bytes, offset, data2, dataLen - dataOffset, len);
} else {
System.arraycopy(data2, dataOffset, data1, dataOffset - len, dataLen - dataOffset);
System.arraycopy(bytes, offset, data1, dataLen - dataOffset, len);
}
dataOffset -= len;
} else {
if (dataOffset > 0) {
if (useData1) {
System.arraycopy(data1, dataOffset, data2, 0, dataLen - dataOffset);
} else {
System.arraycopy(data2, dataOffset, data1, 0, dataLen - dataOffset);
}
}
int copyLen = dataLen - len;
if (useData1) {
System.arraycopy(data1, len, data2, 0, copyLen);
System.arraycopy(bytes, offset, data2, copyLen, len);
} else {
System.arraycopy(data2, len, data1, 0, copyLen);
System.arraycopy(bytes, offset, data1, copyLen, len);
}
}
useData1 = !useData1;
}
byte[] getFrameData() {
return useData1 ? data1 : data2;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment