1/*
2 * Copyright (C) 2016 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 SINE_GENERATOR_H
18#define SINE_GENERATOR_H
19
20#include <math.h>
21
22class SineGenerator
23{
24public:
25    SineGenerator() {}
26    virtual ~SineGenerator() = default;
27
28    void setup(double frequency, double frameRate) {
29        mFrameRate = frameRate;
30        mPhaseIncrement = frequency * M_PI * 2 / frameRate;
31    }
32
33    void setSweep(double frequencyLow, double frequencyHigh, double seconds) {
34        mSweeping = seconds > 0.0;
35        if (mSweeping) {
36            mPhaseIncrementLow = frequencyLow * M_PI * 2 / mFrameRate;
37            mPhaseIncrementHigh = frequencyHigh * M_PI * 2 / mFrameRate;
38            double numFrames = seconds * mFrameRate;
39            mUpScaler = pow((frequencyHigh / frequencyLow), (1.0 / numFrames));
40            mDownScaler = 1.0 / mUpScaler;
41        }
42    }
43
44    void render(int16_t *buffer, int32_t channelStride, int32_t numFrames) {
45        int sampleIndex = 0;
46        for (int i = 0; i < numFrames; i++) {
47            buffer[sampleIndex] = (int16_t) (INT16_MAX * sin(mPhase) * mAmplitude);
48            sampleIndex += channelStride;
49            advancePhase();
50        }
51    }
52    void render(float *buffer, int32_t channelStride, int32_t numFrames) {
53        int sampleIndex = 0;
54        for (int i = 0; i < numFrames; i++) {
55            buffer[sampleIndex] = sin(mPhase) * mAmplitude;
56            sampleIndex += channelStride;
57            advancePhase();
58        }
59    }
60
61    void setAmplitude(double amplitude) {
62        mAmplitude = amplitude;
63    }
64
65    double getAmplitude() const {
66        return mAmplitude;
67    }
68
69private:
70    void advancePhase() {
71        mPhase += mPhaseIncrement;
72        if (mPhase > M_PI * 2) {
73            mPhase -= M_PI * 2;
74        }
75        if (mSweeping) {
76            if (mGoingUp) {
77                mPhaseIncrement *= mUpScaler;
78                if (mPhaseIncrement > mPhaseIncrementHigh) {
79                    mGoingUp = false;
80                }
81            } else {
82                mPhaseIncrement *= mDownScaler;
83                if (mPhaseIncrement < mPhaseIncrementLow) {
84                    mGoingUp = true;
85                }
86            }
87        }
88    }
89
90    double mAmplitude = 0.05;  // unitless scaler
91    double mPhase = 0.0;
92    double mPhaseIncrement = 440 * M_PI * 2 / 48000;
93    double mFrameRate = 48000;
94    double mPhaseIncrementLow;
95    double mPhaseIncrementHigh;
96    double mUpScaler = 1.0;
97    double mDownScaler = 1.0;
98    bool   mGoingUp = false;
99    bool   mSweeping = false;
100};
101
102#endif /* SINE_GENERATOR_H */
103
104