1 /*
2  * Copyright 2020 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 #include <math.h>
17 
18 #include "WaveTableSource.h"
19 
20 /**
21  * Constructor. Sets up to play samples from the provided wave table.
22  * @param waveTbl Contains the samples defining a single cycle of the desired waveform.
23  */
WaveTableSource()24 WaveTableSource::WaveTableSource() {
25     reset();
26 }
27 
setSampleRate(int sampleRate)28 void WaveTableSource::setSampleRate(int sampleRate) {
29     mSampleRate = sampleRate;
30     calcFN();
31 }
32 
33 /**
34  * Calculates the "Nominal" frequency of the wave table.
35  */
calcFN()36 void WaveTableSource::calcFN() {
37     mFN = mSampleRate / (float)mNumWaveTableSamples;
38     mFNInverse = 1.0f / mFN;
39 }
40 
getNumChannels()41 int WaveTableSource::getNumChannels() {
42     return NUMCHANNELS_UNSPECIFIED;
43 }
44 
getEncoding()45 int WaveTableSource::getEncoding() {
46     return ENCODING_FLOAT;
47 }
48 
49 /**
50  * Fills the specified buffer with values generated from the wave table which will playback
51  * at the specified frequency.
52  *
53  * @param buffer The buffer to be filled.
54  * @param numFrames The number of frames of audio to provide.
55  * @param numChans The number of channels (in the buffer) required by the player.
56  * @return  The number of samples generated. Since we are generating a continuous periodic
57  * signal, this will always be <code>numFrames</code>.
58  */
pull(float * buffer,int numFrames,int numChans)59 int WaveTableSource::pull(float* buffer, int numFrames, int numChans) {
60     float phaseIncr = mFreq * mFNInverse;
61     int outIndex = 0;
62     for (int frameIndex = 0; frameIndex < numFrames; frameIndex++) {
63         // 'mod' back into the waveTable
64         while (mSrcPhase >= (float)mNumWaveTableSamples) {
65             mSrcPhase -= (float)mNumWaveTableSamples;
66         }
67 
68         // linear-interpolate
69         int srcIndex = (int)mSrcPhase;
70         float delta = mSrcPhase - (float)srcIndex;
71         float s0 = mWaveTable[srcIndex];
72         float s1 = mWaveTable[srcIndex + 1];
73         float value = s0 + ((s1 - s0) * delta);
74 
75         // Put the same value in all channels.
76         for (int chanIndex = 0; chanIndex < numChans; chanIndex++) {
77             buffer[outIndex++] = value;
78         }
79 
80         mSrcPhase += phaseIncr;
81     }
82 
83     return numFrames;
84 }
85 
86 /*
87  * Standard wavetable generators
88  */
genSinWave(float * buffer,int length)89 void WaveTableSource::genSinWave(float* buffer, int length) {
90     float incr = ((float)M_PI  * 2.0f) / (float)(length - 1);
91     for(int index = 0; index < length; index++) {
92         buffer[index] = sinf(index * incr);
93     }
94 }
95 
genTriangleWave(float * buffer,int size,float maxValue,float minValue,float dutyCycle)96 void WaveTableSource::genTriangleWave(float* buffer, int size,
97                                         float maxValue, float minValue, float dutyCycle) {
98     float range = maxValue - minValue;
99 
100     // Make a triangle that goes 0 -> max -> min -> 0.
101     int index = 0;
102     int phase0Size = (int) (size / 2 * dutyCycle);
103 
104     int breakIndex = phase0Size;
105     float val = 0;
106     // Phase 0 (0 -> max)
107     if (phase0Size != 0) {
108         float phase0Incr = maxValue / (float) phase0Size;
109         for (; index < breakIndex; ++index) {
110             buffer[index] = val;
111             val += phase0Incr;
112         }
113     } else {
114         val = maxValue;
115     }
116 
117     // Phase 1 & 2 (max -> min)
118     breakIndex = size - phase0Size;
119     float incr = -range / ((float) size * (1.0f - dutyCycle));
120     for (; index < breakIndex; ++index) {
121         buffer[index] = val;
122         val += incr;
123     }
124 
125     // Phase 3 (min -> 0)
126     if (phase0Size != 0) {
127         float phase0Incr = maxValue / (float) phase0Size;
128         for (; index < size; ++index) {
129             buffer[index] = val;
130             val += phase0Incr;
131         }
132     }
133 }
134 
genPulseWave(float * buffer,int size,float maxValue,float minValue,float dutyCycle)135 void WaveTableSource::genPulseWave(float* buffer, int size,
136                                     float maxValue, float minValue, float dutyCycle) {
137     int index = 0;
138     int breakIndex = (int) (size * dutyCycle);
139     for (; index < breakIndex; ++index) {
140         buffer[index] = maxValue;
141     }
142     for (; index < size; ++index) {
143         buffer[index] = minValue;
144     }
145 }
146 
147