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