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