164b8787dbf65a13f36a9ae4f7c31eed3c5bc5bc3Phil Burk/*
264b8787dbf65a13f36a9ae4f7c31eed3c5bc5bc3Phil Burk * Copyright (C) 2016 The Android Open Source Project
364b8787dbf65a13f36a9ae4f7c31eed3c5bc5bc3Phil Burk *
464b8787dbf65a13f36a9ae4f7c31eed3c5bc5bc3Phil Burk * Licensed under the Apache License, Version 2.0 (the "License");
564b8787dbf65a13f36a9ae4f7c31eed3c5bc5bc3Phil Burk * you may not use this file except in compliance with the License.
664b8787dbf65a13f36a9ae4f7c31eed3c5bc5bc3Phil Burk * You may obtain a copy of the License at
764b8787dbf65a13f36a9ae4f7c31eed3c5bc5bc3Phil Burk *
864b8787dbf65a13f36a9ae4f7c31eed3c5bc5bc3Phil Burk *      http://www.apache.org/licenses/LICENSE-2.0
964b8787dbf65a13f36a9ae4f7c31eed3c5bc5bc3Phil Burk *
1064b8787dbf65a13f36a9ae4f7c31eed3c5bc5bc3Phil Burk * Unless required by applicable law or agreed to in writing, software
1164b8787dbf65a13f36a9ae4f7c31eed3c5bc5bc3Phil Burk * distributed under the License is distributed on an "AS IS" BASIS,
1264b8787dbf65a13f36a9ae4f7c31eed3c5bc5bc3Phil Burk * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1364b8787dbf65a13f36a9ae4f7c31eed3c5bc5bc3Phil Burk * See the License for the specific language governing permissions and
1464b8787dbf65a13f36a9ae4f7c31eed3c5bc5bc3Phil Burk * limitations under the License.
1564b8787dbf65a13f36a9ae4f7c31eed3c5bc5bc3Phil Burk */
1664b8787dbf65a13f36a9ae4f7c31eed3c5bc5bc3Phil Burk
1764b8787dbf65a13f36a9ae4f7c31eed3c5bc5bc3Phil Burk#ifndef SINE_GENERATOR_H
1864b8787dbf65a13f36a9ae4f7c31eed3c5bc5bc3Phil Burk#define SINE_GENERATOR_H
1964b8787dbf65a13f36a9ae4f7c31eed3c5bc5bc3Phil Burk
2064b8787dbf65a13f36a9ae4f7c31eed3c5bc5bc3Phil Burk#include <math.h>
2164b8787dbf65a13f36a9ae4f7c31eed3c5bc5bc3Phil Burk
2264b8787dbf65a13f36a9ae4f7c31eed3c5bc5bc3Phil Burkclass SineGenerator
2364b8787dbf65a13f36a9ae4f7c31eed3c5bc5bc3Phil Burk{
2464b8787dbf65a13f36a9ae4f7c31eed3c5bc5bc3Phil Burkpublic:
2564b8787dbf65a13f36a9ae4f7c31eed3c5bc5bc3Phil Burk    SineGenerator() {}
2664b8787dbf65a13f36a9ae4f7c31eed3c5bc5bc3Phil Burk    virtual ~SineGenerator() = default;
2764b8787dbf65a13f36a9ae4f7c31eed3c5bc5bc3Phil Burk
2864b8787dbf65a13f36a9ae4f7c31eed3c5bc5bc3Phil Burk    void setup(double frequency, double frameRate) {
2964b8787dbf65a13f36a9ae4f7c31eed3c5bc5bc3Phil Burk        mFrameRate = frameRate;
3064b8787dbf65a13f36a9ae4f7c31eed3c5bc5bc3Phil Burk        mPhaseIncrement = frequency * M_PI * 2 / frameRate;
3164b8787dbf65a13f36a9ae4f7c31eed3c5bc5bc3Phil Burk    }
3264b8787dbf65a13f36a9ae4f7c31eed3c5bc5bc3Phil Burk
3364b8787dbf65a13f36a9ae4f7c31eed3c5bc5bc3Phil Burk    void setSweep(double frequencyLow, double frequencyHigh, double seconds) {
3464b8787dbf65a13f36a9ae4f7c31eed3c5bc5bc3Phil Burk        mPhaseIncrementLow = frequencyLow * M_PI * 2 / mFrameRate;
3564b8787dbf65a13f36a9ae4f7c31eed3c5bc5bc3Phil Burk        mPhaseIncrementHigh = frequencyHigh * M_PI * 2 / mFrameRate;
3664b8787dbf65a13f36a9ae4f7c31eed3c5bc5bc3Phil Burk
3764b8787dbf65a13f36a9ae4f7c31eed3c5bc5bc3Phil Burk        double numFrames = seconds * mFrameRate;
3864b8787dbf65a13f36a9ae4f7c31eed3c5bc5bc3Phil Burk        mUpScaler = pow((frequencyHigh / frequencyLow), (1.0 / numFrames));
3964b8787dbf65a13f36a9ae4f7c31eed3c5bc5bc3Phil Burk        mDownScaler = 1.0 / mUpScaler;
4064b8787dbf65a13f36a9ae4f7c31eed3c5bc5bc3Phil Burk        mGoingUp = true;
4164b8787dbf65a13f36a9ae4f7c31eed3c5bc5bc3Phil Burk        mSweeping = true;
4264b8787dbf65a13f36a9ae4f7c31eed3c5bc5bc3Phil Burk    }
4364b8787dbf65a13f36a9ae4f7c31eed3c5bc5bc3Phil Burk
4464b8787dbf65a13f36a9ae4f7c31eed3c5bc5bc3Phil Burk    void render(int16_t *buffer, int32_t channelStride, int32_t numFrames) {
4564b8787dbf65a13f36a9ae4f7c31eed3c5bc5bc3Phil Burk        int sampleIndex = 0;
4664b8787dbf65a13f36a9ae4f7c31eed3c5bc5bc3Phil Burk        for (int i = 0; i < numFrames; i++) {
4764b8787dbf65a13f36a9ae4f7c31eed3c5bc5bc3Phil Burk            buffer[sampleIndex] = (int16_t) (32767 * sin(mPhase) * mAmplitude);
4864b8787dbf65a13f36a9ae4f7c31eed3c5bc5bc3Phil Burk            sampleIndex += channelStride;
4964b8787dbf65a13f36a9ae4f7c31eed3c5bc5bc3Phil Burk            advancePhase();
5064b8787dbf65a13f36a9ae4f7c31eed3c5bc5bc3Phil Burk        }
5164b8787dbf65a13f36a9ae4f7c31eed3c5bc5bc3Phil Burk    }
5264b8787dbf65a13f36a9ae4f7c31eed3c5bc5bc3Phil Burk    void render(float *buffer, int32_t channelStride, int32_t numFrames) {
5364b8787dbf65a13f36a9ae4f7c31eed3c5bc5bc3Phil Burk        int sampleIndex = 0;
5464b8787dbf65a13f36a9ae4f7c31eed3c5bc5bc3Phil Burk        for (int i = 0; i < numFrames; i++) {
5564b8787dbf65a13f36a9ae4f7c31eed3c5bc5bc3Phil Burk            buffer[sampleIndex] = sin(mPhase) * mAmplitude;
5664b8787dbf65a13f36a9ae4f7c31eed3c5bc5bc3Phil Burk            sampleIndex += channelStride;
5764b8787dbf65a13f36a9ae4f7c31eed3c5bc5bc3Phil Burk            advancePhase();
5864b8787dbf65a13f36a9ae4f7c31eed3c5bc5bc3Phil Burk        }
5964b8787dbf65a13f36a9ae4f7c31eed3c5bc5bc3Phil Burk    }
6064b8787dbf65a13f36a9ae4f7c31eed3c5bc5bc3Phil Burk
6164b8787dbf65a13f36a9ae4f7c31eed3c5bc5bc3Phil Burkprivate:
6264b8787dbf65a13f36a9ae4f7c31eed3c5bc5bc3Phil Burk    void advancePhase() {
6364b8787dbf65a13f36a9ae4f7c31eed3c5bc5bc3Phil Burk        mPhase += mPhaseIncrement;
6464b8787dbf65a13f36a9ae4f7c31eed3c5bc5bc3Phil Burk        if (mPhase > M_PI * 2) {
6564b8787dbf65a13f36a9ae4f7c31eed3c5bc5bc3Phil Burk            mPhase -= M_PI * 2;
6664b8787dbf65a13f36a9ae4f7c31eed3c5bc5bc3Phil Burk        }
6764b8787dbf65a13f36a9ae4f7c31eed3c5bc5bc3Phil Burk        if (mSweeping) {
6864b8787dbf65a13f36a9ae4f7c31eed3c5bc5bc3Phil Burk            if (mGoingUp) {
6964b8787dbf65a13f36a9ae4f7c31eed3c5bc5bc3Phil Burk                mPhaseIncrement *= mUpScaler;
7064b8787dbf65a13f36a9ae4f7c31eed3c5bc5bc3Phil Burk                if (mPhaseIncrement > mPhaseIncrementHigh) {
7164b8787dbf65a13f36a9ae4f7c31eed3c5bc5bc3Phil Burk                    mGoingUp = false;
7264b8787dbf65a13f36a9ae4f7c31eed3c5bc5bc3Phil Burk                }
7364b8787dbf65a13f36a9ae4f7c31eed3c5bc5bc3Phil Burk            } else {
7464b8787dbf65a13f36a9ae4f7c31eed3c5bc5bc3Phil Burk                mPhaseIncrement *= mDownScaler;
7564b8787dbf65a13f36a9ae4f7c31eed3c5bc5bc3Phil Burk                if (mPhaseIncrement < mPhaseIncrementLow) {
7664b8787dbf65a13f36a9ae4f7c31eed3c5bc5bc3Phil Burk                    mGoingUp = true;
7764b8787dbf65a13f36a9ae4f7c31eed3c5bc5bc3Phil Burk                }
7864b8787dbf65a13f36a9ae4f7c31eed3c5bc5bc3Phil Burk            }
7964b8787dbf65a13f36a9ae4f7c31eed3c5bc5bc3Phil Burk        }
8064b8787dbf65a13f36a9ae4f7c31eed3c5bc5bc3Phil Burk    }
8164b8787dbf65a13f36a9ae4f7c31eed3c5bc5bc3Phil Burk
82e572f469de5dca1078a79d3d80e5b04f96ae7505Phil Burk    double mAmplitude = 0.05;  // unitless scaler
8364b8787dbf65a13f36a9ae4f7c31eed3c5bc5bc3Phil Burk    double mPhase = 0.0;
8464b8787dbf65a13f36a9ae4f7c31eed3c5bc5bc3Phil Burk    double mPhaseIncrement = 440 * M_PI * 2 / 48000;
8564b8787dbf65a13f36a9ae4f7c31eed3c5bc5bc3Phil Burk    double mFrameRate = 48000;
8664b8787dbf65a13f36a9ae4f7c31eed3c5bc5bc3Phil Burk    double mPhaseIncrementLow;
8764b8787dbf65a13f36a9ae4f7c31eed3c5bc5bc3Phil Burk    double mPhaseIncrementHigh;
8864b8787dbf65a13f36a9ae4f7c31eed3c5bc5bc3Phil Burk    double mUpScaler = 1.0;
8964b8787dbf65a13f36a9ae4f7c31eed3c5bc5bc3Phil Burk    double mDownScaler = 1.0;
9064b8787dbf65a13f36a9ae4f7c31eed3c5bc5bc3Phil Burk    bool   mGoingUp = false;
9164b8787dbf65a13f36a9ae4f7c31eed3c5bc5bc3Phil Burk    bool   mSweeping = false;
9264b8787dbf65a13f36a9ae4f7c31eed3c5bc5bc3Phil Burk};
9364b8787dbf65a13f36a9ae4f7c31eed3c5bc5bc3Phil Burk
9464b8787dbf65a13f36a9ae4f7c31eed3c5bc5bc3Phil Burk#endif /* SINE_GENERATOR_H */
9564b8787dbf65a13f36a9ae4f7c31eed3c5bc5bc3Phil Burk
96