xref: /aosp_15_r20/external/oboe/apps/OboeTester/app/src/main/cpp/synth/SynthTools.h (revision 05767d913155b055644481607e6fa1e35e2fe72c)
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 SYNTHMARK_SYNTHTOOLS_H
18 #define SYNTHMARK_SYNTHTOOLS_H
19 
20 #include <cmath>
21 #include <cstdint>
22 
23 namespace marksynth {
24 typedef float synth_float_t;
25 
26 // The number of frames that are synthesized at one time.
27 constexpr int kSynthmarkFramesPerRender  =  8;
28 
29 constexpr int kSynthmarkSampleRate = 48000;
30 constexpr int kSynthmarkMaxVoices   = 1024;
31 
32 /**
33  * A fractional amplitude corresponding to exactly -96 dB.
34  * amplitude = pow(10.0, db/20.0)
35  */
36 constexpr double kAmplitudeDb96 = 1.0 / 63095.73444801943;
37 
38 /** A fraction that is approximately -90.3 dB. Defined as 1 bit of an S16. */
39 constexpr double kAmplitudeDb90 = 1.0 / (1 << 15);
40 
41 class SynthTools
42 {
43 public:
44 
fillBuffer(synth_float_t * output,int32_t numSamples,synth_float_t value)45     static void fillBuffer(synth_float_t *output,
46                                   int32_t numSamples,
47                                   synth_float_t value) {
48         for (int i = 0; i < numSamples; i++) {
49             *output++ = value;
50         }
51     }
52 
scaleBuffer(const synth_float_t * input,synth_float_t * output,int32_t numSamples,synth_float_t multiplier)53     static void scaleBuffer(const synth_float_t *input,
54                                   synth_float_t *output,
55                                   int32_t numSamples,
56                                   synth_float_t multiplier) {
57         for (int i = 0; i < numSamples; i++) {
58             *output++ = *input++ * multiplier;
59         }
60     }
61 
scaleOffsetBuffer(const synth_float_t * input,synth_float_t * output,int32_t numSamples,synth_float_t multiplier,synth_float_t offset)62     static void scaleOffsetBuffer(const synth_float_t *input,
63                                   synth_float_t *output,
64                                   int32_t numSamples,
65                                   synth_float_t multiplier,
66                                   synth_float_t offset) {
67         for (int i = 0; i < numSamples; i++) {
68             *output++ = (*input++ * multiplier) + offset;
69         }
70     }
71 
mixBuffers(const synth_float_t * input1,synth_float_t gain1,const synth_float_t * input2,synth_float_t gain2,synth_float_t * output,int32_t numSamples)72     static void mixBuffers(const synth_float_t *input1,
73                            synth_float_t gain1,
74                            const synth_float_t *input2,
75                            synth_float_t gain2,
76                            synth_float_t *output,
77                            int32_t numSamples) {
78         for (int i = 0; i < numSamples; i++) {
79             *output++ = (*input1++ * gain1) + (*input2++ * gain2);
80         }
81     }
82 
multiplyBuffers(const synth_float_t * input1,const synth_float_t * input2,synth_float_t * output,int32_t numSamples)83     static void multiplyBuffers(const synth_float_t *input1,
84                                        const synth_float_t *input2,
85                                        synth_float_t *output,
86                                        int32_t numSamples) {
87         for (int i = 0; i < numSamples; i++) {
88             *output++ = *input1++ * *input2;
89         }
90     }
91 
convertTimeToExponentialScaler(synth_float_t duration,synth_float_t sampleRate)92     static double convertTimeToExponentialScaler(synth_float_t duration, synth_float_t sampleRate) {
93         // Calculate scaler so that scaler^frames = target/source
94         synth_float_t numFrames = duration * sampleRate;
95         return pow(kAmplitudeDb90, (1.0 / numFrames));
96     }
97 
98     /**
99      * Calculate sine using a Taylor expansion.
100      * Code is based on SineOscillator from JSyn.
101      *
102      * @param phase between -PI and +PI
103      */
fastSine(synth_float_t phase)104     static synth_float_t fastSine(synth_float_t phase) {
105         // Factorial coefficients.
106         const synth_float_t IF3 = 1.0 / (2 * 3);
107         const synth_float_t IF5 = IF3 / (4 * 5);
108         const synth_float_t IF7 = IF5 / (6 * 7);
109         const synth_float_t IF9 = IF7 / (8 * 9);
110         const synth_float_t IF11 = IF9 / (10 * 11);
111 
112         /* Wrap phase back into region where results are more accurate. */
113         synth_float_t x = (phase > M_PI_2) ? M_PI - phase
114         : ((phase < -M_PI_2) ? -(M_PI + phase) : phase);
115 
116         synth_float_t x2 = (x * x);
117         /* Taylor expansion out to x**11/11! factored into multiply-adds */
118         return x * (x2 * (x2 * (x2 * (x2 * ((x2 * (-IF11)) + IF9) - IF7) + IF5) - IF3) + 1);
119     }
120 
121     /**
122      * Calculate cosine using a Taylor expansion.
123      *
124      * @param phase between -PI and +PI
125      */
fastCosine(synth_float_t phase)126     static synth_float_t fastCosine(synth_float_t phase) {
127         // Factorial coefficients.
128         const synth_float_t IF2 = 1.0 / (2);
129         const synth_float_t IF4 = IF2 / (3 * 4);
130         const synth_float_t IF6 = IF4 / (5 * 6);
131         const synth_float_t IF8 = IF6 / (7 * 8);
132         const synth_float_t IF10 = IF8 / (9 * 10);
133 
134         /* Wrap phase back into region where results are more accurate. */
135         synth_float_t x = phase;
136         if (x < 0.0) {
137              x = 0.0 - phase;
138         }
139         int negate = 1;
140         if (x > M_PI_2) {
141             x = M_PI_2 - x;
142             negate = -1;
143         }
144 
145         synth_float_t x2 = (x * x);
146         /* Taylor expansion out to x**11/11! factored into multiply-adds */
147         synth_float_t cosine =
148                 1 + (x2 * (x2 * (x2 * (x2 * ((x2 * (-IF10)) + IF8) - IF6) + IF4) - IF2));
149         return cosine * negate;
150     }
151 
152 
153     /**
154      * Calculate random 32 bit number using linear-congruential method.
155      */
nextRandomInteger()156     static uint32_t nextRandomInteger() {
157         static uint64_t seed = 99887766;
158         // Use values for 64-bit sequence from MMIX by Donald Knuth.
159         seed = (seed * 6364136223846793005L) + 1442695040888963407L;
160         return (uint32_t) (seed >> 32); // The higher bits have a longer sequence.
161     }
162 
163     /**
164      * @return a random double between 0.0 and 1.0
165      */
nextRandomDouble()166     static double nextRandomDouble() {
167         const double scaler = 1.0 / (((uint64_t)1) << 32);
168         return nextRandomInteger() * scaler;
169     }
170 
171 };
172 };
173 #endif // SYNTHMARK_SYNTHTOOLS_H
174