1 /*
2  * Copyright (c) 2023 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "intensity_processor.h"
17 
18 #include "audio_utils.h"
19 #include "sensor_log.h"
20 #include "sensors_errors.h"
21 
22 #undef LOG_TAG
23 #define LOG_TAG "IntensityProcessor"
24 
25 namespace OHOS {
26 namespace Sensors {
27 namespace {
28 constexpr double VOLUME_DB_COEF { 10.0 };
29 }  // namespace
30 
GetRMS(const std::vector<double> & data,int32_t hopLength,bool centerFlag)31 std::vector<double> IntensityProcessor::GetRMS(const std::vector<double> &data, int32_t hopLength, bool centerFlag)
32 {
33     CALL_LOG_ENTER;
34     std::vector<double> rmseEnvelop;
35     if ((data.empty()) || (hopLength < 1)) {
36         SEN_HILOGE("data is empty or hopLength is less than 1");
37         return rmseEnvelop;
38     }
39     std::vector<double> paddingData;
40     if (centerFlag) {
41         AudioUtils audioUtil;
42         paddingData = audioUtil.PadData(data, hopLength);
43     } else {
44         paddingData = data;
45     }
46     size_t paddingDataSize = paddingData.size();
47     size_t frmN = paddingDataSize / static_cast<size_t>(hopLength);
48     for (size_t i = 0; i < frmN; ++i) {
49         double accum = 0.0;
50         int32_t index = i * hopLength;
51         for (int32_t j = 0; j < hopLength; ++j, ++index) {
52             accum += pow(paddingData[index], 2);
53         }
54         rmseEnvelop.push_back(sqrt(accum / hopLength));
55     }
56     return rmseEnvelop;
57 }
58 
EnergyEnvelop(const std::vector<double> & data,int32_t nFft,int32_t hopLength)59 std::vector<double> IntensityProcessor::EnergyEnvelop(const std::vector<double> &data, int32_t nFft, int32_t hopLength)
60 {
61     std::vector<double> dataAbsPower;
62     size_t dataSize = data.size();
63     for (size_t i = 0; i < dataSize; ++i) {
64         dataAbsPower.push_back(data[i] * data[i]);
65     }
66     std::vector<double> oneFrmData;
67     std::vector<double> blockAmplitudeSum;
68     auto it = dataAbsPower.begin();
69     for (size_t i = 0; (i + nFft) < dataSize;) {
70         oneFrmData.assign(it + i, it + i + nFft);
71         double accum = accumulate(begin(oneFrmData), end(oneFrmData), 0);
72         blockAmplitudeSum.emplace_back(accum);
73         i += hopLength;
74     }
75     return blockAmplitudeSum;
76 }
77 
RmseNormalize(const std::vector<double> & rmseEnvelope,double lowerDelta,std::vector<double> & rmseBand,std::vector<int32_t> & rmseNorm)78 int32_t IntensityProcessor::RmseNormalize(const std::vector<double> &rmseEnvelope, double lowerDelta,
79     std::vector<double> &rmseBand, std::vector<int32_t> &rmseNorm)
80 {
81     CALL_LOG_ENTER;
82     if (rmseEnvelope.empty()) {
83         SEN_HILOGE("rmseEnvelope is empty");
84         return Sensors::ERROR;
85     }
86     // Set low energy to 0.
87     rmseBand = rmseEnvelope;
88     for (size_t i = 0; i < rmseBand.size(); ++i) {
89         if (rmseBand[i] < lowerDelta) {
90             rmseBand[i] = 0;
91         }
92     }
93     rmseNorm = OHOS::Sensors::NormalizePercentage(rmseBand);
94     if (rmseNorm.empty()) {
95         SEN_HILOGE("rmseNorm is empty");
96         return Sensors::ERROR;
97     }
98     return Sensors::SUCCESS;
99 }
100 
VolumeInLinary(const std::vector<double> & data,int32_t hopLength)101 std::vector<double> IntensityProcessor::VolumeInLinary(const std::vector<double> &data, int32_t hopLength)
102 {
103     CALL_LOG_ENTER;
104     std::vector<double> dataAbsPower;
105     size_t dataSize = data.size();
106     for (size_t i = 0; i < dataSize; ++i) {
107         dataAbsPower.push_back(abs(data[i]));
108     }
109     std::vector<double> oneFrmData;
110     std::vector<double> blockAmplitudeSum;
111     auto it = dataAbsPower.begin();
112     for (size_t i = 0; (i + hopLength) < dataSize;) {
113         oneFrmData.assign(it + i, it + i + hopLength);
114         double accum = accumulate(oneFrmData.begin(), oneFrmData.end(), 0);
115         blockAmplitudeSum.push_back(accum);
116         i += hopLength;
117     }
118     return blockAmplitudeSum;
119 }
120 
VolumeInDB(const std::vector<double> & data,int32_t hopLength)121 std::vector<double> IntensityProcessor::VolumeInDB(const std::vector<double> &data, int32_t hopLength)
122 {
123     CALL_LOG_ENTER;
124     std::vector<double> blockSum = EnergyEnvelop(data, hopLength, hopLength);
125     std::vector<double> db(blockSum.size(), 0.0);
126     for (size_t i = 0; i < blockSum.size(); ++i) {
127         db[i] = VOLUME_DB_COEF * log(blockSum[i]);
128         if (IsLessNotEqual(db[i], 0.0)) {
129             db[i] = 0.0;
130         }
131     }
132     return db;
133 }
134 }  // namespace Sensors
135 }  // namespace OHOS