From 423da0eb5fca091f249f6d456bc54f3141edcdf2 Mon Sep 17 00:00:00 2001 From: hellohyh001 Date: Sat, 10 Jun 2023 13:50:37 +0000 Subject: [PATCH] Audio frequency rotary vibration (part 3) Signed-off-by: hellohyh001 Change-Id: I721ca0b1ca253965316cd2d84799a1620f5eb1df --- vibration_convert/core/utils/include/utils.h | 278 +++++++++++++++++++ vibration_convert/core/utils/src/utils.cpp | 261 +++++++++++++++++ 2 files changed, 539 insertions(+) create mode 100644 vibration_convert/core/utils/include/utils.h create mode 100644 vibration_convert/core/utils/src/utils.cpp diff --git a/vibration_convert/core/utils/include/utils.h b/vibration_convert/core/utils/include/utils.h new file mode 100644 index 00000000..bc9159ef --- /dev/null +++ b/vibration_convert/core/utils/include/utils.h @@ -0,0 +1,278 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * 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 CONVERSION_UTILS_H +#define CONVERSION_UTILS_H + +#include +#include +#include +#include +#include + +namespace OHOS { +namespace Sensors { +namespace { +constexpr double MIN_LOG_HZ = 1000.0; +constexpr double MIN_LOG_MEL = 15.0; +constexpr double FSP = 66.6666666667; +constexpr double MIN_F = 0.0; +constexpr double LOG_STEP = 0.06875177742094912; +constexpr double MAXFRE = 8000.0; +constexpr double HZ_COEF = 700.0; +constexpr double MEL_COEF = 2595.0; +constexpr int32_t LOG_BASE = 10; +constexpr double EPS_MIN = 1e-10; +constexpr int32_t NFFT = 2048; +constexpr int32_t ONSET_HOP_LEN = 512; +constexpr int32_t ENERGY_HOP_LEN = 1024; +constexpr int32_t WINDOW_LENGTH = ENERGY_HOP_LEN / 2; +constexpr int32_t MAGS_SIZE = NFFT / 2; +constexpr int32_t SAMPLE_RATE = 22050; +constexpr int32_t FRM_LEN = 2048; +constexpr double F_HALF = 0.5; +constexpr double F_THREE = 3.0; +constexpr double SAMPLE_IN_MS = 1000.0; +constexpr double INTERSITY_BOUNDARY_POINT = 0.25; +constexpr double INTERSITY_NUMBER_BOUNDARY_POINT = 0.75; +} // namespace + +enum WindowType { + WND_TYPE_BARTLETT = 1, + WND_TYPE_HAMMING = 2, + WND_TYPE_HANNING = 3, +}; + +bool IsPowerOfTwo(uint32_t x); +uint32_t ObtainNumberOfBits(uint32_t powerOfTwo); +uint32_t ReverseBits(uint32_t index, uint32_t numBits); + +/** + * @brief Matrix transpose + * + * @param rows Number of rows + * @param values Matrix + * + * @return Returns the transposed matrix. + */ +std::vector TransposeMatrix(size_t rows, const std::vector &values); + +/** + * @brief Make ID unique + * idx and time appear in pairs + * + * @param idx Original series indexs. + * @param time Original series times. + * @param newIdx Processed indexs. + * @param newTime Processed times. + * + * @return Returns 0 if the operation is successful; returns a negative value otherwise. + */ +int32_t UniqueIdx(const std::vector &idx, const std::vector &time, std::vector &newIdx, + std::vector &newTime); + +/** + * @brief Find the minimum and maximum in Orignal 'values', convert the values into numbers ranging from 0 to 100. + * + * @param values Original values + * + * @return Return the numbers ranging from 0 to 100. + */ +std::vector NormalizePercentage(const std::vector &values); + +/** + * @brief The minimum is 0, convert the values into numbers ranging from 0 to 100. + * + * @param values Original values + * + * @return Return the numbers ranging from 0 to 100. + */ +std::vector NormalizePercentageMin(const std::vector &values); + +/** + * @brief Based on the given minimum and maximum range, convert the values into numbers ranging from 0 to 100. + * + * @param values Original values + * @param minValue The minimum of range. + * @param maxValue The maximum of range. + * + * @return Return the numbers ranging from 0 to 100. + */ +std::vector NormalizePercentageRange(const std::vector &values, double minValue, double maxValue); + +/** + * @brief Processing of effective values for filling in mute positions. + * + * @param values A set of volume(DB or HZ) values. + * @param voiceFlag A set of voice and mute flags. + * @param volumeData A set of volume values. + * @param invalidValues Processed result, include valid values only. + * + * @return Returns 0 if the operation is successful; returns a negative value otherwise. + */ +int32_t ProcessSilence(const std::vector &values, const std::vector &voiceFlag, + const std::vector &volumeData, std::vector &invalidValues); + +/** + * @brief Small window amplitude envelope. + * + * @param data Audio time series. + * @param count length of analysis frame (in samples) for energy calculation + * @param hopLength Hop length + * + * @return Returns amplitude value for each frame + */ +std::vector ObtainAmplitudeEnvelop(const std::vector &data, size_t count, size_t hopLength); + +inline double ConvertSlaneyMel(double hz) +{ + return MEL_COEF * (log10(hz / HZ_COEF + 1.0)); +} + +inline double ConvertSlaneyHz(double mel) +{ + return HZ_COEF * (pow(LOG_BASE, mel / MEL_COEF) - 1.0); +} + +inline bool IsLessOrEqual(double left, double right, const double epsilon) +{ + return (left - right) < epsilon; +} + +template +constexpr bool IsLessOrEqual(const T& left, const T& right); + +template<> +inline bool IsLessOrEqual(const float& left, const float& right) +{ + constexpr double epsilon = std::numeric_limits::epsilon(); + return IsLessOrEqual(left, right, epsilon); +} + +template<> +inline bool IsLessOrEqual(const double& left, const double& right) +{ + constexpr double epsilon = std::numeric_limits::epsilon(); + return IsLessOrEqual(left, right, epsilon); +} + +inline bool IsGreatOrEqual(double left, double right, const double epsilon) +{ + return (left - right) > epsilon; +} + +template +constexpr bool IsGreatOrEqual(const T& left, const T& right); + +template<> +inline bool IsGreatOrEqual(const float& left, const float& right) +{ + constexpr double epsilon = -std::numeric_limits::epsilon(); + return IsGreatOrEqual(left, right, epsilon); +} + +template<> +inline bool IsGreatOrEqual(const double& left, const double& right) +{ + constexpr double epsilon = -std::numeric_limits::epsilon(); + return IsGreatOrEqual(left, right, epsilon); +} + +inline bool IsLessNotEqual(double left, double right, const double epsilon) +{ + return (left - right) < epsilon; +} + +template +constexpr bool IsLessNotEqual(const T& left, const T& right); + +template<> +inline bool IsLessNotEqual(const float& left, const float& right) +{ + constexpr double epsilon = -std::numeric_limits::epsilon(); + return IsLessNotEqual(left, right, epsilon); +} + +template<> +inline bool IsLessNotEqual(const double& left, const double& right) +{ + constexpr double epsilon = -std::numeric_limits::epsilon(); + return IsLessNotEqual(left, right, epsilon); +} + +inline bool IsGreatNotEqual(double left, double right, const double epsilon) +{ + return (left - right) > epsilon; +} + +template +constexpr bool IsGreatNotEqual(const T& left, const T& right); + +template<> +inline bool IsGreatNotEqual(const float& left, const float& right) +{ + constexpr double epsilon = std::numeric_limits::epsilon(); + return IsGreatNotEqual(left, right, epsilon); +} + +template<> +inline bool IsGreatNotEqual(const double& left, const double& right) +{ + constexpr double epsilon = std::numeric_limits::epsilon(); + return IsGreatNotEqual(left, right, epsilon); +} + +inline bool IsEqual(double left, double right, const double epsilon) +{ + return (std::abs(left - right) <= epsilon); +} + +template +constexpr bool IsEqual(const T& left, const T& right); + +template<> +inline bool IsEqual(const float& left, const float& right) +{ + constexpr double epsilon = std::numeric_limits::epsilon(); + return IsEqual(left, right, epsilon); +} + +template<> +inline bool IsEqual(const double& left, const double& right) +{ + constexpr double epsilon = std::numeric_limits::epsilon(); + return IsEqual(left, right, epsilon); +} + +inline double ConvertHtkMel(double frequencies) +{ + double mels = (frequencies - MIN_F) / FSP; + if (IsGreatOrEqual(frequencies, MIN_LOG_HZ)) { + mels = (MIN_LOG_HZ - MIN_F) / FSP + log(frequencies / MIN_LOG_HZ) / LOG_STEP; + } + return mels; +} + +inline double ConvertHtkHz(double mels) +{ + double freqs = MIN_F + FSP * mels; + if (IsGreatOrEqual(mels, MIN_LOG_MEL)) { + freqs = MIN_LOG_HZ * exp(LOG_STEP * (mels - MIN_LOG_MEL)); + } + return freqs; +} +} // namespace Sensors +} // namespace OHOS +#endif \ No newline at end of file diff --git a/vibration_convert/core/utils/src/utils.cpp b/vibration_convert/core/utils/src/utils.cpp new file mode 100644 index 00000000..1c03a9bb --- /dev/null +++ b/vibration_convert/core/utils/src/utils.cpp @@ -0,0 +1,261 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * 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. + */ + +#include "utils.h" + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "sensor_log.h" +#include "sensors_errors.h" + +namespace OHOS { +namespace Sensors { +namespace{ +constexpr OHOS::HiviewDFX::HiLogLabel LABEL = { LOG_CORE, SENSOR_LOG_DOMAIN, "Utils" }; +constexpr double PERCENTAGE_RANGE = 100.0; +constexpr int32_t VOICE_MIN_INTENSITY_NORM = 25; +constexpr size_t MAX_SIZE = 26460000; +} // namespace + +bool IsPowerOfTwo(uint32_t x) +{ + if ((x & (x - 1)) || (x < 2)) { + return false; + } + return true; +} + +uint32_t ObtainNumberOfBits(uint32_t powerOfTwo) +{ + if (powerOfTwo < 2) { + SEN_HILOGE("powerOfTwo is an invalid value"); + return 0; + } + for (uint32_t i = 0;; i++) { + if (powerOfTwo & (1 << i)) { + return i; + } + } + return 0; +} + +uint32_t ReverseBits(uint32_t index, uint32_t numBits) +{ + uint32_t rev = 0; + for (uint32_t i = 0; i < numBits; i++) { + rev = (rev << 1) | (index & 1); + index >>= 1; + } + return rev; +} + +std::vector TransposeMatrix(size_t rows, const std::vector &values) +{ + CALL_LOG_ENTER; + size_t valuesSize = values.size(); + SEN_HILOGD("valuesSize:%{public}zu", valuesSize); + if ((rows == 0) || (valuesSize == 0) || (valuesSize > MAX_SIZE)) { + SEN_HILOGE("Parameter error"); + return {}; + } + std::vector dst(valuesSize, 0.0); + size_t cols = valuesSize / rows; + size_t index = 0; + if ((((cols - 1) * rows) + (rows - 1)) >= valuesSize) { + SEN_HILOGE("dst cross-border access"); + return {}; + } + for (size_t i = 0; i < rows; i++) { + for (size_t j = 0; j < cols; j++) { + dst[j * rows + i] = values[index++]; + } + } + return dst; +} + +int32_t UniqueIdx(const std::vector &idx, const std::vector &time, std::vector &newIdx, + std::vector &newTime) +{ + CALL_LOG_ENTER; + if (idx.size() != time.size()) { + SEN_HILOGE("size of idx and time vectors not equal"); + return Sensors::ERROR; + } + int32_t oldIdxLen = static_cast(idx.size()); + int32_t idxLen = oldIdxLen; + if (idxLen < 1) { + return Sensors::SUCCESS; + } + newIdx = idx; + newTime = time; + int32_t preIdx = newIdx[0]; + int32_t i = 1; + while (i < idxLen) { + if (newIdx[i] == preIdx) { + newIdx.erase(newIdx.begin() + i); + newTime.erase(newTime.begin() + i); + --i; + --idxLen; + } + preIdx = newIdx[i]; + ++i; + } + if (idxLen != oldIdxLen) { + SEN_HILOGI("Idx unique process"); + } + return Sensors::SUCCESS; +} + +std::vector NormalizePercentage(const std::vector &values) +{ + CALL_LOG_ENTER; + double minValue = *min_element(values.begin(), values.end()); + double maxValue = *max_element(values.begin(), values.end()); + double range = maxValue - minValue; + if (IsLessNotEqual(range, EPS_MIN)) { + SEN_HILOGE("range is less than EPS_MIN"); + return {}; + } + std::vector norm; + for (size_t i = 0; i < values.size(); i++) { + norm.push_back(static_cast(round((values[i] - minValue) / range * PERCENTAGE_RANGE ))); + } + return norm; +} + +std::vector NormalizePercentageMin(const std::vector &values) +{ + CALL_LOG_ENTER; + std::vector trimValues = values; + for (size_t i = 0; i < trimValues.size(); i++) { + if (IsLessNotEqual(trimValues[i], 0.0)) { + trimValues[i] = 0.0; + } + } + double minValue = 0.0; + double maxValue = *max_element(trimValues.begin(), trimValues.end()); + double range = maxValue - minValue; + if (IsLessNotEqual(range, EPS_MIN)) { + SEN_HILOGE("range is less than EPS_MIN"); + return {}; + } + std::vector normValues; + for (size_t i = 0; i < trimValues.size(); i++) { + normValues.push_back(static_cast(round((values[i] - minValue) / range * PERCENTAGE_RANGE))); + } + return normValues; +} + +std::vector NormalizePercentageRange(const std::vector &values, double minValue, double maxValue) +{ + CALL_LOG_ENTER; + std::vector trimValues = values; + std::vector norm; + for (size_t i = 0; i < trimValues.size(); i++) { + if (IsLessNotEqual(trimValues[i], minValue)) { + trimValues[i] = minValue; + } + if (IsGreatNotEqual(trimValues[i], maxValue)) { + trimValues[i] = maxValue; + } + } + double range = maxValue - minValue; + if (IsLessNotEqual(range, EPS_MIN)) { + SEN_HILOGE("range is less than EPS_MIN"); + return {}; + } + for (size_t i = 0; i < trimValues.size(); i++) { + norm.push_back(static_cast(round((values[i] - minValue) / range * PERCENTAGE_RANGE))); + } + return norm; +} + +int32_t ProcessSilence(const std::vector &values, const std::vector &voiceFlag, + const std::vector &volumeData, std::vector &invalidValues) +{ + CALL_LOG_ENTER; + std::vector flag; + if (!volumeData.empty()) { + for (size_t i = 0; i < volumeData.size(); i++) { + if (volumeData[i] > VOICE_MIN_INTENSITY_NORM) { + flag.push_back(true); + } else { + flag.push_back(false); + } + } + } else { + if (voiceFlag.size() < 1) { + SEN_HILOGE("The voice flag do not preprocess"); + return Sensors::ERROR; + } + flag = voiceFlag; + } + invalidValues = values; + double preUnzero = -1; + bool bExist = false; + for (size_t j = 0; j < invalidValues.size(); j++) { + if (flag[j]) { + preUnzero = invalidValues[j]; + bExist = true; + break; + } + } + if (bExist) { + for (size_t k = 0; k < invalidValues.size(); k++) { + if (!flag[k]) { + invalidValues[k] = preUnzero; + } else { + preUnzero = invalidValues[k]; + } + } + } else { + SEN_HILOGI("The audio is silence"); + } + return Sensors::SUCCESS; +} + +std::vector ObtainAmplitudeEnvelop(const std::vector &data, size_t count, size_t hopLength) +{ + CALL_LOG_ENTER; + if (data.empty() || (data.size() < count)) { + SEN_HILOGE("data is empty or data is less than count"); + return {}; + } + std::vector absData; + for (size_t i = 0; i < data.size(); i++) { + absData.push_back(fabs(data[i])); + } + std::vector partAmplitude; + std::vector enery; + std::vector::iterator it = absData.begin(); + double accum = 0.0; + for (size_t j = 0; j < (data.size() - count);) { + partAmplitude.assign(it + j, it + j + count); + accum = accumulate(partAmplitude.begin(), partAmplitude.end(), 0); + enery.push_back(accum); + j += hopLength; + } + return enery; +} +} // namespace Sensors +} // namespace OHOS \ No newline at end of file -- Gitee