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