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