xref: /aosp_15_r20/external/oboe/samples/iolib/src/main/cpp/player/SampleBuffer.cpp (revision 05767d913155b055644481607e6fa1e35e2fe72c)
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