Loading services/audioflinger/tests/Android.mk +4 −0 Original line number Original line Diff line number Diff line # Build the unit tests for audioflinger # Build the unit tests for audioflinger # # resampler unit test # LOCAL_PATH:= $(call my-dir) LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) include $(CLEAR_VARS) Loading @@ -20,6 +23,7 @@ LOCAL_C_INCLUDES := \ bionic/libstdc++/include \ bionic/libstdc++/include \ external/gtest/include \ external/gtest/include \ external/stlport/stlport \ external/stlport/stlport \ $(call include-path-for, audio-utils) \ frameworks/av/services/audioflinger frameworks/av/services/audioflinger LOCAL_SRC_FILES := \ LOCAL_SRC_FILES := \ Loading services/audioflinger/tests/resampler_tests.cpp +11 −202 Original line number Original line Diff line number Diff line Loading @@ -33,200 +33,7 @@ #include <gtest/gtest.h> #include <gtest/gtest.h> #include <media/AudioBufferProvider.h> #include <media/AudioBufferProvider.h> #include "AudioResampler.h" #include "AudioResampler.h" #include "test_utils.h" #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) template<typename T, typename U> struct is_same { static const bool value = false; }; template<typename T> struct is_same<T, T> // partial specialization { static const bool value = true; }; template<typename T> static inline T convertValue(double val) { if (is_same<T, int16_t>::value) { return floor(val * 32767.0 + 0.5); } else if (is_same<T, int32_t>::value) { return floor(val * (1UL<<31) + 0.5); } return val; // assume float or double } /* Creates a type-independent audio buffer provider from * a buffer base address, size, framesize, and input increment array. * * No allocation or deallocation of the provided buffer is done. */ class TestProvider : public android::AudioBufferProvider { public: TestProvider(const void* addr, size_t frames, size_t frameSize, const std::vector<size_t>& inputIncr) : mAddr(addr), mNumFrames(frames), mFrameSize(frameSize), mNextFrame(0), mUnrel(0), mInputIncr(inputIncr), mNextIdx(0) { } virtual android::status_t getNextBuffer(Buffer* buffer, int64_t pts __unused = kInvalidPTS ) { size_t requestedFrames = buffer->frameCount; if (requestedFrames > mNumFrames - mNextFrame) { buffer->frameCount = mNumFrames - mNextFrame; } if (!mInputIncr.empty()) { size_t provided = mInputIncr[mNextIdx++]; ALOGV("getNextBuffer() mValue[%d]=%u not %u", mNextIdx-1, provided, buffer->frameCount); if (provided < buffer->frameCount) { buffer->frameCount = provided; } if (mNextIdx >= mInputIncr.size()) { mNextIdx = 0; } } ALOGV("getNextBuffer() requested %u frames out of %u frames available" " and returned %u frames\n", requestedFrames, mNumFrames - mNextFrame, buffer->frameCount); mUnrel = buffer->frameCount; if (buffer->frameCount > 0) { buffer->raw = (char *)mAddr + mFrameSize * mNextFrame; return android::NO_ERROR; } else { buffer->raw = NULL; return android::NOT_ENOUGH_DATA; } } virtual void releaseBuffer(Buffer* buffer) { if (buffer->frameCount > mUnrel) { ALOGE("releaseBuffer() released %u frames but only %u available " "to release\n", buffer->frameCount, mUnrel); mNextFrame += mUnrel; mUnrel = 0; } else { ALOGV("releaseBuffer() released %u frames out of %u frames available " "to release\n", buffer->frameCount, mUnrel); mNextFrame += buffer->frameCount; mUnrel -= buffer->frameCount; } buffer->frameCount = 0; buffer->raw = NULL; } void reset() { mNextFrame = 0; } size_t getNumFrames() { return mNumFrames; } void setIncr(const std::vector<size_t> inputIncr) { mNextIdx = 0; mInputIncr = inputIncr; } protected: const void* mAddr; // base address size_t mNumFrames; // total frames int mFrameSize; // frame size (# channels * bytes per sample) size_t mNextFrame; // index of next frame to provide size_t mUnrel; // number of frames not yet released std::vector<size_t> mInputIncr; // number of frames provided per call size_t mNextIdx; // index of next entry in mInputIncr to use }; /* Creates a buffer filled with a sine wave. * * Returns a pair consisting of the sine signal buffer and the number of frames. * The caller must delete[] the buffer when no longer needed (no shared_ptr<>). */ template<typename T> static std::pair<T*, size_t> createSine(size_t channels, double freq, double samplingRate, double time) { double tscale = 1. / samplingRate; size_t frames = static_cast<size_t>(samplingRate * time); T* buffer = new T[frames * channels]; for (size_t i = 0; i < frames; ++i) { double t = i * tscale; double y = sin(2. * M_PI * freq * t); T yt = convertValue<T>(y); for (size_t j = 0; j < channels; ++j) { buffer[i*channels + j] = yt / (j + 1); } } return std::make_pair(buffer, frames); } /* Creates a buffer filled with a chirp signal (a sine wave sweep). * * Returns a pair consisting of the chirp signal buffer and the number of frames. * The caller must delete[] the buffer when no longer needed (no shared_ptr<>). * * When creating the Chirp, note that the frequency is the true sinusoidal * frequency not the sampling rate. * * http://en.wikipedia.org/wiki/Chirp */ template<typename T> static std::pair<T*, size_t> createChirp(size_t channels, double minfreq, double maxfreq, double samplingRate, double time) { double tscale = 1. / samplingRate; size_t frames = static_cast<size_t>(samplingRate * time); T *buffer = new T[frames * channels]; // note the chirp constant k has a divide-by-two. double k = (maxfreq - minfreq) / (2. * time); for (size_t i = 0; i < frames; ++i) { double t = i * tscale; double y = sin(2. * M_PI * (k * t + minfreq) * t); T yt = convertValue<T>(y); for (size_t j = 0; j < channels; ++j) { buffer[i*channels + j] = yt / (j + 1); } } return std::make_pair(buffer, frames); } /* This derived class creates a buffer provider of datatype T, * consisting of an input signal, e.g. from createChirp(). * The number of frames can be obtained from the base class * TestProvider::getNumFrames(). */ template <typename T> class SignalProvider : public TestProvider { public: SignalProvider(const std::pair<T*, size_t>& bufferInfo, size_t channels, const std::vector<size_t>& values) : TestProvider(bufferInfo.first, bufferInfo.second, channels * sizeof(T), values), mManagedPtr(bufferInfo.first) { } virtual ~SignalProvider() { delete[] mManagedPtr; } protected: T* mManagedPtr; }; void resample(void *output, size_t outputFrames, const std::vector<size_t> &outputIncr, void resample(void *output, size_t outputFrames, const std::vector<size_t> &outputIncr, android::AudioBufferProvider *provider, android::AudioResampler *resampler) android::AudioBufferProvider *provider, android::AudioResampler *resampler) Loading Loading @@ -261,10 +68,11 @@ void testBufferIncrement(size_t channels, unsigned inputFreq, unsigned outputFre enum android::AudioResampler::src_quality quality) enum android::AudioResampler::src_quality quality) { { // create the provider // create the provider std::vector<size_t> inputIncr; std::vector<int> inputIncr; SignalProvider<int16_t> provider(createChirp<int16_t>(channels, SignalProvider provider; 0., outputFreq/2., outputFreq, outputFreq/2000.), provider.setChirp<int16_t>(channels, channels, inputIncr); 0., outputFreq/2., outputFreq, outputFreq/2000.); provider.setIncr(inputIncr); // calculate the output size // calculate the output size size_t outputFrames = ((int64_t) provider.getNumFrames() * outputFreq) / inputFreq; size_t outputFrames = ((int64_t) provider.getNumFrames() * outputFreq) / inputFreq; Loading Loading @@ -339,10 +147,11 @@ void testStopbandDownconversion(size_t channels, enum android::AudioResampler::src_quality quality) enum android::AudioResampler::src_quality quality) { { // create the provider // create the provider std::vector<size_t> inputIncr; std::vector<int> inputIncr; SignalProvider<int16_t> provider(createChirp<int16_t>(channels, SignalProvider provider; 0., inputFreq/2., inputFreq, inputFreq/2000.), provider.setChirp<int16_t>(channels, channels, inputIncr); 0., inputFreq/2., inputFreq, inputFreq/2000.); provider.setIncr(inputIncr); // calculate the output size // calculate the output size size_t outputFrames = ((int64_t) provider.getNumFrames() * outputFreq) / inputFreq; size_t outputFrames = ((int64_t) provider.getNumFrames() * outputFreq) / inputFreq; Loading services/audioflinger/tests/test_utils.h 0 → 100644 +307 −0 Original line number Original line Diff line number Diff line /* * Copyright (C) 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef ANDROID_AUDIO_TEST_UTILS_H #define ANDROID_AUDIO_TEST_UTILS_H #include <audio_utils/sndfile.h> #ifndef ARRAY_SIZE #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) #endif template<typename T, typename U> struct is_same { static const bool value = false; }; template<typename T> struct is_same<T, T> // partial specialization { static const bool value = true; }; template<typename T> static inline T convertValue(double val) { if (is_same<T, int16_t>::value) { return floor(val * 32767.0 + 0.5); } else if (is_same<T, int32_t>::value) { return floor(val * (1UL<<31) + 0.5); } return val; // assume float or double } // Convert a list of integers in CSV format to a Vector of those values. // Returns the number of elements in the list, or -1 on error. static inline int parseCSV(const char *string, std::vector<int>& values) { // pass 1: count the number of values and do syntax check size_t numValues = 0; bool hadDigit = false; for (const char *p = string; ; ) { switch (*p++) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': hadDigit = true; break; case '\0': if (hadDigit) { // pass 2: allocate and initialize vector of values values.resize(++numValues); values[0] = atoi(p = string); for (size_t i = 1; i < numValues; ) { if (*p++ == ',') { values[i++] = atoi(p); } } return numValues; } // fall through case ',': if (hadDigit) { hadDigit = false; numValues++; break; } // fall through default: return -1; } } } /* Creates a type-independent audio buffer provider from * a buffer base address, size, framesize, and input increment array. * * No allocation or deallocation of the provided buffer is done. */ class TestProvider : public android::AudioBufferProvider { public: TestProvider(void* addr, size_t frames, size_t frameSize, const std::vector<int>& inputIncr) : mAddr(addr), mNumFrames(frames), mFrameSize(frameSize), mNextFrame(0), mUnrel(0), mInputIncr(inputIncr), mNextIdx(0) { } TestProvider() : mAddr(NULL), mNumFrames(0), mFrameSize(0), mNextFrame(0), mUnrel(0), mNextIdx(0) { } void setIncr(const std::vector<int>& inputIncr) { mInputIncr = inputIncr; mNextIdx = 0; } virtual android::status_t getNextBuffer(Buffer* buffer, int64_t pts __unused = kInvalidPTS) { size_t requestedFrames = buffer->frameCount; if (requestedFrames > mNumFrames - mNextFrame) { buffer->frameCount = mNumFrames - mNextFrame; } if (!mInputIncr.empty()) { size_t provided = mInputIncr[mNextIdx++]; ALOGV("getNextBuffer() mValue[%d]=%u not %u", mNextIdx-1, provided, buffer->frameCount); if (provided < buffer->frameCount) { buffer->frameCount = provided; } if (mNextIdx >= mInputIncr.size()) { mNextIdx = 0; } } ALOGV("getNextBuffer() requested %u frames out of %u frames available" " and returned %u frames\n", requestedFrames, mNumFrames - mNextFrame, buffer->frameCount); mUnrel = buffer->frameCount; if (buffer->frameCount > 0) { buffer->raw = (char *)mAddr + mFrameSize * mNextFrame; return android::NO_ERROR; } else { buffer->raw = NULL; return android::NOT_ENOUGH_DATA; } } virtual void releaseBuffer(Buffer* buffer) { if (buffer->frameCount > mUnrel) { ALOGE("releaseBuffer() released %u frames but only %u available " "to release\n", buffer->frameCount, mUnrel); mNextFrame += mUnrel; mUnrel = 0; } else { ALOGV("releaseBuffer() released %u frames out of %u frames available " "to release\n", buffer->frameCount, mUnrel); mNextFrame += buffer->frameCount; mUnrel -= buffer->frameCount; } buffer->frameCount = 0; buffer->raw = NULL; } void reset() { mNextFrame = 0; } size_t getNumFrames() { return mNumFrames; } protected: void* mAddr; // base address size_t mNumFrames; // total frames int mFrameSize; // frame size (# channels * bytes per sample) size_t mNextFrame; // index of next frame to provide size_t mUnrel; // number of frames not yet released std::vector<int> mInputIncr; // number of frames provided per call size_t mNextIdx; // index of next entry in mInputIncr to use }; /* Creates a buffer filled with a sine wave. */ template<typename T> static void createSine(void *vbuffer, size_t frames, size_t channels, double sampleRate, double freq) { double tscale = 1. / sampleRate; T* buffer = reinterpret_cast<T*>(vbuffer); for (size_t i = 0; i < frames; ++i) { double t = i * tscale; double y = sin(2. * M_PI * freq * t); T yt = convertValue<T>(y); for (size_t j = 0; j < channels; ++j) { buffer[i*channels + j] = yt / (j + 1); } } } /* Creates a buffer filled with a chirp signal (a sine wave sweep). * * When creating the Chirp, note that the frequency is the true sinusoidal * frequency not the sampling rate. * * http://en.wikipedia.org/wiki/Chirp */ template<typename T> static void createChirp(void *vbuffer, size_t frames, size_t channels, double sampleRate, double minfreq, double maxfreq) { double tscale = 1. / sampleRate; T *buffer = reinterpret_cast<T*>(vbuffer); // note the chirp constant k has a divide-by-two. double k = (maxfreq - minfreq) / (2. * tscale * frames); for (size_t i = 0; i < frames; ++i) { double t = i * tscale; double y = sin(2. * M_PI * (k * t + minfreq) * t); T yt = convertValue<T>(y); for (size_t j = 0; j < channels; ++j) { buffer[i*channels + j] = yt / (j + 1); } } } /* This derived class creates a buffer provider of datatype T, * consisting of an input signal, e.g. from createChirp(). * The number of frames can be obtained from the base class * TestProvider::getNumFrames(). */ class SignalProvider : public TestProvider { public: SignalProvider() : mSampleRate(0), mChannels(0) { } virtual ~SignalProvider() { free(mAddr); mAddr = NULL; } template <typename T> void setChirp(size_t channels, double minfreq, double maxfreq, double sampleRate, double time) { createBufferByFrames<T>(channels, sampleRate, sampleRate*time); createChirp<T>(mAddr, mNumFrames, mChannels, mSampleRate, minfreq, maxfreq); } template <typename T> void setSine(size_t channels, double freq, double sampleRate, double time) { createBufferByFrames<T>(channels, sampleRate, sampleRate*time); createSine<T>(mAddr, mNumFrames, mChannels, mSampleRate, freq); } template <typename T> void setFile(const char *file_in) { SF_INFO info; info.format = 0; SNDFILE *sf = sf_open(file_in, SFM_READ, &info); if (sf == NULL) { perror(file_in); return; } createBufferByFrames<T>(info.channels, info.samplerate, info.frames); if (is_same<T, float>::value) { (void) sf_readf_float(sf, (float *) mAddr, mNumFrames); } else if (is_same<T, short>::value) { (void) sf_readf_short(sf, (short *) mAddr, mNumFrames); } sf_close(sf); } template <typename T> void createBufferByFrames(size_t channels, uint32_t sampleRate, size_t frames) { mNumFrames = frames; mChannels = channels; mFrameSize = mChannels * sizeof(T); free(mAddr); mAddr = malloc(mFrameSize * mNumFrames); mSampleRate = sampleRate; } uint32_t getSampleRate() const { return mSampleRate; } uint32_t getNumChannels() const { return mChannels; } protected: uint32_t mSampleRate; uint32_t mChannels; }; #endif // ANDROID_AUDIO_TEST_UTILS_H Loading
services/audioflinger/tests/Android.mk +4 −0 Original line number Original line Diff line number Diff line # Build the unit tests for audioflinger # Build the unit tests for audioflinger # # resampler unit test # LOCAL_PATH:= $(call my-dir) LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) include $(CLEAR_VARS) Loading @@ -20,6 +23,7 @@ LOCAL_C_INCLUDES := \ bionic/libstdc++/include \ bionic/libstdc++/include \ external/gtest/include \ external/gtest/include \ external/stlport/stlport \ external/stlport/stlport \ $(call include-path-for, audio-utils) \ frameworks/av/services/audioflinger frameworks/av/services/audioflinger LOCAL_SRC_FILES := \ LOCAL_SRC_FILES := \ Loading
services/audioflinger/tests/resampler_tests.cpp +11 −202 Original line number Original line Diff line number Diff line Loading @@ -33,200 +33,7 @@ #include <gtest/gtest.h> #include <gtest/gtest.h> #include <media/AudioBufferProvider.h> #include <media/AudioBufferProvider.h> #include "AudioResampler.h" #include "AudioResampler.h" #include "test_utils.h" #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) template<typename T, typename U> struct is_same { static const bool value = false; }; template<typename T> struct is_same<T, T> // partial specialization { static const bool value = true; }; template<typename T> static inline T convertValue(double val) { if (is_same<T, int16_t>::value) { return floor(val * 32767.0 + 0.5); } else if (is_same<T, int32_t>::value) { return floor(val * (1UL<<31) + 0.5); } return val; // assume float or double } /* Creates a type-independent audio buffer provider from * a buffer base address, size, framesize, and input increment array. * * No allocation or deallocation of the provided buffer is done. */ class TestProvider : public android::AudioBufferProvider { public: TestProvider(const void* addr, size_t frames, size_t frameSize, const std::vector<size_t>& inputIncr) : mAddr(addr), mNumFrames(frames), mFrameSize(frameSize), mNextFrame(0), mUnrel(0), mInputIncr(inputIncr), mNextIdx(0) { } virtual android::status_t getNextBuffer(Buffer* buffer, int64_t pts __unused = kInvalidPTS ) { size_t requestedFrames = buffer->frameCount; if (requestedFrames > mNumFrames - mNextFrame) { buffer->frameCount = mNumFrames - mNextFrame; } if (!mInputIncr.empty()) { size_t provided = mInputIncr[mNextIdx++]; ALOGV("getNextBuffer() mValue[%d]=%u not %u", mNextIdx-1, provided, buffer->frameCount); if (provided < buffer->frameCount) { buffer->frameCount = provided; } if (mNextIdx >= mInputIncr.size()) { mNextIdx = 0; } } ALOGV("getNextBuffer() requested %u frames out of %u frames available" " and returned %u frames\n", requestedFrames, mNumFrames - mNextFrame, buffer->frameCount); mUnrel = buffer->frameCount; if (buffer->frameCount > 0) { buffer->raw = (char *)mAddr + mFrameSize * mNextFrame; return android::NO_ERROR; } else { buffer->raw = NULL; return android::NOT_ENOUGH_DATA; } } virtual void releaseBuffer(Buffer* buffer) { if (buffer->frameCount > mUnrel) { ALOGE("releaseBuffer() released %u frames but only %u available " "to release\n", buffer->frameCount, mUnrel); mNextFrame += mUnrel; mUnrel = 0; } else { ALOGV("releaseBuffer() released %u frames out of %u frames available " "to release\n", buffer->frameCount, mUnrel); mNextFrame += buffer->frameCount; mUnrel -= buffer->frameCount; } buffer->frameCount = 0; buffer->raw = NULL; } void reset() { mNextFrame = 0; } size_t getNumFrames() { return mNumFrames; } void setIncr(const std::vector<size_t> inputIncr) { mNextIdx = 0; mInputIncr = inputIncr; } protected: const void* mAddr; // base address size_t mNumFrames; // total frames int mFrameSize; // frame size (# channels * bytes per sample) size_t mNextFrame; // index of next frame to provide size_t mUnrel; // number of frames not yet released std::vector<size_t> mInputIncr; // number of frames provided per call size_t mNextIdx; // index of next entry in mInputIncr to use }; /* Creates a buffer filled with a sine wave. * * Returns a pair consisting of the sine signal buffer and the number of frames. * The caller must delete[] the buffer when no longer needed (no shared_ptr<>). */ template<typename T> static std::pair<T*, size_t> createSine(size_t channels, double freq, double samplingRate, double time) { double tscale = 1. / samplingRate; size_t frames = static_cast<size_t>(samplingRate * time); T* buffer = new T[frames * channels]; for (size_t i = 0; i < frames; ++i) { double t = i * tscale; double y = sin(2. * M_PI * freq * t); T yt = convertValue<T>(y); for (size_t j = 0; j < channels; ++j) { buffer[i*channels + j] = yt / (j + 1); } } return std::make_pair(buffer, frames); } /* Creates a buffer filled with a chirp signal (a sine wave sweep). * * Returns a pair consisting of the chirp signal buffer and the number of frames. * The caller must delete[] the buffer when no longer needed (no shared_ptr<>). * * When creating the Chirp, note that the frequency is the true sinusoidal * frequency not the sampling rate. * * http://en.wikipedia.org/wiki/Chirp */ template<typename T> static std::pair<T*, size_t> createChirp(size_t channels, double minfreq, double maxfreq, double samplingRate, double time) { double tscale = 1. / samplingRate; size_t frames = static_cast<size_t>(samplingRate * time); T *buffer = new T[frames * channels]; // note the chirp constant k has a divide-by-two. double k = (maxfreq - minfreq) / (2. * time); for (size_t i = 0; i < frames; ++i) { double t = i * tscale; double y = sin(2. * M_PI * (k * t + minfreq) * t); T yt = convertValue<T>(y); for (size_t j = 0; j < channels; ++j) { buffer[i*channels + j] = yt / (j + 1); } } return std::make_pair(buffer, frames); } /* This derived class creates a buffer provider of datatype T, * consisting of an input signal, e.g. from createChirp(). * The number of frames can be obtained from the base class * TestProvider::getNumFrames(). */ template <typename T> class SignalProvider : public TestProvider { public: SignalProvider(const std::pair<T*, size_t>& bufferInfo, size_t channels, const std::vector<size_t>& values) : TestProvider(bufferInfo.first, bufferInfo.second, channels * sizeof(T), values), mManagedPtr(bufferInfo.first) { } virtual ~SignalProvider() { delete[] mManagedPtr; } protected: T* mManagedPtr; }; void resample(void *output, size_t outputFrames, const std::vector<size_t> &outputIncr, void resample(void *output, size_t outputFrames, const std::vector<size_t> &outputIncr, android::AudioBufferProvider *provider, android::AudioResampler *resampler) android::AudioBufferProvider *provider, android::AudioResampler *resampler) Loading Loading @@ -261,10 +68,11 @@ void testBufferIncrement(size_t channels, unsigned inputFreq, unsigned outputFre enum android::AudioResampler::src_quality quality) enum android::AudioResampler::src_quality quality) { { // create the provider // create the provider std::vector<size_t> inputIncr; std::vector<int> inputIncr; SignalProvider<int16_t> provider(createChirp<int16_t>(channels, SignalProvider provider; 0., outputFreq/2., outputFreq, outputFreq/2000.), provider.setChirp<int16_t>(channels, channels, inputIncr); 0., outputFreq/2., outputFreq, outputFreq/2000.); provider.setIncr(inputIncr); // calculate the output size // calculate the output size size_t outputFrames = ((int64_t) provider.getNumFrames() * outputFreq) / inputFreq; size_t outputFrames = ((int64_t) provider.getNumFrames() * outputFreq) / inputFreq; Loading Loading @@ -339,10 +147,11 @@ void testStopbandDownconversion(size_t channels, enum android::AudioResampler::src_quality quality) enum android::AudioResampler::src_quality quality) { { // create the provider // create the provider std::vector<size_t> inputIncr; std::vector<int> inputIncr; SignalProvider<int16_t> provider(createChirp<int16_t>(channels, SignalProvider provider; 0., inputFreq/2., inputFreq, inputFreq/2000.), provider.setChirp<int16_t>(channels, channels, inputIncr); 0., inputFreq/2., inputFreq, inputFreq/2000.); provider.setIncr(inputIncr); // calculate the output size // calculate the output size size_t outputFrames = ((int64_t) provider.getNumFrames() * outputFreq) / inputFreq; size_t outputFrames = ((int64_t) provider.getNumFrames() * outputFreq) / inputFreq; Loading
services/audioflinger/tests/test_utils.h 0 → 100644 +307 −0 Original line number Original line Diff line number Diff line /* * Copyright (C) 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef ANDROID_AUDIO_TEST_UTILS_H #define ANDROID_AUDIO_TEST_UTILS_H #include <audio_utils/sndfile.h> #ifndef ARRAY_SIZE #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) #endif template<typename T, typename U> struct is_same { static const bool value = false; }; template<typename T> struct is_same<T, T> // partial specialization { static const bool value = true; }; template<typename T> static inline T convertValue(double val) { if (is_same<T, int16_t>::value) { return floor(val * 32767.0 + 0.5); } else if (is_same<T, int32_t>::value) { return floor(val * (1UL<<31) + 0.5); } return val; // assume float or double } // Convert a list of integers in CSV format to a Vector of those values. // Returns the number of elements in the list, or -1 on error. static inline int parseCSV(const char *string, std::vector<int>& values) { // pass 1: count the number of values and do syntax check size_t numValues = 0; bool hadDigit = false; for (const char *p = string; ; ) { switch (*p++) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': hadDigit = true; break; case '\0': if (hadDigit) { // pass 2: allocate and initialize vector of values values.resize(++numValues); values[0] = atoi(p = string); for (size_t i = 1; i < numValues; ) { if (*p++ == ',') { values[i++] = atoi(p); } } return numValues; } // fall through case ',': if (hadDigit) { hadDigit = false; numValues++; break; } // fall through default: return -1; } } } /* Creates a type-independent audio buffer provider from * a buffer base address, size, framesize, and input increment array. * * No allocation or deallocation of the provided buffer is done. */ class TestProvider : public android::AudioBufferProvider { public: TestProvider(void* addr, size_t frames, size_t frameSize, const std::vector<int>& inputIncr) : mAddr(addr), mNumFrames(frames), mFrameSize(frameSize), mNextFrame(0), mUnrel(0), mInputIncr(inputIncr), mNextIdx(0) { } TestProvider() : mAddr(NULL), mNumFrames(0), mFrameSize(0), mNextFrame(0), mUnrel(0), mNextIdx(0) { } void setIncr(const std::vector<int>& inputIncr) { mInputIncr = inputIncr; mNextIdx = 0; } virtual android::status_t getNextBuffer(Buffer* buffer, int64_t pts __unused = kInvalidPTS) { size_t requestedFrames = buffer->frameCount; if (requestedFrames > mNumFrames - mNextFrame) { buffer->frameCount = mNumFrames - mNextFrame; } if (!mInputIncr.empty()) { size_t provided = mInputIncr[mNextIdx++]; ALOGV("getNextBuffer() mValue[%d]=%u not %u", mNextIdx-1, provided, buffer->frameCount); if (provided < buffer->frameCount) { buffer->frameCount = provided; } if (mNextIdx >= mInputIncr.size()) { mNextIdx = 0; } } ALOGV("getNextBuffer() requested %u frames out of %u frames available" " and returned %u frames\n", requestedFrames, mNumFrames - mNextFrame, buffer->frameCount); mUnrel = buffer->frameCount; if (buffer->frameCount > 0) { buffer->raw = (char *)mAddr + mFrameSize * mNextFrame; return android::NO_ERROR; } else { buffer->raw = NULL; return android::NOT_ENOUGH_DATA; } } virtual void releaseBuffer(Buffer* buffer) { if (buffer->frameCount > mUnrel) { ALOGE("releaseBuffer() released %u frames but only %u available " "to release\n", buffer->frameCount, mUnrel); mNextFrame += mUnrel; mUnrel = 0; } else { ALOGV("releaseBuffer() released %u frames out of %u frames available " "to release\n", buffer->frameCount, mUnrel); mNextFrame += buffer->frameCount; mUnrel -= buffer->frameCount; } buffer->frameCount = 0; buffer->raw = NULL; } void reset() { mNextFrame = 0; } size_t getNumFrames() { return mNumFrames; } protected: void* mAddr; // base address size_t mNumFrames; // total frames int mFrameSize; // frame size (# channels * bytes per sample) size_t mNextFrame; // index of next frame to provide size_t mUnrel; // number of frames not yet released std::vector<int> mInputIncr; // number of frames provided per call size_t mNextIdx; // index of next entry in mInputIncr to use }; /* Creates a buffer filled with a sine wave. */ template<typename T> static void createSine(void *vbuffer, size_t frames, size_t channels, double sampleRate, double freq) { double tscale = 1. / sampleRate; T* buffer = reinterpret_cast<T*>(vbuffer); for (size_t i = 0; i < frames; ++i) { double t = i * tscale; double y = sin(2. * M_PI * freq * t); T yt = convertValue<T>(y); for (size_t j = 0; j < channels; ++j) { buffer[i*channels + j] = yt / (j + 1); } } } /* Creates a buffer filled with a chirp signal (a sine wave sweep). * * When creating the Chirp, note that the frequency is the true sinusoidal * frequency not the sampling rate. * * http://en.wikipedia.org/wiki/Chirp */ template<typename T> static void createChirp(void *vbuffer, size_t frames, size_t channels, double sampleRate, double minfreq, double maxfreq) { double tscale = 1. / sampleRate; T *buffer = reinterpret_cast<T*>(vbuffer); // note the chirp constant k has a divide-by-two. double k = (maxfreq - minfreq) / (2. * tscale * frames); for (size_t i = 0; i < frames; ++i) { double t = i * tscale; double y = sin(2. * M_PI * (k * t + minfreq) * t); T yt = convertValue<T>(y); for (size_t j = 0; j < channels; ++j) { buffer[i*channels + j] = yt / (j + 1); } } } /* This derived class creates a buffer provider of datatype T, * consisting of an input signal, e.g. from createChirp(). * The number of frames can be obtained from the base class * TestProvider::getNumFrames(). */ class SignalProvider : public TestProvider { public: SignalProvider() : mSampleRate(0), mChannels(0) { } virtual ~SignalProvider() { free(mAddr); mAddr = NULL; } template <typename T> void setChirp(size_t channels, double minfreq, double maxfreq, double sampleRate, double time) { createBufferByFrames<T>(channels, sampleRate, sampleRate*time); createChirp<T>(mAddr, mNumFrames, mChannels, mSampleRate, minfreq, maxfreq); } template <typename T> void setSine(size_t channels, double freq, double sampleRate, double time) { createBufferByFrames<T>(channels, sampleRate, sampleRate*time); createSine<T>(mAddr, mNumFrames, mChannels, mSampleRate, freq); } template <typename T> void setFile(const char *file_in) { SF_INFO info; info.format = 0; SNDFILE *sf = sf_open(file_in, SFM_READ, &info); if (sf == NULL) { perror(file_in); return; } createBufferByFrames<T>(info.channels, info.samplerate, info.frames); if (is_same<T, float>::value) { (void) sf_readf_float(sf, (float *) mAddr, mNumFrames); } else if (is_same<T, short>::value) { (void) sf_readf_short(sf, (short *) mAddr, mNumFrames); } sf_close(sf); } template <typename T> void createBufferByFrames(size_t channels, uint32_t sampleRate, size_t frames) { mNumFrames = frames; mChannels = channels; mFrameSize = mChannels * sizeof(T); free(mAddr); mAddr = malloc(mFrameSize * mNumFrames); mSampleRate = sampleRate; } uint32_t getSampleRate() const { return mSampleRate; } uint32_t getNumChannels() const { return mChannels; } protected: uint32_t mSampleRate; uint32_t mChannels; }; #endif // ANDROID_AUDIO_TEST_UTILS_H