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