blob: 9e6d46d5f1f330d64963d38a3bc645e5bd666924 [file] [log] [blame]
/*
* Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef SINE_GENERATOR_H
#define SINE_GENERATOR_H
#include <math.h>
class SineGenerator
{
public:
SineGenerator() {}
virtual ~SineGenerator() = default;
void setup(double frequency, double frameRate) {
mFrameRate = frameRate;
mPhaseIncrement = frequency * M_PI * 2 / frameRate;
}
void setSweep(double frequencyLow, double frequencyHigh, double seconds) {
mSweeping = seconds > 0.0;
if (mSweeping) {
mPhaseIncrementLow = frequencyLow * M_PI * 2 / mFrameRate;
mPhaseIncrementHigh = frequencyHigh * M_PI * 2 / mFrameRate;
double numFrames = seconds * mFrameRate;
mUpScaler = pow((frequencyHigh / frequencyLow), (1.0 / numFrames));
mDownScaler = 1.0 / mUpScaler;
}
}
void render(int16_t *buffer, int32_t channelStride, int32_t numFrames) {
int sampleIndex = 0;
for (int i = 0; i < numFrames; i++) {
buffer[sampleIndex] = (int16_t) (INT16_MAX * sin(mPhase) * mAmplitude);
sampleIndex += channelStride;
advancePhase();
}
}
void render(float *buffer, int32_t channelStride, int32_t numFrames) {
int sampleIndex = 0;
for (int i = 0; i < numFrames; i++) {
buffer[sampleIndex] = sin(mPhase) * mAmplitude;
sampleIndex += channelStride;
advancePhase();
}
}
void setAmplitude(double amplitude) {
mAmplitude = amplitude;
}
double getAmplitude() const {
return mAmplitude;
}
private:
void advancePhase() {
mPhase += mPhaseIncrement;
if (mPhase > M_PI * 2) {
mPhase -= M_PI * 2;
}
if (mSweeping) {
if (mGoingUp) {
mPhaseIncrement *= mUpScaler;
if (mPhaseIncrement > mPhaseIncrementHigh) {
mGoingUp = false;
}
} else {
mPhaseIncrement *= mDownScaler;
if (mPhaseIncrement < mPhaseIncrementLow) {
mGoingUp = true;
}
}
}
}
double mAmplitude = 0.05; // unitless scaler
double mPhase = 0.0;
double mPhaseIncrement = 440 * M_PI * 2 / 48000;
double mFrameRate = 48000;
double mPhaseIncrementLow;
double mPhaseIncrementHigh;
double mUpScaler = 1.0;
double mDownScaler = 1.0;
bool mGoingUp = false;
bool mSweeping = false;
};
#endif /* SINE_GENERATOR_H */