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 // 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