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 #ifndef PEAK_FINDER_H
17 #define PEAK_FINDER_H
18 
19 #include <vector>
20 
21 namespace OHOS {
22 namespace Sensors {
23 /**
24  * @brief Three points on the left, middle, and right of a mountainPosition peak, aka low + high + low.
25  */
26 struct MountainPosition {
27     /** Index of the first low point on the left */
28     std::vector<int32_t> firstPos;
29     /** Index of the middle highest point on the peak */
30     std::vector<int32_t> peakPos;
31     /** Index of the last low point on the right */
32     std::vector<int32_t> lastPos;
33 };
34 
35 /** Points on both sides of the mountainPosition peak */
36 struct BothSidesOfPeak {
37     /** Index of the left low postion */
38     int32_t leftPos { 0 };
39     /** Index of the right low postion */
40     int32_t rightPos { 0 };
41 };
42 
43 /** The position and value of points on the envelope appear in pairs */
44 struct ValleyPoint {
45     std::vector<int32_t> pos;
46     std::vector<double> values;
47 };
48 
49 /**
50  * @brief Peak information.
51  */
52 struct PeaksInfo {
53     /** amplitude envelope */
54     std::vector<double> ampPeakEnvelope;
55     /** All peak point IDs */
56     std::vector<int32_t> ampPeakAllIdx;
57     /** Peak IDs, after filtered. */
58     std::vector<int32_t> ampPeakIdxs;
59     /** Filtered, corresponding time for each peak point */
60     std::vector<double> ampPeakTimes;
61 };
62 
63 /**
64  * @brief Continuous merging of several long events. Continuous merging of several short events.
65  */
66 struct EnvelopeSegmentInfo {
67     /** The starting and ending points of a paragraph. the endpoint is the starting point of the next paragraph */
68     std::vector<int32_t> demarcPos;
69     /** True, all events within this segment are long events, otherwise they are all short events */
70     std::vector<bool> continuousEventFlag;
71 };
72 
73 /** Outline Description of Peak Detection */
74 struct IsolatedEnvelopeInfo {
75     /** Whether the envelope contains long events */
76     bool isHaveContinuousEvent { false };
77     /** Number of points for the longest continuous signal */
78     int32_t longestSampleCount { 0 };
79     /** The flag of peak is a transient event. */
80     std::vector<bool> transientEventFlags;
81     MountainPosition mountainPosition;
82 };
83 
84 /**
85  * @brief Estimation of the downward trend from the peak to the lowest point on the right.
86  */
87 struct DownwardTrendInfo {
88     /** Is it a rapidly decaying peak. */
89     bool isRapidlyDecay { false };
90     /** 100 point descent height */
91     double dropHeight { 0.0 };
92     /** The proportion of descent interval in a rms-hop length. */
93     double ducyCycle { 0.0 };
94 
95     DownwardTrendInfo() = default;
DownwardTrendInfoDownwardTrendInfo96     DownwardTrendInfo(bool isDecay, double drop, double cycle)
97     {
98         isRapidlyDecay = isDecay;
99         dropHeight = drop;
100         ducyCycle = cycle;
101     }
102 };
103 
104 class PeakFinder {
105 public:
106     /**
107      * @brief Calculate peak value by difference, method: low+high+low
108      * 1. When equal to 0, all peak points are selected
109      * 2. Like heartbeat. wav, the secondary peak point is not from the lowest point and must be removed
110      *
111      * @param envelope Envelope curve of the peak point to be searched.
112      * @param peakThreshold If the peak drop is less than 'peakThreshold',
113      * it is considered not the peak. Value range 0~1.0.
114      * @return Return the index of peaks.
115      */
116     std::vector<int32_t> DetectPeak(const std::vector<double> &envelope, double peakThreshold);
117 
118     /**
119      * @brief Get the Transient By Amplitude object
120      * Find all isolated short events through the original amplitude
121      * @param data Audio time series.
122      * @param isolatedEnvelopeInfo A series of parameters for independent envelopes.
123      *
124      * @return Returns <b>0</b> if the operation is successful; returns a negative value otherwise.
125      */
126     int32_t ObtainTransientByAmplitude(const std::vector<double> &data, IsolatedEnvelopeInfo &isolatedEnvelopeInfo);
127 
128     /**
129      * @brief Get the Voice Segment Flag
130      * Must first call 'ObtainTransientByAmplitude'
131      *
132      * @return Return the Voice Segment Flags.
133      */
134     std::vector<bool> GetVoiceSegmentFlag() const;
135 
136 private:
137     bool GetDeleteFlagOfPeak(const std::vector<double> &envelope, int32_t peakIndex, int32_t valleyIndex,
138         const std::vector<double> &valleysValue, const MountainPosition &mountainPosition);
139     std::vector<double> ExtractValues(const std::vector<double> &envelope, const std::vector<int32_t> &idxs);
140     std::vector<bool> GetVoiceFlag(const std::vector<double> &data,
141         const std::vector<int32_t> &peaks, double lowerAmp);
142     void GetEachIndependentEnvelope(const std::vector<double> &data, const std::vector<int32_t> &peaks,
143         double lowerAmp, MountainPosition &mountainPosition);
144     bool FindPeakBoundary(const std::vector<double> &data, int32_t peakPlace, double threshold,
145         BothSidesOfPeak &bothSides);
146     std::vector<int32_t> PeakFilterMinRange(const std::vector<double> &data,
147         std::vector<int32_t> &peaks, int32_t minSampleCount);
148     std::vector<int32_t> FilterLowPeak(const std::vector<double> &envelope,
149         const std::vector<int32_t> &peaks, double removeRatio);
150     std::vector<bool> SplitVoiceSlienceRange(int32_t dataSize, const std::vector<int32_t> &envelopeStart,
151         const std::vector<int32_t> &envelopeLast);
152     std::vector<int32_t> FilterSecondaryPeak(const std::vector<double> &envelope,
153         const std::vector<int32_t> &peaks, double lowerAmp);
154     int32_t DeletePeaks(const std::vector<double> &envelope, int32_t startPos, int32_t endPos,
155         MountainPosition &mountainPosition, int32_t &index);
156     int32_t DetectValley(const std::vector<double> &envelope, int32_t startPos, int32_t endPos,
157         const MountainPosition &mountainPosition, ValleyPoint &valleyPoint);
158 
159     double GetLowestPeakValue(const std::vector<double> &envelope, const std::vector<int32_t> &peaks);
160     int32_t GetPeakEnvelope(const std::vector<double> &data, int32_t samplingRate, int32_t hopLength,
161         PeaksInfo &peakDetection);
162     int32_t EstimateDownwardTrend(const std::vector<double> &data, const std::vector<int32_t> &peaksPoint,
163         const std::vector<int32_t> &lastPeaksPoint, std::vector<DownwardTrendInfo> &downwardTrends);
164 
165     /**
166      * @brief Merge continuous long envelopes and continuous pure instantaneous event intervals to avoid low energy
167      *  long event outputs.
168      *
169      * between two short events, such as CoinDrop.wav.
170      * Pre processing before peak point co envelope refinement
171      * a0[0],a2[0],a0[1],a2[1]... May be discontinuous
172      * Output list_I is continuous
173      *
174      * @param dataSize Length of envelope points
175      * @param firstPos Start positions.
176      * @param lastPos Last positions.
177      * @param envelopeList Output continuous Long or Short Envelope Results.
178      */
179     void SplitLongShortEnvelope(int32_t dataSize, const std::vector<int32_t> &firstPos,
180         const std::vector<int32_t> &lastPos, EnvelopeSegmentInfo &envelopeList);
181     int32_t GetIsolatedEnvelope(const std::vector<double> &data, const std::vector<int32_t> &peaks,
182         double lowerAmp, IsolatedEnvelopeInfo &isolatedEnvelopeInfo);
183     // Descending energy
184     // 1.Energy occupation ratio(area occupation ratio)
185     // 2.Lowering energy difference
186     // Returns < b>0 < / b > if the operation is successful; returns a negative value otherwise.
187     int32_t EstimateDesentEnergy(const std::vector<double> &data, double &dropHeight, double &dutyCycle);
188 
189 private:
190     std::vector<bool> voiceSegmentFlag_;
191     int32_t hopLength_ { 1024 };
192 };
193 }  // namespace Sensors
194 }  // namespace OHOS
195 #endif // PEAK_FINDER_H