xref: /aosp_15_r20/external/oboe/apps/OboeTester/app/src/main/cpp/synth/PitchToFrequency.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  * This code was translated from the JSyn Java code.
17  * JSyn is Copyright 2009 Phil Burk, Mobileer Inc
18  * JSyn is licensed under the Apache License, Version 2.0
19  */
20 
21 #ifndef SYNTHMARK_PITCH_TO_FREQUENCY_H
22 #define SYNTHMARK_PITCH_TO_FREQUENCY_H
23 
24 #include <cstdint>
25 #include <math.h>
26 #include "SynthTools.h"
27 #include "LookupTable.h"
28 
29 namespace marksynth {
30 
31 constexpr int kSemitonesPerOctave = 12;
32 // Pitches are in semitones based on the MIDI standard.
33 constexpr int kPitchMiddleC = 60;
34 constexpr double kFrequencyMiddleC  = 261.625549;
35 
36 class PowerOfTwoTable : public LookupTable {
37 public:
PowerOfTwoTable(int32_t numEntries)38     PowerOfTwoTable(int32_t numEntries)
39         : LookupTable(numEntries)
40         {
41             fillTable();
42         }
43 
~PowerOfTwoTable()44     virtual ~PowerOfTwoTable() {}
45 
calculate(float input)46     virtual float calculate(float input) override {
47         return powf(2.0f, input);
48     }
49 };
50 
51 class PitchToFrequency
52 {
53 public:
PitchToFrequency()54     PitchToFrequency() {}
55 
~PitchToFrequency()56     virtual ~PitchToFrequency() {
57     }
58 
convertPitchToFrequency(double pitch)59     static double convertPitchToFrequency(double pitch) {
60         double exponent = (pitch - kPitchMiddleC) * (1.0 / kSemitonesPerOctave);
61         return kFrequencyMiddleC * pow(2.0, exponent);
62     }
63 
lookupPitchToFrequency(synth_float_t pitch)64     synth_float_t lookupPitchToFrequency(synth_float_t pitch) {
65         // Only calculate if input changed since last time.
66         if (pitch != lastInput) {
67             synth_float_t octavePitch = (pitch - kPitchMiddleC) * (1.0 / kSemitonesPerOctave);
68             int32_t octaveIndex = (int) floor(octavePitch);
69             synth_float_t fractionalOctave = octavePitch - octaveIndex;
70 
71             // Do table lookup.
72             synth_float_t value = kFrequencyMiddleC * mPowerTable.lookup(fractionalOctave);
73 
74             // Adjust for octave by multiplying by a power of 2. Allow for +/- 16 octaves;
75             const int32_t octaveOffset = 16;
76             synth_float_t octaveScaler = ((synth_float_t)(1 << (octaveIndex + octaveOffset)))
77                 * (1.0 / (1 << octaveOffset));
78             value *= octaveScaler;
79 
80             lastInput = pitch;
81             lastOutput = value;
82         }
83         return lastOutput;
84     }
85 
86     /**
87      * @param pitches an array of fractional MIDI pitches
88      */
generate(const synth_float_t * pitches,synth_float_t * frequencies,int32_t count)89     void generate(const synth_float_t *pitches, synth_float_t *frequencies, int32_t count) {
90         for (int i = 0; i < count; i++) {
91             frequencies[i] = lookupPitchToFrequency(pitches[i]);
92         }
93     }
94 
95 private:
96     static PowerOfTwoTable mPowerTable;
97 
98     synth_float_t lastInput = kPitchMiddleC;
99     synth_float_t lastOutput = kFrequencyMiddleC;
100 
101 };
102 
103 };
104 #endif // SYNTHMARK_PITCH_TO_FREQUENCY_H
105