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