Home | History | Annotate | Download | only in tests
      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 
     26 template<typename T, typename U>
     27 struct is_same
     28 {
     29     static const bool value = false;
     30 };
     31 
     32 template<typename T>
     33 struct is_same<T, T>  // partial specialization
     34 {
     35     static const bool value = true;
     36 };
     37 
     38 template<typename T>
     39 static 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.
     51 static 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  */
     93 class TestProvider : public android::AudioBufferProvider {
     94 public:
     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, int64_t pts __unused = kInvalidPTS)
    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 
    174 protected:
    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  */
    186 template<typename T>
    187 static 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  */
    210 template<typename T>
    211 static 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 
    235 class SignalProvider : public TestProvider {
    236 public:
    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 
    302 protected:
    303     uint32_t mSampleRate;
    304     uint32_t mChannels;
    305 };
    306 
    307 #endif // ANDROID_AUDIO_TEST_UTILS_H
    308