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