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