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