1 /*
2  * Copyright (C) 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 
17 #include "SampleBuffer.h"
18 
19 // Resampler Includes
20 #include <resampler/MultiChannelResampler.h>
21 
22 #include "wav/WavStreamReader.h"
23 
24 using namespace resampler;
25 
26 namespace iolib {
27 
loadSampleData(parselib::WavStreamReader * reader)28 void SampleBuffer::loadSampleData(parselib::WavStreamReader* reader) {
29     // Although we read this in, at this time we know a-priori that the data is mono
30     mAudioProperties.channelCount = reader->getNumChannels();
31     mAudioProperties.sampleRate = reader->getSampleRate();
32 
33     reader->positionToAudio();
34 
35     mNumSamples = reader->getNumSampleFrames() * reader->getNumChannels();
36     mSampleData = new float[mNumSamples];
37 
38     reader->getDataFloat(mSampleData, reader->getNumSampleFrames());
39 }
40 
unloadSampleData()41 void SampleBuffer::unloadSampleData() {
42     if (mSampleData != nullptr) {
43         delete[] mSampleData;
44         mSampleData = nullptr;
45     }
46     mNumSamples = 0;
47 }
48 
49 class ResampleBlock {
50 public:
51     int32_t mSampleRate;
52     float*  mBuffer;
53     int32_t mNumFrames;
54 };
55 
resampleData(const ResampleBlock & input,ResampleBlock * output,int numChannels)56 void resampleData(const ResampleBlock& input, ResampleBlock* output, int numChannels) {
57     // Calculate output buffer size
58     double temp =
59             ((double)input.mNumFrames * (double)output->mSampleRate) / (double)input.mSampleRate;
60 
61     // round up
62     int32_t numOutFrames = (int32_t)(temp + 0.5);
63     // We iterate thousands of times through the loop. Roundoff error could accumulate
64     // so add a few more frames for padding
65     numOutFrames += 8;
66 
67     MultiChannelResampler *resampler = MultiChannelResampler::make(
68             numChannels, // channel count
69             input.mSampleRate, // input sampleRate
70             output->mSampleRate, // output sampleRate
71             MultiChannelResampler::Quality::Medium); // conversion quality
72 
73     float *inputBuffer = input.mBuffer;;     // multi-channel buffer to be consumed
74     float *outputBuffer = new float[numOutFrames];    // multi-channel buffer to be filled
75     output->mBuffer = outputBuffer;
76 
77     int numOutputFrames = 0;
78     int inputFramesLeft = input.mNumFrames;
79     while (inputFramesLeft > 0) {
80         if(resampler->isWriteNeeded()) {
81             resampler->writeNextFrame(inputBuffer);
82             inputBuffer += numChannels;
83             inputFramesLeft--;
84         } else {
85             resampler->readNextFrame(outputBuffer);
86             outputBuffer += numChannels;
87             numOutputFrames++;
88         }
89     }
90     output->mNumFrames = numOutputFrames;
91 
92     delete resampler;
93 }
94 
resampleData(int sampleRate)95 void SampleBuffer::resampleData(int sampleRate) {
96     if (mAudioProperties.sampleRate == sampleRate) {
97         // nothing to do
98         return;
99     }
100 
101     ResampleBlock inputBlock;
102     inputBlock.mBuffer = mSampleData;
103     inputBlock.mNumFrames = mNumSamples;
104     inputBlock.mSampleRate = mAudioProperties.sampleRate;
105 
106     ResampleBlock outputBlock;
107     outputBlock.mSampleRate = sampleRate;
108     iolib::resampleData(inputBlock, &outputBlock, mAudioProperties.channelCount);
109 
110     // delete previous samples
111     delete[] mSampleData;
112 
113     // install the resampled data
114     mSampleData = outputBlock.mBuffer;
115     mNumSamples = outputBlock.mNumFrames;
116     mAudioProperties.sampleRate = outputBlock.mSampleRate;
117 }
118 
119 } // namespace iolib
120