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