1 /* 2 * Copyright (C) 2014 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 #ifndef ANDROID_AUDIO_TEST_UTILS_H 18 #define ANDROID_AUDIO_TEST_UTILS_H 19 20 #ifndef LOG_TAG 21 #define LOG_TAG "test_utils" 22 #endif 23 24 #include <log/log.h> 25 26 #include <android-base/macros.h> 27 #include <audio_utils/sndfile.h> 28 29 #ifndef ARRAY_SIZE 30 #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) 31 #endif 32 33 template<typename T, typename U> 34 struct is_same 35 { 36 static const bool value = false; 37 }; 38 39 template<typename T> 40 struct is_same<T, T> // partial specialization 41 { 42 static const bool value = true; 43 }; 44 45 template<typename T> 46 static inline T convertValue(double val) 47 { 48 if (is_same<T, int16_t>::value) { 49 return floor(val * 32767.0 + 0.5); 50 } else if (is_same<T, int32_t>::value) { 51 return floor(val * (1UL<<31) + 0.5); 52 } 53 return val; // assume float or double 54 } 55 56 // Convert a list of integers in CSV format to a Vector of those values. 57 // Returns the number of elements in the list, or -1 on error. 58 static inline int parseCSV(const char *string, std::vector<int>& values) 59 { 60 // pass 1: count the number of values and do syntax check 61 size_t numValues = 0; 62 bool hadDigit = false; 63 for (const char *p = string; ; ) { 64 switch (*p++) { 65 case '0': case '1': case '2': case '3': case '4': 66 case '5': case '6': case '7': case '8': case '9': 67 hadDigit = true; 68 break; 69 case '\0': 70 if (hadDigit) { 71 // pass 2: allocate and initialize vector of values 72 values.resize(++numValues); 73 values[0] = atoi(p = string); 74 for (size_t i = 1; i < numValues; ) { 75 if (*p++ == ',') { 76 values[i++] = atoi(p); 77 } 78 } 79 return numValues; 80 } 81 FALLTHROUGH_INTENDED; 82 case ',': 83 if (hadDigit) { 84 hadDigit = false; 85 numValues++; 86 break; 87 } 88 FALLTHROUGH_INTENDED; 89 default: 90 return -1; 91 } 92 } 93 } 94 95 /* Creates a type-independent audio buffer provider from 96 * a buffer base address, size, framesize, and input increment array. 97 * 98 * No allocation or deallocation of the provided buffer is done. 99 */ 100 class TestProvider : public android::AudioBufferProvider { 101 public: 102 TestProvider(void* addr, size_t frames, size_t frameSize, 103 const std::vector<int>& inputIncr) 104 : mAddr(addr), 105 mNumFrames(frames), 106 mFrameSize(frameSize), 107 mNextFrame(0), mUnrel(0), mInputIncr(inputIncr), mNextIdx(0) 108 { 109 } 110 111 TestProvider() 112 : mAddr(NULL), mNumFrames(0), mFrameSize(0), 113 mNextFrame(0), mUnrel(0), mNextIdx(0) 114 { 115 } 116 117 void setIncr(const std::vector<int>& inputIncr) { 118 mInputIncr = inputIncr; 119 mNextIdx = 0; 120 } 121 122 virtual android::status_t getNextBuffer(Buffer* buffer) 123 { 124 size_t requestedFrames = buffer->frameCount; 125 if (requestedFrames > mNumFrames - mNextFrame) { 126 buffer->frameCount = mNumFrames - mNextFrame; 127 } 128 if (!mInputIncr.empty()) { 129 size_t provided = mInputIncr[mNextIdx++]; 130 ALOGV("getNextBuffer() mValue[%zu]=%zu not %zu", 131 mNextIdx-1, provided, buffer->frameCount); 132 if (provided < buffer->frameCount) { 133 buffer->frameCount = provided; 134 } 135 if (mNextIdx >= mInputIncr.size()) { 136 mNextIdx = 0; 137 } 138 } 139 ALOGV("getNextBuffer() requested %zu frames out of %zu frames available" 140 " and returned %zu frames", 141 requestedFrames, mNumFrames - mNextFrame, buffer->frameCount); 142 mUnrel = buffer->frameCount; 143 if (buffer->frameCount > 0) { 144 buffer->raw = (char *)mAddr + mFrameSize * mNextFrame; 145 return android::NO_ERROR; 146 } else { 147 buffer->raw = NULL; 148 return android::NOT_ENOUGH_DATA; 149 } 150 } 151 152 virtual void releaseBuffer(Buffer* buffer) 153 { 154 if (buffer->frameCount > mUnrel) { 155 ALOGE("releaseBuffer() released %zu frames but only %zu available " 156 "to release", buffer->frameCount, mUnrel); 157 mNextFrame += mUnrel; 158 mUnrel = 0; 159 } else { 160 161 ALOGV("releaseBuffer() released %zu frames out of %zu frames available " 162 "to release", buffer->frameCount, mUnrel); 163 mNextFrame += buffer->frameCount; 164 mUnrel -= buffer->frameCount; 165 } 166 buffer->frameCount = 0; 167 buffer->raw = NULL; 168 } 169 170 void reset() 171 { 172 mNextFrame = 0; 173 } 174 175 size_t getNumFrames() 176 { 177 return mNumFrames; 178 } 179 180 181 protected: 182 void* mAddr; // base address 183 size_t mNumFrames; // total frames 184 int mFrameSize; // frame size (# channels * bytes per sample) 185 size_t mNextFrame; // index of next frame to provide 186 size_t mUnrel; // number of frames not yet released 187 std::vector<int> mInputIncr; // number of frames provided per call 188 size_t mNextIdx; // index of next entry in mInputIncr to use 189 }; 190 191 /* Creates a buffer filled with a sine wave. 192 */ 193 template<typename T> 194 static void createSine(void *vbuffer, size_t frames, 195 size_t channels, double sampleRate, double freq) 196 { 197 double tscale = 1. / sampleRate; 198 T* buffer = reinterpret_cast<T*>(vbuffer); 199 for (size_t i = 0; i < frames; ++i) { 200 double t = i * tscale; 201 double y = sin(2. * M_PI * freq * t); 202 T yt = convertValue<T>(y); 203 204 for (size_t j = 0; j < channels; ++j) { 205 buffer[i*channels + j] = yt / T(j + 1); 206 } 207 } 208 } 209 210 /* Creates a buffer filled with a chirp signal (a sine wave sweep). 211 * 212 * When creating the Chirp, note that the frequency is the true sinusoidal 213 * frequency not the sampling rate. 214 * 215 * http://en.wikipedia.org/wiki/Chirp 216 */ 217 template<typename T> 218 static void createChirp(void *vbuffer, size_t frames, 219 size_t channels, double sampleRate, double minfreq, double maxfreq) 220 { 221 double tscale = 1. / sampleRate; 222 T *buffer = reinterpret_cast<T*>(vbuffer); 223 // note the chirp constant k has a divide-by-two. 224 double k = (maxfreq - minfreq) / (2. * tscale * frames); 225 for (size_t i = 0; i < frames; ++i) { 226 double t = i * tscale; 227 double y = sin(2. * M_PI * (k * t + minfreq) * t); 228 T yt = convertValue<T>(y); 229 230 for (size_t j = 0; j < channels; ++j) { 231 buffer[i*channels + j] = yt / T(j + 1); 232 } 233 } 234 } 235 236 /* This derived class creates a buffer provider of datatype T, 237 * consisting of an input signal, e.g. from createChirp(). 238 * The number of frames can be obtained from the base class 239 * TestProvider::getNumFrames(). 240 */ 241 242 class SignalProvider : public TestProvider { 243 public: 244 SignalProvider() 245 : mSampleRate(0), 246 mChannels(0) 247 { 248 } 249 250 virtual ~SignalProvider() 251 { 252 free(mAddr); 253 mAddr = NULL; 254 } 255 256 template <typename T> 257 void setChirp(size_t channels, double minfreq, double maxfreq, double sampleRate, double time) 258 { 259 createBufferByFrames<T>(channels, sampleRate, sampleRate*time); 260 createChirp<T>(mAddr, mNumFrames, mChannels, mSampleRate, minfreq, maxfreq); 261 } 262 263 template <typename T> 264 void setSine(size_t channels, 265 double freq, double sampleRate, double time) 266 { 267 createBufferByFrames<T>(channels, sampleRate, sampleRate*time); 268 createSine<T>(mAddr, mNumFrames, mChannels, mSampleRate, freq); 269 } 270 271 template <typename T> 272 void setFile(const char *file_in) 273 { 274 SF_INFO info; 275 info.format = 0; 276 SNDFILE *sf = sf_open(file_in, SFM_READ, &info); 277 if (sf == NULL) { 278 perror(file_in); 279 return; 280 } 281 createBufferByFrames<T>(info.channels, info.samplerate, info.frames); 282 if (is_same<T, float>::value) { 283 (void) sf_readf_float(sf, (float *) mAddr, mNumFrames); 284 } else if (is_same<T, short>::value) { 285 (void) sf_readf_short(sf, (short *) mAddr, mNumFrames); 286 } 287 sf_close(sf); 288 } 289 290 template <typename T> 291 void createBufferByFrames(size_t channels, uint32_t sampleRate, size_t frames) 292 { 293 mNumFrames = frames; 294 mChannels = channels; 295 mFrameSize = mChannels * sizeof(T); 296 free(mAddr); 297 mAddr = malloc(mFrameSize * mNumFrames); 298 mSampleRate = sampleRate; 299 } 300 301 uint32_t getSampleRate() const { 302 return mSampleRate; 303 } 304 305 uint32_t getNumChannels() const { 306 return mChannels; 307 } 308 309 protected: 310 uint32_t mSampleRate; 311 uint32_t mChannels; 312 }; 313 314 #endif // ANDROID_AUDIO_TEST_UTILS_H 315