summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'audio/utils/src/Resampler.cpp')
-rw-r--r--audio/utils/src/Resampler.cpp292
1 files changed, 292 insertions, 0 deletions
diff --git a/audio/utils/src/Resampler.cpp b/audio/utils/src/Resampler.cpp
new file mode 100644
index 0000000..f63c69b
--- /dev/null
+++ b/audio/utils/src/Resampler.cpp
@@ -0,0 +1,292 @@
1/*
2 * Copyright (C) 2013 Texas Instruments
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// #define LOG_NDEBUG 0
18// #define VERY_VERBOSE_LOGGING
19
20#include <errno.h>
21#include <speex/speex_resampler.h>
22
23#include <tiaudioutils/Log.h>
24#include <tiaudioutils/Resampler.h>
25
26namespace tiaudioutils {
27
28Resampler::Resampler(const PcmParams &params, uint32_t quality)
29 : mInParams(params), mOutParams(params), mQuality(quality),
30 mAvail(0), mBufferFrames(0), mRatioNum(0), mRatioDen(1)
31{
32 createResampler();
33
34 /* initial buffer to hold the equivalent frames of input buffer size */
35 uint32_t frames = (mInParams.frameCount * mRatioNum) / mRatioDen;
36 reallocateBuffer(frames);
37}
38
39Resampler::Resampler(const PcmParams &inParams,
40 const PcmParams &outParams,
41 uint32_t quality)
42 : mInParams(inParams), mOutParams(outParams), mQuality(quality),
43 mAvail(0), mBufferFrames(0), mRatioNum(0), mRatioDen(1)
44{
45 createResampler();
46
47 /* initial buffer to hold the equivalent frames of input buffer size */
48 uint32_t frames = (mInParams.frameCount * mRatioNum) / mRatioDen;
49 reallocateBuffer(frames);
50}
51
52Resampler::~Resampler()
53{
54 if (mBuffer.i16)
55 delete [] mBuffer.i16;
56
57 if (mSpeexRsmp)
58 speex_resampler_destroy(mSpeexRsmp);
59}
60
61bool Resampler::initCheck() const
62{
63 if ((mInParams.sampleBits != 16) || (mOutParams.sampleBits != 16)) {
64 ALOGE("Resampler: %u bits/sample is not supported",
65 mInParams.sampleBits);
66 return false;
67 }
68
69 if (mInParams.channels != mOutParams.channels) {
70 ALOGE("Resampler: channel count mismatch, in %u out %u",
71 mInParams.channels, mOutParams.channels);
72 return false;
73 }
74
75 if (!mSpeexRsmp || !mBuffer.raw)
76 return false;
77
78 return true;
79}
80
81int Resampler::setInSampleRate(uint32_t rate)
82{
83 AutoMutex lock(mLock);
84
85 if (rate == mInParams.sampleRate)
86 return 0;
87
88 ALOGV("Resampler: set new input sample rate %u", rate);
89
90 int ret = speex_resampler_set_rate(mSpeexRsmp,
91 rate,
92 mOutParams.sampleRate);
93 if (ret) {
94 ALOGE("Resampler: failed to set new input sample rate: %s",
95 speex_resampler_strerror(ret));
96 return ret;
97 }
98
99 mInParams.sampleRate = rate;
100 speex_resampler_get_ratio(mSpeexRsmp, &mRatioNum, &mRatioDen);
101
102 uint32_t frames = (mInParams.frameCount * mRatioNum) / mRatioDen;
103 if (frames > mBufferFrames)
104 reallocateBuffer(frames);
105
106 return 0;
107}
108
109int Resampler::setOutSampleRate(uint32_t rate)
110{
111 AutoMutex lock(mLock);
112
113 if (rate == mOutParams.sampleRate)
114 return 0;
115
116 ALOGV("Resampler: set new output sample rate %u", rate);
117
118 int ret = speex_resampler_set_rate(mSpeexRsmp,
119 mInParams.sampleRate,
120 rate);
121 if (ret) {
122 ALOGE("Resampler: failed to set new output sample rate: %s",
123 speex_resampler_strerror(ret));
124 return ret;
125 }
126
127 mOutParams.sampleRate = rate;
128 speex_resampler_get_ratio(mSpeexRsmp, &mRatioNum, &mRatioDen);
129
130 uint32_t frames = (mInParams.frameCount * mRatioNum) / mRatioDen;
131 if (frames > mBuffer.frameCount)
132 reallocateBuffer(frames);
133
134 return 0;
135}
136
137void Resampler::getRatio(uint32_t &num, uint32_t &den) const
138{
139 num = mRatioNum;
140 den = mRatioDen;
141}
142
143int Resampler::resample(BufferProvider &provider,
144 void *outBuffer,
145 uint32_t outFrames)
146{
147 if (!outBuffer)
148 return -EINVAL;
149
150 if (!outFrames)
151 return 0;
152
153 AutoMutex lock(mLock);
154
155 /*
156 * Calculate the number of frames required on the input side to
157 * produce the requested output frames. Intermediate buffer is
158 * resized accordingly.
159 */
160 uint32_t reqInFrames = (outFrames * mRatioNum) / mRatioDen + 1;
161 if (reqInFrames > mBuffer.frameCount)
162 reallocateBuffer(reqInFrames);
163
164 uint32_t written = 0;
165 while (written < outFrames) {
166 if (mAvail < reqInFrames) {
167 BufferProvider::Buffer buf;
168
169 buf.frameCount = reqInFrames - mAvail;
170
171 int ret = provider.getNextBuffer(&buf);
172 if (ret) {
173 ALOGE("Resampler: failed to get next buffer %d", ret);
174 return ret;
175 }
176
177 /* append new buffer to existing frames in local buffer */
178 memcpy(mBuffer.i8 + mOutParams.framesToBytes(mAvail),
179 buf.i8,
180 mOutParams.framesToBytes(buf.frameCount));
181 mAvail += buf.frameCount;
182
183 provider.releaseBuffer(&buf);
184 }
185
186 uint32_t framesIn = mAvail;
187 uint32_t framesOut = outFrames - written;
188 int16_t *bufferIn = mBuffer.i16;
189 int16_t *bufferOut = (int16_t *)outBuffer + (written * mOutParams.channels);
190
191 /* resample */
192 if (mOutParams.channels == 1) {
193 speex_resampler_process_int(mSpeexRsmp,
194 0,
195 bufferIn,
196 &framesIn,
197 bufferOut,
198 &framesOut);
199 } else {
200 speex_resampler_process_interleaved_int(mSpeexRsmp,
201 bufferIn,
202 &framesIn,
203 bufferOut,
204 &framesOut);
205 }
206 written += framesOut;
207 mAvail -= framesIn;
208
209 /* move samples left to the beginning of the local buffer */
210 if (mAvail) {
211 memmove(mBuffer.raw,
212 mBuffer.i8 + mOutParams.framesToBytes(framesIn),
213 mOutParams.framesToBytes(mAvail));
214 }
215 }
216
217 ALOGW_IF(written != outFrames,
218 "Resampler: frame count mismatch, req %u written %u", outFrames, written);
219
220 return 0;
221}
222
223int Resampler::resample(const void *inBuffer, uint32_t &inFrames,
224 void *outBuffer, uint32_t &outFrames)
225{
226 AutoMutex lock(mLock);
227
228 /* resample */
229 if (mOutParams.channels == 1) {
230 speex_resampler_process_int(mSpeexRsmp,
231 0,
232 (int16_t *)inBuffer,
233 &inFrames,
234 (int16_t *)outBuffer,
235 &outFrames);
236 } else {
237 speex_resampler_process_interleaved_int(mSpeexRsmp,
238 (int16_t *)inBuffer,
239 &inFrames,
240 (int16_t *)outBuffer,
241 &outFrames);
242 }
243
244 return 0;
245}
246
247void Resampler::createResampler()
248{
249 ALOGV("Resampler: create speex resampler %u to %u Hz",
250 mInParams.sampleRate, mOutParams.sampleRate);
251
252 if (mQuality > SPEEX_RESAMPLER_QUALITY_MAX)
253 mQuality = SPEEX_RESAMPLER_QUALITY_MAX;
254
255 int ret;
256 mSpeexRsmp = speex_resampler_init(mInParams.channels,
257 mInParams.sampleRate,
258 mOutParams.sampleRate,
259 mQuality,
260 &ret);
261 if (!mSpeexRsmp) {
262 ALOGE("Resampler: failed to create Speex resampler: %s",
263 speex_resampler_strerror(ret));
264 return;
265 }
266
267 speex_resampler_reset_mem(mSpeexRsmp);
268 speex_resampler_get_ratio(mSpeexRsmp, &mRatioNum, &mRatioDen);
269}
270
271void Resampler::reallocateBuffer(uint32_t frames)
272{
273 /* current buffer is large enough */
274 if (frames < mBufferFrames)
275 return;
276
277 int16_t *oldBuf = mBuffer.i16;
278 mBufferFrames = frames;
279
280 /* keep the frame count with the headroom frames under the hood */
281 mBuffer.frameCount = mBufferFrames + kHeadRoomFrames;
282 mBuffer.i16 = new int16_t[mBuffer.frameCount * mInParams.channels];
283
284 /* copy frames in the old buffer to the new larger buffer */
285 if (mAvail)
286 memcpy(mBuffer.raw, oldBuf, mInParams.framesToBytes(mAvail));
287
288 if (oldBuf)
289 delete [] oldBuf;
290}
291
292} /* namespace tiaudioutils */