Created
September 11, 2018 11:36
-
-
Save junlincao/2f7f2a1e47d9858ecf338390f655f31c to your computer and use it in GitHub Desktop.
pcm voice wave view
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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