1 /* 2 * Copyright 2019 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 17 #include <math.h> 18 19 #include "SincResamplerStereo.h" 20 21 using namespace resampler; 22 23 #define STEREO 2 24 SincResamplerStereo(const MultiChannelResampler::Builder & builder)25SincResamplerStereo::SincResamplerStereo(const MultiChannelResampler::Builder &builder) 26 : SincResampler(builder) { 27 assert(builder.getChannelCount() == STEREO); 28 } 29 writeFrame(const float * frame)30void SincResamplerStereo::writeFrame(const float *frame) { 31 // Move cursor before write so that cursor points to last written frame in read. 32 if (--mCursor < 0) { 33 mCursor = getNumTaps() - 1; 34 } 35 float *dest = &mX[mCursor * STEREO]; 36 const int offset = mNumTaps * STEREO; 37 // Write each channel twice so we avoid having to wrap when running the FIR. 38 const float left = frame[0]; 39 const float right = frame[1]; 40 // Put ordered writes together. 41 dest[0] = left; 42 dest[1] = right; 43 dest[offset] = left; 44 dest[1 + offset] = right; 45 } 46 47 // Multiply input times windowed sinc function. readFrame(float * frame)48void SincResamplerStereo::readFrame(float *frame) { 49 // Clear accumulator for mixing. 50 std::fill(mSingleFrame.begin(), mSingleFrame.end(), 0.0); 51 std::fill(mSingleFrame2.begin(), mSingleFrame2.end(), 0.0); 52 53 // Determine indices into coefficients table. 54 double tablePhase = getIntegerPhase() * mPhaseScaler; 55 int index1 = static_cast<int>(floor(tablePhase)); 56 float *coefficients1 = &mCoefficients[index1 * getNumTaps()]; 57 int index2 = (index1 + 1); 58 if (index2 >= mNumRows) { // no guard row needed because we wrap the indices 59 index2 = 0; 60 } 61 float *coefficients2 = &mCoefficients[index2 * getNumTaps()]; 62 float *xFrame = &mX[mCursor * getChannelCount()]; 63 for (int i = 0; i < mNumTaps; i++) { 64 float coefficient1 = *coefficients1++; 65 float coefficient2 = *coefficients2++; 66 for (int channel = 0; channel < getChannelCount(); channel++) { 67 float sample = *xFrame++; 68 mSingleFrame[channel] += sample * coefficient1; 69 mSingleFrame2[channel] += sample * coefficient2; 70 } 71 } 72 73 // Interpolate and copy to output. 74 float fraction = tablePhase - index1; 75 for (int channel = 0; channel < getChannelCount(); channel++) { 76 float low = mSingleFrame[channel]; 77 float high = mSingleFrame2[channel]; 78 frame[channel] = low + (fraction * (high - low)); 79 } 80 } 81