xref: /aosp_15_r20/external/oboe/samples/shared/SynthSound.h (revision 05767d913155b055644481607e6fa1e35e2fe72c)
1*05767d91SRobert Wu /*
2*05767d91SRobert Wu  * Copyright 2018 The Android Open Source Project
3*05767d91SRobert Wu  *
4*05767d91SRobert Wu  * Licensed under the Apache License, Version 2.0 (the "License");
5*05767d91SRobert Wu  * you may not use this file except in compliance with the License.
6*05767d91SRobert Wu  * You may obtain a copy of the License at
7*05767d91SRobert Wu  *
8*05767d91SRobert Wu  *      http://www.apache.org/licenses/LICENSE-2.0
9*05767d91SRobert Wu  *
10*05767d91SRobert Wu  * Unless required by applicable law or agreed to in writing, software
11*05767d91SRobert Wu  * distributed under the License is distributed on an "AS IS" BASIS,
12*05767d91SRobert Wu  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*05767d91SRobert Wu  * See the License for the specific language governing permissions and
14*05767d91SRobert Wu  * limitations under the License.
15*05767d91SRobert Wu  */
16*05767d91SRobert Wu #ifndef SHARED_SYNTH_SOUND_H
17*05767d91SRobert Wu #define SHARED_SYNTH_SOUND_H
18*05767d91SRobert Wu #include <cstdint>
19*05767d91SRobert Wu #include <atomic>
20*05767d91SRobert Wu #include <math.h>
21*05767d91SRobert Wu #include <memory>
22*05767d91SRobert Wu #include "IRenderableAudio.h"
23*05767d91SRobert Wu constexpr float kDefaultFrequency = 440.0;
24*05767d91SRobert Wu constexpr int32_t kDefaultSampleRate = 48000;
25*05767d91SRobert Wu constexpr float kPi = M_PI;
26*05767d91SRobert Wu constexpr float kTwoPi = kPi * 2;
27*05767d91SRobert Wu constexpr int32_t kNumSineWaves = 5;
28*05767d91SRobert Wu constexpr float kSustainMultiplier = 0.99999;
29*05767d91SRobert Wu constexpr float kReleaseMultiplier = 0.999;
30*05767d91SRobert Wu // Stop playing music below this cutoff
31*05767d91SRobert Wu constexpr float kMasterAmplitudeCutOff = 0.01;
32*05767d91SRobert Wu 
33*05767d91SRobert Wu class SynthSound : public IRenderableAudio {
34*05767d91SRobert Wu 
35*05767d91SRobert Wu public:
SynthSound()36*05767d91SRobert Wu     SynthSound() {
37*05767d91SRobert Wu 
38*05767d91SRobert Wu     }
39*05767d91SRobert Wu 
~SynthSound()40*05767d91SRobert Wu     ~SynthSound() {
41*05767d91SRobert Wu 
42*05767d91SRobert Wu     };
43*05767d91SRobert Wu 
noteOn()44*05767d91SRobert Wu     void noteOn() {
45*05767d91SRobert Wu         mTrigger = true; // start a note envelope
46*05767d91SRobert Wu         mAmplitudeScaler = kSustainMultiplier;
47*05767d91SRobert Wu     }
48*05767d91SRobert Wu 
noteOff()49*05767d91SRobert Wu     void noteOff() {
50*05767d91SRobert Wu         mAmplitudeScaler = kReleaseMultiplier;
51*05767d91SRobert Wu     }
52*05767d91SRobert Wu 
setSampleRate(int32_t sampleRate)53*05767d91SRobert Wu     void setSampleRate(int32_t sampleRate) {
54*05767d91SRobert Wu         mSampleRate = sampleRate;
55*05767d91SRobert Wu         updatePhaseIncrement();
56*05767d91SRobert Wu     };
setFrequency(float frequency)57*05767d91SRobert Wu     void setFrequency(float frequency) {
58*05767d91SRobert Wu         mFrequency = frequency;
59*05767d91SRobert Wu         updatePhaseIncrement();
60*05767d91SRobert Wu     };
61*05767d91SRobert Wu     // Amplitudes from https://epubs.siam.org/doi/pdf/10.1137/S00361445003822
setAmplitude(float amplitude)62*05767d91SRobert Wu     inline void setAmplitude(float amplitude) {
63*05767d91SRobert Wu         mAmplitudes[0] = amplitude * .2f;
64*05767d91SRobert Wu         mAmplitudes[1] = amplitude;
65*05767d91SRobert Wu         mAmplitudes[2] = amplitude * .1f;
66*05767d91SRobert Wu         mAmplitudes[3] = amplitude * .02f;
67*05767d91SRobert Wu         mAmplitudes[4] = amplitude * .15f;
68*05767d91SRobert Wu     };
69*05767d91SRobert Wu     // From IRenderableAudio
renderAudio(float * audioData,int32_t numFrames)70*05767d91SRobert Wu     void renderAudio(float *audioData, int32_t numFrames) override {
71*05767d91SRobert Wu         for (int i = 0; i < numFrames; ++i) {
72*05767d91SRobert Wu             if (mTrigger.exchange(false)) {
73*05767d91SRobert Wu                 mMasterAmplitude = 1.0;
74*05767d91SRobert Wu                 mPhase = 0.0f;
75*05767d91SRobert Wu             } else {
76*05767d91SRobert Wu                 mMasterAmplitude *= mAmplitudeScaler;
77*05767d91SRobert Wu             }
78*05767d91SRobert Wu 
79*05767d91SRobert Wu             audioData[i] = 0;
80*05767d91SRobert Wu             if (mMasterAmplitude < kMasterAmplitudeCutOff) {
81*05767d91SRobert Wu                 continue;
82*05767d91SRobert Wu             }
83*05767d91SRobert Wu             for (int j = 0; j < kNumSineWaves; ++j) {
84*05767d91SRobert Wu                 audioData[i] += sinf(mPhase * (j + 1)) * mAmplitudes[j] * mMasterAmplitude;
85*05767d91SRobert Wu             }
86*05767d91SRobert Wu             mPhase += mPhaseIncrement;
87*05767d91SRobert Wu             if (mPhase > kTwoPi) {
88*05767d91SRobert Wu                 mPhase -=  kTwoPi;
89*05767d91SRobert Wu             }
90*05767d91SRobert Wu         }
91*05767d91SRobert Wu     };
92*05767d91SRobert Wu 
93*05767d91SRobert Wu private:
94*05767d91SRobert Wu     std::atomic<bool> mTrigger { false };
95*05767d91SRobert Wu     float mMasterAmplitude = 0.0f;
96*05767d91SRobert Wu     std::atomic<float> mAmplitudeScaler { 0.0f };
97*05767d91SRobert Wu     std::array<std::atomic<float>, kNumSineWaves> mAmplitudes;
98*05767d91SRobert Wu     float mPhase = 0.0f;
99*05767d91SRobert Wu     std::atomic<float> mPhaseIncrement { 0 };
100*05767d91SRobert Wu     std::atomic<float> mFrequency { kDefaultFrequency };
101*05767d91SRobert Wu     std::atomic<int32_t> mSampleRate { kDefaultSampleRate };
updatePhaseIncrement()102*05767d91SRobert Wu     void updatePhaseIncrement(){
103*05767d91SRobert Wu         // Note how there is a division here. If this file is changed so that updatePhaseIncrement
104*05767d91SRobert Wu         // is called more frequently, please cache 1/mSampleRate. This allows this operation to not
105*05767d91SRobert Wu         // need divisions.
106*05767d91SRobert Wu         mPhaseIncrement = kTwoPi * mFrequency / static_cast<float>(mSampleRate);
107*05767d91SRobert Wu     };
108*05767d91SRobert Wu };
109*05767d91SRobert Wu #endif //SHARED_SYNTH_SOUND_H
110