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