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