1 /*
2  * Copyright (C) 2015 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.wavelib;
18 
19 import android.util.Log;
20 
21 public class DspBufferMath {
22     private static final String TAG = "DspBufferMath";
23     public static final int OPERANDS_TYPE_UNKNOWN  = -1;
24     public static final int OPERANDS_TYPE_REAL     = 0;
25     public static final int OPERANDS_TYPE_COMPLEX  = 1;
26     public static final int OPERANDS_TYPE_MIXED    = 2;
27 
28     public static final int MATH_RESULT_UNDEFINED  = -1;
29     public static final int MATH_RESULT_SUCCESS    = 0;
30     public static final int MATH_RESULT_ERROR      = 1;
31 
estimateOperandsType(T a, T b)32     static private<T extends DspBufferBase> int estimateOperandsType(T a, T b) {
33         if (a instanceof DspBufferComplex) {
34             if (b instanceof DspBufferComplex) {
35                 return OPERANDS_TYPE_COMPLEX;
36             } else if (b instanceof DspBufferDouble) {
37                 return OPERANDS_TYPE_MIXED;
38             }
39         } else if (a instanceof DspBufferDouble) {
40             if (b instanceof DspBufferComplex) {
41                 return OPERANDS_TYPE_MIXED;
42             } else if (b instanceof DspBufferDouble) {
43                 return OPERANDS_TYPE_REAL;
44             }
45         }
46         return OPERANDS_TYPE_UNKNOWN;
47     }
48 
49     /**
50      * adds r = a + b; element by element
51      *
52      * If the result is double vector, the imaginary part of complex operations is ignored.
53      */
add(T r, T a, T b)54     static public <T extends DspBufferBase> int add(T r, T a, T b) {
55         int size = Math.min(a.getSize(), b.getSize());
56         r.setSize(size);
57 
58         T x = a;
59         T y = b;
60         int opType = estimateOperandsType(a, b);
61 
62         if (opType == OPERANDS_TYPE_MIXED) {
63             if (a instanceof  DspBufferDouble)  {
64                 x = b; //Complex first
65                 y = a;
66             }
67         }
68 
69         if (opType == OPERANDS_TYPE_UNKNOWN) {
70             return MATH_RESULT_UNDEFINED;
71         }
72 
73         if (r instanceof DspBufferComplex) {
74             switch (opType) {
75                 case OPERANDS_TYPE_REAL:
76                     for (int i = 0; i < size; i++) {
77                         ((DspBufferComplex) r).mReal[i] =
78                                 ((DspBufferDouble) x).mData[i] + ((DspBufferDouble) y).mData[i];
79                         ((DspBufferComplex) r).mImag[i] = 0;
80                     }
81                     return MATH_RESULT_SUCCESS;
82                 case OPERANDS_TYPE_COMPLEX:
83                     for (int i = 0; i < size; i++) {
84                         ((DspBufferComplex) r).mReal[i] =
85                                 ((DspBufferComplex) x).mReal[i] + ((DspBufferComplex) y).mReal[i];
86                         ((DspBufferComplex) r).mImag[i] =
87                                 ((DspBufferComplex) x).mImag[i] + ((DspBufferComplex) y).mImag[i];
88                     }
89                     return MATH_RESULT_SUCCESS;
90                 case OPERANDS_TYPE_MIXED:
91                     for (int i = 0; i < size; i++) {
92                         ((DspBufferComplex) r).mReal[i] =
93                                 ((DspBufferComplex) x).mReal[i] + ((DspBufferDouble) y).mData[i];
94                         ((DspBufferComplex) r).mImag[i] = ((DspBufferComplex) x).mImag[i];
95                     }
96                     return MATH_RESULT_SUCCESS;
97             }
98         } else if (r instanceof DspBufferDouble) {
99             switch (opType) {
100                 case OPERANDS_TYPE_REAL:
101                     for (int i = 0; i < size; i++) {
102                         ((DspBufferDouble) r).mData[i] =
103                                 ((DspBufferDouble) x).mData[i] + ((DspBufferDouble) y).mData[i];
104                     }
105                     return MATH_RESULT_SUCCESS;
106                 case OPERANDS_TYPE_COMPLEX:
107                     for (int i = 0; i < size; i++) {
108                         ((DspBufferDouble) r).mData[i] =
109                                 ((DspBufferComplex) x).mReal[i] + ((DspBufferComplex) y).mReal[i];
110                     }
111                     return MATH_RESULT_SUCCESS;
112                 case OPERANDS_TYPE_MIXED:
113                     for (int i = 0; i < size; i++) {
114                         ((DspBufferDouble) r).mData[i] =
115                                 ((DspBufferComplex) x).mReal[i] + ((DspBufferDouble) y).mData[i];
116                     }
117                     return MATH_RESULT_SUCCESS;
118             }
119         }
120         return MATH_RESULT_ERROR;
121     }
122 
123     /**
124      * mult r = a * b; element by element
125      */
mult(T r, T a, T b)126     static public <T extends DspBufferBase> int mult(T r, T a, T b) {
127         int size = Math.min(a.getSize(), b.getSize());
128         r.setSize(size);
129 
130         T x = a;
131         T y = b;
132         int opType = estimateOperandsType(a, b);
133 
134         if (opType == OPERANDS_TYPE_MIXED) {
135             if (a instanceof  DspBufferDouble)  {
136                 x = b; //Complex first
137                 y = a;
138             }
139         }
140 
141         if (opType == OPERANDS_TYPE_UNKNOWN) {
142             return MATH_RESULT_UNDEFINED;
143         }
144 
145         if (r instanceof DspBufferComplex) {
146             switch (opType) {
147                 case OPERANDS_TYPE_REAL:
148                     for (int i = 0; i < size; i++) {
149                         ((DspBufferComplex) r).mReal[i] =
150                                 ((DspBufferDouble) x).mData[i] * ((DspBufferDouble) y).mData[i];
151                         ((DspBufferComplex) r).mImag[i] = 0;
152                     }
153                     return MATH_RESULT_SUCCESS;
154                 case OPERANDS_TYPE_COMPLEX:
155                     for (int i = 0; i < size; i++) {
156                         double A = ((DspBufferComplex) x).mReal[i];
157                         double B = ((DspBufferComplex) x).mImag[i];
158                         double C = ((DspBufferComplex) y).mReal[i];
159                         double D = ((DspBufferComplex) y).mImag[i];
160                         ((DspBufferComplex) r).mReal[i] = (C * A) - (B * D);
161                         ((DspBufferComplex) r).mImag[i] = (C * B) + (A * D);
162                     }
163                     return MATH_RESULT_SUCCESS;
164                 case OPERANDS_TYPE_MIXED:
165                     for (int i = 0; i < size; i++) {
166                         double A = ((DspBufferComplex) x).mReal[i];
167                         double B = ((DspBufferComplex) x).mImag[i];
168                         double C = ((DspBufferDouble) y).mData[i];
169                         //double D = 0;
170                         ((DspBufferComplex) r).mReal[i] = C * A;
171                         ((DspBufferComplex) r).mImag[i] = C * B;
172                     }
173                     return MATH_RESULT_SUCCESS;
174             }
175         } else if (r instanceof DspBufferDouble) {
176             switch (opType) {
177                 case OPERANDS_TYPE_REAL:
178                     for (int i = 0; i < size; i++) {
179                         ((DspBufferDouble) r).mData[i] =
180                                 ((DspBufferDouble) x).mData[i] * ((DspBufferDouble) y).mData[i];
181                     }
182                     return MATH_RESULT_SUCCESS;
183                 case OPERANDS_TYPE_COMPLEX:
184                     for (int i = 0; i < size; i++) {
185                         double A = ((DspBufferComplex) x).mReal[i];
186                         double B = ((DspBufferComplex) x).mImag[i];
187                         double C = ((DspBufferComplex) y).mReal[i];
188                         double D = ((DspBufferComplex) y).mImag[i];
189                         ((DspBufferDouble) r).mData[i] = (C * A) - (B * D);
190                     }
191                     return MATH_RESULT_SUCCESS;
192                 case OPERANDS_TYPE_MIXED:
193                     for (int i = 0; i < size; i++) {
194                         double A = ((DspBufferComplex) x).mReal[i];
195                         double B = ((DspBufferComplex) x).mImag[i];
196                         double C = ((DspBufferDouble) y).mData[i];
197                         //double D = 0;
198                         ((DspBufferDouble) r).mData[i] = C * A;
199                     }
200                     return MATH_RESULT_SUCCESS;
201             }
202         }
203         return MATH_RESULT_ERROR;
204     }
205 
206     /**
207      * mult r = a * v; element by element
208      */
mult(T r, T a, double v)209     static public <T extends DspBufferBase> int mult(T r, T a, double v) {
210         int size = a.getSize();
211         r.setSize(size);
212 
213         T x = a;
214         int opType = estimateOperandsType(r, a);
215 
216         if (opType == OPERANDS_TYPE_UNKNOWN) {
217             return MATH_RESULT_UNDEFINED;
218         }
219 
220         if (r instanceof DspBufferComplex) {
221             switch (opType) {
222                 case OPERANDS_TYPE_MIXED:
223                     for (int i = 0; i < size; i++) {
224                         ((DspBufferComplex) r).mReal[i] = ((DspBufferDouble) x).mData[i] * v;
225                         ((DspBufferComplex) r).mImag[i] = 0;
226                     }
227                     return MATH_RESULT_SUCCESS;
228                 case OPERANDS_TYPE_COMPLEX:
229                     for (int i = 0; i < size; i++) {
230                         ((DspBufferComplex) r).mReal[i] = ((DspBufferComplex) x).mReal[i] * v;
231                         ((DspBufferComplex) r).mImag[i] = ((DspBufferComplex) x).mImag[i] * v;
232                     }
233                     return MATH_RESULT_SUCCESS;
234             }
235         } else if (r instanceof DspBufferDouble) {
236             switch (opType) {
237                 case OPERANDS_TYPE_REAL:
238                     for (int i = 0; i < size; i++) {
239                         ((DspBufferDouble) r).mData[i] = ((DspBufferDouble) x).mData[i] * v;
240                     }
241                     return MATH_RESULT_SUCCESS;
242                 case OPERANDS_TYPE_MIXED:
243                     for (int i = 0; i < size; i++) {
244                         ((DspBufferDouble) r).mData[i] = ((DspBufferComplex) x).mReal[i] * v;
245                     }
246                     return MATH_RESULT_SUCCESS;
247             }
248         }
249         return MATH_RESULT_ERROR;
250     }
251 
252     /**
253      * set r = a ; element by element
254      */
set(T r, T a)255     static public <T extends DspBufferBase> int set(T r, T a) {
256         int size = a.getSize();
257         r.setSize(size);
258 
259         T x = a;
260         int opType = estimateOperandsType(r, a);
261 
262         if (opType == OPERANDS_TYPE_UNKNOWN) {
263             return MATH_RESULT_UNDEFINED;
264         }
265 
266         if (r instanceof DspBufferComplex) {
267             switch (opType) {
268                 case OPERANDS_TYPE_MIXED:
269                     for (int i = 0; i < size; i++) {
270                         ((DspBufferComplex) r).mReal[i] = ((DspBufferDouble) x).mData[i];
271                         ((DspBufferComplex) r).mImag[i] = 0;
272                     }
273                     return MATH_RESULT_SUCCESS;
274                 case OPERANDS_TYPE_COMPLEX:
275                     for (int i = 0; i < size; i++) {
276                         ((DspBufferComplex) r).mReal[i] = ((DspBufferComplex) x).mReal[i];
277                         ((DspBufferComplex) r).mImag[i] = ((DspBufferComplex) x).mImag[i];
278                     }
279                     return MATH_RESULT_SUCCESS;
280             }
281         } else if (r instanceof DspBufferDouble) {
282             switch(opType) {
283                 case OPERANDS_TYPE_REAL:
284                     for (int i = 0; i < size; i++) {
285                         ((DspBufferDouble) r).mData[i] = ((DspBufferDouble) x).mData[i];
286                     }
287                     return MATH_RESULT_SUCCESS;
288                 case OPERANDS_TYPE_MIXED:
289                     for (int i = 0; i < size; i++) {
290                         ((DspBufferDouble) r).mData[i] = ((DspBufferComplex) x).mReal[i];
291                     }
292                     return MATH_RESULT_SUCCESS;
293             }
294         }
295         return MATH_RESULT_ERROR;
296     }
297 
298 
299     /**
300      * set r = v ; all elements the same
301      * It keeps the size of the return vector
302      */
set(T r, double ...values)303     static public <T extends DspBufferBase> int set(T r, double ...values) {
304         int size = r.getSize();
305 
306         double a = 0;
307         double b = 0;
308         if (values.length > 0) {
309             a = values[0];
310         }
311         if (values.length > 1) {
312             b = values[1];
313         }
314 
315         if (r instanceof DspBufferComplex) {
316             for (int i = 0; i < size; i++) {
317                 ((DspBufferComplex) r).mReal[i] = a;
318                 ((DspBufferComplex) r).mImag[i] = b;
319             }
320             return MATH_RESULT_SUCCESS;
321         } else if (r instanceof DspBufferDouble) {
322             for (int i = 0; i < size; i++) {
323                 ((DspBufferDouble) r).mData[i] = a;
324             }
325             return MATH_RESULT_SUCCESS;
326         }
327         return MATH_RESULT_ERROR;
328     }
329 
330 
331     /**
332      * compute normalized cross correlation r = a (*) b
333      */
334 
crossCorrelation(T r, T a, T b)335     static public <T extends DspBufferDouble> int crossCorrelation(T r, T a, T b) {
336         int size = Math.min(a.getSize(), b.getSize());
337         r.setSize(size);
338 
339         //statistics
340         double mean1 = 0; //mean
341         double mean2 = 0;
342         double var1 = 0;  //variance
343         double var2 = 0;
344 
345         double sum1 = 0;
346         double sum2 = 0;
347         for (int i = 0; i < size; i++) {
348             sum1 += ((DspBufferDouble) a).mData[i];
349             sum2 += ((DspBufferDouble) b).mData[i];
350         }
351         mean1 = sum1/size;
352         mean2 = sum2/size;
353 
354         double temp1 = 0;
355         double temp2 = 0;
356         for (int i = 0; i < size; i++) {
357             temp1 += (((DspBufferDouble) a).mData[i] - mean1)*(((DspBufferDouble) a).mData[i] -
358                     mean1);
359             temp2 += (((DspBufferDouble) b).mData[i] - mean2)*(((DspBufferDouble) b).mData[i] -
360                     mean2);
361         }
362         var1 = temp1/size;
363         var2 = temp2/size;
364 
365         double varScaling = Math.sqrt(var1 * var2);
366 
367         if (varScaling > 0.0000001) {
368             for (int i = 0; i < size; i++) {
369                 ((DspBufferDouble) r).mData[i] = 0;
370                 double tempCross = 0;
371                 for (int j = 0; j < size - i; j++) {
372                     tempCross += (((DspBufferDouble) a).mData[j] - mean1) *
373                             (((DspBufferDouble) b).mData[i + j] - mean2);
374                 }
375                 ((DspBufferDouble) r).mData[i] = (float) (tempCross / (size * varScaling));
376             }
377         }
378         return MATH_RESULT_SUCCESS;
379     }
380 }
381