1 /*
2  * Copyright 2022 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 package org.hyphonate.megaaudio.player.sources;
17 
18 /**
19  * An AudioSourceProvider for multi-channel sine waves with control over which
20  * channels have audio data and which channels have silence.
21  */
22 public class SparseChannelAudioSource extends WaveTableSource {
23     /**
24      * The number of SAMPLES in the Sin Wave table.
25      * This is plenty of samples for a clear sine wave.
26      * the + 1 is to avoid special handling of the interpolation on the last sample.
27      */
28     static final int WAVETABLE_LENGTH = 2049;
29 
30     int mChannelsMask;
31 
SparseChannelAudioSource(int mask)32     public SparseChannelAudioSource(int mask) {
33         super();
34         float[] waveTbl = new float[WAVETABLE_LENGTH];
35         WaveTableSource.genSinWave(waveTbl);
36 
37         setWaveTable(waveTbl);
38 
39         mChannelsMask = mask;
40     }
41 
setMask(int mask)42     public void setMask(int mask) {
43         mChannelsMask = mask;
44     }
45 
channelNumToMask(int chanNum)46     private int channelNumToMask(int chanNum) {
47         if (chanNum <= 0) {
48             return 0;
49         }
50         return 1 << (chanNum - 1);
51     }
52 
53     @Override
pull(float[] buffer, int numFrames, int numChans)54     public int pull(float[] buffer, int numFrames, int numChans) {
55         final 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) mNumWaveTblSamples) {
60                 mSrcPhase -= (float) mNumWaveTblSamples;
61             }
62 
63             // linear-interpolate
64             int srcIndex = (int) mSrcPhase;
65             float delta0 = mSrcPhase - (float) srcIndex;
66             float delta1 = 1.0f - delta0;
67             float value = ((mWaveTbl[srcIndex] * delta0) + (mWaveTbl[srcIndex + 1] * delta1));
68 
69             // Put the same value in all channels.
70             // This is inefficient and should be pulled out of this loop
71             for (int chanIndex = 0; chanIndex < numChans; chanIndex++) {
72                 if ((mChannelsMask & (1 << chanIndex)) != 0) {
73                     buffer[outIndex++] = value;
74                 } else {
75                     buffer[outIndex++] = 0.0f;
76                 }
77             }
78 
79             mSrcPhase += phaseIncr;
80         }
81 
82         return numFrames;
83     }
84 
85 }
86