• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.cts.verifier.audio.audiolib;
18 
19 import android.content.Context;
20 import android.graphics.Canvas;
21 import android.graphics.Color;
22 import android.graphics.Paint;
23 import android.util.AttributeSet;
24 import android.view.View;
25 
26 public class WaveScopeView extends View {
27     @SuppressWarnings("unused")
28     private static final String TAG = "WaveScopeView";
29 
30     private final Paint mPaint = new Paint();
31 
32     private int mBackgroundColor = Color.WHITE;
33     private int mTraceColor = Color.BLACK;
34 
35     private short[] mPCM16Buffer;
36     private float[] mPCMFloatBuffer;
37 
38     private int mNumChannels = 2;
39     private int mNumFrames = 0;
40 
41     private float[] mPointsBuffer;
42 
43     // Horrible kludge
44     private static int mCachedWidth = 0;
45 
WaveScopeView(Context context, AttributeSet attrs)46     public WaveScopeView(Context context, AttributeSet attrs) {
47         super(context, attrs);
48     }
49 
50     @Override
setBackgroundColor(int color)51     public void setBackgroundColor(int color) { mBackgroundColor = color; }
52 
setTraceColor(int color)53     public void setTraceColor(int color) { mTraceColor = color; }
54 
setPCM16Buff(short[] smpl16Buff, int numChans, int numFrames)55     public void setPCM16Buff(short[] smpl16Buff, int numChans, int numFrames) {
56         mPCM16Buffer = smpl16Buff;
57         mPCMFloatBuffer = null;
58 
59         mNumChannels = numChans;
60         mNumFrames = numFrames;
61 
62         setupPointBuffer();
63 
64         invalidate();
65     }
66 
setPCMFloatBuff(float[] smplFloatBuff, int numChans, int numFrames)67     public void setPCMFloatBuff(float[] smplFloatBuff, int numChans, int numFrames) {
68         mPCMFloatBuffer = smplFloatBuff;
69         mPCM16Buffer = null;
70 
71         mNumChannels = numChans;
72         mNumFrames = numFrames;
73 
74         setupPointBuffer();
75 
76         invalidate();
77     }
78 
setupPointBuffer()79     private void setupPointBuffer() {
80         int width = getWidth();
81 
82         // Horrible kludge
83         if (width == 0) {
84             width = mCachedWidth;
85         } else {
86             mCachedWidth = width;
87         }
88 
89         // Canvas.drawLines() uses 2 points (float pairs) per line-segment
90         mPointsBuffer = new float[mNumFrames * 4];
91 
92         float xIncr = (float) width / (float) mNumFrames;
93 
94         float X = 0;
95         int len = mPointsBuffer.length;
96         for (int pntIndex = 0; pntIndex < len;) {
97             mPointsBuffer[pntIndex] = X;
98             pntIndex += 2; // skip Y
99 
100             X += xIncr;
101 
102             mPointsBuffer[pntIndex] = X;
103             pntIndex += 2; // skip Y
104         }
105     }
106 
107     /**
108      * Draws 1 channel of an interleaved block of SMPL16 samples.
109      * @param cvs The Canvas to draw into.
110      * @param samples The (potentially) multi-channel sample block.
111      * @param numFrames The number of FRAMES in the specified sample block.
112      * @param numChans The number of interleaved channels in the specified sample block.
113      * @param chanIndex The (0-based) index of the channel to draw.
114      * @param zeroY The Y-coordinate of sample value 0 (zero).
115      */
drawChannel16(Canvas cvs, short[] samples, int numFrames, int numChans, int chanIndex, float zeroY)116     private void drawChannel16(Canvas cvs, short[] samples, int numFrames, int numChans,
117             int chanIndex, float zeroY) {
118         float yScale = getHeight() / (float) (Short.MAX_VALUE * 2 * numChans);
119         int pntIndex = 1; // of the first Y coordinate
120         float Y = zeroY;
121         int smpl = chanIndex;
122         for (int frame = 0; frame < numFrames; frame++) {
123             mPointsBuffer[pntIndex] = Y;
124             pntIndex += 2;
125 
126             Y = zeroY - (samples[smpl] * yScale);
127 
128             mPointsBuffer[pntIndex] = Y;
129             pntIndex += 2;
130 
131             smpl += numChans;
132         }
133         cvs.drawLines(mPointsBuffer, mPaint);
134     }
135 
136     /**
137      * Draws 1 channel of an interleaved block of FLOAT samples.
138      * @param cvs The Canvas to draw into.
139      * @param samples The (potentially) multi-channel sample block.
140      * @param numFrames The number of FRAMES in the specified sample block.
141      * @param numChans The number of interleaved channels in the specified sample block.
142      * @param chanIndex The (0-based) index of the channel to draw.
143      * @param zeroY The Y-coordinate of sample value 0 (zero).
144      */
drawChannelFloat(Canvas cvs, float[] samples, int numFrames, int numChans, int chanIndex, float zeroY)145     private void drawChannelFloat(Canvas cvs, float[] samples, int numFrames, int numChans,
146             int chanIndex, float zeroY) {
147         float yScale = getHeight() / (float) (2 * numChans);
148         int pntIndex = 1; // of the first Y coordinate
149         float Y = zeroY;
150         int smpl = chanIndex;
151         for (int frame = 0; frame < numFrames; frame++) {
152             mPointsBuffer[pntIndex] = Y;
153             pntIndex += 2;
154 
155             Y = zeroY - (samples[smpl] * yScale);
156 
157             mPointsBuffer[pntIndex] = Y;
158             pntIndex += 2;
159 
160             smpl += numChans;
161         }
162         cvs.drawLines(mPointsBuffer, mPaint);
163     }
164 
165     @Override
onDraw(Canvas canvas)166     protected void onDraw(Canvas canvas) {
167         int height = getHeight();
168         mPaint.setColor(mBackgroundColor);
169         canvas.drawRect(0, 0, getWidth(), height, mPaint);
170 
171         mPaint.setColor(mTraceColor);
172         if (mPCM16Buffer != null) {
173             float yOffset = height / (2.0f * mNumChannels);
174             float yDelta = height / (float) mNumChannels;
175             for(int channel = 0; channel < mNumChannels; channel++) {
176                 drawChannel16(canvas, mPCM16Buffer, mNumFrames, mNumChannels, channel, yOffset);
177                 yOffset += yDelta;
178             }
179         } else if (mPCMFloatBuffer != null) {
180             float yOffset = height / (2.0f * mNumChannels);
181             float yDelta = height / (float) mNumChannels;
182             for(int channel = 0; channel < mNumChannels; channel++) {
183                 drawChannelFloat(canvas, mPCMFloatBuffer, mNumFrames, mNumChannels, channel, yOffset);
184                 yOffset += yDelta;
185             }
186         }
187         // Log.i("WaveView", "onDraw() - done");
188     }
189 }
190