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