1 /*
2  * Copyright 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #ifndef AAUDIO_LINEAR_RAMP_H
18 #define AAUDIO_LINEAR_RAMP_H
19 
20 #include <atomic>
21 #include <stdint.h>
22 
23 /**
24  * Generate segments along a linear ramp.
25  * The ramp target can be updated from another thread.
26  * When the target is updated, a new ramp is started from the current position.
27  *
28  * The first ramp starts at 0.0.
29  *
30  */
31 class LinearRamp {
32 public:
LinearRamp()33     LinearRamp() {
34         mTarget.store(1.0f);
35     }
36 
setLengthInFrames(int32_t frames)37     void setLengthInFrames(int32_t frames) {
38         mLengthInFrames = frames;
39     }
40 
getLengthInFrames()41     int32_t getLengthInFrames() {
42         return mLengthInFrames;
43     }
44 
45     /**
46      * This may be called by another thread.
47      * @param target
48      */
setTarget(float target)49     void setTarget(float target) {
50         mTarget.store(target);
51     }
52 
getTarget()53     float getTarget() {
54         return mTarget.load();
55     }
56 
57     /**
58      * Force the nextSegment to start from this level.
59      *
60      * WARNING: this can cause a discontinuity if called while the ramp is being used.
61      * Only call this when setting the initial ramp.
62      *
63      * @param level
64      */
forceCurrent(float level)65     void forceCurrent(float level) {
66         mLevelFrom = level;
67         mLevelTo = level; // forces a ramp if it does not match target
68     }
69 
getCurrent()70     float getCurrent() {
71         return mLevelFrom;
72     }
73 
74     /**
75      * Get levels for next ramp segment.
76      *
77      * @param frames number of frames in the segment
78      * @param levelFrom pointer to starting amplitude
79      * @param levelTo pointer to ending amplitude
80      * @return true if ramp is still moving towards the target
81      */
82     bool nextSegment(int32_t frames, float *levelFrom, float *levelTo);
83 
84 private:
85 
86     bool isRamping();
87 
88     std::atomic<float>   mTarget;
89 
90     int32_t mLengthInFrames  = 48000 / 100; // 10 msec at 48000 Hz
91     int32_t mRemaining       = 0;
92     float   mLevelFrom       = 0.0f;
93     float   mLevelTo         = 0.0f;
94 };
95 
96 
97 #endif //AAUDIO_LINEAR_RAMP_H
98