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 #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 
     32 template<typename T, typename U>
     33 struct is_same
     34 {
     35     static const bool value = false;
     36 };
     37 
     38 template<typename T>
     39 struct is_same<T, T>  // partial specialization
     40 {
     41     static const bool value = true;
     42 };
     43 
     44 template<typename T>
     45 static 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.
     57 static 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  */
     99 class TestProvider : public android::AudioBufferProvider {
    100 public:
    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 
    180 protected:
    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  */
    192 template<typename T>
    193 static 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  */
    216 template<typename T>
    217 static 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 
    241 class SignalProvider : public TestProvider {
    242 public:
    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 
    308 protected:
    309     uint32_t mSampleRate;
    310     uint32_t mChannels;
    311 };
    312 
    313 #endif // ANDROID_AUDIO_TEST_UTILS_H
    314