android13/frameworks/av/media/libaaudio/examples/utils/SineGenerator.h

137 lines
4.3 KiB
C++

/*
* 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;
}
}
float next() {
float value = sinf(mPhase) * mAmplitude;
advancePhase();
return value;
}
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 * next());
sampleIndex += channelStride;
}
}
void render(float *buffer, int32_t channelStride, int32_t numFrames) {
int sampleIndex = 0;
for (int i = 0; i < numFrames; i++) {
buffer[sampleIndex] = next();
sampleIndex += channelStride;
}
}
void render(int32_t *buffer, int32_t channelStride, int32_t numFrames) {
int sampleIndex = 0;
for (int i = 0; i < numFrames; i++) {
buffer[sampleIndex] = (int32_t) (INT32_MAX * next());
sampleIndex += channelStride;
}
}
void render24(uint8_t *buffer, int32_t channelStride, int32_t numFrames) {
int sampleIndex = 0;
constexpr int32_t INT24_MAX = (1 << 23) - 1;
constexpr int bytesPerSample = getBytesPerSample(AAUDIO_FORMAT_PCM_I24_PACKED);
const bool isLittleEndian = isNativeLittleEndian();
for (int i = 0; i < numFrames; i++) {
int32_t sample = (int32_t) (INT24_MAX * next());
uint32_t usample = (uint32_t) sample;
if (isLittleEndian) {
buffer[sampleIndex] = usample; // little end first
buffer[sampleIndex + 1] = usample >> 8;
buffer[sampleIndex + 2] = usample >> 16;
} else {
buffer[sampleIndex] = usample >> 16; // big end first
buffer[sampleIndex + 1] = usample >> 8;
buffer[sampleIndex + 2] = usample;
}
sampleIndex += channelStride * bytesPerSample;
}
}
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 */