From b674db8360be8109a838351f4527f6b9f420e04a Mon Sep 17 00:00:00 2001 From: Jin Qian Date: Sat, 18 Mar 2017 02:43:21 +0000 Subject: [PATCH] Revert "Add power logging" This reverts commit 13082f80dcee5f119cdb68a4dbc972cd2b939668. Change-Id: I6bd03874fd219ef5b82e23d6e0dc97decbb87198 --- audio_utils/Android.bp | 2 - audio_utils/PowerLog.cpp | 263 ------------------------- audio_utils/include/audio_utils/PowerLog.h | 164 ---------------- audio_utils/include/audio_utils/clock.h | 66 ------- audio_utils/include/audio_utils/power.h | 100 ---------- audio_utils/power.cpp | 306 ----------------------------- audio_utils/tests/Android.bp | 24 --- audio_utils/tests/power_tests.cpp | 167 ---------------- 8 files changed, 1092 deletions(-) delete mode 100644 audio_utils/PowerLog.cpp delete mode 100644 audio_utils/include/audio_utils/PowerLog.h delete mode 100644 audio_utils/include/audio_utils/clock.h delete mode 100644 audio_utils/include/audio_utils/power.h delete mode 100644 audio_utils/power.cpp delete mode 100644 audio_utils/tests/power_tests.cpp diff --git a/audio_utils/Android.bp b/audio_utils/Android.bp index b6d01ea5..11ed72cf 100644 --- a/audio_utils/Android.bp +++ b/audio_utils/Android.bp @@ -24,8 +24,6 @@ cc_library { "format.c", "limiter.c", "minifloat.c", - "power.cpp", - "PowerLog.cpp", "primitives.c", "roundup.c", ], diff --git a/audio_utils/PowerLog.cpp b/audio_utils/PowerLog.cpp deleted file mode 100644 index 64e3c650..00000000 --- a/audio_utils/PowerLog.cpp +++ /dev/null @@ -1,263 +0,0 @@ -/* - * Copyright 2017 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. - */ - -// #define LOG_NDEBUG 0 -#define LOG_TAG "audio_utils_PowerLog" -#include - -#include -#include -#include -#include -#include - -#include -#include -#include - -namespace android { - -// TODO move to separate file -template -constexpr size_t array_size(const T(&)[N]) -{ - return N; -} - -PowerLog::PowerLog(uint32_t sampleRate, - uint32_t channelCount, - audio_format_t format, - size_t entries, - size_t framesPerEntry) - : mCurrentTime(0) - , mCurrentEnergy(0) - , mCurrentFrames(0) - , mIdx(0) - , mConsecutiveZeroes(0) - , mSampleRate(sampleRate) - , mChannelCount(channelCount) - , mFormat(format) - , mFramesPerEntry(framesPerEntry) - , mEntries(entries) -{ - (void)mSampleRate; // currently unused, for future use - LOG_ALWAYS_FATAL_IF(!audio_utils_is_compute_power_format_supported(format), - "unsupported format: %#x", format); -} - -void PowerLog::log(const void *buffer, size_t frames, int64_t nowNs) -{ - std::lock_guard guard(mLock); - - const size_t bytes_per_sample = audio_bytes_per_sample(mFormat); - while (frames > 0) { - // check partial computation - size_t required = mFramesPerEntry - mCurrentFrames; - size_t process = std::min(required, frames); - - if (mCurrentTime == 0) { - mCurrentTime = nowNs; - } - mCurrentEnergy += - audio_utils_compute_energy_mono(buffer, mFormat, process * mChannelCount); - mCurrentFrames += process; - - ALOGV("nowNs:%lld, required:%zu, process:%zu, mCurrentEnergy:%f, mCurrentFrames:%zu", - (long long)nowNs, required, process, mCurrentEnergy, mCurrentFrames); - if (process < required) { - return; - } - - // We store the data as normalized energy per sample. The energy sequence is - // zero terminated. Consecutive zeroes are ignored. - if (mCurrentEnergy == 0.f) { - if (mConsecutiveZeroes++ == 0) { - mEntries[mIdx++] = std::make_pair(nowNs, 0.f); - // zero terminate the signal sequence. - } - } else { - mConsecutiveZeroes = 0; - mEntries[mIdx++] = std::make_pair(mCurrentTime, mCurrentEnergy); - ALOGV("writing %lld %f", (long long)mCurrentTime, mCurrentEnergy); - } - if (mIdx >= mEntries.size()) { - mIdx -= mEntries.size(); - } - mCurrentTime = 0; - mCurrentEnergy = 0; - mCurrentFrames = 0; - frames -= process; - buffer = (const uint8_t *)buffer + mCurrentFrames * mChannelCount * bytes_per_sample; - } -} - -std::string PowerLog::dumpToString(size_t lines, int64_t limitNs) const -{ - std::lock_guard guard(mLock); - - const size_t maxColumns = 10; - const size_t numberOfEntries = mEntries.size(); - if (lines == 0) lines = SIZE_MAX; - - // compute where to start logging - enum { - AT_END, - IN_SIGNAL, - } state = IN_SIGNAL; - size_t count = 1; - size_t column = 0; - size_t nonzeros = 0; - ssize_t offset; // TODO doesn't dump if # entries exceeds SSIZE_MAX - for (offset = 0; offset < (ssize_t)numberOfEntries && count < lines; ++offset) { - const size_t idx = (mIdx + numberOfEntries - offset - 1) % numberOfEntries; // reverse direction - const int64_t time = mEntries[idx].first; - const float energy = mEntries[idx].second; - - if (state == AT_END) { - if (energy == 0.f) { - ALOGV("two zeroes detected"); - break; // normally single zero terminated - two zeroes means no more data. - } - state = IN_SIGNAL; - } else { // IN_SIGNAL - if (energy == 0.f) { - if (column != 0) { - column = 0; - ++count; - } - state = AT_END; - continue; - } - } - if (column == 0 && time <= limitNs) { - break; - } - ++nonzeros; - if (++column == maxColumns) { - column = 0; - // TODO ideally we would peek the previous entry to see if it is 0 - // to ensure we properly put in a starting signal bracket. - // We don't do that because it would complicate the logic here. - ++count; - } - } - if (offset > 0) { - --offset; - } - // We accumulate the log info into a string, and write to the fd once. - std::stringstream ss; - ss << std::fixed << std::setprecision(1); - // ss << std::scientific; - if (nonzeros == 0) { - ss << " Signal power history: (none)\n"; - } else { - ss << " Signal power history:\n"; - - size_t column = 0; - bool first = true; - bool start = false; - float cumulative = 0.f; - for (; offset >= 0; --offset) { - const size_t idx = (mIdx + numberOfEntries - offset - 1) % numberOfEntries; - const int64_t time = mEntries[idx].first; - const float energy = mEntries[idx].second; - - if (energy == 0.f) { - if (!first) { - ss << " ] sum(" << audio_utils_power_from_energy(cumulative) << ")"; - } - cumulative = 0.f; - column = 0; - start = true; - continue; - } - if (column == 0) { - // print time if at start of column - char timeinfo[32]; - audio_utils_ns_to_string(time, timeinfo, array_size(timeinfo)); - if (!first) { - ss << "\n"; - } - ss << timeinfo << (start ? ": [ ": ": "); - first = false; - start = false; - } else { - ss << " "; - } - if (++column >= maxColumns) { - column = 0; - } - - cumulative += energy; - // convert energy to power and print - const float power = - audio_utils_power_from_energy(energy / (mChannelCount * mFramesPerEntry)); - ss << std::setw(6) << power; - ALOGV("state: %d %lld %f", state, (long long)time, power); - } - ss << "\n"; - } - return ss.str(); -} - -status_t PowerLog::dump(int fd, size_t lines, int64_t limitNs) const -{ - // Since dumpToString and write are thread safe, this function - // is conceptually thread-safe but simultaneous calls to dump - // by different threads to the same file descriptor may not write - // the two logs in time order. - const std::string s = dumpToString(lines, limitNs); - if (s.size() > 0 && write(fd, s.c_str(), s.size()) < 0) { - return -errno; - } - return NO_ERROR; -} - -} // namespace android - -using namespace android; - -power_log_t *power_log_create(uint32_t sample_rate, - uint32_t channel_count, audio_format_t format, size_t entries, size_t frames_per_entry) -{ - if (!audio_utils_is_compute_power_format_supported(format)) { - return nullptr; - } - return reinterpret_cast - (new PowerLog(sample_rate, channel_count, format, entries, frames_per_entry)); -} - -void power_log_log(power_log_t *power_log, - const void *buffer, size_t frames, int64_t now_ns) -{ - if (power_log == nullptr) { - return; - } - reinterpret_cast(power_log)->log(buffer, frames, now_ns); -} - -int power_log_dump(power_log_t *power_log, int fd, size_t lines, int64_t limit_ns) -{ - if (power_log == nullptr) { - return BAD_VALUE; - } - return reinterpret_cast(power_log)->dump(fd, lines, limit_ns); -} - -void power_log_destroy(power_log_t *power_log) -{ - delete reinterpret_cast(power_log); -} diff --git a/audio_utils/include/audio_utils/PowerLog.h b/audio_utils/include/audio_utils/PowerLog.h deleted file mode 100644 index 497bb3c9..00000000 --- a/audio_utils/include/audio_utils/PowerLog.h +++ /dev/null @@ -1,164 +0,0 @@ -/* - * Copyright 2017 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_POWER_LOG_H -#define ANDROID_AUDIO_POWER_LOG_H - -#ifdef __cplusplus - -#include -#include - -#include - -namespace android { - -/** - * PowerLog captures the audio data power (measured in dBFS) over time. - * - * For the purposes of power evaluation, the audio data is divided into "bins", - * and grouped by signals consisting of consecutive non-zero energy bins. - * The sum energy in dB of each signal is computed for comparison purposes. - * - * No distinction is made between channels in an audio frame; they are all - * summed together for energy purposes. - * - * The public methods are internally protected by a mutex to be thread-safe. - */ -class PowerLog { -public: - /** - * \brief Creates a PowerLog object. - * - * \param sampleRate sample rate of the audio data. - * \param channelCount channel count of the audio data. - * \param format format of the audio data. It must be allowed by - * audio_utils_is_compute_power_format_supported() - * else the constructor will abort. - * \param entries total number of energy entries "bins" to use. - * \param framesPerEntry total number of audio frames used in each entry. - */ - explicit PowerLog(uint32_t sampleRate, - uint32_t channelCount, - audio_format_t format, - size_t entries, - size_t framesPerEntry); - - /** - * \brief Adds new audio data to the power log. - * - * \param buffer pointer to the audio data buffer. - * \param frames buffer size in audio frames. - * \param nowNs current time in nanoseconds. - */ - void log(const void *buffer, size_t frames, int64_t nowNs); - - /** - * \brief Dumps the log to a std::string. - * - * \param lines maximum number of lines to output (0 disables). - * \param limitNs limit dump to data more recent than limitNs (0 disables). - * \return the std::string for the log. - */ - std::string dumpToString(size_t lines = 0, int64_t limitNs = 0) const; - - /** - * \brief Dumps the log to a raw file descriptor. - * - * \param fd file descriptor to use. - * \param lines maximum number of lines to output (0 disables). - * \param limitNs limit dump to data more recent than limitNs (0 disables). - * \return - * NO_ERROR on success or a negative number (-errno) on failure of write(). - */ - status_t dump(int fd, size_t lines = 0, int64_t limitNs = 0) const; - -private: - mutable std::mutex mLock; // monitor mutex - int64_t mCurrentTime; // time of first frame in buffer - float mCurrentEnergy; // local energy accumulation - size_t mCurrentFrames; // number of frames in the energy - size_t mIdx; // next usable index in mEntries - size_t mConsecutiveZeroes; // current run of consecutive zero entries - const uint32_t mSampleRate; // audio data sample rate - const uint32_t mChannelCount; // audio data channel count - const audio_format_t mFormat; // audio data format - const size_t mFramesPerEntry; // number of audio frames per entry - std::vector> mEntries; -}; - -} // namespace android - -#endif // __cplusplus - -/** \cond */ -__BEGIN_DECLS -/** \endcond */ - -// C API (see C++ api above for details) - -typedef struct power_log_t power_log_t; - -/** - * \brief Creates a power log object. - * - * \param sample_rate sample rate of the audio data. - * \param channel_count channel count of the audio data. - * \param format format of the audio data. It must be allowed by - * audio_utils_is_compute_power_format_supported(). - * \param entries total number of energy entries "bins" to use. - * \param frames_per_entry total number of audio frames used in each entry. - * - * \return power log object or NULL on failure. - */ -power_log_t *power_log_create(uint32_t sample_rate, - uint32_t channel_count, audio_format_t format, size_t entries, size_t frames_per_entry); - -/** - * \brief Adds new audio data to the power log. - * - * \param power_log object returned by create, if NULL nothing happens. - * \param buffer pointer to the audio data buffer. - * \param frames buffer size in audio frames. - * \param now_ns current time in nanoseconds. - */ -void power_log_log(power_log_t *power_log, const void *buffer, size_t frames, int64_t now_ns); - -/** - * \brief Dumps the log to a raw file descriptor. - * - * \param power_log object returned by create, if NULL nothing happens. - * \param fd file descriptor to use. - * \param lines maximum number of lines to output (0 disables). - * \param limit_ns limit dump to data more recent than limit_ns (0 disables). - * \return - * NO_ERROR on success or a negative number (-errno) on failure of write(). - * if power_log is NULL, BAD_VALUE is returned. - */ -int power_log_dump(power_log_t *power_log, int fd, size_t lines, int64_t limit_ns); - -/** - * \brief Destroys the power log object. - * - * \param power_log object returned by create, if NULL nothing happens. - */ -void power_log_destroy(power_log_t *power_log); - -/** \cond */ -__END_DECLS -/** \endcond */ - -#endif // !ANDROID_AUDIO_POWER_LOG_H diff --git a/audio_utils/include/audio_utils/clock.h b/audio_utils/include/audio_utils/clock.h deleted file mode 100644 index 149ac8cc..00000000 --- a/audio_utils/include/audio_utils/clock.h +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright 2017 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_CLOCK_H -#define ANDROID_AUDIO_CLOCK_H - -#include - -/** - * \brief Converts time in ns to a time string, with format similar to logcat. - * \param ns input time in nanoseconds to convert. - * \param buffer caller allocated string buffer, buffer_length must be >= 19 chars - * in order to fully fit in time. The string is always returned - * null terminated if buffer_size is greater than zero. - * \param buffer_size size of buffer. - */ -static inline void audio_utils_ns_to_string(int64_t ns, char *buffer, int buffer_size) -{ - const int one_second = 1000000000; - const time_t sec = ns / one_second; - struct tm tm; - localtime_r(&sec, &tm); - if (snprintf(buffer, buffer_size, "%02d-%02d %02d:%02d:%02d.%03d", - tm.tm_mon + 1, // localtime_r uses months in 0 - 11 range - tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec, - (int)(ns % one_second / 1000000)) < 0) { - buffer[0] = '\0'; // null terminate on format error, which should not happen - } -} - -/** - * \brief Converts a timespec to nanoseconds. - * \param ts input timespec to convert. - * \return timespec converted to nanoseconds. - */ -static inline int64_t audio_utils_ns_from_timespec(const struct timespec *ts) -{ - return ts->tv_sec * 1000000000LL + ts->tv_nsec; -} - -/** - * \brief Gets the real time clock in nanoseconds. - * \return the real time clock in nanoseconds, or 0 on error. - */ -static inline int64_t audio_utils_get_real_time_ns() { - struct timespec now_ts; - if (clock_gettime(CLOCK_REALTIME, &now_ts) == 0) { - return audio_utils_ns_from_timespec(&now_ts); - } - return 0; // should not happen. -} - -#endif // !ANDROID_AUDIO_CLOCK_H diff --git a/audio_utils/include/audio_utils/power.h b/audio_utils/include/audio_utils/power.h deleted file mode 100644 index 385b6a79..00000000 --- a/audio_utils/include/audio_utils/power.h +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright 2017 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_POWER_H -#define ANDROID_AUDIO_POWER_H - -#include -#include -#include -#include - -/** \cond */ -__BEGIN_DECLS -/** \endcond */ - -/** - * \brief Compute signal power on a scale of 0 dBFS. - * - * \param buffer buffer of samples. - * \param format one of AUDIO_FORMAT_PCM_8_BIT, AUDIO_FORMAT_PCM_16_BIT, - * AUDIO_FORMAT_PCM_24_BIT_PACKED, AUDIO_FORMAT_PCM_8_24_BIT, - * AUDIO_FORMAT_PCM_32_BIT, AUDIO_FORMAT_PCM_FLOAT. - * \param samples number of samples in buffer. This is not audio frames; - * usually the number of samples is the number of audio frames - * multiplied by channel count. - * - * \return - * signal power of the samples in the buffer. It is possible to return negative infinity - * if the power is zero. - */ - -float audio_utils_compute_power_mono(const void *buffer, audio_format_t format, size_t samples); - -/** - * \brief Compute signal energy (sum of squared amplitudes). - * - * \param buffer buffer of samples. - * \param format one of AUDIO_FORMAT_PCM_8_BIT, AUDIO_FORMAT_PCM_16_BIT, - * AUDIO_FORMAT_PCM_24_BIT_PACKED, AUDIO_FORMAT_PCM_8_24_BIT, - * AUDIO_FORMAT_PCM_32_BIT, AUDIO_FORMAT_PCM_FLOAT. - * \param samples number of samples in buffer. This is not audio frames; - * usually the number of samples is the number of audio frames - * multiplied by channel count. - * - * \return - * signal energy of the samples in the buffer (sum of squares) where each sample is - * normalized to peak to peak range of 1.f. - */ - -float audio_utils_compute_energy_mono(const void *buffer, audio_format_t format, size_t samples); - -/** - * \brief Returns true if the format is supported for compute_energy_for_mono() - * and compute_power_for_mono(). - * \param format format under consideration. - * \return true if supported. - */ -bool audio_utils_is_compute_power_format_supported(audio_format_t format); - -/** - * \brief Returns the signal power from amplitude. - * \param amplitude the signal amplitude. A negative amplitude is treated - * the same as a positive amplitude. - * \return signal power in dB. It is possible to return negative infinity - * if the input is zero. - */ -static inline float audio_utils_power_from_amplitude(float amplitude) -{ - return 20.f * log10f(fabsf(amplitude)); -} - -/** - * \brief Returns the signal power from energy. - * \param energy the signal energy. This should be non-negative. - * \return signal power in dB. It is possible to return NaN if the input is - * negative, or negative infinity if the input is zero. - */ -static inline float audio_utils_power_from_energy(float energy) -{ - return 10.f * log10f(energy); -} - -/** \cond */ -__END_DECLS -/** \endcond */ - -#endif // !ANDROID_AUDIO_POWER_H diff --git a/audio_utils/power.cpp b/audio_utils/power.cpp deleted file mode 100644 index e801da05..00000000 --- a/audio_utils/power.cpp +++ /dev/null @@ -1,306 +0,0 @@ -/* - * Copyright 2017 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. - */ - -// #define LOG_NDEBUG 0 -#define LOG_TAG "audio_utils_power" -#include - -#include - -#include -#include - -#if defined(__aarch64__) || defined(__ARM_NEON__) -#include -#define USE_NEON -#endif - -namespace { - -constexpr inline bool isFormatSupported(audio_format_t format) { - switch (format) { - case AUDIO_FORMAT_PCM_8_BIT: - case AUDIO_FORMAT_PCM_16_BIT: - case AUDIO_FORMAT_PCM_24_BIT_PACKED: - case AUDIO_FORMAT_PCM_8_24_BIT: - case AUDIO_FORMAT_PCM_32_BIT: - case AUDIO_FORMAT_PCM_FLOAT: - return true; - default: - return false; - } -} - -template -inline T getPtrPtrValueAndIncrement(const void **data) -{ - return *(*reinterpret_cast(data))++; -} - -template -inline float convertToFloatAndIncrement(const void **data) -{ - switch (FORMAT) { - case AUDIO_FORMAT_PCM_8_BIT: - return float_from_u8(getPtrPtrValueAndIncrement(data)); - - case AUDIO_FORMAT_PCM_16_BIT: - return float_from_i16(getPtrPtrValueAndIncrement(data)); - - case AUDIO_FORMAT_PCM_24_BIT_PACKED: { - const uint8_t *uptr = reinterpret_cast(*data); - *data = uptr + 3; - return float_from_p24(uptr); - } - - case AUDIO_FORMAT_PCM_8_24_BIT: - return float_from_q8_23(getPtrPtrValueAndIncrement(data)); - - case AUDIO_FORMAT_PCM_32_BIT: - return float_from_i32(getPtrPtrValueAndIncrement(data)); - - case AUDIO_FORMAT_PCM_FLOAT: - return getPtrPtrValueAndIncrement(data); - - default: - // static_assert cannot use false because the compiler may interpret it - // even though this code path may never be taken. - static_assert(isFormatSupported(FORMAT), "unsupported format"); - } -} - -// used to normalize integer fixed point value to the floating point equivalent. -template -constexpr inline float normalizeAmplitude() -{ - switch (FORMAT) { - case AUDIO_FORMAT_PCM_8_BIT: - return 1.f / (1 << 7); - - case AUDIO_FORMAT_PCM_16_BIT: - return 1.f / (1 << 15); - - case AUDIO_FORMAT_PCM_24_BIT_PACKED: // fall through - case AUDIO_FORMAT_PCM_8_24_BIT: - return 1.f / (1 << 23); - - case AUDIO_FORMAT_PCM_32_BIT: - return 1.f / (1U << 31); - - case AUDIO_FORMAT_PCM_FLOAT: - return 1.f; - - default: - // static_assert cannot use false because the compiler may interpret it - // even though this code path may never be taken. - static_assert(isFormatSupported(FORMAT), "unsupported format"); - } -} - -template -constexpr inline float normalizeEnergy() -{ - const float val = normalizeAmplitude(); - return val * val; -} - -template -inline float energyMonoRef(const void *amplitudes, size_t size) -{ - float accum(0.f); - for (size_t i = 0; i < size; ++i) { - const float amplitude = convertToFloatAndIncrement(&litudes); - accum += amplitude * amplitude; - } - return accum; -} - -template -inline float energyMono(const void *amplitudes, size_t size) -{ - return energyMonoRef(amplitudes, size); -} - -// fast float power computation for ARM processors that support NEON. -#ifdef USE_NEON - -template <> -inline float energyMono(const void *amplitudes, size_t size) -{ - float32x4_t *famplitudes = (float32x4_t *)amplitudes; - - // clear accumulator - float32x4_t accum = vdupq_n_f32(0); - - // iterate over array getting sum of squares in 4 lanes. - size_t i; - for (i = 0; i < (size & ~3); i += 4) { - accum = vmlaq_f32(accum, *famplitudes, *famplitudes); - ++famplitudes; - } - - // narrow 4 lanes of floats - float32x2_t accum2 = vadd_f32(vget_low_f32(accum), vget_high_f32(accum)); // get stereo volume - accum2 = vpadd_f32(accum2, accum2); // combine to mono - - // accumulate remainder - float value = vget_lane_f32(accum2, 0); - for (; i < size; ++i) { - const float amplitude = ((float *)amplitudes)[i]; - value += amplitude * amplitude; - } - - return value; -} - -template <> -inline float energyMono(const void *amplitudes, size_t size) -{ - int16x4_t *samplitudes = (int16x4_t *)amplitudes; - - // clear accumulator - float32x4_t accum = vdupq_n_f32(0); - - // iterate over array getting sum of squares in 4 lanes. - size_t i; - for (i = 0; i < (size & ~3); i += 4) { - // expand s16 to s32 - int32x4_t amplitude = vmovl_s16(*samplitudes); - ++samplitudes; - // convert s32 to f32 - float32x4_t famplitude = vcvtq_f32_s32(amplitude); - accum = vmlaq_f32(accum, famplitude, famplitude); - } - - // narrow 4 lanes of floats - float32x2_t accum2 = vadd_f32(vget_low_f32(accum), vget_high_f32(accum)); // get stereo volume - accum2 = vpadd_f32(accum2, accum2); // combine to mono - - // accumulate remainder - float value = vget_lane_f32(accum2, 0); - for (; i < size; ++i) { - const float amplitude = (float)((int16_t *)amplitudes)[i]; - value += amplitude * amplitude; - } - - return value * normalizeEnergy(); -} - -// fast int32_t power computation for PCM_32 -template <> -inline float energyMono(const void *amplitudes, size_t size) -{ - int32x4_t *samplitudes = (int32x4_t *)amplitudes; - - // clear accumulator - float32x4_t accum = vdupq_n_f32(0); - - // iterate over array getting sum of squares in 4 lanes. - size_t i; - for (i = 0; i < (size & ~3); i += 4) { - // convert s32 to f32 - float32x4_t famplitude = vcvtq_f32_s32(*samplitudes); - ++samplitudes; - accum = vmlaq_f32(accum, famplitude, famplitude); - } - - // narrow 4 lanes of floats - float32x2_t accum2 = vadd_f32(vget_low_f32(accum), vget_high_f32(accum)); // get stereo volume - accum2 = vpadd_f32(accum2, accum2); // combine to mono - - // accumulate remainder - float value = vget_lane_f32(accum2, 0); - for (; i < size; ++i) { - const float amplitude = (float)((int32_t *)amplitudes)[i]; - value += amplitude * amplitude; - } - - return value * normalizeEnergy(); -} - -// fast int32_t power computation for PCM_8_24 (essentially identical to PCM_32 above) -template <> -inline float energyMono(const void *amplitudes, size_t size) -{ - int32x4_t *samplitudes = (int32x4_t *)amplitudes; - - // clear accumulator - float32x4_t accum = vdupq_n_f32(0); - - // iterate over array getting sum of squares in 4 lanes. - size_t i; - for (i = 0; i < (size & ~3); i += 4) { - // convert s32 to f32 - float32x4_t famplitude = vcvtq_f32_s32(*samplitudes); - ++samplitudes; - accum = vmlaq_f32(accum, famplitude, famplitude); - } - - // narrow 4 lanes of floats - float32x2_t accum2 = vadd_f32(vget_low_f32(accum), vget_high_f32(accum)); // get stereo volume - accum2 = vpadd_f32(accum2, accum2); // combine to mono - - // accumulate remainder - float value = vget_lane_f32(accum2, 0); - for (; i < size; ++i) { - const float amplitude = (float)((int32_t *)amplitudes)[i]; - value += amplitude * amplitude; - } - - return value * normalizeEnergy(); -} - -#endif // USE_NEON - -} // namespace - -float audio_utils_compute_energy_mono(const void *buffer, audio_format_t format, size_t samples) -{ - switch (format) { - case AUDIO_FORMAT_PCM_8_BIT: - return energyMono(buffer, samples); - - case AUDIO_FORMAT_PCM_16_BIT: - return energyMono(buffer, samples); - - case AUDIO_FORMAT_PCM_24_BIT_PACKED: - return energyMono(buffer, samples); - - case AUDIO_FORMAT_PCM_8_24_BIT: - return energyMono(buffer, samples); - - case AUDIO_FORMAT_PCM_32_BIT: - return energyMono(buffer, samples); - - case AUDIO_FORMAT_PCM_FLOAT: - return energyMono(buffer, samples); - - default: - LOG_ALWAYS_FATAL("invalid format: %#x", format); - } -} - -float audio_utils_compute_power_mono(const void *buffer, audio_format_t format, size_t samples) -{ - return audio_utils_power_from_energy( - audio_utils_compute_energy_mono(buffer, format, samples) / samples); -} - -bool audio_utils_is_compute_power_format_supported(audio_format_t format) -{ - return isFormatSupported(format); -} - diff --git a/audio_utils/tests/Android.bp b/audio_utils/tests/Android.bp index 91eef0f0..6fa3f829 100644 --- a/audio_utils/tests/Android.bp +++ b/audio_utils/tests/Android.bp @@ -74,27 +74,3 @@ cc_binary_host { "-UNDEBUG", ], } - -cc_test { - name: "power_tests", - host_supported: true, - - shared_libs: [ - "libcutils", - "liblog", - ], - srcs: ["power_tests.cpp"], - cflags: [ - "-Wall", - "-Werror", - "-Wextra", - ], - target: { - android: { - shared_libs: ["libaudioutils"], - }, - host: { - static_libs: ["libaudioutils"], - }, - } -} diff --git a/audio_utils/tests/power_tests.cpp b/audio_utils/tests/power_tests.cpp deleted file mode 100644 index b86dac30..00000000 --- a/audio_utils/tests/power_tests.cpp +++ /dev/null @@ -1,167 +0,0 @@ -/* - * Copyright 2017 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. - */ - -//#define LOG_NDEBUG 0 -#define LOG_TAG "audio_utils_power_tests" - -#include -#include - -#include -#include -#include - -typedef struct { uint8_t c[3]; } __attribute__((__packed__)) uint8x3_t; - -void testFloatValue(float f_value, size_t length) { - const float power = audio_utils_power_from_amplitude(f_value); - float f_ary[length]; - uint8_t u8_ary[length]; - int16_t i16_ary[length]; - int32_t i32_ary[length]; - int32_t q8_23_ary[length]; - uint8x3_t p24_ary[length]; - - // magic formulas to convert floating point to fixed point representations. - // we negate the floating point value to ensure full integer range for 1.f. - const uint8_t u8_value((1.f - f_value) * 128); - const int16_t i16_value(f_value * INT16_MIN); - const int32_t i32_value (f_value * INT32_MIN); - const int32_t q8_23_value(f_value * -(1 << 23)); - - // PCM_24_BIT_PACKED is native endian. -#if HAVE_BIG_ENDIAN - const uint8x3_t p24_value{{ - uint8_t(q8_23_value >> 16), - uint8_t(q8_23_value >> 8), - uint8_t(q8_23_value), - }}; -#else - const uint8x3_t p24_value{{ - uint8_t(q8_23_value), - uint8_t(q8_23_value >> 8), - uint8_t(q8_23_value >> 16), - }}; -#endif - - for (size_t i = 0; i < length; ++i) { - f_ary[i] = f_value; - u8_ary[i] = u8_value; - i16_ary[i] = i16_value; - i32_ary[i] = i32_value; - q8_23_ary[i] = q8_23_value; - p24_ary[i] = p24_value; - } - - EXPECT_EQ(power, - audio_utils_compute_power_mono(f_ary, AUDIO_FORMAT_PCM_FLOAT, length)); - EXPECT_EQ(power, - audio_utils_compute_power_mono(u8_ary, AUDIO_FORMAT_PCM_8_BIT, length)); - EXPECT_EQ(power, - audio_utils_compute_power_mono(i16_ary, AUDIO_FORMAT_PCM_16_BIT, length)); - EXPECT_EQ(power, - audio_utils_compute_power_mono(i32_ary, AUDIO_FORMAT_PCM_32_BIT, length)); - EXPECT_EQ(power, - audio_utils_compute_power_mono(q8_23_ary, AUDIO_FORMAT_PCM_8_24_BIT, length)); - EXPECT_EQ(power, - audio_utils_compute_power_mono(p24_ary, AUDIO_FORMAT_PCM_24_BIT_PACKED, length)); -} - -void testFloatRamp(size_t length) { - float f_ary[length]; - uint8_t u8_ary[length]; - int16_t i16_ary[length]; - int32_t i32_ary[length]; - int32_t q8_23_ary[length]; - uint8x3_t p24_ary[length]; - - for (size_t i = 0; i < length; ++i) { - // must be expressed cleanly in uint8_t - const float f_value = (int(length & 0xff) - 128) / 128.f; - - // magic formulas to convert floating point to fixed point representations. - // we negate the floating point value to ensure full integer range for 1.f. - const uint8_t u8_value((1.f - f_value) * 128); - const int16_t i16_value(f_value * INT16_MIN); - const int32_t i32_value (f_value * INT32_MIN); - const int32_t q8_23_value(f_value * -(1 << 23)); - - // PCM_24_BIT_PACKED is native endian. - #if HAVE_BIG_ENDIAN - const uint8x3_t p24_value{{ - uint8_t(q8_23_value >> 16), - uint8_t(q8_23_value >> 8), - uint8_t(q8_23_value), - }}; - #else - const uint8x3_t p24_value{{ - uint8_t(q8_23_value), - uint8_t(q8_23_value >> 8), - uint8_t(q8_23_value >> 16), - }}; - #endif - - f_ary[i] = f_value; - u8_ary[i] = u8_value; - i16_ary[i] = i16_value; - i32_ary[i] = i32_value; - q8_23_ary[i] = q8_23_value; - p24_ary[i] = p24_value; - } - - const float power8 = audio_utils_compute_power_mono(u8_ary, AUDIO_FORMAT_PCM_8_BIT, length); - - EXPECT_EQ(power8, - audio_utils_compute_power_mono(f_ary, AUDIO_FORMAT_PCM_FLOAT, length)); - EXPECT_EQ(power8, - audio_utils_compute_power_mono(i16_ary, AUDIO_FORMAT_PCM_16_BIT, length)); - EXPECT_EQ(power8, - audio_utils_compute_power_mono(i32_ary, AUDIO_FORMAT_PCM_32_BIT, length)); - EXPECT_EQ(power8, - audio_utils_compute_power_mono(q8_23_ary, AUDIO_FORMAT_PCM_8_24_BIT, length)); - EXPECT_EQ(power8, - audio_utils_compute_power_mono(p24_ary, AUDIO_FORMAT_PCM_24_BIT_PACKED, length)); -} - -// power_mono implicitly tests energy_mono -TEST(audio_utils_power, power_mono) { - // f_values should have limited mantissa - for (float f_value : { 0.f, 0.25f, 0.5f, 0.75f, 1.f }) { - const float power = audio_utils_power_from_amplitude(f_value); - printf("power_mono: amplitude: %f power: %f\n", f_value, power); - - for (size_t length : { 1, 3, 5, 7, 16, 21, 32, 37 }) { - testFloatValue(f_value, length); - } - } -} - -// power_mono implicitly tests energy_mono -TEST(audio_utils_power, power_mono_ramp) { - for (size_t length : { 1, 3, 5, 7, 16, 21, 32, 37, 297 }) { - testFloatRamp(length); - } -} - -TEST(audio_utils_power, power_from) { - EXPECT_EQ(0.f, audio_utils_power_from_amplitude(1.f)); - EXPECT_EQ(-INFINITY, audio_utils_power_from_amplitude(0.f)); - EXPECT_EQ(0.f, audio_utils_power_from_amplitude(-1.f)); - - EXPECT_EQ(0.f, audio_utils_power_from_energy(1.f)); - EXPECT_EQ(-INFINITY, audio_utils_power_from_energy(0.f)); - EXPECT_TRUE(std::isnan(audio_utils_power_from_energy(-1.f))); -} -- 2.11.0